config,arch,cpu,kern,sim: Extract kernel information from System.

Information about what kernel to load and how to load it was built
into the System object and its subclasses. That overloaded the System
object and made it responsible for too many things, and also was
somewhat awkward when working with SE mode which doesn't have a kernel.

This change extracts the kernel and information related to it from the
System object and puts into into a OsKernel or Workload object.
Currently the idea of a "Workload" to run and a kernel are a bit
muddled, an unfortunate carry-over from the original code. It's also an
implication of trying not to make too sweeping of a change, and to
minimize the number of times configs need to change, ie avoiding
creating a "kernel" parameter which would shortly thereafter be
renamed to "workload".

In future changes, the ideas of a kernel and a workload will be
disentangled, and workloads will be expanded to include emulated
operating systems which shephard and contain Process-es for syscall
emulation.

This change was originally split into pieces to make reviewing it
easier. Those reviews are here:

https: //gem5-review.googlesource.com/c/public/gem5/+/22243
https: //gem5-review.googlesource.com/c/public/gem5/+/24144
https: //gem5-review.googlesource.com/c/public/gem5/+/24145
https: //gem5-review.googlesource.com/c/public/gem5/+/24146
https: //gem5-review.googlesource.com/c/public/gem5/+/24147
https: //gem5-review.googlesource.com/c/public/gem5/+/24286

Change-Id: Ia3d863db276a023b6a2c7ee7a656d8142ff75589
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/26466
Reviewed-by: Gabe Black <gabeblack@google.com>
Maintainer: Gabe Black <gabeblack@google.com>
Tested-by: kokoro <noreply+kokoro@google.com>
This commit is contained in:
Gabe Black
2019-10-28 18:55:02 -07:00
parent ba78eaf876
commit 73fdc2eb57
63 changed files with 2384 additions and 1726 deletions

View File

@@ -123,10 +123,6 @@ def makeSparcSystem(mem_mode, mdesc=None, cmdline=None):
AddrRange(Addr('2GB'), size ='256MB')]
self.bridge.master = self.iobus.slave
self.bridge.slave = self.membus.master
self.rom.port = self.membus.master
self.nvram.port = self.membus.master
self.hypervisor_desc.port = self.membus.master
self.partition_desc.port = self.membus.master
self.intrctrl = IntrControl()
self.disk0 = CowMmDisk()
self.disk0.childImage(mdesc.disks()[0])
@@ -150,15 +146,37 @@ def makeSparcSystem(mem_mode, mdesc=None, cmdline=None):
AddrRange(self.t1000.hvuart.pio_addr,
self.t1000.hvuart.pio_addr + uart_pio_size - 1)
]
self.reset_bin = binary('reset_new.bin')
self.hypervisor_bin = binary('q_new.bin')
self.openboot_bin = binary('openboot_new.bin')
self.nvram_bin = binary('nvram1')
self.hypervisor_desc_bin = binary('1up-hv.bin')
self.partition_desc_bin = binary('1up-md.bin')
workload = SparcFsWorkload(
reset_bin=binary('reset_new.bin'),
hypervisor_bin=binary('q_new.bin'),
openboot_bin=binary('openboot_new.bin'),
nvram_bin=binary('nvram1'),
hypervisor_desc_bin=binary('1up-hv.bin'),
partition_desc_bin=binary('1up-md.bin'),
)
# ROM for OBP/Reset/Hypervisor
self.rom = SimpleMemory(range=AddrRange(workload._rom_base, size='8MB'))
# nvram
self.nvram = SimpleMemory(
range=AddrRange(workload._nvram_base, size='8kB'))
# hypervisor description
self.hypervisor_desc = SimpleMemory(
range=AddrRange(workload._hypervisor_desc_base, size='8kB'))
# partition description
self.partition_desc = SimpleMemory(
range=AddrRange(workload._partition_desc_base, size='8kB'))
self.rom.port = self.membus.master
self.nvram.port = self.membus.master
self.hypervisor_desc.port = self.membus.master
self.partition_desc.port = self.membus.master
self.system_port = self.membus.slave
self.workload = workload
return self
def makeArmSystem(mem_mode, machine_type, num_cpus=1, mdesc=None,
@@ -169,10 +187,7 @@ def makeArmSystem(mem_mode, machine_type, num_cpus=1, mdesc=None,
pci_devices = []
if bare_metal:
self = ArmSystem()
else:
self = LinuxArmSystem()
self = ArmSystem()
if not mdesc:
# generic system
@@ -242,11 +257,13 @@ def makeArmSystem(mem_mode, machine_type, num_cpus=1, mdesc=None,
# EOT character on UART will end the simulation
self.realview.uart[0].end_on_eot = True
else:
if dtb_filename:
self.dtb_filename = binary(dtb_filename)
workload = ArmFsLinux()
self.machine_type = machine_type if machine_type in ArmMachineType.map \
else "DTOnly"
if dtb_filename:
workload.dtb_filename = binary(dtb_filename)
workload.machine_type = \
machine_type if machine_type in ArmMachineType.map else "DTOnly"
# Ensure that writes to the UART actually go out early in the boot
if not cmdline:
@@ -254,8 +271,6 @@ def makeArmSystem(mem_mode, machine_type, num_cpus=1, mdesc=None,
'lpj=19988480 norandmaps rw loglevel=8 ' + \
'mem=%(mem)s root=%(rootdev)s'
self.realview.setupBootLoader(self, binary, bootloader)
if hasattr(self.realview.gic, 'cpu_addr'):
self.gic_cpu_addr = self.realview.gic.cpu_addr
@@ -292,7 +307,11 @@ def makeArmSystem(mem_mode, machine_type, num_cpus=1, mdesc=None,
"androidboot.selinux=permissive " + \
"video=Virtual-1:1920x1080-16"
self.boot_osflags = fillInCmdline(mdesc, cmdline)
workload.command_line = fillInCmdline(mdesc, cmdline)
self.workload = workload
self.realview.setupBootLoader(self, binary)
if external_memory:
# I/O traffic enters iobus
@@ -381,7 +400,7 @@ def makeLinuxMipsSystem(mem_mode, mdesc=None, cmdline=None):
self.console = binary('mips/console')
if not cmdline:
cmdline = 'root=/dev/hda1 console=ttyS0'
self.boot_osflags = fillInCmdline(mdesc, cmdline)
self.workload = OsKernel(command_line=fillInCmdline(mdesc, cmdline))
self.system_port = self.membus.slave
@@ -445,9 +464,12 @@ def connectX86RubySystem(x86_sys):
x86_sys.pc.attachIO(x86_sys.iobus, x86_sys._dma_ports)
def makeX86System(mem_mode, numCPUs=1, mdesc=None, self=None, Ruby=False):
if self == None:
self = X86System()
def makeX86System(mem_mode, numCPUs=1, mdesc=None, workload=None, Ruby=False):
self = X86System()
if workload is None:
workload = X86FsWorkload()
self.workload = workload
if not mdesc:
# generic system
@@ -489,7 +511,7 @@ def makeX86System(mem_mode, numCPUs=1, mdesc=None, self=None, Ruby=False):
# Add in a Bios information structure.
structures = [X86SMBiosBiosInformation()]
self.smbios_table.structures = structures
workload.smbios_table.structures = structures
# Set up the Intel MP table
base_entries = []
@@ -509,8 +531,8 @@ def makeX86System(mem_mode, numCPUs=1, mdesc=None, self=None, Ruby=False):
self.pc.south_bridge.io_apic.apic_id = io_apic.id
base_entries.append(io_apic)
# In gem5 Pc::calcPciConfigAddr(), it required "assert(bus==0)",
# but linux kernel cannot config PCI device if it was not connected to PCI bus,
# so we fix PCI bus id to 0, and ISA bus id to 1.
# but linux kernel cannot config PCI device if it was not connected to
# PCI bus, so we fix PCI bus id to 0, and ISA bus id to 1.
pci_bus = X86IntelMPBus(bus_id = 0, bus_type='PCI ')
base_entries.append(pci_bus)
isa_bus = X86IntelMPBus(bus_id = 1, bus_type='ISA ')
@@ -550,15 +572,15 @@ def makeX86System(mem_mode, numCPUs=1, mdesc=None, self=None, Ruby=False):
assignISAInt(1, 1)
for i in range(3, 15):
assignISAInt(i, i)
self.intel_mp_table.base_entries = base_entries
self.intel_mp_table.ext_entries = ext_entries
workload.intel_mp_table.base_entries = base_entries
workload.intel_mp_table.ext_entries = ext_entries
return self
def makeLinuxX86System(mem_mode, numCPUs=1, mdesc=None, Ruby=False,
cmdline=None):
self = LinuxX86System()
# Build up the x86 system and then specialize it for Linux
makeX86System(mem_mode, numCPUs, mdesc, self, Ruby)
self = makeX86System(mem_mode, numCPUs, mdesc, X86FsLinux(), Ruby)
# We assume below that there's at least 1MB of memory. We'll require 2
# just to avoid corner cases.
@@ -596,12 +618,12 @@ def makeLinuxX86System(mem_mode, numCPUs=1, mdesc=None, Ruby=False,
entries.append(X86E820Entry(addr = 0x100000000,
size = '%dB' % (self.mem_ranges[1].size()), range_type = 1))
self.e820_table.entries = entries
self.workload.e820_table.entries = entries
# Command line
if not cmdline:
cmdline = 'earlyprintk=ttyS0 console=ttyS0 lpj=7999923 root=/dev/hda1'
self.boot_osflags = fillInCmdline(mdesc, cmdline)
self.workload.command_line = fillInCmdline(mdesc, cmdline)
return self

View File

@@ -125,7 +125,7 @@ def config_mem(options, system):
port_data=opt_tlm_memory,
port=system.membus.master,
addr_ranges=system.mem_ranges)
system.kernel_addr_check = False
system.workload.addr_check = False
return
if opt_external_memory_system:
@@ -133,7 +133,7 @@ def config_mem(options, system):
port_type=opt_external_memory_system,
port_data="init_mem0", port=xbar.master,
addr_ranges=system.mem_ranges)
subsystem.kernel_addr_check = False
subsystem.workload.addr_check = False
return
nbr_mem_ctrls = opt_mem_channels

View File

@@ -98,7 +98,8 @@ def create(args):
args.mem_size,
platform=VExpress_GEM5_V2(),
mem_mode=mem_mode,
kernel=args.kernel,
workload=ArmFsWorkload(
object_file=args.kernel),
readfile=args.readfile)
MemConfig.config_mem(args, system)
@@ -215,7 +216,7 @@ def main():
if args.dtb_gen:
# No run, autogenerate DTB and exit
root.system.generateDtb(m5.options.outdir, 'system.dtb')
root.system.generateDtb(os.path.join(m5.options.outdir, 'system.dtb'))
else:
run(args)

View File

@@ -118,9 +118,10 @@ def createSystem(caches, kernel, bootscript, machine_type="VExpress_GEM5",
platform = ObjectList.platform_list.get(machine_type)
m5.util.inform("Simulated platform: %s", platform.__name__)
sys = devices.simpleSystem(LinuxArmSystem,
sys = devices.simpleSystem(ArmSystem,
caches, mem_size, platform(),
kernel=SysPaths.binary(kernel),
workload=ArmFsLinux(
object_file=SysPaths.binary(kernel)),
readfile=bootscript)
sys.mem_ctrls = [ SimpleMemory(range=r, port=sys.membus.master)
@@ -243,9 +244,9 @@ def build(options):
root.system = system
if options.kernel_cmd:
system.boot_osflags = options.kernel_cmd
system.workload.command_line = options.kernel_cmd
else:
system.boot_osflags = " ".join(kernel_cmd)
system.workload.command_line = " ".join(kernel_cmd)
if options.big_cpus + options.little_cpus == 0:
m5.util.panic("Empty CPU clusters")
@@ -287,9 +288,11 @@ def build(options):
# Linux device tree
if options.dtb is not None:
system.dtb_filename = SysPaths.binary(options.dtb)
system.workload.dtb_filename = SysPaths.binary(options.dtb)
else:
system.generateDtb(m5.options.outdir, 'system.dtb')
system.workload.dtb_filename = \
os.path.join(m5.options.outdir, 'system.dtb')
system.generateDtb(system.workload.dtb_filename)
if devices.have_fastmodel and issubclass(big_model, FastmodelCluster):
from m5 import arm_fast_model as fm, systemc as sc

View File

@@ -99,11 +99,13 @@ def create(args):
# Only simulate caches when using a timing CPU (e.g., the HPI model)
want_caches = True if mem_mode == "timing" else False
system = devices.simpleSystem(LinuxArmSystem,
system = devices.simpleSystem(ArmSystem,
want_caches,
args.mem_size,
mem_mode=mem_mode,
kernel=SysPaths.binary(args.kernel),
workload=ArmFsLinux(
object_file=
SysPaths.binary(args.kernel)),
readfile=args.script)
MemConfig.config_mem(args, system)
@@ -146,10 +148,12 @@ def create(args):
system.realview.setupBootLoader(system, SysPaths.binary)
if args.dtb:
system.dtb_filename = args.dtb
system.workload.dtb_filename = args.dtb
else:
# No DTB specified: autogenerate DTB
system.generateDtb(m5.options.outdir, 'system.dtb')
system.workload.dtb_filename = \
os.path.join(m5.options.outdir, 'system.dtb')
system.generateDtb(system.workload.dtb_filename)
# Linux boot command flags
kernel_cmd = [
@@ -161,13 +165,13 @@ def create(args):
# memory layout.
"norandmaps",
# Tell Linux where to find the root disk image.
"root=/dev/vda1",
"root=/dev/vda",
# Mount the root disk read-write by default.
"rw",
# Tell Linux about the amount of physical memory present.
"mem=%s" % args.mem_size,
]
system.boot_osflags = " ".join(kernel_cmd)
system.workload.command_line = " ".join(kernel_cmd)
return system

View File

@@ -124,7 +124,7 @@ def build_test_system(np):
test_sys.cpu_voltage_domain)
if options.kernel is not None:
test_sys.kernel = binary(options.kernel)
test_sys.workload.object_file = binary(options.kernel)
if options.script is not None:
test_sys.readfile = options.script
@@ -269,7 +269,7 @@ def build_drive_system(np):
drive_sys.cpu.createInterruptController()
drive_sys.cpu.connectAllPorts(drive_sys.membus)
if options.kernel is not None:
drive_sys.kernel = binary(options.kernel)
drive_sys.workload.object_file = binary(options.kernel)
if ObjectList.is_kvm_cpu(DriveCPUClass):
drive_sys.kvm_vm = KvmVM()
@@ -369,7 +369,9 @@ if buildEnv['TARGET_ISA'] == "arm" and not options.bare_metal \
for sysname in ('system', 'testsys', 'drivesys'):
if hasattr(root, sysname):
sys = getattr(root, sysname)
sys.generateDtb(m5.options.outdir, '%s.dtb' % sysname)
sys.workload.dtb_filename = \
os.path.join(m5.options.outdir, '%s.dtb' % sysname)
sys.generateDtb(sys.workload.dtb_filename)
Simulation.setWorkCountOptions(test_sys, options)
Simulation.run(options, root, test_sys, FutureClass)

View File

@@ -50,6 +50,7 @@ import os
import m5
from m5.defines import buildEnv
from m5.objects import *
from m5.params import NULL
from m5.util import addToPath, fatal, warn
addToPath('../')
@@ -171,7 +172,8 @@ np = options.num_cpus
system = System(cpu = [CPUClass(cpu_id=i) for i in range(np)],
mem_mode = test_mem_mode,
mem_ranges = [AddrRange(options.mem_size)],
cache_line_size = options.cacheline_size)
cache_line_size = options.cacheline_size,
workload = NULL)
if numThreads > 1:
system.multi_thread = True

View File

@@ -0,0 +1,90 @@
# Copyright (c) 2009, 2012-2013, 2015-2019 ARM Limited
# All rights reserved.
#
# The license below extends only to copyright in the software and shall
# not be construed as granting a license to any other intellectual
# property including but not limited to intellectual property relating
# to a hardware implementation of the functionality of the software
# licensed hereunder. You may use the software subject to the license
# terms below provided that you ensure that this notice is replicated
# unmodified and in its entirety in all distributions of the software,
# modified or unmodified, in source code or in binary form.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from m5.params import *
from m5.options import *
from m5.SimObject import *
from m5.objects.OsKernel import OsKernel
class ArmMachineType(Enum):
map = {
'VExpress_EMM' : 2272,
'VExpress_EMM64' : 2272,
'DTOnly' : -1,
}
class ArmFsWorkload(OsKernel):
type = 'ArmFsWorkload'
cxx_header = "arch/arm/fs_workload.hh"
cxx_class = "ArmISA::FsWorkload"
load_addr_mask = 0
boot_loader = VectorParam.String([],
"File that contains the boot loader code. Zero or more files may be "
"specified. The first boot loader that matches the kernel's "
"architecture will be used.")
dtb_filename = Param.String("",
"File that contains the Device Tree Blob. Don't use DTB if empty.")
machine_type = Param.ArmMachineType('DTOnly',
"Machine id from http://www.arm.linux.org.uk/developer/machines/")
atags_addr = Param.Addr("Address where default atags structure should " \
"be written")
early_kernel_symbols = Param.Bool(False,
"enable early kernel symbol tables before MMU")
enable_context_switch_stats_dump = Param.Bool(False,
"enable stats/task info dumping at context switch boundaries")
panic_on_panic = Param.Bool(False, "Trigger a gem5 panic if the " \
"guest kernel panics")
panic_on_oops = Param.Bool(False, "Trigger a gem5 panic if the " \
"guest kernel oopses")
class ArmFsLinux(ArmFsWorkload):
type = 'ArmFsLinux'
cxx_header = "arch/arm/linux/fs_workload.hh"
cxx_class = "ArmISA::FsLinux"
@cxxMethod
def dumpDmesg(self):
"""Dump dmesg from the simulated kernel to standard out"""
pass
class ArmFsFreebsd(ArmFsWorkload):
type = 'ArmFsFreebsd'
cxx_header = "arch/arm/freebsd/fs_workload.hh"
cxx_class = "ArmISA::FsFreebsd"

View File

@@ -41,23 +41,12 @@ from m5.util.fdthelper import *
from m5.objects.System import System
from m5.objects.ArmSemihosting import ArmSemihosting
class ArmMachineType(Enum):
map = {
'VExpress_EMM' : 2272,
'VExpress_EMM64' : 2272,
'DTOnly' : -1,
}
class SveVectorLength(UInt8): min = 1; max = 16
class ArmSystem(System):
type = 'ArmSystem'
cxx_header = "arch/arm/system.hh"
multi_proc = Param.Bool(True, "Multiprocessor system?")
boot_loader = VectorParam.String([],
"File that contains the boot loader code. Zero or more files may be "
"specified. The first boot loader that matches the kernel's "
"architecture will be used.")
gic_cpu_addr = Param.Addr(0, "Addres of the GIC CPU interface")
flags_addr = Param.Addr(0, "Address of the flags register for MP booting")
have_security = Param.Bool(False,
@@ -90,10 +79,11 @@ class ArmSystem(System):
semihosting = Param.ArmSemihosting(NULL,
"Enable support for the Arm semihosting by settings this parameter")
dtb_filename = Param.String("",
"File that contains the Device Tree Blob. Don't use DTB if empty.")
m5ops_base = Param.Addr(0,
"Base of the 64KiB PA range used for memory-mapped m5ops. Set to 0 "
"to disable.")
def generateDtb(self, outdir, filename):
def generateDtb(self, filename):
"""
Autogenerate DTB. Arguments are the folder where the DTB
will be stored, and the name of the DTB file.
@@ -103,8 +93,7 @@ class ArmSystem(System):
fdt = Fdt()
fdt.add_rootnode(rootNode)
dtb_filename = os.path.join(outdir, filename)
self.dtb_filename = fdt.writeDtbFile(dtb_filename)
fdt.writeDtbFile(filename)
def generateDeviceTree(self, state):
@@ -139,37 +128,3 @@ class ArmSystem(System):
root.append(node)
return root
class GenericArmSystem(ArmSystem):
type = 'GenericArmSystem'
cxx_header = "arch/arm/system.hh"
machine_type = Param.ArmMachineType('DTOnly',
"Machine id from http://www.arm.linux.org.uk/developer/machines/")
atags_addr = Param.Addr("Address where default atags structure should " \
"be written")
early_kernel_symbols = Param.Bool(False,
"enable early kernel symbol tables before MMU")
enable_context_switch_stats_dump = Param.Bool(False,
"enable stats/task info dumping at context switch boundaries")
panic_on_panic = Param.Bool(False, "Trigger a gem5 panic if the " \
"guest kernel panics")
panic_on_oops = Param.Bool(False, "Trigger a gem5 panic if the " \
"guest kernel oopses")
class LinuxArmSystem(GenericArmSystem):
type = 'LinuxArmSystem'
cxx_header = "arch/arm/linux/system.hh"
@cxxMethod
def dumpDmesg(self):
"""Dump dmesg from the simulated kernel to standard out"""
pass
# Have Linux systems for ARM auto-calc their load_addr_mask for proper
# kernel relocation.
load_addr_mask = 0x0
class FreebsdArmSystem(GenericArmSystem):
type = 'FreebsdArmSystem'
cxx_header = "arch/arm/freebsd/system.hh"

View File

@@ -67,10 +67,11 @@ if env['TARGET_ISA'] == 'arm':
Source('isa_device.cc')
Source('linux/linux.cc')
Source('linux/process.cc')
Source('linux/system.cc')
Source('linux/fs_workload.cc')
Source('freebsd/freebsd.cc')
Source('freebsd/process.cc')
Source('freebsd/system.cc')
Source('freebsd/fs_workload.cc')
Source('fs_workload.cc')
Source('miscregs.cc')
Source('nativetrace.cc')
Source('pauth_helpers.cc')
@@ -89,6 +90,7 @@ if env['TARGET_ISA'] == 'arm':
Source('utility.cc')
Source('vtophys.cc')
SimObject('ArmFsWorkload.py')
SimObject('ArmInterrupts.py')
SimObject('ArmISA.py')
SimObject('ArmNativeTrace.py')

View File

@@ -30,7 +30,7 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "arch/arm/freebsd/system.hh"
#include "arch/arm/freebsd/fs_workload.hh"
#include "arch/arm/isa_traits.hh"
#include "arch/arm/utility.hh"
@@ -47,13 +47,13 @@
#include "mem/physical.hh"
#include "sim/stat_control.hh"
using namespace ArmISA;
using namespace FreeBSD;
FreebsdArmSystem::FreebsdArmSystem(Params *p)
: GenericArmSystem(p),
enableContextSwitchStatsDump(p->enable_context_switch_stats_dump),
taskFile(nullptr), kernelPanicEvent(nullptr), kernelOopsEvent(nullptr)
namespace ArmISA
{
FsFreebsd::FsFreebsd(Params *p) : ArmISA::FsWorkload(p),
enableContextSwitchStatsDump(p->enable_context_switch_stats_dump)
{
if (p->panic_on_panic) {
kernelPanicEvent = addKernelFuncEventOrPanic<PanicPCEvent>(
@@ -74,36 +74,24 @@ FreebsdArmSystem::FreebsdArmSystem(Params *p)
}
void
FreebsdArmSystem::initState()
FsFreebsd::initState()
{
// Moved from the constructor to here since it relies on the
// address map being resolved in the interconnect
// Call the initialisation of the super class
GenericArmSystem::initState();
ArmISA::FsWorkload::initState();
// Load symbols at physical address, we might not want
// to do this permanently, for but early bootup work
// it is helpful.
if (params()->early_kernel_symbols) {
kernel->loadGlobalSymbols(kernelSymtab, 0, 0, loadAddrMask);
kernel->loadGlobalSymbols(debugSymbolTable, 0, 0, loadAddrMask);
obj->loadGlobalSymbols(symtab, 0, 0, loadAddrMask);
obj->loadGlobalSymbols(debugSymbolTable, 0, 0, loadAddrMask);
}
// Setup boot data structure
Addr addr = 0;
// Check if the kernel image has a symbol that tells us it supports
// device trees.
bool kernel_has_fdt_support =
kernelSymtab->findAddress("fdt_get_range", addr);
bool dtb_file_specified = params()->dtb_filename != "";
if (!dtb_file_specified)
fatal("dtb file is not specified\n");
if (!kernel_has_fdt_support)
fatal("kernel must have fdt support\n");
Addr addr;
fatal_if(!symtab->findAddress("fdt_get_range", addr),
"Kernel must have fdt support.");
fatal_if(params()->dtb_filename == "", "dtb file is not specified.");
// Kernel supports flattened device tree and dtb file specified.
// Using Device Tree Blob to describe system configuration.
@@ -112,38 +100,36 @@ FreebsdArmSystem::initState()
DtbFile *dtb_file = new DtbFile(params()->dtb_filename);
if (!dtb_file->addBootCmdLine(params()->boot_osflags.c_str(),
params()->boot_osflags.size())) {
warn("couldn't append bootargs to DTB file: %s\n",
params()->dtb_filename);
}
warn_if(!dtb_file->addBootCmdLine(commandLine.c_str(), commandLine.size()),
"Couldn't append bootargs to DTB file: %s",
params()->dtb_filename);
Addr ra = dtb_file->findReleaseAddr();
if (ra)
bootReleaseAddr = ra & ~ULL(0x7F);
dtb_file->buildImage().
offset(params()->atags_addr + loadAddrOffset).write(physProxy);
offset(params()->atags_addr + loadAddrOffset).
write(system->physProxy);
delete dtb_file;
// Kernel boot requirements to set up r0, r1 and r2 in ARMv7
for (int i = 0; i < threadContexts.size(); i++) {
threadContexts[i]->setIntReg(0, 0);
threadContexts[i]->setIntReg(1, params()->machine_type);
threadContexts[i]->setIntReg(2, params()->atags_addr + loadAddrOffset);
for (auto tc: system->threadContexts) {
tc->setIntReg(0, 0);
tc->setIntReg(1, params()->machine_type);
tc->setIntReg(2, params()->atags_addr + loadAddrOffset);
}
}
FreebsdArmSystem::~FreebsdArmSystem()
FsFreebsd::~FsFreebsd()
{
if (uDelaySkipEvent)
delete uDelaySkipEvent;
if (constUDelaySkipEvent)
delete constUDelaySkipEvent;
delete uDelaySkipEvent;
}
FreebsdArmSystem *
FreebsdArmSystemParams::create()
} // namespace ArmISA
ArmISA::FsFreebsd *
ArmFsFreebsdParams::create()
{
return new FreebsdArmSystem(this);
return new ArmISA::FsFreebsd(this);
}

View File

@@ -30,29 +30,27 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __ARCH_ARM_FREEBSD_SYSTEM_HH__
#define __ARCH_ARM_FREEBSD_SYSTEM_HH__
#ifndef __ARCH_ARM_FREEBSD_FS_WORKLOAD_HH__
#define __ARCH_ARM_FREEBSD_FS_WORKLOAD_HH__
#include <cstdio>
#include <map>
#include <string>
#include <vector>
#include "arch/arm/system.hh"
#include "base/output.hh"
#include "arch/arm/fs_workload.hh"
#include "kern/freebsd/events.hh"
#include "params/FreebsdArmSystem.hh"
#include "sim/core.hh"
#include "params/ArmFsFreebsd.hh"
class FreebsdArmSystem : public GenericArmSystem
namespace ArmISA
{
class FsFreebsd : public ArmISA::FsWorkload
{
public:
/** Boilerplate params code */
typedef FreebsdArmSystemParams Params;
typedef ArmFsFreebsdParams Params;
const Params *
params() const
{
return dynamic_cast<const Params *>(_params);
return dynamic_cast<const Params *>(&_params);
}
/** When enabled, dump stats/task info on context switches for
@@ -69,10 +67,10 @@ class FreebsdArmSystem : public GenericArmSystem
* mappings between taskIds and OS process IDs */
std::ostream* taskFile;
FreebsdArmSystem(Params *p);
~FreebsdArmSystem();
FsFreebsd(Params *p);
~FsFreebsd();
void initState();
void initState() override;
/** This function creates a new task Id for the given pid.
* @param tc thread context that is currentyl executing */
@@ -80,24 +78,17 @@ class FreebsdArmSystem : public GenericArmSystem
private:
/** Event to halt the simulator if the kernel calls panic() */
PCEvent *kernelPanicEvent;
PCEvent *kernelPanicEvent = nullptr;
/** Event to halt the simulator if the kernel calls oopses */
PCEvent *kernelOopsEvent;
PCEvent *kernelOopsEvent = nullptr;
/**
* PC based event to skip udelay(<time>) calls and quiesce the
* processor for the appropriate amount of time. This is not functionally
* required but does speed up simulation.
*/
FreeBSD::UDelayEvent *uDelaySkipEvent;
/** Another PC based skip event for const_udelay(). Similar to the udelay
* skip, but this function precomputes the first multiply that is done
* in the generic case since the parameter is known at compile time.
* Thus we need to do some division to get back to us.
*/
FreeBSD::UDelayEvent *constUDelaySkipEvent;
FreeBSD::UDelayEvent *uDelaySkipEvent = nullptr;
/** These variables store addresses of important data structures
* that are normaly kept coherent at boot with cache mainetence operations.
@@ -111,5 +102,6 @@ class FreebsdArmSystem : public GenericArmSystem
Addr bootReleaseAddr;
};
#endif // __ARCH_ARM_FREEBSD_SYSTEM_HH__
} // namespace ArmISA
#endif // __ARCH_ARM_FREEBSD_FS_WORKLOAD_HH__

149
src/arch/arm/fs_workload.cc Normal file
View File

@@ -0,0 +1,149 @@
/*
* Copyright (c) 2010, 2012-2013, 2015,2017-2019 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* Copyright (c) 2002-2006 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "arch/arm/fs_workload.hh"
#include "arch/arm/faults.hh"
#include "base/loader/object_file.hh"
#include "base/loader/symtab.hh"
#include "cpu/thread_context.hh"
#include "dev/arm/gic_v2.hh"
#include "kern/system_events.hh"
#include "params/ArmFsWorkload.hh"
namespace ArmISA
{
FsWorkload::FsWorkload(Params *p) : OsKernel(*p)
{
bootLoaders.reserve(p->boot_loader.size());
for (const auto &bl : p->boot_loader) {
std::unique_ptr<ObjectFile> bl_obj;
bl_obj.reset(createObjectFile(bl));
fatal_if(!bl_obj, "Could not read bootloader: %s", bl);
bootLoaders.emplace_back(std::move(bl_obj));
}
if (obj) {
bootldr = getBootLoader(obj);
} else if (!bootLoaders.empty()) {
// No kernel specified, default to the first boot loader
bootldr = bootLoaders[0].get();
}
fatal_if(!bootLoaders.empty() && !bootldr,
"Can't find a matching boot loader / kernel combination!");
if (bootldr) {
bootldr->loadGlobalSymbols(debugSymbolTable);
entry = bootldr->entryPoint();
_highestELIs64 = (bootldr->getArch() == ObjectFile::Arm64);
}
}
void
FsWorkload::initState()
{
OsKernel::initState();
// Reset CP15?? What does that mean -- ali
// FPEXC.EN = 0
for (auto *tc: system->threadContexts) {
Reset().invoke(tc);
tc->activate();
}
auto *arm_sys = dynamic_cast<ArmSystem *>(system);
Addr kernel_entry = (obj->entryPoint() & loadAddrMask) + loadAddrOffset;
if (bootldr) {
bool is_gic_v2 =
arm_sys->getGIC()->supportsVersion(BaseGic::GicVersion::GIC_V2);
bootldr->buildImage().write(system->physProxy);
inform("Using bootloader at address %#x", bootldr->entryPoint());
// Put the address of the boot loader into r7 so we know
// where to branch to after the reset fault
// All other values needed by the boot loader to know what to do
fatal_if(!arm_sys->params()->flags_addr,
"flags_addr must be set with bootloader");
fatal_if(!arm_sys->params()->gic_cpu_addr && is_gic_v2,
"gic_cpu_addr must be set with bootloader");
for (auto tc: arm_sys->threadContexts) {
if (!arm_sys->highestELIs64())
tc->setIntReg(3, kernel_entry);
if (is_gic_v2)
tc->setIntReg(4, arm_sys->params()->gic_cpu_addr);
tc->setIntReg(5, arm_sys->params()->flags_addr);
}
inform("Using kernel entry physical address at %#x\n", kernel_entry);
} else {
// Set the initial PC to be at start of the kernel code
if (!arm_sys->highestELIs64())
arm_sys->threadContexts[0]->pcState(entry);
}
}
ObjectFile *
FsWorkload::getBootLoader(ObjectFile *const obj)
{
for (auto &bl : bootLoaders) {
if (bl->getArch() == obj->getArch())
return bl.get();
}
return nullptr;
}
} // namespace ArmISA
ArmISA::FsWorkload *
ArmFsWorkloadParams::create()
{
return new ArmISA::FsWorkload(this);
}

View File

@@ -0,0 +1,97 @@
/*
* Copyright (c) 2010, 2012-2013, 2015-2019 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* Copyright (c) 2002-2005 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __ARCH_ARM_FS_WORKLOAD_HH__
#define __ARCH_ARM_FS_WORKLOAD_HH__
#include <memory>
#include <vector>
#include "kern/linux/events.hh"
#include "params/ArmFsWorkload.hh"
#include "sim/os_kernel.hh"
#include "sim/sim_object.hh"
namespace ArmISA
{
class FsWorkload : public OsKernel
{
protected:
/** Bootloaders */
std::vector<std::unique_ptr<ObjectFile>> bootLoaders;
/**
* Pointer to the bootloader object
*/
ObjectFile *bootldr = nullptr;
/**
* Whether the highest exception level in software is 64 it.
*/
bool _highestELIs64 = true;
/**
* Get a boot loader that matches the kernel.
*
* @param obj Kernel binary
* @return Pointer to boot loader ObjectFile or nullptr if there
* is no matching boot loader.
*/
ObjectFile *getBootLoader(ObjectFile *const obj);
public:
typedef ArmFsWorkloadParams Params;
const Params *
params() const
{
return dynamic_cast<const Params *>(&_params);
}
FsWorkload(Params *p);
void initState() override;
bool highestELIs64() const { return _highestELIs64; }
};
} // namespace ArmISA
#endif // __ARCH_ARM_FS_WORKLOAD_HH__

View File

@@ -38,10 +38,11 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "arch/arm/linux/system.hh"
#include "arch/arm/linux/fs_workload.hh"
#include "arch/arm/isa_traits.hh"
#include "arch/arm/linux/atag.hh"
#include "arch/arm/system.hh"
#include "arch/arm/utility.hh"
#include "arch/generic/linux/threadinfo.hh"
#include "base/loader/dtb_file.hh"
@@ -53,20 +54,159 @@
#include "debug/Loader.hh"
#include "kern/linux/events.hh"
#include "kern/linux/helpers.hh"
#include "kern/system_events.hh"
#include "mem/fs_translating_port_proxy.hh"
#include "mem/physical.hh"
#include "sim/stat_control.hh"
using namespace ArmISA;
using namespace Linux;
LinuxArmSystem::LinuxArmSystem(Params *p)
: GenericArmSystem(p), dumpStatsPCEvent(nullptr),
enableContextSwitchStatsDump(p->enable_context_switch_stats_dump),
taskFile(nullptr), kernelPanicEvent(nullptr), kernelOopsEvent(nullptr)
namespace ArmISA
{
FsLinux::FsLinux(Params *p) : ArmISA::FsWorkload(p),
enableContextSwitchStatsDump(p->enable_context_switch_stats_dump)
{}
void
FsLinux::initState()
{
ArmISA::FsWorkload::initState();
// Load symbols at physical address, we might not want
// to do this permanently, for but early bootup work
// it is helpful.
if (params()->early_kernel_symbols) {
obj->loadGlobalSymbols(symtab, 0, 0, loadAddrMask);
obj->loadGlobalSymbols(debugSymbolTable, 0, 0, loadAddrMask);
}
// Setup boot data structure
Addr addr;
// Check if the kernel image has a symbol that tells us it supports
// device trees.
bool kernel_has_fdt_support =
symtab->findAddress("unflatten_device_tree", addr);
bool dtb_file_specified = params()->dtb_filename != "";
if (kernel_has_fdt_support && dtb_file_specified) {
// Kernel supports flattened device tree and dtb file specified.
// Using Device Tree Blob to describe system configuration.
inform("Loading DTB file: %s at address %#x\n", params()->dtb_filename,
params()->atags_addr + loadAddrOffset);
DtbFile *dtb_file = new DtbFile(params()->dtb_filename);
if (!dtb_file->addBootCmdLine(
commandLine.c_str(), commandLine.size())) {
warn("couldn't append bootargs to DTB file: %s\n",
params()->dtb_filename);
}
dtb_file->buildImage().
offset(params()->atags_addr + loadAddrOffset).
write(system->physProxy);
delete dtb_file;
} else {
// Using ATAGS
// Warn if the kernel supports FDT and we haven't specified one
if (kernel_has_fdt_support) {
assert(!dtb_file_specified);
warn("Kernel supports device tree, but no DTB file specified\n");
}
// Warn if the kernel doesn't support FDT and we have specified one
if (dtb_file_specified) {
assert(!kernel_has_fdt_support);
warn("DTB file specified, but no device tree support in kernel\n");
}
AtagCore ac;
ac.flags(1); // read-only
ac.pagesize(8192);
ac.rootdev(0);
AddrRangeList atagRanges = system->getPhysMem().getConfAddrRanges();
fatal_if(atagRanges.size() != 1,
"Expected a single ATAG memory entry but got %d",
atagRanges.size());
AtagMem am;
am.memSize(atagRanges.begin()->size());
am.memStart(atagRanges.begin()->start());
AtagCmdline ad;
ad.cmdline(commandLine);
DPRINTF(Loader, "boot command line %d bytes: %s\n",
ad.size() << 2, commandLine);
AtagNone an;
uint32_t size = ac.size() + am.size() + ad.size() + an.size();
uint32_t offset = 0;
uint8_t *boot_data = new uint8_t[size << 2];
offset += ac.copyOut(boot_data + offset);
offset += am.copyOut(boot_data + offset);
offset += ad.copyOut(boot_data + offset);
offset += an.copyOut(boot_data + offset);
DPRINTF(Loader, "Boot atags was %d bytes in total\n", size << 2);
DDUMP(Loader, boot_data, size << 2);
system->physProxy.writeBlob(params()->atags_addr + loadAddrOffset,
boot_data, size << 2);
delete[] boot_data;
}
// Kernel boot requirements to set up r0, r1 and r2 in ARMv7
for (auto tc: system->threadContexts) {
tc->setIntReg(0, 0);
tc->setIntReg(1, params()->machine_type);
tc->setIntReg(2, params()->atags_addr + loadAddrOffset);
}
}
FsLinux::~FsLinux()
{
delete uDelaySkipEvent;
delete constUDelaySkipEvent;
delete dumpStatsPCEvent;
delete debugPrintkEvent;
}
void
FsLinux::startup()
{
FsWorkload::startup();
auto *arm_sys = dynamic_cast<ArmSystem *>(system);
if (enableContextSwitchStatsDump) {
if (!arm_sys->highestELIs64()) {
dumpStatsPCEvent =
addKernelFuncEvent<DumpStatsPCEvent>("__switch_to");
} else {
dumpStatsPCEvent =
addKernelFuncEvent<DumpStatsPCEvent64>("__switch_to");
}
panic_if(!dumpStatsPCEvent, "dumpStatsPCEvent not created!");
std::string task_filename = "tasks.txt";
taskFile = simout.create(name() + "." + task_filename);
for (const auto tc : arm_sys->threadContexts) {
uint32_t pid = tc->getCpuPtr()->getPid();
if (pid != BaseCPU::invldPid) {
mapPid(tc, pid);
tc->getCpuPtr()->taskId(taskMap[pid]);
}
}
}
const std::string dmesg_output = name() + ".dmesg";
if (p->panic_on_panic) {
if (params()->panic_on_panic) {
kernelPanicEvent = addKernelFuncEventOrPanic<Linux::KernelPanicEvent>(
"panic", "Kernel panic in simulated kernel", dmesg_output);
} else {
@@ -74,7 +214,7 @@ LinuxArmSystem::LinuxArmSystem(Params *p)
"panic", "Kernel panic in simulated kernel", dmesg_output);
}
if (p->panic_on_oops) {
if (params()->panic_on_oops) {
kernelOopsEvent = addKernelFuncEventOrPanic<Linux::KernelPanicEvent>(
"oops_exit", "Kernel oops in guest", dmesg_output);
} else {
@@ -98,160 +238,11 @@ LinuxArmSystem::LinuxArmSystem(Params *p)
constUDelaySkipEvent = addKernelFuncEventOrPanic<UDelayEvent>(
"__const_udelay", "__const_udelay", 1000, 107374);
debugPrintkEvent = addKernelFuncEvent<DebugPrintkEvent>("dprintk");
}
void
LinuxArmSystem::initState()
{
// Moved from the constructor to here since it relies on the
// address map being resolved in the interconnect
// Call the initialisation of the super class
GenericArmSystem::initState();
// Load symbols at physical address, we might not want
// to do this permanently, for but early bootup work
// it is helpful.
if (params()->early_kernel_symbols) {
kernel->loadGlobalSymbols(kernelSymtab, 0, 0, loadAddrMask);
kernel->loadGlobalSymbols(debugSymbolTable, 0, 0, loadAddrMask);
}
// Setup boot data structure
Addr addr = 0;
// Check if the kernel image has a symbol that tells us it supports
// device trees.
bool kernel_has_fdt_support =
kernelSymtab->findAddress("unflatten_device_tree", addr);
bool dtb_file_specified = params()->dtb_filename != "";
if (kernel_has_fdt_support && dtb_file_specified) {
// Kernel supports flattened device tree and dtb file specified.
// Using Device Tree Blob to describe system configuration.
inform("Loading DTB file: %s at address %#x\n", params()->dtb_filename,
params()->atags_addr + loadAddrOffset);
DtbFile *dtb_file = new DtbFile(params()->dtb_filename);
if (!dtb_file->addBootCmdLine(params()->boot_osflags.c_str(),
params()->boot_osflags.size())) {
warn("couldn't append bootargs to DTB file: %s\n",
params()->dtb_filename);
}
dtb_file->buildImage().
offset(params()->atags_addr + loadAddrOffset).write(physProxy);
delete dtb_file;
} else {
// Using ATAGS
// Warn if the kernel supports FDT and we haven't specified one
if (kernel_has_fdt_support) {
assert(!dtb_file_specified);
warn("Kernel supports device tree, but no DTB file specified\n");
}
// Warn if the kernel doesn't support FDT and we have specified one
if (dtb_file_specified) {
assert(!kernel_has_fdt_support);
warn("DTB file specified, but no device tree support in kernel\n");
}
AtagCore ac;
ac.flags(1); // read-only
ac.pagesize(8192);
ac.rootdev(0);
AddrRangeList atagRanges = physmem.getConfAddrRanges();
if (atagRanges.size() != 1) {
fatal("Expected a single ATAG memory entry but got %d\n",
atagRanges.size());
}
AtagMem am;
am.memSize(atagRanges.begin()->size());
am.memStart(atagRanges.begin()->start());
AtagCmdline ad;
ad.cmdline(params()->boot_osflags);
DPRINTF(Loader, "boot command line %d bytes: %s\n",
ad.size() <<2, params()->boot_osflags.c_str());
AtagNone an;
uint32_t size = ac.size() + am.size() + ad.size() + an.size();
uint32_t offset = 0;
uint8_t *boot_data = new uint8_t[size << 2];
offset += ac.copyOut(boot_data + offset);
offset += am.copyOut(boot_data + offset);
offset += ad.copyOut(boot_data + offset);
offset += an.copyOut(boot_data + offset);
DPRINTF(Loader, "Boot atags was %d bytes in total\n", size << 2);
DDUMP(Loader, boot_data, size << 2);
physProxy.writeBlob(params()->atags_addr + loadAddrOffset, boot_data,
size << 2);
delete[] boot_data;
}
// Kernel boot requirements to set up r0, r1 and r2 in ARMv7
for (int i = 0; i < threadContexts.size(); i++) {
threadContexts[i]->setIntReg(0, 0);
threadContexts[i]->setIntReg(1, params()->machine_type);
threadContexts[i]->setIntReg(2, params()->atags_addr + loadAddrOffset);
}
}
LinuxArmSystem::~LinuxArmSystem()
{
if (uDelaySkipEvent)
delete uDelaySkipEvent;
if (constUDelaySkipEvent)
delete constUDelaySkipEvent;
if (dumpStatsPCEvent)
delete dumpStatsPCEvent;
}
LinuxArmSystem *
LinuxArmSystemParams::create()
{
return new LinuxArmSystem(this);
}
void
LinuxArmSystem::startup()
{
GenericArmSystem::startup();
if (enableContextSwitchStatsDump) {
if (!highestELIs64()) {
dumpStatsPCEvent =
addKernelFuncEvent<DumpStatsPCEvent>("__switch_to");
} else {
dumpStatsPCEvent =
addKernelFuncEvent<DumpStatsPCEvent64>("__switch_to");
}
if (!dumpStatsPCEvent)
panic("dumpStatsPCEvent not created!");
std::string task_filename = "tasks.txt";
taskFile = simout.create(name() + "." + task_filename);
for (const auto tc : threadContexts) {
uint32_t pid = tc->getCpuPtr()->getPid();
if (pid != BaseCPU::invldPid) {
mapPid(tc, pid);
tc->getCpuPtr()->taskId(taskMap[pid]);
}
}
}
}
void
LinuxArmSystem::mapPid(ThreadContext *tc, uint32_t pid)
FsLinux::mapPid(ThreadContext *tc, uint32_t pid)
{
// Create a new unique identifier for this pid
std::map<uint32_t, uint32_t>::iterator itr = taskMap.find(pid);
@@ -267,9 +258,9 @@ LinuxArmSystem::mapPid(ThreadContext *tc, uint32_t pid)
}
void
LinuxArmSystem::dumpDmesg()
FsLinux::dumpDmesg()
{
Linux::dumpDmesg(getThreadContext(0), std::cout);
Linux::dumpDmesg(system->getThreadContext(0), std::cout);
}
/**
@@ -337,26 +328,24 @@ DumpStatsPCEvent::process(ThreadContext *tc)
next_task_str = "kernel";
}
LinuxArmSystem* sys = dynamic_cast<LinuxArmSystem *>(tc->getSystemPtr());
if (!sys) {
panic("System is not LinuxArmSystem while getting Linux process info!");
}
std::map<uint32_t, uint32_t>& taskMap = sys->taskMap;
FsLinux* wl = dynamic_cast<FsLinux *>(tc->getSystemPtr()->workload);
panic_if(!wl, "System workload is not ARM Linux!");
std::map<uint32_t, uint32_t>& taskMap = wl->taskMap;
// Create a new unique identifier for this pid
sys->mapPid(tc, pid);
wl->mapPid(tc, pid);
// Set cpu task id, output process info, and dump stats
tc->getCpuPtr()->taskId(taskMap[pid]);
tc->getCpuPtr()->setPid(pid);
OutputStream* taskFile = sys->taskFile;
OutputStream* taskFile = wl->taskFile;
// Task file is read by cache occupancy plotting script or
// Streamline conversion script.
ccprintf(*(taskFile->stream()),
"tick=%lld %d cpu_id=%d next_pid=%d next_tgid=%d next_task=%s\n",
curTick(), taskMap[pid], tc->cpuId(), (int) pid, (int) tgid,
curTick(), taskMap[pid], tc->cpuId(), (int)pid, (int)tgid,
next_task_str);
taskFile->stream()->flush();
@@ -364,3 +353,10 @@ DumpStatsPCEvent::process(ThreadContext *tc)
Stats::schedStatEvent(true, true, curTick(), 0);
}
} // namespace ArmISA
FsLinux *
ArmFsLinuxParams::create()
{
return new FsLinux(this);
}

View File

@@ -38,34 +38,42 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __ARCH_ARM_LINUX_SYSTEM_HH__
#define __ARCH_ARM_LINUX_SYSTEM_HH__
#ifndef __ARCH_ARM_LINUX_FS_WORKLOAD_HH__
#define __ARCH_ARM_LINUX_FS_WORKLOAD_HH__
#include <cstdio>
#include <map>
#include <string>
#include <vector>
#include "arch/arm/system.hh"
#include "arch/arm/fs_workload.hh"
#include "base/output.hh"
#include "kern/linux/events.hh"
#include "params/LinuxArmSystem.hh"
#include "params/ArmFsLinux.hh"
#include "sim/core.hh"
namespace ArmISA
{
class DumpStatsPCEvent;
class LinuxArmSystem : public GenericArmSystem
class FsLinux : public ArmISA::FsWorkload
{
protected:
DumpStatsPCEvent *dumpStatsPCEvent;
/**
* PC based event to skip the dprink() call and emulate its
* functionality
*/
Linux::DebugPrintkEvent *debugPrintkEvent = nullptr;
DumpStatsPCEvent *dumpStatsPCEvent = nullptr;
public:
/** Boilerplate params code */
typedef LinuxArmSystemParams Params;
typedef ArmFsLinuxParams Params;
const Params *
params() const
{
return dynamic_cast<const Params *>(_params);
return dynamic_cast<const Params *>(&_params);
}
/** When enabled, dump stats/task info on context switches for
@@ -80,14 +88,14 @@ class LinuxArmSystem : public GenericArmSystem
/** This is a file that is placed in the run directory that prints out
* mappings between taskIds and OS process IDs */
OutputStream* taskFile;
OutputStream *taskFile = nullptr;
LinuxArmSystem(Params *p);
~LinuxArmSystem();
FsLinux(Params *p);
~FsLinux();
void initState();
void initState() override;
void startup();
void startup() override;
/** This function creates a new task Id for the given pid.
* @param tc thread context that is currentyl executing */
@@ -101,10 +109,10 @@ class LinuxArmSystem : public GenericArmSystem
private:
/** Event to halt the simulator if the kernel calls panic() */
PCEvent *kernelPanicEvent;
PCEvent *kernelPanicEvent = nullptr;
/** Event to halt the simulator if the kernel calls oopses */
PCEvent *kernelOopsEvent;
PCEvent *kernelOopsEvent = nullptr;
/**
* PC based event to skip udelay(<time>) calls and quiesce the
@@ -129,14 +137,15 @@ class DumpStatsPCEvent : public PCEvent
: PCEvent(s, desc, addr)
{}
virtual void process(ThreadContext* tc);
void process(ThreadContext* tc) override;
protected:
virtual void getTaskDetails(ThreadContext *tc, uint32_t &pid,
uint32_t &tgid, std::string &next_task_str, int32_t &mm);
};
class DumpStatsPCEvent64 : public DumpStatsPCEvent {
class DumpStatsPCEvent64 : public DumpStatsPCEvent
{
public:
DumpStatsPCEvent64(PCEventScope *s, const std::string &desc, Addr addr)
: DumpStatsPCEvent(s, desc, addr)
@@ -146,6 +155,7 @@ class DumpStatsPCEvent64 : public DumpStatsPCEvent {
std::string &next_task_str, int32_t &mm) override;
};
} // namespace ArmISA
#endif // __ARCH_ARM_LINUX_SYSTEM_HH__
#endif // __ARCH_ARM_LINUX_FS_WORKLOAD_HH__

View File

@@ -46,7 +46,7 @@ static int32_t
readSymbol(ThreadContext *tc, const std::string name)
{
PortProxy &vp = tc->getVirtProxy();
SymbolTable *symtab = tc->getSystemPtr()->kernelSymtab;
SymbolTable *symtab = tc->getSystemPtr()->workload->symtab;
Addr addr;
if (!symtab->findAddress(name, addr))

View File

@@ -42,7 +42,7 @@
#include <iostream>
#include "arch/arm/faults.hh"
#include "arch/arm/fs_workload.hh"
#include "arch/arm/semihosting.hh"
#include "base/loader/object_file.hh"
#include "base/loader/symtab.hh"
@@ -56,16 +56,12 @@ using namespace Linux;
ArmSystem::ArmSystem(Params *p)
: System(p),
bootLoaders(), bootldr(nullptr),
_haveSecurity(p->have_security),
_haveLPAE(p->have_lpae),
_haveVirtualization(p->have_virtualization),
_haveCrypto(p->have_crypto),
_genericTimer(nullptr),
_gic(nullptr),
_resetAddr(p->auto_reset_addr ?
(kernelEntry & loadAddrMask) + loadAddrOffset :
p->reset_addr),
_highestELIs64(p->highest_el_is_64),
_physAddrRange64(p->phys_addr_range_64),
_haveLargeAsid64(p->have_large_asid_64),
@@ -76,107 +72,36 @@ ArmSystem::ArmSystem(Params *p)
semihosting(p->semihosting),
multiProc(p->multi_proc)
{
// Check if the physical address range is valid
if (p->auto_reset_addr) {
_resetAddr = (workload->entry & workload->loadAddrMask) +
workload->loadAddrOffset;
} else {
_resetAddr = p->reset_addr;
}
auto *arm_workload = dynamic_cast<ArmISA::FsWorkload *>(p->workload);
panic_if(!arm_workload,
"Workload was not the expected type (ArmISA::FsWorkload).");
warn_if(workload->entry != _resetAddr,
"Workload entry point %#x overriding reset address %#x",
workload->entry, _resetAddr);
_resetAddr = workload->entry;
if (arm_workload->highestELIs64() != _highestELIs64) {
warn("Highest ARM exception-level set to AArch%d but the workload "
"is for AArch%d. Assuming you wanted these to match.",
_highestELIs64 ? 64 : 32,
arm_workload->highestELIs64() ? 64 : 32);
_highestELIs64 = arm_workload->highestELIs64();
}
if (_highestELIs64 && (
_physAddrRange64 < 32 ||
_physAddrRange64 > 48 ||
(_physAddrRange64 % 4 != 0 && _physAddrRange64 != 42))) {
fatal("Invalid physical address range (%d)\n", _physAddrRange64);
}
bootLoaders.reserve(p->boot_loader.size());
for (const auto &bl : p->boot_loader) {
std::unique_ptr<ObjectFile> obj;
obj.reset(createObjectFile(bl));
fatal_if(!obj, "Could not read bootloader: %s\n", bl);
bootLoaders.emplace_back(std::move(obj));
}
if (kernel) {
bootldr = getBootLoader(kernel);
} else if (!bootLoaders.empty()) {
// No kernel specified, default to the first boot loader
bootldr = bootLoaders[0].get();
}
if (!bootLoaders.empty() && !bootldr)
fatal("Can't find a matching boot loader / kernel combination!");
if (bootldr) {
bootldr->loadGlobalSymbols(debugSymbolTable);
warn_if(bootldr->entryPoint() != _resetAddr,
"Bootloader entry point %#x overriding reset address %#x",
bootldr->entryPoint(), _resetAddr);
const_cast<Addr&>(_resetAddr) = bootldr->entryPoint();
if ((bootldr->getArch() == ObjectFile::Arm64) && !_highestELIs64) {
warn("Highest ARM exception-level set to AArch32 but bootloader "
"is for AArch64. Assuming you wanted these to match.\n");
_highestELIs64 = true;
} else if ((bootldr->getArch() == ObjectFile::Arm) && _highestELIs64) {
warn("Highest ARM exception-level set to AArch64 but bootloader "
"is for AArch32. Assuming you wanted these to match.\n");
_highestELIs64 = false;
}
}
debugPrintkEvent = addKernelFuncEvent<DebugPrintkEvent>("dprintk");
}
void
ArmSystem::initState()
{
// Moved from the constructor to here since it relies on the
// address map being resolved in the interconnect
// Call the initialisation of the super class
System::initState();
// Reset CP15?? What does that mean -- ali
// FPEXC.EN = 0
for (auto *tc: threadContexts) {
Reset().invoke(tc);
tc->activate();
}
const Params* p = params();
if (bootldr) {
bool is_gic_v2 =
getGIC()->supportsVersion(BaseGic::GicVersion::GIC_V2);
bootldr->buildImage().write(physProxy);
inform("Using bootloader at address %#x\n", bootldr->entryPoint());
// Put the address of the boot loader into r7 so we know
// where to branch to after the reset fault
// All other values needed by the boot loader to know what to do
if (!p->flags_addr)
fatal("flags_addr must be set with bootloader\n");
if (!p->gic_cpu_addr && is_gic_v2)
fatal("gic_cpu_addr must be set with bootloader\n");
for (int i = 0; i < threadContexts.size(); i++) {
if (!_highestELIs64)
threadContexts[i]->setIntReg(3, (kernelEntry & loadAddrMask) +
loadAddrOffset);
if (is_gic_v2)
threadContexts[i]->setIntReg(4, params()->gic_cpu_addr);
threadContexts[i]->setIntReg(5, params()->flags_addr);
}
inform("Using kernel entry physical address at %#x\n",
(kernelEntry & loadAddrMask) + loadAddrOffset);
} else {
// Set the initial PC to be at start of the kernel code
if (!_highestELIs64)
threadContexts[0]->pcState((kernelEntry & loadAddrMask) +
loadAddrOffset);
}
}
bool
@@ -185,24 +110,6 @@ ArmSystem::haveSecurity(ThreadContext *tc)
return FullSystem? getArmSystem(tc)->haveSecurity() : false;
}
ArmSystem::~ArmSystem()
{
if (debugPrintkEvent)
delete debugPrintkEvent;
}
ObjectFile *
ArmSystem::getBootLoader(ObjectFile *const obj)
{
for (auto &bl : bootLoaders) {
if (bl->getArch() == obj->getArch())
return bl.get();
}
return nullptr;
}
bool
ArmSystem::haveLPAE(ThreadContext *tc)
{
@@ -295,20 +202,3 @@ ArmSystemParams::create()
{
return new ArmSystem(this);
}
void
GenericArmSystem::initState()
{
// Moved from the constructor to here since it relies on the
// address map being resolved in the interconnect
// Call the initialisation of the super class
ArmSystem::initState();
}
GenericArmSystem *
GenericArmSystemParams::create()
{
return new GenericArmSystem(this);
}

View File

@@ -47,7 +47,6 @@
#include "kern/linux/events.hh"
#include "params/ArmSystem.hh"
#include "params/GenericArmSystem.hh"
#include "sim/full_system.hh"
#include "sim/sim_object.hh"
#include "sim/system.hh"
@@ -59,20 +58,6 @@ class ThreadContext;
class ArmSystem : public System
{
protected:
/**
* PC based event to skip the dprink() call and emulate its
* functionality
*/
Linux::DebugPrintkEvent *debugPrintkEvent;
/** Bootloaders */
std::vector<std::unique_ptr<ObjectFile>> bootLoaders;
/**
* Pointer to the bootloader object
*/
ObjectFile *bootldr;
/**
* True if this system implements the Security Extensions
*/
@@ -102,7 +87,7 @@ class ArmSystem : public System
/**
* Reset address (ARMv8)
*/
const Addr _resetAddr;
Addr _resetAddr;
/**
* True if the register width of the highest implemented exception level is
@@ -142,16 +127,6 @@ class ArmSystem : public System
*/
ArmSemihosting *const semihosting;
protected:
/**
* Get a boot loader that matches the kernel.
*
* @param obj Kernel binary
* @return Pointer to boot loader ObjectFile or nullptr if there
* is no matching boot loader.
*/
ObjectFile *getBootLoader(ObjectFile *const obj);
public:
typedef ArmSystemParams Params;
const Params *
@@ -161,20 +136,13 @@ class ArmSystem : public System
}
ArmSystem(Params *p);
~ArmSystem();
/**
* Initialise the system
*/
virtual void initState();
virtual Addr fixFuncEventAddr(Addr addr)
Addr
fixFuncEventAddr(Addr addr) override
{
// Remove the low bit that thumb symbols have set
// but that aren't actually odd aligned
if (addr & 0x1)
return addr & ~1;
return addr;
return addr & ~1;
}
/** true if this a multiprocessor system */
@@ -198,16 +166,14 @@ class ArmSystem : public System
bool haveCrypto() const { return _haveCrypto; }
/** Sets the pointer to the Generic Timer. */
void setGenericTimer(GenericTimer *generic_timer)
void
setGenericTimer(GenericTimer *generic_timer)
{
_genericTimer = generic_timer;
}
/** Sets the pointer to the GIC. */
void setGIC(BaseGic *gic)
{
_gic = gic;
}
void setGIC(BaseGic *gic) { _gic = gic; }
/** Get a pointer to the system's generic timer model */
GenericTimer *getGenericTimer() const { return _genericTimer; }
@@ -220,7 +186,8 @@ class ArmSystem : public System
bool highestELIs64() const { return _highestELIs64; }
/** Returns the highest implemented exception level */
ExceptionLevel highestEL() const
ExceptionLevel
highestEL() const
{
if (_haveSecurity)
return EL3;
@@ -232,6 +199,7 @@ class ArmSystem : public System
/** Returns the reset address if the highest implemented exception level is
* 64 bits (ARMv8) */
Addr resetAddr() const { return _resetAddr; }
void setResetAddr(Addr addr) { _resetAddr = addr; }
/** Returns true if ASID is 16 bits in AArch64 (ARMv8) */
bool haveLargeAsid64() const { return _haveLargeAsid64; }
@@ -253,7 +221,8 @@ class ArmSystem : public System
uint8_t physAddrRange64() const { return _physAddrRange64; }
/** Returns the supported physical address range in bits */
uint8_t physAddrRange() const
uint8_t
physAddrRange() const
{
if (_highestELIs64)
return _physAddrRange64;
@@ -263,10 +232,7 @@ class ArmSystem : public System
}
/** Returns the physical address mask */
Addr physAddrMask() const
{
return mask(physAddrRange());
}
Addr physAddrMask() const { return mask(physAddrRange()); }
/** Is Arm Semihosting support enabled? */
bool haveSemihosting() const { return semihosting != nullptr; }
@@ -341,23 +307,4 @@ class ArmSystem : public System
uint32_t op, uint32_t param);
};
class GenericArmSystem : public ArmSystem
{
public:
typedef GenericArmSystemParams Params;
const Params *
params() const
{
return dynamic_cast<const Params *>(_params);
}
GenericArmSystem(Params *p) : ArmSystem(p) {};
virtual ~GenericArmSystem() {};
/**
* Initialise the system
*/
virtual void initState();
};
#endif

View File

@@ -47,7 +47,7 @@ class ThreadInfo
get_data(const char *symbol, T &data)
{
Addr addr = 0;
if (!sys->kernelSymtab->findAddress(symbol, addr)) {
if (!sys->workload->symtab->findAddress(symbol, addr)) {
warn_once("Unable to find kernel symbol %s\n", symbol);
warn_once("Kernel not compiled with task_struct info; can't get "
"currently executing task/process/thread name/ids!\n");

View File

@@ -40,7 +40,6 @@ class MipsSystem(System):
hex_file_name = Param.String("test.hex","hex file that contains [address,data] pairs")
system_type = Param.UInt64("Type of system we are emulating")
system_rev = Param.UInt64("Revision of system we are emulating")
load_addr_mask = 0xffffffffff
class LinuxMipsSystem(MipsSystem):
type = 'LinuxMipsSystem'

View File

@@ -0,0 +1,51 @@
# -*- mode:python -*-
# Copyright (c) 2016 RISC-V Foundation
# Copyright (c) 2016 The University of Virginia
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from m5.params import *
from m5.objects.System import System
from m5.objects.OsKernel import OsKernel
class RiscvFsWorkload(OsKernel):
type = 'RiscvFsWorkload'
cxx_class = 'RiscvISA::FsWorkload'
cxx_header = 'arch/riscv/fs_workload.hh'
abstract = True
bare_metal = Param.Bool(False, "Using Bare Metal Application?")
reset_vect = Param.Addr(0x0, 'Reset vector')
class RiscvBareMetal(RiscvFsWorkload):
type = 'RiscvBareMetal'
cxx_class = 'RiscvISA::BareMetal'
cxx_header = 'arch/riscv/bare_metal/fs_workload.hh'
bootloader = Param.String("File, that contains the bootloader code")
bare_metal = True

View File

@@ -34,14 +34,3 @@ from m5.objects.System import System
class RiscvSystem(System):
type = 'RiscvSystem'
cxx_header = 'arch/riscv/system.hh'
bare_metal = Param.Bool(False, "Using Bare Metal Application?")
reset_vect = Param.Addr(0x0, 'Reset vector')
load_addr_mask = 0xFFFFFFFFFFFFFFFF
class BareMetalRiscvSystem(RiscvSystem):
type = 'BareMetalRiscvSystem'
cxx_header = 'arch/riscv/bare_metal/system.hh'
bootloader = Param.String("File, that contains the bootloader code")
bare_metal = True

View File

@@ -57,8 +57,9 @@ if env['TARGET_ISA'] == 'riscv':
Source('linux/process.cc')
Source('linux/linux.cc')
Source('bare_metal/system.cc')
Source('bare_metal/fs_workload.cc')
SimObject('RiscvFsWorkload.py')
SimObject('RiscvInterrupts.py')
SimObject('RiscvISA.py')
SimObject('RiscvTLB.py')

View File

@@ -0,0 +1,64 @@
/*
* Copyright (c) 2018 TU Dresden
* All rights reserved
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "arch/riscv/bare_metal/fs_workload.hh"
#include "base/loader/object_file.hh"
#include "sim/system.hh"
namespace RiscvISA
{
BareMetal::BareMetal(Params *p) : RiscvISA::FsWorkload(p),
bootloader(createObjectFile(p->bootloader)),
bootloaderSymtab(new SymbolTable)
{
fatal_if(!bootloader, "Could not load bootloader file %s.", p->bootloader);
_resetVect = bootloader->entryPoint();
}
BareMetal::~BareMetal()
{
delete bootloader;
}
void
BareMetal::initState()
{
RiscvISA::FsWorkload::initState();
warn_if(!bootloader->buildImage().write(system->physProxy),
"Could not load sections to memory.");
}
} // namespace RiscvISA
RiscvISA::BareMetal *
RiscvBareMetalParams::create()
{
return new RiscvISA::BareMetal(this);
}

View File

@@ -0,0 +1,54 @@
/*
* Copyright (c) 2018 TU Dresden
* All rights reserved
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __ARCH_RISCV_BARE_METAL_SYSTEM_HH__
#define __ARCH_RISCV_BARE_METAL_SYSTEM_HH__
#include "arch/riscv/fs_workload.hh"
#include "params/RiscvBareMetal.hh"
namespace RiscvISA
{
class BareMetal : public RiscvISA::FsWorkload
{
protected:
ObjectFile *bootloader;
SymbolTable *bootloaderSymtab;
public:
typedef RiscvBareMetalParams Params;
BareMetal(Params *p);
~BareMetal();
void initState() override;
};
} // namespace RiscvISA
#endif // __ARCH_RISCV_BARE_METAL_FS_WORKLOAD_HH__

View File

@@ -30,9 +30,9 @@
#include "arch/riscv/faults.hh"
#include "arch/riscv/fs_workload.hh"
#include "arch/riscv/isa.hh"
#include "arch/riscv/registers.hh"
#include "arch/riscv/system.hh"
#include "arch/riscv/utility.hh"
#include "cpu/base.hh"
#include "cpu/thread_context.hh"
@@ -146,7 +146,8 @@ void Reset::invoke(ThreadContext *tc, const StaticInstPtr &inst)
tc->setMiscReg(MISCREG_MCAUSE, 0);
// Advance the PC to the implementation-defined reset vector
PCState pc = static_cast<RiscvSystem *>(tc->getSystemPtr())->resetVect();
auto workload = dynamic_cast<FsWorkload *>(tc->getSystemPtr()->workload);
PCState pc = workload->resetVect();
tc->pcState(pc);
}

View File

@@ -0,0 +1,62 @@
/*
* Copyright (c) 2002-2005 The Regents of The University of Michigan
* Copyright (c) 2007 MIPS Technologies, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __ARCH_RISCV_FS_WORKLOAD_HH__
#define __ARCH_RISCV_FS_WORKLOAD_HH__
#include "params/RiscvFsWorkload.hh"
#include "sim/os_kernel.hh"
#include "sim/sim_object.hh"
namespace RiscvISA
{
class FsWorkload : public OsKernel
{
protected:
// checker for bare metal application
bool _isBareMetal;
// entry point for simulation
Addr _resetVect;
public:
FsWorkload(RiscvFsWorkloadParams *p) : OsKernel(*p),
_isBareMetal(p->bare_metal), _resetVect(p->reset_vect)
{}
// return reset vector
Addr resetVect() const { return _resetVect; }
// return bare metal checker
bool isBareMetal() const { return _isBareMetal; }
};
} // namespace RiscvISA
#endif // __ARCH_RISCV_FS_WORKLOAD_HH__

View File

@@ -29,40 +29,7 @@
#include "arch/riscv/system.hh"
#include "arch/vtophys.hh"
#include "base/loader/object_file.hh"
#include "base/loader/symtab.hh"
#include "base/trace.hh"
#include "mem/physical.hh"
#include "params/RiscvSystem.hh"
#include "sim/byteswap.hh"
RiscvSystem::RiscvSystem(Params *p)
: System(p),
_isBareMetal(p->bare_metal),
_resetVect(p->reset_vect)
{
}
RiscvSystem::~RiscvSystem()
{
}
Addr
RiscvSystem::fixFuncEventAddr(Addr addr)
{
return addr;
}
void
RiscvSystem::setRiscvAccess(Addr access)
{}
bool
RiscvSystem::breakpoint()
{
return 0;
}
RiscvSystem *
RiscvSystemParams::create()

View File

@@ -30,55 +30,13 @@
#ifndef __ARCH_RISCV_SYSTEM_HH__
#define __ARCH_RISCV_SYSTEM_HH__
#include <string>
#include <vector>
#include "base/loader/symtab.hh"
#include "cpu/pc_event.hh"
#include "kern/system_events.hh"
#include "params/RiscvSystem.hh"
#include "sim/sim_object.hh"
#include "sim/system.hh"
class RiscvSystem : public System
{
protected:
// checker for bare metal application
bool _isBareMetal;
// entry point for simulation
Addr _resetVect;
public:
typedef RiscvSystemParams Params;
RiscvSystem(Params *p);
~RiscvSystem();
// return reset vector
Addr resetVect() const { return _resetVect; }
// return bare metal checker
bool isBareMetal() const { return _isBareMetal; }
virtual bool breakpoint();
public:
/**
* Set the m5RiscvAccess pointer in the console
*/
void setRiscvAccess(Addr access);
/** console symbol table */
SymbolTable *consoleSymtab;
/** Object pointer for the console code */
ObjectFile *console;
protected:
const Params *params() const { return (const Params *)_params; }
virtual Addr fixFuncEventAddr(Addr addr);
using System::System;
Addr fixFuncEventAddr(Addr addr) override { return addr; }
};
#endif

View File

@@ -33,6 +33,7 @@
#include <vector>
#include "arch/riscv/faults.hh"
#include "arch/riscv/fs_workload.hh"
#include "arch/riscv/pagetable.hh"
#include "arch/riscv/pra_constants.hh"
#include "arch/riscv/system.hh"
@@ -285,7 +286,9 @@ TLB::translateInst(const RequestPtr &req, ThreadContext *tc)
* check if we simulate a bare metal system
* if so, we have no tlb, phys addr == virt addr
*/
if (static_cast<RiscvSystem *>(tc->getSystemPtr())->isBareMetal())
auto *workload = dynamic_cast<FsWorkload *>(
tc->getSystemPtr()->workload);
if (workload->isBareMetal())
req->setFlags(Request::PHYSICAL);
if (req->getFlags() & Request::PHYSICAL) {
@@ -320,7 +323,9 @@ TLB::translateData(const RequestPtr &req, ThreadContext *tc, bool write)
* check if we simulate a bare metal system
* if so, we have no tlb, phys addr == virt addr
*/
if (static_cast<RiscvSystem *>(tc->getSystemPtr())->isBareMetal())
auto *workload = dynamic_cast<FsWorkload *>(
tc->getSystemPtr()->workload);
if (workload->isBareMetal())
req->setFlags(Request::PHYSICAL);
if (req->getFlags() & Request::PHYSICAL) {

View File

@@ -32,6 +32,7 @@ if env['TARGET_ISA'] == 'sparc':
Source('asi.cc')
Source('decoder.cc')
Source('faults.cc')
Source('fs_workload.cc')
Source('interrupts.cc')
Source('isa.cc')
Source('linux/linux.cc')
@@ -49,6 +50,7 @@ if env['TARGET_ISA'] == 'sparc':
Source('utility.cc')
Source('vtophys.cc')
SimObject('SparcFsWorkload.py')
SimObject('SparcInterrupts.py')
SimObject('SparcISA.py')
SimObject('SparcNativeTrace.py')

View File

@@ -0,0 +1,62 @@
# Copyright (c) 2007 The Regents of The University of Michigan
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from m5.params import *
from m5.objects.SimpleMemory import SimpleMemory
from m5.objects.OsKernel import OsKernel
class SparcFsWorkload(OsKernel):
type = 'SparcFsWorkload'
cxx_header = 'arch/sparc/fs_workload.hh'
cxx_class = 'SparcISA::FsWorkload'
load_addr_mask = 0xffffffffff
_rom_base = 0xfff0000000
_nvram_base = 0x1f11000000
_hypervisor_desc_base = 0x1f12080000
_partition_desc_base = 0x1f12000000
reset_addr = Param.Addr(_rom_base, "Address to load ROM at")
hypervisor_addr = Param.Addr(Addr('64kB') + _rom_base,
"Address to load hypervisor at")
openboot_addr = Param.Addr(Addr('512kB') + _rom_base,
"Address to load openboot at")
nvram_addr = Param.Addr(_nvram_base, "Address to put the nvram")
hypervisor_desc_addr = Param.Addr(_hypervisor_desc_base,
"Address for the hypervisor description")
partition_desc_addr = Param.Addr(_partition_desc_base,
"Address for the partition description")
reset_bin = Param.String("file that contains the reset code")
hypervisor_bin = Param.String("file that contains the hypervisor code")
openboot_bin = Param.String("file that contains the openboot code")
nvram_bin = Param.String("file that contains the contents of nvram")
hypervisor_desc_bin = Param.String(
"file that contains the hypervisor description")
partition_desc_bin = Param.String(
"file that contains the partition description")

View File

@@ -26,48 +26,8 @@
from m5.params import *
from m5.objects.SimpleMemory import SimpleMemory
from m5.objects.System import System
class SparcSystem(System):
type = 'SparcSystem'
cxx_header = 'arch/sparc/system.hh'
_rom_base = 0xfff0000000
_nvram_base = 0x1f11000000
_hypervisor_desc_base = 0x1f12080000
_partition_desc_base = 0x1f12000000
# ROM for OBP/Reset/Hypervisor
rom = Param.SimpleMemory(
SimpleMemory(range=AddrRange(_rom_base, size='8MB')),
"Memory to hold the ROM data")
# nvram
nvram = Param.SimpleMemory(
SimpleMemory(range=AddrRange(_nvram_base, size='8kB')),
"Memory to hold the nvram data")
# hypervisor description
hypervisor_desc = Param.SimpleMemory(
SimpleMemory(range=AddrRange(_hypervisor_desc_base, size='8kB')),
"Memory to hold the hypervisor description")
# partition description
partition_desc = Param.SimpleMemory(
SimpleMemory(range=AddrRange(_partition_desc_base, size='8kB')),
"Memory to hold the partition description")
reset_addr = Param.Addr(_rom_base, "Address to load ROM at")
hypervisor_addr = Param.Addr(Addr('64kB') + _rom_base,
"Address to load hypervisor at")
openboot_addr = Param.Addr(Addr('512kB') + _rom_base,
"Address to load openboot at")
nvram_addr = Param.Addr(_nvram_base, "Address to put the nvram")
hypervisor_desc_addr = Param.Addr(_hypervisor_desc_base,
"Address for the hypervisor description")
partition_desc_addr = Param.Addr(_partition_desc_base,
"Address for the partition description")
reset_bin = Param.String("file that contains the reset code")
hypervisor_bin = Param.String("file that contains the hypervisor code")
openboot_bin = Param.String("file that contains the openboot code")
nvram_bin = Param.String("file that contains the contents of nvram")
hypervisor_desc_bin = Param.String("file that contains the hypervisor description")
partition_desc_bin = Param.String("file that contains the partition description")
load_addr_mask = 0xffffffffff

View File

@@ -0,0 +1,207 @@
/*
* Copyright (c) 2002-2006 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "arch/sparc/fs_workload.hh"
#include "arch/sparc/faults.hh"
#include "arch/vtophys.hh"
#include "base/loader/object_file.hh"
#include "base/loader/symtab.hh"
#include "base/trace.hh"
#include "mem/physical.hh"
#include "params/SparcFsWorkload.hh"
#include "sim/byteswap.hh"
#include "sim/system.hh"
namespace
{
ObjectFile *
loadFirmwareImage(const std::string &fname, const std::string &name)
{
ObjectFile *obj = createObjectFile(fname, true);
fatal_if(!obj, "Could not load %s %s.", name, fname);
return obj;
}
void
writeFirmwareImage(ObjectFile *obj, Addr addr, const PortProxy &proxy)
{
MemoryImage image = obj->buildImage();
// If the entry point isn't somewhere in the image, we assume we need to
// move where it's loaded so that it is.
if (addr < image.minAddr() || addr >= image.maxAddr()) {
// Move the image by the difference between the expected entry address,
// and the entry point in the object file.
image.offset(addr - obj->entryPoint());
}
image.write(proxy);
}
} // anonymous namespace
namespace SparcISA
{
FsWorkload::FsWorkload(Params *p) : OsKernel(*p)
{
resetSymtab = new SymbolTable;
hypervisorSymtab = new SymbolTable;
openbootSymtab = new SymbolTable;
nvramSymtab = new SymbolTable;
hypervisorDescSymtab = new SymbolTable;
partitionDescSymtab = new SymbolTable;
reset = loadFirmwareImage(params()->reset_bin, "reset binary");
openboot = loadFirmwareImage(params()->openboot_bin, "openboot binary");
hypervisor = loadFirmwareImage(
params()->hypervisor_bin, "hypervisor binary");
nvram = loadFirmwareImage(params()->nvram_bin, "nvram image");
hypervisor_desc = loadFirmwareImage(
params()->hypervisor_desc_bin, "hypervisor description image");
partition_desc = loadFirmwareImage(
params()->partition_desc_bin, "partition description image");
// load symbols
panic_if(!reset->loadGlobalSymbols(resetSymtab),
"could not load reset symbols");
panic_if(!openboot->loadGlobalSymbols(openbootSymtab),
"could not load openboot symbols");
panic_if(!hypervisor->loadLocalSymbols(hypervisorSymtab),
"could not load hypervisor symbols");
panic_if(!nvram->loadLocalSymbols(nvramSymtab),
"could not load nvram symbols");
panic_if(!hypervisor_desc->loadLocalSymbols(hypervisorDescSymtab),
"could not load hypervisor description symbols");
panic_if(!partition_desc->loadLocalSymbols(partitionDescSymtab),
"could not load partition description symbols");
// load symbols into debug table
panic_if(!reset->loadGlobalSymbols(debugSymbolTable),
"could not load reset symbols");
panic_if(!openboot->loadGlobalSymbols(debugSymbolTable),
"could not load openboot symbols");
panic_if(!hypervisor->loadLocalSymbols(debugSymbolTable),
"could not load hypervisor symbols");
// Strip off the rom address so when the hypervisor is copied into memory
// we have symbols still
panic_if(!hypervisor->loadLocalSymbols(debugSymbolTable, 0, 0, 0xFFFFFF),
"could not load hypervisor symbols");
panic_if(!nvram->loadGlobalSymbols(debugSymbolTable),
"could not load reset symbols");
panic_if(!hypervisor_desc->loadGlobalSymbols(debugSymbolTable),
"could not load hypervisor description symbols");
panic_if(!partition_desc->loadLocalSymbols(debugSymbolTable),
"could not load partition description symbols");
}
void
FsWorkload::initState()
{
OsKernel::initState();
if (system->threadContexts.empty())
return;
// Other CPUs will get activated by IPIs.
auto *tc = system->threadContexts[0];
SparcISA::PowerOnReset().invoke(tc);
tc->activate();
auto phys_proxy = system->physProxy;
writeFirmwareImage(reset, params()->reset_addr, phys_proxy);
writeFirmwareImage(openboot, params()->openboot_addr, phys_proxy);
writeFirmwareImage(hypervisor, params()->hypervisor_addr, phys_proxy);
writeFirmwareImage(nvram, params()->nvram_addr, phys_proxy);
writeFirmwareImage(
hypervisor_desc, params()->hypervisor_desc_addr, phys_proxy);
writeFirmwareImage(
partition_desc, params()->partition_desc_addr, phys_proxy);
}
FsWorkload::~FsWorkload()
{
delete resetSymtab;
delete hypervisorSymtab;
delete openbootSymtab;
delete nvramSymtab;
delete hypervisorDescSymtab;
delete partitionDescSymtab;
delete reset;
delete openboot;
delete hypervisor;
delete nvram;
delete hypervisor_desc;
delete partition_desc;
}
void
FsWorkload::serializeSymtab(CheckpointOut &cp) const
{
resetSymtab->serialize("reset_symtab", cp);
hypervisorSymtab->serialize("hypervisor_symtab", cp);
openbootSymtab->serialize("openboot_symtab", cp);
nvramSymtab->serialize("nvram_symtab", cp);
hypervisorDescSymtab->serialize("hypervisor_desc_symtab", cp);
partitionDescSymtab->serialize("partition_desc_symtab", cp);
}
void
FsWorkload::unserializeSymtab(CheckpointIn &cp)
{
resetSymtab->unserialize("reset_symtab", cp);
hypervisorSymtab->unserialize("hypervisor_symtab", cp);
openbootSymtab->unserialize("openboot_symtab", cp);
nvramSymtab->unserialize("nvram_symtab", cp);
hypervisorDescSymtab->unserialize("hypervisor_desc_symtab", cp);
partitionDescSymtab->unserialize("partition_desc_symtab", cp);
}
} // namespace SparcISA
SparcISA::FsWorkload *
SparcFsWorkloadParams::create()
{
return new SparcISA::FsWorkload(this);
}

View File

@@ -0,0 +1,124 @@
/*
* Copyright (c) 2002-2005 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __ARCH_SPARC_FS_WORKLOAD_HH__
#define __ARCH_SPARC_FS_WORKLOAD_HH__
#include "base/loader/symtab.hh"
#include "cpu/pc_event.hh"
#include "kern/system_events.hh"
#include "params/SparcFsWorkload.hh"
#include "sim/os_kernel.hh"
#include "sim/sim_object.hh"
namespace SparcISA
{
class FsWorkload : public OsKernel
{
public:
typedef SparcFsWorkloadParams Params;
FsWorkload(Params *p);
~FsWorkload();
void initState() override;
/**
* Serialization stuff
*/
public:
void serializeSymtab(CheckpointOut &cp) const override;
void unserializeSymtab(CheckpointIn &cp) override;
/** reset binary symbol table */
SymbolTable *resetSymtab;
/** hypervison binary symbol table */
SymbolTable *hypervisorSymtab;
/** openboot symbol table */
SymbolTable *openbootSymtab;
/** nvram symbol table? */
SymbolTable *nvramSymtab;
/** hypervisor desc symbol table? */
SymbolTable *hypervisorDescSymtab;
/** partition desc symbol table? */
SymbolTable *partitionDescSymtab;
/** Object pointer for the reset binary */
ObjectFile *reset;
/** Object pointer for the hypervisor code */
ObjectFile *hypervisor;
/** Object pointer for the openboot code */
ObjectFile *openboot;
/** Object pointer for the nvram image */
ObjectFile *nvram;
/** Object pointer for the hypervisor description image */
ObjectFile *hypervisor_desc;
/** Object pointer for the partition description image */
ObjectFile *partition_desc;
protected:
const Params *params() const { return (const Params *)&_params; }
/** Add a function-based event to reset binary. */
template <class T>
T *
addResetFuncEvent(const char *lbl)
{
return addFuncEvent<T>(resetSymtab, lbl);
}
/** Add a function-based event to the hypervisor. */
template <class T>
T *
addHypervisorFuncEvent(const char *lbl)
{
return addFuncEvent<T>(hypervisorSymtab, lbl);
}
/** Add a function-based event to the openboot. */
template <class T>
T *
addOpenbootFuncEvent(const char *lbl)
{
return addFuncEvent<T>(openbootSymtab, lbl);
}
};
} // namespace SparcISA
#endif // __ARCH_SPARC_FS_WORKLOAD_HH__

View File

@@ -28,179 +28,7 @@
#include "arch/sparc/system.hh"
#include "arch/sparc/faults.hh"
#include "arch/vtophys.hh"
#include "base/loader/object_file.hh"
#include "base/loader/symtab.hh"
#include "base/trace.hh"
#include "mem/physical.hh"
#include "params/SparcSystem.hh"
#include "sim/byteswap.hh"
namespace
{
ObjectFile *
loadFirmwareImage(const std::string &fname, const std::string &name)
{
ObjectFile *obj = createObjectFile(fname, true);
fatal_if(!obj, "Could not load %s %s.", name, fname);
return obj;
}
} // anonymous namespace
SparcSystem::SparcSystem(Params *p)
: System(p), sysTick(0)
{
resetSymtab = new SymbolTable;
hypervisorSymtab = new SymbolTable;
openbootSymtab = new SymbolTable;
nvramSymtab = new SymbolTable;
hypervisorDescSymtab = new SymbolTable;
partitionDescSymtab = new SymbolTable;
reset = loadFirmwareImage(params()->reset_bin, "reset binary");
openboot = loadFirmwareImage(params()->openboot_bin, "openboot binary");
hypervisor = loadFirmwareImage(
params()->hypervisor_bin, "hypervisor binary");
nvram = loadFirmwareImage(params()->nvram_bin, "nvram image");
hypervisor_desc = loadFirmwareImage(
params()->hypervisor_desc_bin, "hypervisor description image");
partition_desc = loadFirmwareImage(
params()->partition_desc_bin, "partition description image");
// load symbols
if (!reset->loadGlobalSymbols(resetSymtab))
panic("could not load reset symbols\n");
if (!openboot->loadGlobalSymbols(openbootSymtab))
panic("could not load openboot symbols\n");
if (!hypervisor->loadLocalSymbols(hypervisorSymtab))
panic("could not load hypervisor symbols\n");
if (!nvram->loadLocalSymbols(nvramSymtab))
panic("could not load nvram symbols\n");
if (!hypervisor_desc->loadLocalSymbols(hypervisorDescSymtab))
panic("could not load hypervisor description symbols\n");
if (!partition_desc->loadLocalSymbols(partitionDescSymtab))
panic("could not load partition description symbols\n");
// load symbols into debug table
if (!reset->loadGlobalSymbols(debugSymbolTable))
panic("could not load reset symbols\n");
if (!openboot->loadGlobalSymbols(debugSymbolTable))
panic("could not load openboot symbols\n");
if (!hypervisor->loadLocalSymbols(debugSymbolTable))
panic("could not load hypervisor symbols\n");
// Strip off the rom address so when the hypervisor is copied into memory we
// have symbols still
if (!hypervisor->loadLocalSymbols(debugSymbolTable, 0, 0, 0xFFFFFF))
panic("could not load hypervisor symbols\n");
if (!nvram->loadGlobalSymbols(debugSymbolTable))
panic("could not load reset symbols\n");
if (!hypervisor_desc->loadGlobalSymbols(debugSymbolTable))
panic("could not load hypervisor description symbols\n");
if (!partition_desc->loadLocalSymbols(debugSymbolTable))
panic("could not load partition description symbols\n");
}
namespace
{
void
writeFirmwareImage(ObjectFile *obj, Addr addr, const PortProxy &proxy)
{
MemoryImage image = obj->buildImage();
// If the entry point isn't somewhere in the image, we assume we need to
// move where it's loaded so that it is.
if (addr < image.minAddr() || addr >= image.maxAddr()) {
// Move the image by the difference between the expected entry address,
// and the entry point in the object file.
image.offset(addr - obj->entryPoint());
}
image.write(proxy);
}
} // anonymous namespace
void
SparcSystem::initState()
{
// Call the initialisation of the super class
System::initState();
writeFirmwareImage(reset, params()->reset_addr, physProxy);
writeFirmwareImage(openboot, params()->openboot_addr, physProxy);
writeFirmwareImage(hypervisor, params()->hypervisor_addr, physProxy);
writeFirmwareImage(nvram, params()->nvram_addr, physProxy);
writeFirmwareImage(
hypervisor_desc, params()->hypervisor_desc_addr, physProxy);
writeFirmwareImage(
partition_desc, params()->partition_desc_addr, physProxy);
// @todo any fixup code over writing data in binaries on setting break
// events on functions should happen here.
if (threadContexts.empty())
return;
// Other CPUs will get activated by IPIs.
auto *tc = threadContexts[0];
SparcISA::PowerOnReset().invoke(tc);
tc->activate();
}
SparcSystem::~SparcSystem()
{
delete resetSymtab;
delete hypervisorSymtab;
delete openbootSymtab;
delete nvramSymtab;
delete hypervisorDescSymtab;
delete partitionDescSymtab;
delete reset;
delete openboot;
delete hypervisor;
delete nvram;
delete hypervisor_desc;
delete partition_desc;
}
void
SparcSystem::serializeSymtab(CheckpointOut &cp) const
{
resetSymtab->serialize("reset_symtab", cp);
hypervisorSymtab->serialize("hypervisor_symtab", cp);
openbootSymtab->serialize("openboot_symtab", cp);
nvramSymtab->serialize("nvram_symtab", cp);
hypervisorDescSymtab->serialize("hypervisor_desc_symtab", cp);
partitionDescSymtab->serialize("partition_desc_symtab", cp);
}
void
SparcSystem::unserializeSymtab(CheckpointIn &cp)
{
resetSymtab->unserialize("reset_symtab", cp);
hypervisorSymtab->unserialize("hypervisor_symtab", cp);
openbootSymtab->unserialize("openboot_symtab", cp);
nvramSymtab->unserialize("nvram_symtab", cp);
hypervisorDescSymtab->unserialize("hypervisor_desc_symtab", cp);
partitionDescSymtab->unserialize("partition_desc_symtab", cp);
}
SparcSystem *
SparcSystemParams::create()

View File

@@ -29,104 +29,14 @@
#ifndef __ARCH_SPARC_SYSTEM_HH__
#define __ARCH_SPARC_SYSTEM_HH__
#include <string>
#include <vector>
#include "base/loader/symtab.hh"
#include "cpu/pc_event.hh"
#include "kern/system_events.hh"
#include "params/SparcSystem.hh"
#include "sim/sim_object.hh"
#include "sim/system.hh"
class SparcSystem : public System
{
public:
typedef SparcSystemParams Params;
SparcSystem(Params *p);
~SparcSystem();
using System::System;
void initState() override;
/**
* Serialization stuff
*/
public:
void serializeSymtab(CheckpointOut &cp) const override;
void unserializeSymtab(CheckpointIn &cp) override;
/** reset binary symbol table */
SymbolTable *resetSymtab;
/** hypervison binary symbol table */
SymbolTable *hypervisorSymtab;
/** openboot symbol table */
SymbolTable *openbootSymtab;
/** nvram symbol table? */
SymbolTable *nvramSymtab;
/** hypervisor desc symbol table? */
SymbolTable *hypervisorDescSymtab;
/** partition desc symbol table? */
SymbolTable *partitionDescSymtab;
/** Object pointer for the reset binary */
ObjectFile *reset;
/** Object pointer for the hypervisor code */
ObjectFile *hypervisor;
/** Object pointer for the openboot code */
ObjectFile *openboot;
/** Object pointer for the nvram image */
ObjectFile *nvram;
/** Object pointer for the hypervisor description image */
ObjectFile *hypervisor_desc;
/** Object pointer for the partition description image */
ObjectFile *partition_desc;
/** System Tick for syncronized tick across all cpus. */
Tick sysTick;
protected:
const Params *params() const { return (const Params *)_params; }
/** Add a function-based event to reset binary. */
template <class T>
T *
addResetFuncEvent(const char *lbl)
{
return addFuncEvent<T>(resetSymtab, lbl);
}
/** Add a function-based event to the hypervisor. */
template <class T>
T *
addHypervisorFuncEvent(const char *lbl)
{
return addFuncEvent<T>(hypervisorSymtab, lbl);
}
/** Add a function-based event to the openboot. */
template <class T>
T *
addOpenbootFuncEvent(const char *lbl)
{
return addFuncEvent<T>(openbootSymtab, lbl);
}
Addr
fixFuncEventAddr(Addr addr) override
{
//XXX This may eventually have to do something useful.
return addr;
}
Addr fixFuncEventAddr(Addr addr) override { return addr; }
};
#endif

View File

@@ -46,6 +46,7 @@ if env['TARGET_ISA'] == 'x86':
Source('decoder_tables.cc')
Source('emulenv.cc')
Source('faults.cc')
Source('fs_workload.cc')
Source('insts/badmicroop.cc')
Source('insts/microfpop.cc')
Source('insts/microldstop.cc')
@@ -55,9 +56,9 @@ if env['TARGET_ISA'] == 'x86':
Source('insts/static_inst.cc')
Source('interrupts.cc')
Source('isa.cc')
Source('linux/fs_workload.cc')
Source('linux/linux.cc')
Source('linux/process.cc')
Source('linux/system.cc')
Source('nativetrace.cc')
Source('pagetable.cc')
Source('pagetable_walker.cc')
@@ -71,6 +72,7 @@ if env['TARGET_ISA'] == 'x86':
Source('utility.cc')
Source('vtophys.cc')
SimObject('X86FsWorkload.py')
SimObject('X86ISA.py')
SimObject('X86LocalApic.py')
SimObject('X86NativeTrace.py')

View File

@@ -0,0 +1,66 @@
# Copyright (c) 2007-2008 The Hewlett-Packard Development Company
# All rights reserved.
#
# The license below extends only to copyright in the software and shall
# not be construed as granting a license to any other intellectual
# property including but not limited to intellectual property relating
# to a hardware implementation of the functionality of the software
# licensed hereunder. You may use the software subject to the license
# terms below provided that you ensure that this notice is replicated
# unmodified and in its entirety in all distributions of the software,
# modified or unmodified, in source code or in binary form.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from m5.params import *
from m5.objects.E820 import X86E820Table, X86E820Entry
from m5.objects.SMBios import X86SMBiosSMBiosTable
from m5.objects.IntelMP import X86IntelMPFloatingPointer, X86IntelMPConfigTable
from m5.objects.ACPI import X86ACPIRSDP
from m5.objects.OsKernel import OsKernel
class X86FsWorkload(OsKernel):
type = 'X86FsWorkload'
cxx_header = 'arch/x86/fs_workload.hh'
cxx_class = 'X86ISA::FsWorkload'
smbios_table = Param.X86SMBiosSMBiosTable(
X86SMBiosSMBiosTable(), 'table of smbios/dmi information')
intel_mp_pointer = Param.X86IntelMPFloatingPointer(
X86IntelMPFloatingPointer(),
'intel mp spec floating pointer structure')
intel_mp_table = Param.X86IntelMPConfigTable(
X86IntelMPConfigTable(),
'intel mp spec configuration table')
acpi_description_table_pointer = Param.X86ACPIRSDP(
X86ACPIRSDP(), 'ACPI root description pointer structure')
class X86FsLinux(X86FsWorkload):
type = 'X86FsLinux'
cxx_header = 'arch/x86/linux/fs_workload.hh'
cxx_class = 'X86ISA::FsLinux'
e820_table = Param.X86E820Table(
X86E820Table(), 'E820 map of physical memory')

View File

@@ -33,32 +33,8 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from m5.params import *
from m5.objects.E820 import X86E820Table, X86E820Entry
from m5.objects.SMBios import X86SMBiosSMBiosTable
from m5.objects.IntelMP import X86IntelMPFloatingPointer, X86IntelMPConfigTable
from m5.objects.ACPI import X86ACPIRSDP
from m5.objects.System import System
class X86System(System):
type = 'X86System'
cxx_header = 'arch/x86/system.hh'
smbios_table = Param.X86SMBiosSMBiosTable(
X86SMBiosSMBiosTable(), 'table of smbios/dmi information')
intel_mp_pointer = Param.X86IntelMPFloatingPointer(
X86IntelMPFloatingPointer(),
'intel mp spec floating pointer structure')
intel_mp_table = Param.X86IntelMPConfigTable(
X86IntelMPConfigTable(),
'intel mp spec configuration table')
acpi_description_table_pointer = Param.X86ACPIRSDP(
X86ACPIRSDP(), 'ACPI root description pointer structure')
load_addr_mask = 0xffffffffffffffff
class LinuxX86System(X86System):
type = 'LinuxX86System'
cxx_header = 'arch/x86/linux/system.hh'
e820_table = Param.X86E820Table(
X86E820Table(), 'E820 map of physical memory')

373
src/arch/x86/fs_workload.cc Normal file
View File

@@ -0,0 +1,373 @@
/*
* Copyright (c) 2007 The Hewlett-Packard Development Company
* Copyright (c) 2018 TU Dresden
* All rights reserved.
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "arch/x86/fs_workload.hh"
#include "arch/x86/bios/intelmp.hh"
#include "arch/x86/bios/smbios.hh"
#include "arch/x86/faults.hh"
#include "arch/x86/isa_traits.hh"
#include "base/loader/object_file.hh"
#include "cpu/thread_context.hh"
#include "params/X86FsWorkload.hh"
#include "sim/system.hh"
namespace X86ISA
{
FsWorkload::FsWorkload(Params *p) : OsKernel(*p),
smbiosTable(p->smbios_table),
mpFloatingPointer(p->intel_mp_pointer),
mpConfigTable(p->intel_mp_table),
rsdp(p->acpi_description_table_pointer)
{}
void
installSegDesc(ThreadContext *tc, SegmentRegIndex seg,
SegDescriptor desc, bool longmode)
{
bool honorBase = !longmode || seg == SEGMENT_REG_FS ||
seg == SEGMENT_REG_GS ||
seg == SEGMENT_REG_TSL ||
seg == SYS_SEGMENT_REG_TR;
SegAttr attr = 0;
attr.dpl = desc.dpl;
attr.unusable = 0;
attr.defaultSize = desc.d;
attr.longMode = desc.l;
attr.avl = desc.avl;
attr.granularity = desc.g;
attr.present = desc.p;
attr.system = desc.s;
attr.type = desc.type;
if (desc.s) {
if (desc.type.codeOrData) {
// Code segment
attr.expandDown = 0;
attr.readable = desc.type.r;
attr.writable = 0;
} else {
// Data segment
attr.expandDown = desc.type.e;
attr.readable = 1;
attr.writable = desc.type.w;
}
} else {
attr.readable = 1;
attr.writable = 1;
attr.expandDown = 0;
}
tc->setMiscReg(MISCREG_SEG_BASE(seg), desc.base);
tc->setMiscReg(MISCREG_SEG_EFF_BASE(seg), honorBase ? desc.base : 0);
tc->setMiscReg(MISCREG_SEG_LIMIT(seg), desc.limit);
tc->setMiscReg(MISCREG_SEG_ATTR(seg), (RegVal)attr);
}
void
FsWorkload::initState()
{
OsKernel::initState();
for (auto *tc: system->threadContexts) {
X86ISA::InitInterrupt(0).invoke(tc);
if (tc->contextId() == 0) {
tc->activate();
} else {
// This is an application processor (AP). It should be initialized
// to look like only the BIOS POST has run on it and put then put
// it into a halted state.
tc->suspend();
}
}
fatal_if(!obj, "No kernel to load.");
fatal_if(obj->getArch() == ObjectFile::I386,
"Loading a 32 bit x86 kernel is not supported.");
ThreadContext *tc = system->threadContexts[0];
auto phys_proxy = system->physProxy;
// This is the boot strap processor (BSP). Initialize it to look like
// the boot loader has just turned control over to the 64 bit OS. We
// won't actually set up real mode or legacy protected mode descriptor
// tables because we aren't executing any code that would require
// them. We do, however toggle the control bits in the correct order
// while allowing consistency checks and the underlying mechansims
// just to be safe.
const int NumPDTs = 4;
const Addr PageMapLevel4 = 0x70000;
const Addr PageDirPtrTable = 0x71000;
const Addr PageDirTable[NumPDTs] =
{0x72000, 0x73000, 0x74000, 0x75000};
const Addr GDTBase = 0x76000;
const int PML4Bits = 9;
const int PDPTBits = 9;
const int PDTBits = 9;
/*
* Set up the gdt.
*/
uint8_t numGDTEntries = 0;
// Place holder at selector 0
uint64_t nullDescriptor = 0;
phys_proxy.writeBlob(GDTBase + numGDTEntries * 8, &nullDescriptor, 8);
numGDTEntries++;
SegDescriptor initDesc = 0;
initDesc.type.codeOrData = 0; // code or data type
initDesc.type.c = 0; // conforming
initDesc.type.r = 1; // readable
initDesc.dpl = 0; // privilege
initDesc.p = 1; // present
initDesc.l = 1; // longmode - 64 bit
initDesc.d = 0; // operand size
initDesc.g = 1; // granularity
initDesc.s = 1; // system segment
initDesc.limit = 0xFFFFFFFF;
initDesc.base = 0;
// 64 bit code segment
SegDescriptor csDesc = initDesc;
csDesc.type.codeOrData = 1;
csDesc.dpl = 0;
// Because we're dealing with a pointer and I don't think it's
// guaranteed that there isn't anything in a nonvirtual class between
// it's beginning in memory and it's actual data, we'll use an
// intermediary.
uint64_t csDescVal = csDesc;
phys_proxy.writeBlob(GDTBase + numGDTEntries * 8, (&csDescVal), 8);
numGDTEntries++;
SegSelector cs = 0;
cs.si = numGDTEntries - 1;
tc->setMiscReg(MISCREG_CS, (RegVal)cs);
// 32 bit data segment
SegDescriptor dsDesc = initDesc;
uint64_t dsDescVal = dsDesc;
phys_proxy.writeBlob(GDTBase + numGDTEntries * 8, (&dsDescVal), 8);
numGDTEntries++;
SegSelector ds = 0;
ds.si = numGDTEntries - 1;
tc->setMiscReg(MISCREG_DS, (RegVal)ds);
tc->setMiscReg(MISCREG_ES, (RegVal)ds);
tc->setMiscReg(MISCREG_FS, (RegVal)ds);
tc->setMiscReg(MISCREG_GS, (RegVal)ds);
tc->setMiscReg(MISCREG_SS, (RegVal)ds);
tc->setMiscReg(MISCREG_TSL, 0);
tc->setMiscReg(MISCREG_TSG_BASE, GDTBase);
tc->setMiscReg(MISCREG_TSG_LIMIT, 8 * numGDTEntries - 1);
SegDescriptor tssDesc = initDesc;
uint64_t tssDescVal = tssDesc;
phys_proxy.writeBlob(GDTBase + numGDTEntries * 8, (&tssDescVal), 8);
numGDTEntries++;
SegSelector tss = 0;
tss.si = numGDTEntries - 1;
tc->setMiscReg(MISCREG_TR, (RegVal)tss);
installSegDesc(tc, SYS_SEGMENT_REG_TR, tssDesc, true);
/*
* Identity map the first 4GB of memory. In order to map this region
* of memory in long mode, there needs to be one actual page map level
* 4 entry which points to one page directory pointer table which
* points to 4 different page directory tables which are full of two
* megabyte pages. All of the other entries in valid tables are set
* to indicate that they don't pertain to anything valid and will
* cause a fault if used.
*/
// Put valid values in all of the various table entries which indicate
// that those entries don't point to further tables or pages. Then
// set the values of those entries which are needed.
// Page Map Level 4
// read/write, user, not present
uint64_t pml4e = htole<uint64_t>(0x6);
for (int offset = 0; offset < (1 << PML4Bits) * 8; offset += 8)
phys_proxy.writeBlob(PageMapLevel4 + offset, (&pml4e), 8);
// Point to the only PDPT
pml4e = htole<uint64_t>(0x7 | PageDirPtrTable);
phys_proxy.writeBlob(PageMapLevel4, (&pml4e), 8);
// Page Directory Pointer Table
// read/write, user, not present
uint64_t pdpe = htole<uint64_t>(0x6);
for (int offset = 0; offset < (1 << PDPTBits) * 8; offset += 8)
phys_proxy.writeBlob(PageDirPtrTable + offset, &pdpe, 8);
// Point to the PDTs
for (int table = 0; table < NumPDTs; table++) {
pdpe = htole<uint64_t>(0x7 | PageDirTable[table]);
phys_proxy.writeBlob(PageDirPtrTable + table * 8, &pdpe, 8);
}
// Page Directory Tables
Addr base = 0;
const Addr pageSize = 2 << 20;
for (int table = 0; table < NumPDTs; table++) {
for (int offset = 0; offset < (1 << PDTBits) * 8; offset += 8) {
// read/write, user, present, 4MB
uint64_t pdte = htole(0x87 | base);
phys_proxy.writeBlob(PageDirTable[table] + offset, &pdte, 8);
base += pageSize;
}
}
/*
* Transition from real mode all the way up to Long mode
*/
CR0 cr0 = tc->readMiscRegNoEffect(MISCREG_CR0);
// Turn off paging.
cr0.pg = 0;
tc->setMiscReg(MISCREG_CR0, cr0);
// Turn on protected mode.
cr0.pe = 1;
tc->setMiscReg(MISCREG_CR0, cr0);
CR4 cr4 = tc->readMiscRegNoEffect(MISCREG_CR4);
// Turn on pae.
cr4.pae = 1;
tc->setMiscReg(MISCREG_CR4, cr4);
// Point to the page tables.
tc->setMiscReg(MISCREG_CR3, PageMapLevel4);
Efer efer = tc->readMiscRegNoEffect(MISCREG_EFER);
// Enable long mode.
efer.lme = 1;
tc->setMiscReg(MISCREG_EFER, efer);
// Start using longmode segments.
installSegDesc(tc, SEGMENT_REG_CS, csDesc, true);
installSegDesc(tc, SEGMENT_REG_DS, dsDesc, true);
installSegDesc(tc, SEGMENT_REG_ES, dsDesc, true);
installSegDesc(tc, SEGMENT_REG_FS, dsDesc, true);
installSegDesc(tc, SEGMENT_REG_GS, dsDesc, true);
installSegDesc(tc, SEGMENT_REG_SS, dsDesc, true);
// Activate long mode.
cr0.pg = 1;
tc->setMiscReg(MISCREG_CR0, cr0);
tc->pcState(entry);
// We should now be in long mode. Yay!
Addr ebdaPos = 0xF0000;
Addr fixed, table;
// Write out the SMBios/DMI table.
writeOutSMBiosTable(ebdaPos, fixed, table);
ebdaPos += (fixed + table);
ebdaPos = roundUp(ebdaPos, 16);
// Write out the Intel MP Specification configuration table.
writeOutMPTable(ebdaPos, fixed, table);
ebdaPos += (fixed + table);
}
void
FsWorkload::writeOutSMBiosTable(Addr header,
Addr &headerSize, Addr &structSize, Addr table)
{
// If the table location isn't specified, just put it after the header.
// The header size as of the 2.5 SMBios specification is 0x1F bytes.
if (!table)
table = header + 0x1F;
smbiosTable->setTableAddr(table);
smbiosTable->writeOut(system->physProxy, header, headerSize, structSize);
// Do some bounds checking to make sure we at least didn't step on
// ourselves.
assert(header > table || header + headerSize <= table);
assert(table > header || table + structSize <= header);
}
void
FsWorkload::writeOutMPTable(Addr fp, Addr &fpSize, Addr &tableSize, Addr table)
{
// If the table location isn't specified and it exists, just put
// it after the floating pointer. The fp size as of the 1.4 Intel MP
// specification is 0x10 bytes.
if (mpConfigTable) {
if (!table)
table = fp + 0x10;
mpFloatingPointer->setTableAddr(table);
}
fpSize = mpFloatingPointer->writeOut(system->physProxy, fp);
if (mpConfigTable)
tableSize = mpConfigTable->writeOut(system->physProxy, table);
else
tableSize = 0;
// Do some bounds checking to make sure we at least didn't step on
// ourselves and the fp structure was the size we thought it was.
assert(fp > table || fp + fpSize <= table);
assert(table > fp || table + tableSize <= fp);
assert(fpSize == 0x10);
}
} // namespace X86ISA
X86ISA::FsWorkload *
X86FsWorkloadParams::create()
{
return new X86ISA::FsWorkload(this);
}

109
src/arch/x86/fs_workload.hh Normal file
View File

@@ -0,0 +1,109 @@
/*
* Copyright (c) 2007 The Hewlett-Packard Development Company
* All rights reserved.
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __ARCH_X86_FS_WORKLOAD_HH__
#define __ARCH_X86_FS_WORKLOAD_HH__
#include <string>
#include <vector>
#include "arch/x86/regs/misc.hh"
#include "arch/x86/regs/segment.hh"
#include "base/types.hh"
#include "cpu/thread_context.hh"
#include "params/X86FsWorkload.hh"
#include "sim/os_kernel.hh"
namespace X86ISA
{
namespace SMBios
{
class SMBiosTable;
} // namespace SMBios
namespace IntelMP
{
class FloatingPointer;
class ConfigTable;
} // namespace IntelMP
/* memory mappings for KVMCpu in SE mode */
const Addr syscallCodeVirtAddr = 0xffff800000000000;
const Addr GDTVirtAddr = 0xffff800000001000;
const Addr IDTVirtAddr = 0xffff800000002000;
const Addr TSSVirtAddr = 0xffff800000003000;
const Addr TSSPhysAddr = 0x63000;
const Addr ISTVirtAddr = 0xffff800000004000;
const Addr PFHandlerVirtAddr = 0xffff800000005000;
const Addr MMIORegionVirtAddr = 0xffffc90000000000;
const Addr MMIORegionPhysAddr = 0xffff0000;
void installSegDesc(ThreadContext *tc, SegmentRegIndex seg,
SegDescriptor desc, bool longmode);
class FsWorkload : public OsKernel
{
public:
typedef X86FsWorkloadParams Params;
FsWorkload(Params *p);
public:
void initState() override;
protected:
SMBios::SMBiosTable *smbiosTable;
IntelMP::FloatingPointer *mpFloatingPointer;
IntelMP::ConfigTable *mpConfigTable;
ACPI::RSDP *rsdp;
void writeOutSMBiosTable(Addr header,
Addr &headerSize, Addr &tableSize, Addr table=0);
void writeOutMPTable(Addr fp,
Addr &fpSize, Addr &tableSize, Addr table=0);
const Params *params() const { return (const Params *)&_params; }
};
} // namespace X86ISA
#endif // __ARCH_X86_FS_WORKLOAD_HH__

View File

@@ -35,7 +35,7 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "arch/x86/linux/system.hh"
#include "arch/x86/linux/fs_workload.hh"
#include "arch/vtophys.hh"
#include "arch/x86/isa_traits.hh"
@@ -43,24 +43,22 @@
#include "base/trace.hh"
#include "cpu/thread_context.hh"
#include "mem/port_proxy.hh"
#include "params/LinuxX86System.hh"
#include "params/X86FsLinux.hh"
#include "sim/byteswap.hh"
#include "sim/system.hh"
using namespace X86ISA;
LinuxX86System::LinuxX86System(Params *p)
: X86System(p), commandLine(p->boot_osflags), e820Table(p->e820_table)
namespace X86ISA
{
}
LinuxX86System::~LinuxX86System()
{
}
FsLinux::FsLinux(Params *p) : X86ISA::FsWorkload(p), e820Table(p->e820_table)
{}
void
LinuxX86System::initState()
FsLinux::initState()
{
X86System::initState();
X86ISA::FsWorkload::initState();
auto phys_proxy = system->physProxy;
// The location of the real mode data structure.
const Addr realModeData = 0x90200;
@@ -74,17 +72,16 @@ LinuxX86System::initState()
// A pointer to the commandLineBuff stored in the real mode data.
const Addr commandLinePointer = realModeData + 0x228;
if (commandLine.length() + 1 > realModeData - commandLineBuff)
panic("Command line \"%s\" is longer than %d characters.\n",
panic_if(commandLine.length() + 1 > realModeData - commandLineBuff,
"Command line \"%s\" is longer than %d characters.",
commandLine, realModeData - commandLineBuff - 1);
physProxy.writeBlob(commandLineBuff, commandLine.c_str(),
commandLine.length() + 1);
phys_proxy.writeString(commandLineBuff, commandLine.c_str());
// Generate a pointer of the right size and endianness to put into
// commandLinePointer.
uint32_t guestCommandLineBuff = htole((uint32_t)commandLineBuff);
physProxy.writeBlob(commandLinePointer, &guestCommandLineBuff,
sizeof(guestCommandLineBuff));
phys_proxy.writeBlob(commandLinePointer, &guestCommandLineBuff,
sizeof(guestCommandLineBuff));
/*
* Screen Info.
@@ -121,17 +118,19 @@ LinuxX86System::initState()
// A pointer to the buffer for E820 entries.
const Addr e820MapPointer = realModeData + 0x2d0;
e820Table->writeTo(physProxy, e820MapNrPointer, e820MapPointer);
e820Table->writeTo(phys_proxy, e820MapNrPointer, e820MapPointer);
/*
* Pass the location of the real mode data structure to the kernel
* using register %esi. We'll use %rsi which should be equivalent.
*/
threadContexts[0]->setIntReg(INTREG_RSI, realModeData);
system->threadContexts[0]->setIntReg(INTREG_RSI, realModeData);
}
LinuxX86System *
LinuxX86SystemParams::create()
} // namespace X86ISA
X86ISA::FsLinux *
X86FsLinuxParams::create()
{
return new LinuxX86System(this);
return new X86ISA::FsLinux(this);
}

View File

@@ -35,29 +35,28 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __ARCH_LINUX_X86_SYSTEM_HH__
#define __ARCH_LINUX_X86_SYSTEM_HH__
#include <string>
#include <vector>
#ifndef __ARCH_X86_LINUX_FS_WORKLOAD_HH__
#define __ARCH_X86_LINUX_FS_WORKLOAD_HH__
#include "arch/x86/bios/e820.hh"
#include "arch/x86/system.hh"
#include "params/LinuxX86System.hh"
#include "arch/x86/fs_workload.hh"
#include "params/X86FsLinux.hh"
class LinuxX86System : public X86System
namespace X86ISA
{
class FsLinux : public X86ISA::FsWorkload
{
protected:
std::string commandLine;
X86ISA::E820Table * e820Table;
E820Table *e820Table;
public:
typedef LinuxX86SystemParams Params;
LinuxX86System(Params *p);
~LinuxX86System();
typedef X86FsLinuxParams Params;
FsLinux(Params *p);
void initState();
void initState() override;
};
#endif
} // namespace X86ISA
#endif // __ARCH_X86_LINUX_FS_WORKLOAD_HH__

View File

@@ -44,6 +44,7 @@
#include <string>
#include <vector>
#include "arch/x86/fs_workload.hh"
#include "arch/x86/isa_traits.hh"
#include "arch/x86/regs/misc.hh"
#include "arch/x86/regs/segment.hh"

View File

@@ -28,7 +28,8 @@
#include "arch/x86/pseudo_inst.hh"
#include "arch/x86/system.hh"
#include "arch/x86/fs_workload.hh"
#include "arch/x86/isa_traits.hh"
#include "cpu/thread_context.hh"
#include "debug/PseudoInst.hh"
#include "mem/se_translating_port_proxy.hh"

View File

@@ -46,7 +46,7 @@ static int32_t
readSymbol(ThreadContext *tc, const std::string name)
{
PortProxy &vp = tc->getVirtProxy();
SymbolTable *symtab = tc->getSystemPtr()->kernelSymtab;
SymbolTable *symtab = tc->getSystemPtr()->workload->symtab;
Addr addr;
if (!symtab->findAddress(name, addr))
@@ -190,7 +190,7 @@ void
StackTrace::dump()
{
StringWrap name(tc->getCpuPtr()->name());
SymbolTable *symtab = tc->getSystemPtr()->kernelSymtab;
SymbolTable *symtab = tc->getSystemPtr()->workload->symtab;
DPRINTFN("------ Stack ------\n");

View File

@@ -38,338 +38,8 @@
#include "arch/x86/system.hh"
#include "arch/x86/bios/intelmp.hh"
#include "arch/x86/bios/smbios.hh"
#include "arch/x86/faults.hh"
#include "arch/x86/isa_traits.hh"
#include "base/loader/object_file.hh"
#include "cpu/thread_context.hh"
#include "params/X86System.hh"
using namespace X86ISA;
X86System::X86System(Params *p) :
System(p), smbiosTable(p->smbios_table),
mpFloatingPointer(p->intel_mp_pointer),
mpConfigTable(p->intel_mp_table),
rsdp(p->acpi_description_table_pointer)
{
}
void
X86ISA::installSegDesc(ThreadContext *tc, SegmentRegIndex seg,
SegDescriptor desc, bool longmode)
{
bool honorBase = !longmode || seg == SEGMENT_REG_FS ||
seg == SEGMENT_REG_GS ||
seg == SEGMENT_REG_TSL ||
seg == SYS_SEGMENT_REG_TR;
SegAttr attr = 0;
attr.dpl = desc.dpl;
attr.unusable = 0;
attr.defaultSize = desc.d;
attr.longMode = desc.l;
attr.avl = desc.avl;
attr.granularity = desc.g;
attr.present = desc.p;
attr.system = desc.s;
attr.type = desc.type;
if (desc.s) {
if (desc.type.codeOrData) {
// Code segment
attr.expandDown = 0;
attr.readable = desc.type.r;
attr.writable = 0;
} else {
// Data segment
attr.expandDown = desc.type.e;
attr.readable = 1;
attr.writable = desc.type.w;
}
} else {
attr.readable = 1;
attr.writable = 1;
attr.expandDown = 0;
}
tc->setMiscReg(MISCREG_SEG_BASE(seg), desc.base);
tc->setMiscReg(MISCREG_SEG_EFF_BASE(seg), honorBase ? desc.base : 0);
tc->setMiscReg(MISCREG_SEG_LIMIT(seg), desc.limit);
tc->setMiscReg(MISCREG_SEG_ATTR(seg), (RegVal)attr);
}
void
X86System::initState()
{
System::initState();
for (auto *tc: threadContexts) {
X86ISA::InitInterrupt(0).invoke(tc);
if (tc->contextId() == 0) {
tc->activate();
} else {
// This is an application processor (AP). It should be initialized
// to look like only the BIOS POST has run on it and put then put
// it into a halted state.
tc->suspend();
}
}
if (!kernel)
fatal("No kernel to load.\n");
if (kernel->getArch() == ObjectFile::I386)
fatal("Loading a 32 bit x86 kernel is not supported.\n");
ThreadContext *tc = threadContexts[0];
// This is the boot strap processor (BSP). Initialize it to look like
// the boot loader has just turned control over to the 64 bit OS. We
// won't actually set up real mode or legacy protected mode descriptor
// tables because we aren't executing any code that would require
// them. We do, however toggle the control bits in the correct order
// while allowing consistency checks and the underlying mechansims
// just to be safe.
const int NumPDTs = 4;
const Addr PageMapLevel4 = 0x70000;
const Addr PageDirPtrTable = 0x71000;
const Addr PageDirTable[NumPDTs] =
{0x72000, 0x73000, 0x74000, 0x75000};
const Addr GDTBase = 0x76000;
const int PML4Bits = 9;
const int PDPTBits = 9;
const int PDTBits = 9;
/*
* Set up the gdt.
*/
uint8_t numGDTEntries = 0;
// Place holder at selector 0
uint64_t nullDescriptor = 0;
physProxy.writeBlob(GDTBase + numGDTEntries * 8, &nullDescriptor, 8);
numGDTEntries++;
SegDescriptor initDesc = 0;
initDesc.type.codeOrData = 0; // code or data type
initDesc.type.c = 0; // conforming
initDesc.type.r = 1; // readable
initDesc.dpl = 0; // privilege
initDesc.p = 1; // present
initDesc.l = 1; // longmode - 64 bit
initDesc.d = 0; // operand size
initDesc.g = 1; // granularity
initDesc.s = 1; // system segment
initDesc.limit = 0xFFFFFFFF;
initDesc.base = 0;
// 64 bit code segment
SegDescriptor csDesc = initDesc;
csDesc.type.codeOrData = 1;
csDesc.dpl = 0;
// Because we're dealing with a pointer and I don't think it's
// guaranteed that there isn't anything in a nonvirtual class between
// it's beginning in memory and it's actual data, we'll use an
// intermediary.
uint64_t csDescVal = csDesc;
physProxy.writeBlob(GDTBase + numGDTEntries * 8, (&csDescVal), 8);
numGDTEntries++;
SegSelector cs = 0;
cs.si = numGDTEntries - 1;
tc->setMiscReg(MISCREG_CS, (RegVal)cs);
// 32 bit data segment
SegDescriptor dsDesc = initDesc;
uint64_t dsDescVal = dsDesc;
physProxy.writeBlob(GDTBase + numGDTEntries * 8, (&dsDescVal), 8);
numGDTEntries++;
SegSelector ds = 0;
ds.si = numGDTEntries - 1;
tc->setMiscReg(MISCREG_DS, (RegVal)ds);
tc->setMiscReg(MISCREG_ES, (RegVal)ds);
tc->setMiscReg(MISCREG_FS, (RegVal)ds);
tc->setMiscReg(MISCREG_GS, (RegVal)ds);
tc->setMiscReg(MISCREG_SS, (RegVal)ds);
tc->setMiscReg(MISCREG_TSL, 0);
tc->setMiscReg(MISCREG_TSG_BASE, GDTBase);
tc->setMiscReg(MISCREG_TSG_LIMIT, 8 * numGDTEntries - 1);
SegDescriptor tssDesc = initDesc;
uint64_t tssDescVal = tssDesc;
physProxy.writeBlob(GDTBase + numGDTEntries * 8, (&tssDescVal), 8);
numGDTEntries++;
SegSelector tss = 0;
tss.si = numGDTEntries - 1;
tc->setMiscReg(MISCREG_TR, (RegVal)tss);
installSegDesc(tc, SYS_SEGMENT_REG_TR, tssDesc, true);
/*
* Identity map the first 4GB of memory. In order to map this region
* of memory in long mode, there needs to be one actual page map level
* 4 entry which points to one page directory pointer table which
* points to 4 different page directory tables which are full of two
* megabyte pages. All of the other entries in valid tables are set
* to indicate that they don't pertain to anything valid and will
* cause a fault if used.
*/
// Put valid values in all of the various table entries which indicate
// that those entries don't point to further tables or pages. Then
// set the values of those entries which are needed.
// Page Map Level 4
// read/write, user, not present
uint64_t pml4e = htole<uint64_t>(0x6);
for (int offset = 0; offset < (1 << PML4Bits) * 8; offset += 8) {
physProxy.writeBlob(PageMapLevel4 + offset, (&pml4e), 8);
}
// Point to the only PDPT
pml4e = htole<uint64_t>(0x7 | PageDirPtrTable);
physProxy.writeBlob(PageMapLevel4, (&pml4e), 8);
// Page Directory Pointer Table
// read/write, user, not present
uint64_t pdpe = htole<uint64_t>(0x6);
for (int offset = 0; offset < (1 << PDPTBits) * 8; offset += 8)
physProxy.writeBlob(PageDirPtrTable + offset, &pdpe, 8);
// Point to the PDTs
for (int table = 0; table < NumPDTs; table++) {
pdpe = htole<uint64_t>(0x7 | PageDirTable[table]);
physProxy.writeBlob(PageDirPtrTable + table * 8, &pdpe, 8);
}
// Page Directory Tables
Addr base = 0;
const Addr pageSize = 2 << 20;
for (int table = 0; table < NumPDTs; table++) {
for (int offset = 0; offset < (1 << PDTBits) * 8; offset += 8) {
// read/write, user, present, 4MB
uint64_t pdte = htole(0x87 | base);
physProxy.writeBlob(PageDirTable[table] + offset, &pdte, 8);
base += pageSize;
}
}
/*
* Transition from real mode all the way up to Long mode
*/
CR0 cr0 = tc->readMiscRegNoEffect(MISCREG_CR0);
// Turn off paging.
cr0.pg = 0;
tc->setMiscReg(MISCREG_CR0, cr0);
// Turn on protected mode.
cr0.pe = 1;
tc->setMiscReg(MISCREG_CR0, cr0);
CR4 cr4 = tc->readMiscRegNoEffect(MISCREG_CR4);
// Turn on pae.
cr4.pae = 1;
tc->setMiscReg(MISCREG_CR4, cr4);
// Point to the page tables.
tc->setMiscReg(MISCREG_CR3, PageMapLevel4);
Efer efer = tc->readMiscRegNoEffect(MISCREG_EFER);
// Enable long mode.
efer.lme = 1;
tc->setMiscReg(MISCREG_EFER, efer);
// Start using longmode segments.
installSegDesc(tc, SEGMENT_REG_CS, csDesc, true);
installSegDesc(tc, SEGMENT_REG_DS, dsDesc, true);
installSegDesc(tc, SEGMENT_REG_ES, dsDesc, true);
installSegDesc(tc, SEGMENT_REG_FS, dsDesc, true);
installSegDesc(tc, SEGMENT_REG_GS, dsDesc, true);
installSegDesc(tc, SEGMENT_REG_SS, dsDesc, true);
// Activate long mode.
cr0.pg = 1;
tc->setMiscReg(MISCREG_CR0, cr0);
tc->pcState(tc->getSystemPtr()->kernelEntry);
// We should now be in long mode. Yay!
Addr ebdaPos = 0xF0000;
Addr fixed, table;
// Write out the SMBios/DMI table.
writeOutSMBiosTable(ebdaPos, fixed, table);
ebdaPos += (fixed + table);
ebdaPos = roundUp(ebdaPos, 16);
// Write out the Intel MP Specification configuration table.
writeOutMPTable(ebdaPos, fixed, table);
ebdaPos += (fixed + table);
}
void
X86System::writeOutSMBiosTable(Addr header,
Addr &headerSize, Addr &structSize, Addr table)
{
// If the table location isn't specified, just put it after the header.
// The header size as of the 2.5 SMBios specification is 0x1F bytes.
if (!table)
table = header + 0x1F;
smbiosTable->setTableAddr(table);
smbiosTable->writeOut(physProxy, header, headerSize, structSize);
// Do some bounds checking to make sure we at least didn't step on
// ourselves.
assert(header > table || header + headerSize <= table);
assert(table > header || table + structSize <= header);
}
void
X86System::writeOutMPTable(Addr fp,
Addr &fpSize, Addr &tableSize, Addr table)
{
// If the table location isn't specified and it exists, just put
// it after the floating pointer. The fp size as of the 1.4 Intel MP
// specification is 0x10 bytes.
if (mpConfigTable) {
if (!table)
table = fp + 0x10;
mpFloatingPointer->setTableAddr(table);
}
fpSize = mpFloatingPointer->writeOut(physProxy, fp);
if (mpConfigTable)
tableSize = mpConfigTable->writeOut(physProxy, table);
else
tableSize = 0;
// Do some bounds checking to make sure we at least didn't step on
// ourselves and the fp structure was the size we thought it was.
assert(fp > table || fp + fpSize <= table);
assert(table > fp || table + tableSize <= fp);
assert(fpSize == 0x10);
}
X86System::~X86System()
{
delete smbiosTable;
}
X86System *
X86SystemParams::create()
{

View File

@@ -38,75 +38,14 @@
#ifndef __ARCH_X86_SYSTEM_HH__
#define __ARCH_X86_SYSTEM_HH__
#include <string>
#include <vector>
#include "arch/x86/regs/misc.hh"
#include "params/X86System.hh"
#include "sim/system.hh"
namespace X86ISA
{
namespace SMBios
{
class SMBiosTable;
}
namespace IntelMP
{
class FloatingPointer;
class ConfigTable;
}
void installSegDesc(ThreadContext *tc, SegmentRegIndex seg,
SegDescriptor desc, bool longmode);
/* memory mappings for KVMCpu in SE mode */
const uint64_t syscallCodeVirtAddr = 0xffff800000000000;
const uint64_t GDTVirtAddr = 0xffff800000001000;
const uint64_t IDTVirtAddr = 0xffff800000002000;
const uint64_t TSSVirtAddr = 0xffff800000003000;
const uint64_t TSSPhysAddr = 0x63000;
const uint64_t ISTVirtAddr = 0xffff800000004000;
const uint64_t PFHandlerVirtAddr = 0xffff800000005000;
const uint64_t MMIORegionVirtAddr = 0xffffc90000000000;
const uint64_t MMIORegionPhysAddr = 0xffff0000;
}
class X86System : public System
{
public:
typedef X86SystemParams Params;
X86System(Params *p);
~X86System();
/**
* Serialization stuff
*/
public:
void initState();
protected:
X86ISA::SMBios::SMBiosTable * smbiosTable;
X86ISA::IntelMP::FloatingPointer * mpFloatingPointer;
X86ISA::IntelMP::ConfigTable * mpConfigTable;
X86ISA::ACPI::RSDP * rsdp;
void writeOutSMBiosTable(Addr header,
Addr &headerSize, Addr &tableSize, Addr table = 0);
void writeOutMPTable(Addr fp,
Addr &fpSize, Addr &tableSize, Addr table = 0);
const Params *params() const { return (const Params *)_params; }
virtual Addr fixFuncEventAddr(Addr addr)
{
// XXX This may eventually have to do something useful.
return addr;
}
using System::System;
Addr fixFuncEventAddr(Addr addr) override { return addr; }
};
#endif
#endif // __ARCH_X86_SYSTEM_HH__

View File

@@ -104,7 +104,7 @@ struct O3ThreadState : public ThreadState {
if (cpu->params()->profile) {
profile = new FunctionProfile(
cpu->params()->system->kernelSymtab);
cpu->params()->system->workload->symtab);
Callback *cb =
new MakeCallback<O3ThreadState,
&O3ThreadState::dumpFuncProfile>(this);

View File

@@ -98,7 +98,7 @@ SimpleThread::SimpleThread(BaseCPU *_cpu, int _thread_num, System *_sys,
clearArchRegs();
if (baseCpu->params()->profile) {
profile = new FunctionProfile(system->kernelSymtab);
profile = new FunctionProfile(system->workload->symtab);
Callback *cb =
new MakeCallback<SimpleThread,
&SimpleThread::dumpFuncProfile>(this);

View File

@@ -619,9 +619,9 @@ class RealView(Platform):
self._attach_io(self._off_chip_devices(), *args, **kwargs)
def setupBootLoader(self, cur_sys, boot_loader, atags_addr, load_offset):
cur_sys.boot_loader = boot_loader
cur_sys.atags_addr = atags_addr
cur_sys.load_offset = load_offset
cur_sys.workload.boot_loader = boot_loader
cur_sys.workload.atags_addr = atags_addr
cur_sys.workload.load_addr_offset = load_offset
def generateDeviceTree(self, state):
node = FdtNode("/") # Things in this module need to end up in the root

View File

@@ -93,7 +93,7 @@ Linux::dumpDmesg(ThreadContext *tc, std::ostream &os)
{
System *system = tc->getSystemPtr();
const ByteOrder bo = system->getGuestByteOrder();
const SymbolTable *symtab = system->kernelSymtab;
const SymbolTable *symtab = system->workload->symtab;
PortProxy &proxy = tc->getVirtProxy();
Addr addr_lb = 0, addr_lb_len = 0, addr_first = 0, addr_next = 0;

47
src/sim/OsKernel.py Normal file
View File

@@ -0,0 +1,47 @@
# Copyright 2019 Google Inc.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from m5.params import *
from m5.SimObject import SimObject
from m5.objects.SimpleMemory import *
class OsKernel(SimObject):
type = 'OsKernel'
cxx_header = "sim/os_kernel.hh"
object_file = Param.String("", "File that contains the kernel code")
extras = VectorParam.String([], "Additional object files to load")
extras_addrs = VectorParam.Addr([],
"Load addresses for additional object files")
addr_check = Param.Bool(True,
"whether to bounds check kernel addresses (disable for baremetal)")
load_addr_mask = Param.UInt64(0xffffffffffffffff,
"Mask to apply to kernel addresses. If zero, "
"auto-calculated to be the most restrictive.")
load_addr_offset = Param.UInt64(0, "Address to offset the kernel with")
command_line = Param.String("a", "boot flags to pass to the kernel")

View File

@@ -30,6 +30,7 @@ Import('*')
SimObject('ClockedObject.py')
SimObject('TickedObject.py')
SimObject('OsKernel.py')
SimObject('Root.py')
SimObject('ClockDomain.py')
SimObject('VoltageDomain.py')
@@ -53,6 +54,7 @@ Source('global_event.cc')
Source('init.cc', add_tags='python')
Source('init_signals.cc')
Source('main.cc', tags='main')
Source('os_kernel.cc')
Source('port.cc')
Source('python.cc', add_tags='python')
Source('redirect_path.cc')

View File

@@ -99,21 +99,10 @@ class System(SimObject):
work_cpus_ckpt_count = Param.Counter(0,
"create checkpoint when active cpu count value is reached")
workload = Param.OsKernel(NULL, "Operating system kernel")
init_param = Param.UInt64(0, "numerical value to pass into simulator")
boot_osflags = Param.String("a", "boot flags to pass to the kernel")
kernel = Param.String("", "file that contains the kernel code")
kernel_addr_check = Param.Bool(True,
"whether to address check on kernel (disable for baremetal)")
kernel_extras = VectorParam.String([], "Additional object files to load")
kernel_extras_addrs = VectorParam.Addr([],
"Load addresses for additional object files")
readfile = Param.String("", "file to read startup script from")
symbolfile = Param.String("", "file to get the symbols from")
load_addr_mask = Param.UInt64(0xffffffffffffffff,
"Address to mask loading binaries with, if 0, system "
"auto-calculates the mask to be the most restrictive, "
"otherwise it obeys a custom mask.")
load_offset = Param.UInt64(0, "Address to offset loading binaries with")
multi_thread = Param.Bool(False,
"Supports multi-threaded CPUs? Impacts Thread/Context IDs")

171
src/sim/os_kernel.cc Normal file
View File

@@ -0,0 +1,171 @@
/*
* Copyright 2019 Google Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "sim/os_kernel.hh"
#include "base/loader/object_file.hh"
#include "base/loader/symtab.hh"
#include "debug/Loader.hh"
#include "params/OsKernel.hh"
#include "sim/system.hh"
OsKernel::OsKernel(const Params &p) : SimObject(&p), _params(p),
commandLine(p.command_line), symtab(new SymbolTable),
loadAddrMask(p.load_addr_mask), loadAddrOffset(p.load_addr_offset)
{
if (!debugSymbolTable)
debugSymbolTable = new SymbolTable;
if (params().object_file == "") {
inform("No kernel set for full system simulation. "
"Assuming you know what you're doing.");
} else {
obj = createObjectFile(params().object_file);
inform("kernel located at: %s", params().object_file);
fatal_if(!obj, "Could not load kernel file %s", params().object_file);
image = obj->buildImage();
start = image.minAddr();
end = image.maxAddr();
entry = obj->entryPoint();
// If load_addr_mask is set to 0x0, then calculate the smallest mask to
// cover all kernel addresses so gem5 can relocate the kernel to a new
// offset.
if (loadAddrMask == 0)
loadAddrMask = mask(findMsbSet(end - start) + 1);
image.move([this](Addr a) {
return (a & loadAddrMask) + loadAddrOffset;
});
// load symbols
fatal_if(!obj->loadGlobalSymbols(symtab),
"Could not load kernel symbols.");
fatal_if(!obj->loadLocalSymbols(symtab),
"Could not load kernel local symbols.");
fatal_if(!obj->loadGlobalSymbols(debugSymbolTable),
"Could not load kernel symbols.");
fatal_if(!obj->loadLocalSymbols(debugSymbolTable),
"Could not load kernel local symbols.");
}
// Loading only needs to happen once and after memory system is
// connected so it will happen in initState()
std::vector<Addr> extras_addrs = p.extras_addrs;
if (extras_addrs.empty())
extras_addrs.resize(p.extras.size(), MaxAddr);
fatal_if(p.extras.size() != extras_addrs.size(),
"Additional kernel objects, not all load addresses specified\n");
for (int ker_idx = 0; ker_idx < p.extras.size(); ker_idx++) {
const std::string &obj_name = p.extras[ker_idx];
const bool raw = extras_addrs[ker_idx] != MaxAddr;
ObjectFile *obj = createObjectFile(obj_name, raw);
fatal_if(!obj, "Failed to build additional kernel object '%s'.\n",
obj_name);
extras.push_back(obj);
}
}
Addr
OsKernel::fixFuncEventAddr(Addr addr)
{
return system->fixFuncEventAddr(addr);
}
OsKernel::~OsKernel()
{
delete symtab;
}
void
OsKernel::initState()
{
auto &phys_mem = system->physProxy;
/**
* Load the kernel code into memory.
*/
auto mapper = [this](Addr a) {
return (a & loadAddrMask) + loadAddrOffset;
};
if (params().object_file != "") {
if (params().addr_check) {
// Validate kernel mapping before loading binary
fatal_if(!system->isMemAddr(mapper(start)) ||
!system->isMemAddr(mapper(end)),
"Kernel is mapped to invalid location (not memory). "
"start (%#x) - end (%#x) %#x:%#x\n",
start, end, mapper(start), mapper(end));
}
// Load program sections into memory
image.write(phys_mem);
DPRINTF(Loader, "Kernel start = %#x\n", start);
DPRINTF(Loader, "Kernel end = %#x\n", end);
DPRINTF(Loader, "Kernel entry = %#x\n", entry);
DPRINTF(Loader, "Kernel loaded...\n");
}
std::vector<Addr> extras_addrs = params().extras_addrs;
if (extras_addrs.empty())
extras_addrs.resize(params().extras.size(), MaxAddr);
for (int idx = 0; idx < extras.size(); idx++) {
const Addr load_addr = extras_addrs[idx];
auto image = extras[idx]->buildImage();
if (load_addr != MaxAddr)
image = image.offset(load_addr);
else
image = image.move(mapper);
image.write(phys_mem);
}
}
void
OsKernel::serialize(CheckpointOut &cp) const
{
symtab->serialize("symtab", cp);
serializeSymtab(cp);
}
void
OsKernel::unserialize(CheckpointIn &cp)
{
symtab->unserialize("symtab", cp);
unserializeSymtab(cp);
}
OsKernel *
OsKernelParams::create()
{
return new OsKernel(*this);
}

189
src/sim/os_kernel.hh Normal file
View File

@@ -0,0 +1,189 @@
/*
* Copyright 2019 Google Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __SIM_OS_KERNEL_HH__
#define __SIM_OS_KERNEL_HH__
#include "base/loader/memory_image.hh"
#include "base/loader/symtab.hh"
#include "params/OsKernel.hh"
#include "sim/sim_object.hh"
class ObjectFile;
class SymbolTable;
class System;
class OsKernel : public SimObject
{
public:
using Params = OsKernelParams;
protected:
const Params &_params;
Addr fixFuncEventAddr(Addr);
public:
OsKernel(const Params &p);
~OsKernel();
const Params &params() { return _params; }
void initState() override;
const std::string commandLine;
void serialize(CheckpointOut &cp) const override;
void unserialize(CheckpointIn &cp) override;
System *system = nullptr;
ObjectFile *obj = nullptr;
SymbolTable *symtab = nullptr;
MemoryImage image;
Addr start = 0;
Addr end = MaxAddr;
Addr entry = 0;
/** Mask that should be anded for binary/symbol loading.
* This allows one two different OS requirements for the same ISA to be
* handled. Some OSes are compiled for a virtual address and need to be
* loaded into physical memory that starts at address 0, while other
* bare metal tools generate images that start at address 0.
*/
Addr loadAddrMask;
/** Offset that should be used for binary/symbol loading.
* This further allows more flexibility than the loadAddrMask allows alone
* in loading kernels and similar. The loadAddrOffset is applied after the
* loadAddrMask.
*/
Addr loadAddrOffset;
std::vector<ObjectFile *> extras;
/** @{ */
/**
* Add a function-based event to the given function, to be looked
* up in the specified symbol table.
*
* The ...OrPanic flavor of the method causes the simulator to
* panic if the symbol can't be found.
*
* @param symtab Symbol table to use for look up.
* @param lbl Function to hook the event to.
* @param desc Description to be passed to the event.
* @param args Arguments to be forwarded to the event constructor.
*/
template <class T, typename... Args>
T *
addFuncEvent(const SymbolTable *symtab, const char *lbl,
const std::string &desc, Args... args)
{
Addr addr M5_VAR_USED = 0; // initialize only to avoid compiler warning
if (symtab->findAddress(lbl, addr)) {
return new T(system, desc, fixFuncEventAddr(addr),
std::forward<Args>(args)...);
}
return nullptr;
}
template <class T>
T *
addFuncEvent(const SymbolTable *symtab, const char *lbl)
{
return addFuncEvent<T>(symtab, lbl, lbl);
}
template <class T, typename... Args>
T *
addFuncEventOrPanic(const SymbolTable *symtab, const char *lbl,
Args... args)
{
T *e = addFuncEvent<T>(symtab, lbl, std::forward<Args>(args)...);
panic_if(!e, "Failed to find symbol '%s'", lbl);
return e;
}
/** @} */
/** @{ */
/**
* Add a function-based event to a kernel symbol.
*
* These functions work like their addFuncEvent() and
* addFuncEventOrPanic() counterparts. The only difference is that
* they automatically use the kernel symbol table. All arguments
* are forwarded to the underlying method.
*
* @see addFuncEvent()
* @see addFuncEventOrPanic()
*
* @param lbl Function to hook the event to.
* @param args Arguments to be passed to addFuncEvent
*/
template <class T, typename... Args>
T *
addKernelFuncEvent(const char *lbl, Args... args)
{
return addFuncEvent<T>(symtab, lbl, std::forward<Args>(args)...);
}
template <class T, typename... Args>
T *
addKernelFuncEventOrPanic(const char *lbl, Args... args)
{
T *e(addFuncEvent<T>(symtab, lbl, std::forward<Args>(args)...));
if (!e)
panic("Failed to find kernel symbol '%s'", lbl);
return e;
}
/** @} */
protected:
/**
* If needed, serialize additional symbol table entries for a
* specific subclass of this system.
*
* @param os stream to serialize to
*/
virtual void serializeSymtab(CheckpointOut &os) const {}
/**
* If needed, unserialize additional symbol table entries for a
* specific subclass of this system.
*
* @param cp checkpoint to unserialize from
* @param section relevant section in the checkpoint
*/
virtual void unserializeSymtab(CheckpointIn &cp) {}
};
#endif // __SIM_OS_KERNEL_HH__

View File

@@ -217,7 +217,7 @@ loadsymbol(ThreadContext *tc)
if (!to_number(address, addr))
continue;
if (!tc->getSystemPtr()->kernelSymtab->insert(addr, symbol))
if (!tc->getSystemPtr()->workload->symtab->insert(addr, symbol))
continue;
@@ -239,7 +239,7 @@ addsymbol(ThreadContext *tc, Addr addr, Addr symbolAddr)
DPRINTF(Loader, "Loaded symbol: %s @ %#llx\n", symbol, addr);
tc->getSystemPtr()->kernelSymtab->insert(addr,symbol);
tc->getSystemPtr()->workload->symtab->insert(addr,symbol);
debugSymbolTable->insert(addr,symbol);
}

View File

@@ -88,10 +88,7 @@ System::System(Params *p)
pagePtr(0),
init_param(p->init_param),
physProxy(_systemPort, p->cache_line_size),
kernelSymtab(nullptr),
kernel(nullptr),
loadAddrMask(p->load_addr_mask),
loadAddrOffset(p->load_offset),
workload(p->workload),
#if USE_KVM
kvmVM(p->kvm_vm),
#else
@@ -111,6 +108,8 @@ System::System(Params *p)
totalNumInsts(0),
redirectPaths(p->redirect_paths)
{
if (workload)
workload->system = this;
// add self to global system list
systemList.push_back(this);
@@ -121,12 +120,6 @@ System::System(Params *p)
}
#endif
if (FullSystem) {
kernelSymtab = new SymbolTable;
if (!debugSymbolTable)
debugSymbolTable = new SymbolTable;
}
// check if the cache line size is a value known to work
if (!(_cacheLineSize == 16 || _cacheLineSize == 32 ||
_cacheLineSize == 64 || _cacheLineSize == 128))
@@ -141,68 +134,6 @@ System::System(Params *p)
tmp_id = getMasterId(this, "interrupt");
assert(tmp_id == Request::intMasterId);
if (FullSystem) {
if (params()->kernel == "") {
inform("No kernel set for full system simulation. "
"Assuming you know what you're doing\n");
} else {
// Get the kernel code
kernel = createObjectFile(params()->kernel);
inform("kernel located at: %s", params()->kernel);
if (kernel == NULL)
fatal("Could not load kernel file %s", params()->kernel);
kernelImage = kernel->buildImage();
// setup entry points
kernelStart = kernelImage.minAddr();
kernelEnd = kernelImage.maxAddr();
kernelEntry = kernel->entryPoint();
// If load_addr_mask is set to 0x0, then auto-calculate
// the smallest mask to cover all kernel addresses so gem5
// can relocate the kernel to a new offset.
if (loadAddrMask == 0) {
Addr shift_amt = findMsbSet(kernelEnd - kernelStart) + 1;
loadAddrMask = ((Addr)1 << shift_amt) - 1;
}
kernelImage.move([this](Addr a) {
return (a & loadAddrMask) + loadAddrOffset;
});
// load symbols
if (!kernel->loadGlobalSymbols(kernelSymtab))
fatal("could not load kernel symbols\n");
if (!kernel->loadLocalSymbols(kernelSymtab))
fatal("could not load kernel local symbols\n");
if (!kernel->loadGlobalSymbols(debugSymbolTable))
fatal("could not load kernel symbols\n");
if (!kernel->loadLocalSymbols(debugSymbolTable))
fatal("could not load kernel local symbols\n");
// Loading only needs to happen once and after memory system is
// connected so it will happen in initState()
}
if (p->kernel_extras_addrs.empty())
p->kernel_extras_addrs.resize(p->kernel_extras.size(), MaxAddr);
fatal_if(p->kernel_extras.size() != p->kernel_extras_addrs.size(),
"Additional kernel objects, not all load addresses specified\n");
for (int ker_idx = 0; ker_idx < p->kernel_extras.size(); ker_idx++) {
const std::string &obj_name = p->kernel_extras[ker_idx];
const bool raw = p->kernel_extras_addrs[ker_idx] != MaxAddr;
ObjectFile *obj = createObjectFile(obj_name, raw);
fatal_if(!obj, "Failed to build additional kernel object '%s'.\n",
obj_name);
kernelExtras.push_back(obj);
}
}
// increment the number of running systems
numSystemsRunning++;
@@ -213,9 +144,6 @@ System::System(Params *p)
System::~System()
{
delete kernelSymtab;
delete kernel;
for (uint32_t j = 0; j < numWorkIds; j++)
delete workItemStats[j];
}
@@ -356,50 +284,6 @@ System::numRunningContexts()
);
}
void
System::initState()
{
if (FullSystem) {
// Moved from the constructor to here since it relies on the
// address map being resolved in the interconnect
/**
* Load the kernel code into memory
*/
auto mapper = [this](Addr a) {
return (a & loadAddrMask) + loadAddrOffset;
};
if (params()->kernel != "") {
if (params()->kernel_addr_check) {
// Validate kernel mapping before loading binary
if (!isMemAddr(mapper(kernelStart)) ||
!isMemAddr(mapper(kernelEnd))) {
fatal("Kernel is mapped to invalid location (not memory). "
"kernelStart 0x(%x) - kernelEnd 0x(%x) %#x:%#x\n",
kernelStart, kernelEnd,
mapper(kernelStart), mapper(kernelEnd));
}
}
// Load program sections into memory
kernelImage.write(physProxy);
DPRINTF(Loader, "Kernel start = %#x\n", kernelStart);
DPRINTF(Loader, "Kernel end = %#x\n", kernelEnd);
DPRINTF(Loader, "Kernel entry = %#x\n", kernelEntry);
DPRINTF(Loader, "Kernel loaded...\n");
}
std::function<Addr(Addr)> extra_mapper;
for (auto ker_idx = 0; ker_idx < kernelExtras.size(); ker_idx++) {
const Addr load_addr = params()->kernel_extras_addrs[ker_idx];
auto image = kernelExtras[ker_idx]->buildImage();
if (load_addr != MaxAddr)
image = image.offset(load_addr);
else
image = image.move(mapper);
image.write(physProxy);
}
}
}
void
System::replaceThreadContext(ThreadContext *tc, ContextID context_id)
{
@@ -481,10 +365,7 @@ System::drainResume()
void
System::serialize(CheckpointOut &cp) const
{
if (FullSystem)
kernelSymtab->serialize("kernel_symtab", cp);
SERIALIZE_SCALAR(pagePtr);
serializeSymtab(cp);
// also serialize the memories in the system
physmem.serializeSection(cp, "physmem");
@@ -494,10 +375,7 @@ System::serialize(CheckpointOut &cp) const
void
System::unserialize(CheckpointIn &cp)
{
if (FullSystem)
kernelSymtab->unserialize("kernel_symtab", cp);
UNSERIALIZE_SCALAR(pagePtr);
unserializeSymtab(cp);
// also unserialize the memories in the system
physmem.unserializeSection(cp, "physmem");

View File

@@ -60,6 +60,7 @@
#include "mem/port_proxy.hh"
#include "params/System.hh"
#include "sim/futex_map.hh"
#include "sim/os_kernel.hh"
#include "sim/redirect_path.hh"
#include "sim/se_signal.hh"
#include "sim/sim_object.hh"
@@ -209,39 +210,8 @@ class System : public SimObject, public PCEventScope
* boot.*/
PortProxy physProxy;
/** kernel symbol table */
SymbolTable *kernelSymtab;
/** Object pointer for the kernel code */
ObjectFile *kernel;
MemoryImage kernelImage;
/** Additional object files */
std::vector<ObjectFile *> kernelExtras;
/** Beginning of kernel code */
Addr kernelStart;
/** End of kernel code */
Addr kernelEnd;
/** Entry point in the kernel to start at */
Addr kernelEntry;
/** Mask that should be anded for binary/symbol loading.
* This allows one two different OS requirements for the same ISA to be
* handled. Some OSes are compiled for a virtual address and need to be
* loaded into physical memory that starts at address 0, while other
* bare metal tools generate images that start at address 0.
*/
Addr loadAddrMask;
/** Offset that should be used for binary/symbol loading.
* This further allows more flexibility than the loadAddrMask allows alone
* in loading kernels and similar. The loadAddrOffset is applied after the
* loadAddrMask.
*/
Addr loadAddrOffset;
/** OS kernel */
OsKernel *workload = nullptr;
public:
/**
@@ -474,84 +444,6 @@ class System : public SimObject, public PCEventScope
panic("Base fixFuncEventAddr not implemented.\n");
}
/** @{ */
/**
* Add a function-based event to the given function, to be looked
* up in the specified symbol table.
*
* The ...OrPanic flavor of the method causes the simulator to
* panic if the symbol can't be found.
*
* @param symtab Symbol table to use for look up.
* @param lbl Function to hook the event to.
* @param desc Description to be passed to the event.
* @param args Arguments to be forwarded to the event constructor.
*/
template <class T, typename... Args>
T *addFuncEvent(const SymbolTable *symtab, const char *lbl,
const std::string &desc, Args... args)
{
Addr addr M5_VAR_USED = 0; // initialize only to avoid compiler warning
if (symtab->findAddress(lbl, addr)) {
T *ev = new T(this, desc, fixFuncEventAddr(addr),
std::forward<Args>(args)...);
return ev;
}
return NULL;
}
template <class T>
T *addFuncEvent(const SymbolTable *symtab, const char *lbl)
{
return addFuncEvent<T>(symtab, lbl, lbl);
}
template <class T, typename... Args>
T *addFuncEventOrPanic(const SymbolTable *symtab, const char *lbl,
Args... args)
{
T *e(addFuncEvent<T>(symtab, lbl, std::forward<Args>(args)...));
if (!e)
panic("Failed to find symbol '%s'", lbl);
return e;
}
/** @} */
/** @{ */
/**
* Add a function-based event to a kernel symbol.
*
* These functions work like their addFuncEvent() and
* addFuncEventOrPanic() counterparts. The only difference is that
* they automatically use the kernel symbol table. All arguments
* are forwarded to the underlying method.
*
* @see addFuncEvent()
* @see addFuncEventOrPanic()
*
* @param lbl Function to hook the event to.
* @param args Arguments to be passed to addFuncEvent
*/
template <class T, typename... Args>
T *addKernelFuncEvent(const char *lbl, Args... args)
{
return addFuncEvent<T>(kernelSymtab, lbl,
std::forward<Args>(args)...);
}
template <class T, typename... Args>
T *addKernelFuncEventOrPanic(const char *lbl, Args... args)
{
T *e(addFuncEvent<T>(kernelSymtab, lbl,
std::forward<Args>(args)...));
if (!e)
panic("Failed to find kernel symbol '%s'", lbl);
return e;
}
/** @} */
public:
std::vector<BaseRemoteGDB *> remoteGDB;
bool breakpoint();
@@ -572,8 +464,6 @@ class System : public SimObject, public PCEventScope
System(Params *p);
~System();
void initState() override;
const Params *params() const { return (const Params *)_params; }
/**
@@ -584,24 +474,6 @@ class System : public SimObject, public PCEventScope
public:
/**
* Returns the address the kernel starts at.
* @return address the kernel starts at
*/
Addr getKernelStart() const { return kernelStart; }
/**
* Returns the address the kernel ends at.
* @return address the kernel ends at
*/
Addr getKernelEnd() const { return kernelEnd; }
/**
* Returns the address the entry point to the kernel code.
* @return entry point of the kernel code
*/
Addr getKernelEntry() const { return kernelEntry; }
/// Allocate npages contiguous unused physical pages
/// @return Starting address of first page
Addr allocPhysPages(int npages);
@@ -646,26 +518,6 @@ class System : public SimObject, public PCEventScope
// to be redirected to the faux-filesystem (a duplicate filesystem
// intended to replace certain files on the host filesystem).
std::vector<RedirectPath*> redirectPaths;
protected:
/**
* If needed, serialize additional symbol table entries for a
* specific subclass of this system. Currently this is used by
* Alpha and MIPS.
*
* @param os stream to serialize to
*/
virtual void serializeSymtab(CheckpointOut &os) const {}
/**
* If needed, unserialize additional symbol table entries for a
* specific subclass of this system.
*
* @param cp checkpoint to unserialize from
* @param section relevant section in the checkpoint
*/
virtual void unserializeSymtab(CheckpointIn &cp) {}
};
void printSystems();

View File

@@ -104,14 +104,17 @@ class LinuxArmSystemBuilder(object):
# We typically want the simulator to panic if the kernel
# panics or oopses. This prevents the simulator from running
# an obviously failed test case until the end of time.
system.panic_on_panic = True
system.panic_on_oops = True
system.workload.panic_on_panic = True
system.workload.panic_on_oops = True
system.kernel = SysPaths.binary(default_kernels[self.machine_type])
system.workload.object_file = SysPaths.binary(
default_kernels[self.machine_type])
self.init_system(system)
system.generateDtb(m5.options.outdir, 'system.dtb')
system.workload.dtb_filename = \
os.path.join(m5.options.outdir, 'system.dtb')
system.generateDtb(system.workload.dtb_filename)
return system
class LinuxArmFSSystem(LinuxArmSystemBuilder,