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:
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
90
src/arch/arm/ArmFsWorkload.py
Normal file
90
src/arch/arm/ArmFsWorkload.py
Normal 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"
|
||||
@@ -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"
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
149
src/arch/arm/fs_workload.cc
Normal 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);
|
||||
}
|
||||
97
src/arch/arm/fs_workload.hh
Normal file
97
src/arch/arm/fs_workload.hh
Normal 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__
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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__
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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'
|
||||
|
||||
51
src/arch/riscv/RiscvFsWorkload.py
Normal file
51
src/arch/riscv/RiscvFsWorkload.py
Normal 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
|
||||
@@ -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
|
||||
|
||||
@@ -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')
|
||||
|
||||
64
src/arch/riscv/bare_metal/fs_workload.cc
Normal file
64
src/arch/riscv/bare_metal/fs_workload.cc
Normal 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);
|
||||
}
|
||||
54
src/arch/riscv/bare_metal/fs_workload.hh
Normal file
54
src/arch/riscv/bare_metal/fs_workload.hh
Normal 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__
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
62
src/arch/riscv/fs_workload.hh
Normal file
62
src/arch/riscv/fs_workload.hh
Normal 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__
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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')
|
||||
|
||||
62
src/arch/sparc/SparcFsWorkload.py
Normal file
62
src/arch/sparc/SparcFsWorkload.py
Normal 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")
|
||||
@@ -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
|
||||
|
||||
207
src/arch/sparc/fs_workload.cc
Normal file
207
src/arch/sparc/fs_workload.cc
Normal 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);
|
||||
}
|
||||
124
src/arch/sparc/fs_workload.hh
Normal file
124
src/arch/sparc/fs_workload.hh
Normal 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__
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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')
|
||||
|
||||
66
src/arch/x86/X86FsWorkload.py
Normal file
66
src/arch/x86/X86FsWorkload.py
Normal 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')
|
||||
@@ -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
373
src/arch/x86/fs_workload.cc
Normal 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
109
src/arch/x86/fs_workload.hh
Normal 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__
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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__
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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");
|
||||
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
@@ -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__
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
47
src/sim/OsKernel.py
Normal 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")
|
||||
@@ -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')
|
||||
|
||||
@@ -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
171
src/sim/os_kernel.cc
Normal 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
189
src/sim/os_kernel.hh
Normal 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 ¶ms() { 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__
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user