arch,sim,kern,dev,cpu: Create a Workload SimObject.

This generalized Workload SimObject is not geared towards FS or SE
simulations, although currently it's only used in FS. This gets rid
of the ARM specific highestELIs64 property (from the workload, not the
system) and replaces it with a generic getArch.

The old globally accessible kernel symtab has been replaced with a
symtab accessor which takes a ThreadContext *. The parameter isn't used
for anything for now, but in cases where there might be multiple
symbol tables to choose from (kernel vs. current user space?) the
method will now be able to distinguish which to use. This also makes
it possible for the workload to manage its symbol table with whatever
policy makes sense for it.

That method returns a const SymbolTable * since most of the time the
symbol table doesn't need to be modified. In the one case where an
external entity needs to modify the table, two pseudo instructions,
the table to modify isn't necessarily the one that's currently active.
For instance, the pseudo instruction will likely execute in user space,
but might be intended to add a symbol to the kernel in case something
like a module was loaded.

To support that usage, the workload has a generic "insertSymbol" method
which will insert the symbol in the table that "makes sense". There is
a lot of ambiguity what that means, but it's no less ambiguous than
today where we're only saved by the fact that there is generally only
one active symbol table to worry about.

This change also introduces a KernelWorkload SimObject class which
inherits from Workload and adds in kernel related members for cases
where the kernel is specified in the config and loaded by gem5 itself.
That's the common case, but the base Workload class would be used
directly when, for instance, doing a baremetal simulation or if the
kernel is loaded by software within the simulation as is the case for
SPARC FS.

Because a given architecture specific workload class needs to inherit
from either Workload or KernelWorkload, this change removes the
ability to boot ARM without a kernel. This ability should be restored
in the future.

To make having or not having a kernel more flexible, the kernel
specific members of the KernelWorkload should be factored out into
their own object which can then be attached to a workload through a
(potentially unused) property rather than inheritance.

Change-Id: Idf72615260266d7b4478d20d4035ed5a1e7aa241
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/24283
Reviewed-by: Giacomo Travaglini <giacomo.travaglini@arm.com>
Maintainer: Gabe Black <gabeblack@google.com>
Tested-by: kokoro <noreply+kokoro@google.com>
This commit is contained in:
Gabe Black
2020-01-12 17:21:32 -08:00
parent b1d434363b
commit da4f5726be
34 changed files with 360 additions and 370 deletions

View File

@@ -388,7 +388,7 @@ def makeLinuxMipsSystem(mem_mode, mdesc=None, cmdline=None):
self.console = binary('mips/console')
if not cmdline:
cmdline = 'root=/dev/hda1 console=ttyS0'
self.workload = OsKernel(command_line=fillInCmdline(mdesc, cmdline))
self.workload = KernelWorkload(command_line=fillInCmdline(mdesc, cmdline))
self.system_port = self.membus.slave

View File

@@ -36,7 +36,7 @@
from m5.params import *
from m5.options import *
from m5.SimObject import *
from m5.objects.OsKernel import OsKernel
from m5.objects.Workload import KernelWorkload
class ArmMachineType(Enum):
map = {
@@ -45,7 +45,7 @@ class ArmMachineType(Enum):
'DTOnly' : -1,
}
class ArmFsWorkload(OsKernel):
class ArmFsWorkload(KernelWorkload):
type = 'ArmFsWorkload'
cxx_header = "arch/arm/fs_workload.hh"
cxx_class = "ArmISA::FsWorkload"

View File

@@ -81,21 +81,21 @@ FsFreebsd::initState()
// 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);
kernelObj->loadGlobalSymbols(kernelSymtab, 0, 0, _loadAddrMask);
kernelObj->loadGlobalSymbols(debugSymbolTable, 0, 0, _loadAddrMask);
}
// Check if the kernel image has a symbol that tells us it supports
// device trees.
Addr addr;
fatal_if(!symtab->findAddress("fdt_get_range", addr),
fatal_if(!kernelSymtab->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.
inform("Loading DTB file: %s at address %#x\n", params()->dtb_filename,
params()->atags_addr + loadAddrOffset);
params()->atags_addr + _loadAddrOffset);
DtbFile *dtb_file = new DtbFile(params()->dtb_filename);
@@ -108,7 +108,7 @@ FsFreebsd::initState()
bootReleaseAddr = ra & ~ULL(0x7F);
dtb_file->buildImage().
offset(params()->atags_addr + loadAddrOffset).
offset(params()->atags_addr + _loadAddrOffset).
write(system->physProxy);
delete dtb_file;
@@ -116,7 +116,7 @@ FsFreebsd::initState()
for (auto tc: system->threadContexts) {
tc->setIntReg(0, 0);
tc->setIntReg(1, params()->machine_type);
tc->setIntReg(2, params()->atags_addr + loadAddrOffset);
tc->setIntReg(2, params()->atags_addr + _loadAddrOffset);
}
}

View File

@@ -69,9 +69,8 @@ SkipFunc::returnFromFuncIn(ThreadContext *tc)
}
}
FsWorkload::FsWorkload(Params *p)
: OsKernel(*p),
kernelEntry((entry & loadAddrMask) + loadAddrOffset)
FsWorkload::FsWorkload(Params *p) : KernelWorkload(*p),
kernelEntry((kernelObj->entryPoint() & loadAddrMask()) + loadAddrOffset())
{
bootLoaders.reserve(p->boot_loader.size());
for (const auto &bl : p->boot_loader) {
@@ -82,29 +81,19 @@ FsWorkload::FsWorkload(Params *p)
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();
}
bootldr = getBootLoader(kernelObj);
fatal_if(!bootLoaders.empty() && !bootldr,
"Can't find a matching boot loader / kernel combination!");
if (bootldr) {
if (bootldr)
bootldr->loadGlobalSymbols(debugSymbolTable);
_highestELIs64 = (bootldr->getArch() == ObjectFile::Arm64);
} else if (obj) {
_highestELIs64 = (obj->getArch() == ObjectFile::Arm64);
}
}
void
FsWorkload::initState()
{
OsKernel::initState();
KernelWorkload::initState();
// Reset CP15?? What does that mean -- ali
@@ -144,31 +133,25 @@ FsWorkload::initState()
} else {
// Set the initial PC to be at start of the kernel code
if (!arm_sys->highestELIs64())
arm_sys->threadContexts[0]->pcState(entry);
arm_sys->threadContexts[0]->pcState(kernelObj->entryPoint());
}
}
ObjectFile *
FsWorkload::getBootLoader(ObjectFile *const obj)
{
for (auto &bl : bootLoaders) {
if (bl->getArch() == obj->getArch())
return bl.get();
if (obj) {
for (auto &bl : bootLoaders) {
if (bl->getArch() == obj->getArch())
return bl.get();
}
} else if (!bootLoaders.empty()) {
return bootLoaders[0].get();
}
return nullptr;
}
Addr
FsWorkload::resetAddr() const
{
if (bootldr) {
return bootldr->entryPoint();
} else {
return kernelEntry;
}
}
} // namespace ArmISA
ArmISA::FsWorkload *

View File

@@ -46,7 +46,7 @@
#include "kern/linux/events.hh"
#include "params/ArmFsWorkload.hh"
#include "sim/os_kernel.hh"
#include "sim/kernel_workload.hh"
#include "sim/sim_object.hh"
namespace ArmISA
@@ -59,7 +59,7 @@ class SkipFunc : public SkipFuncBase
void returnFromFuncIn(ThreadContext *tc) override;
};
class FsWorkload : public OsKernel
class FsWorkload : public KernelWorkload
{
protected:
/** Bootloaders */
@@ -70,11 +70,6 @@ class FsWorkload : public OsKernel
*/
ObjectFile *bootldr = nullptr;
/**
* Whether the highest exception level in software is 64 it.
*/
bool _highestELIs64 = true;
/**
* This differs from entry since it takes into account where
* the kernel is loaded in memory (with loadAddrMask and
@@ -99,19 +94,29 @@ class FsWorkload : public OsKernel
return dynamic_cast<const Params *>(&_params);
}
Addr
getEntry() const override
{
if (bootldr)
return bootldr->entryPoint();
else
return kernelEntry;
}
ObjectFile::Arch
getArch() const override
{
if (bootldr)
return bootldr->getArch();
else if (kernelObj)
return kernelObj->getArch();
else
return ObjectFile::Arm64;
}
FsWorkload(Params *p);
void initState() override;
/**
* Returns the reset address to be used by an ArmSystem.
* It the workload is using a bootloader, it will return
* the bootloader entry point.
* @returns Arm reset address
*/
Addr resetAddr() const;
bool highestELIs64() const { return _highestELIs64; }
};
} // namespace ArmISA

View File

@@ -76,8 +76,8 @@ FsLinux::initState()
// 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);
kernelObj->loadGlobalSymbols(kernelSymtab, 0, 0, _loadAddrMask);
kernelObj->loadGlobalSymbols(debugSymbolTable, 0, 0, _loadAddrMask);
}
// Setup boot data structure
@@ -85,14 +85,14 @@ FsLinux::initState()
// 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);
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);
params()->atags_addr + _loadAddrOffset);
DtbFile *dtb_file = new DtbFile(params()->dtb_filename);
@@ -103,7 +103,7 @@ FsLinux::initState()
}
dtb_file->buildImage().
offset(params()->atags_addr + loadAddrOffset).
offset(params()->atags_addr + _loadAddrOffset).
write(system->physProxy);
delete dtb_file;
} else {
@@ -152,7 +152,7 @@ FsLinux::initState()
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,
system->physProxy.writeBlob(params()->atags_addr + _loadAddrOffset,
boot_data, size << 2);
delete[] boot_data;
@@ -162,7 +162,7 @@ FsLinux::initState()
for (auto tc: system->threadContexts) {
tc->setIntReg(0, 0);
tc->setIntReg(1, params()->machine_type);
tc->setIntReg(2, params()->atags_addr + loadAddrOffset);
tc->setIntReg(2, params()->atags_addr + _loadAddrOffset);
}
}
@@ -183,19 +183,18 @@ FsLinux::startup()
{
FsWorkload::startup();
auto *arm_sys = dynamic_cast<ArmSystem *>(system);
if (enableContextSwitchStatsDump) {
if (!arm_sys->highestELIs64())
dumpStats = addKernelFuncEvent<DumpStats>("__switch_to");
else
if (getArch() == ObjectFile::Arm64)
dumpStats = addKernelFuncEvent<DumpStats64>("__switch_to");
else
dumpStats = addKernelFuncEvent<DumpStats>("__switch_to");
panic_if(!dumpStats, "dumpStats not created!");
std::string task_filename = "tasks.txt";
taskFile = simout.create(name() + "." + task_filename);
for (const auto tc : arm_sys->threadContexts) {
for (const auto tc : system->threadContexts) {
uint32_t pid = tc->getCpuPtr()->getPid();
if (pid != BaseCPU::invldPid) {
mapPid(tc, pid);
@@ -238,7 +237,7 @@ FsLinux::startup()
"__const_udelay", "__const_udelay", 1000, 107374);
}
if (highestELIs64()) {
if (getArch() == ObjectFile::Arm64) {
debugPrintk = addKernelFuncEvent<
DebugPrintk<SkipFuncLinux64>>("dprintk");
} else {

View File

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

View File

@@ -73,25 +73,21 @@ ArmSystem::ArmSystem(Params *p)
semihosting(p->semihosting),
multiProc(p->multi_proc)
{
auto *arm_workload = dynamic_cast<ArmISA::FsWorkload *>(p->workload);
panic_if(!arm_workload,
"Workload was not the expected type (ArmISA::FsWorkload).");
if (p->auto_reset_addr) {
_resetAddr = arm_workload->resetAddr();
_resetAddr = workload->getEntry();
} else {
_resetAddr = p->reset_addr;
warn_if(arm_workload->resetAddr() != _resetAddr,
warn_if(workload->getEntry() != _resetAddr,
"Workload entry point %#x and reset address %#x are different",
arm_workload->resetAddr(), _resetAddr);
workload->getEntry(), _resetAddr);
}
if (arm_workload->highestELIs64() != _highestELIs64) {
bool wl_is_64 = (workload->getArch() == ObjectFile::Arm64);
if (wl_is_64 != _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();
_highestELIs64 ? 64 : 32, wl_is_64 ? 64 : 32);
_highestELIs64 = wl_is_64;
}
if (_highestELIs64 && (

View File

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

View File

@@ -30,9 +30,9 @@
from m5.params import *
from m5.objects.System import System
from m5.objects.OsKernel import OsKernel
from m5.objects.Workload import Workload
class RiscvFsWorkload(OsKernel):
class RiscvFsWorkload(Workload):
type = 'RiscvFsWorkload'
cxx_class = 'RiscvISA::FsWorkload'
cxx_header = 'arch/riscv/fs_workload.hh'

View File

@@ -28,6 +28,7 @@
#include "arch/riscv/bare_metal/fs_workload.hh"
#include "arch/riscv/faults.hh"
#include "base/loader/object_file.hh"
#include "sim/system.hh"
@@ -51,6 +52,12 @@ void
BareMetal::initState()
{
RiscvISA::FsWorkload::initState();
for (auto *tc: system->threadContexts) {
RiscvISA::Reset().invoke(tc);
tc->activate();
}
warn_if(!bootloader->buildImage().write(system->physProxy),
"Could not load sections to memory.");
}

View File

@@ -47,6 +47,22 @@ class BareMetal : public RiscvISA::FsWorkload
~BareMetal();
void initState() override;
ObjectFile::Arch
getArch() const override
{
return bootloader->getArch();
}
const SymbolTable *
symtab(ThreadContext *tc) override
{
return bootloaderSymtab;
}
bool
insertSymbol(Addr address, const std::string &symbol) override
{
return bootloaderSymtab->insert(address, symbol);
}
};
} // namespace RiscvISA

View File

@@ -1,72 +0,0 @@
/*
* 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/system.hh"
#include "arch/riscv/faults.hh"
#include "base/loader/object_file.hh"
BareMetalRiscvSystem::BareMetalRiscvSystem(Params *p)
: RiscvSystem(p),
bootloader(createObjectFile(p->bootloader))
{
if (bootloader == NULL) {
fatal("Could not load bootloader file %s", p->bootloader);
}
_resetVect = bootloader->entryPoint();
}
BareMetalRiscvSystem::~BareMetalRiscvSystem()
{
delete bootloader;
}
void
BareMetalRiscvSystem::initState()
{
// Call the initialisation of the super class
RiscvSystem::initState();
for (auto *tc: threadContexts) {
RiscvISA::Reset().invoke(tc);
tc->activate();
}
// load program sections into memory
if (!bootloader->buildImage().write(physProxy)) {
warn("could not load sections to memory");
}
}
BareMetalRiscvSystem *
BareMetalRiscvSystemParams::create()
{
return new BareMetalRiscvSystem(this);
}

View File

@@ -31,13 +31,13 @@
#define __ARCH_RISCV_FS_WORKLOAD_HH__
#include "params/RiscvFsWorkload.hh"
#include "sim/os_kernel.hh"
#include "sim/sim_object.hh"
#include "sim/workload.hh"
namespace RiscvISA
{
class FsWorkload : public OsKernel
class FsWorkload : public Workload
{
protected:
// checker for bare metal application
@@ -46,7 +46,7 @@ class FsWorkload : public OsKernel
Addr _resetVect;
public:
FsWorkload(RiscvFsWorkloadParams *p) : OsKernel(*p),
FsWorkload(RiscvFsWorkloadParams *p) : Workload(p),
_isBareMetal(p->bare_metal), _resetVect(p->reset_vect)
{}
@@ -55,6 +55,8 @@ class FsWorkload : public OsKernel
// return bare metal checker
bool isBareMetal() const { return _isBareMetal; }
Addr getEntry() const override { return _resetVect; }
};
} // namespace RiscvISA

View File

@@ -26,11 +26,9 @@
from m5.params import *
from m5.objects.OsKernel import OsKernel
from m5.objects.Workload import Workload
class SparcFsWorkload(OsKernel):
class SparcFsWorkload(Workload):
type = 'SparcFsWorkload'
cxx_header = 'arch/sparc/fs_workload.hh'
cxx_class = 'SparcISA::FsWorkload'
load_addr_mask = 0xffffffffff

View File

@@ -38,7 +38,7 @@ namespace SparcISA
void
FsWorkload::initState()
{
OsKernel::initState();
Workload::initState();
if (system->threadContexts.empty())
return;

View File

@@ -29,17 +29,42 @@
#ifndef __ARCH_SPARC_FS_WORKLOAD_HH__
#define __ARCH_SPARC_FS_WORKLOAD_HH__
#include "arch/sparc/faults.hh"
#include "params/SparcFsWorkload.hh"
#include "sim/os_kernel.hh"
#include "sim/workload.hh"
namespace SparcISA
{
class FsWorkload : public OsKernel
class FsWorkload : public Workload
{
protected:
SymbolTable defaultSymtab;
public:
FsWorkload(SparcFsWorkloadParams *p) : OsKernel(*p) {}
FsWorkload(SparcFsWorkloadParams *params) : Workload(params) {}
void initState() override;
Addr
getEntry() const override
{
Addr pc, npc;
getREDVector(0x001, pc, npc);
return pc;
}
ObjectFile::Arch getArch() const override { return ObjectFile::SPARC64; }
const SymbolTable *
symtab(ThreadContext *tc) override
{
return &defaultSymtab;
}
bool
insertSymbol(Addr address, const std::string &symbol) override
{
return defaultSymtab.insert(address, symbol);
}
};
} // namespace SparcISA

View File

@@ -39,9 +39,9 @@ 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
from m5.objects.Workload import KernelWorkload
class X86FsWorkload(OsKernel):
class X86FsWorkload(KernelWorkload):
type = 'X86FsWorkload'
cxx_header = 'arch/x86/fs_workload.hh'
cxx_class = 'X86ISA::FsWorkload'

View File

@@ -50,7 +50,7 @@
namespace X86ISA
{
FsWorkload::FsWorkload(Params *p) : OsKernel(*p),
FsWorkload::FsWorkload(Params *p) : KernelWorkload(*p),
smbiosTable(p->smbios_table),
mpFloatingPointer(p->intel_mp_pointer),
mpConfigTable(p->intel_mp_table),
@@ -104,7 +104,7 @@ installSegDesc(ThreadContext *tc, SegmentRegIndex seg,
void
FsWorkload::initState()
{
OsKernel::initState();
KernelWorkload::initState();
for (auto *tc: system->threadContexts) {
X86ISA::InitInterrupt(0).invoke(tc);
@@ -119,9 +119,9 @@ FsWorkload::initState()
}
}
fatal_if(!obj, "No kernel to load.");
fatal_if(!kernelObj, "No kernel to load.");
fatal_if(obj->getArch() == ObjectFile::I386,
fatal_if(kernelObj->getArch() == ObjectFile::I386,
"Loading a 32 bit x86 kernel is not supported.");
ThreadContext *tc = system->threadContexts[0];
@@ -304,7 +304,7 @@ FsWorkload::initState()
cr0.pg = 1;
tc->setMiscReg(MISCREG_CR0, cr0);
tc->pcState(entry);
tc->pcState(kernelObj->entryPoint());
// We should now be in long mode. Yay!

View File

@@ -46,7 +46,7 @@
#include "base/types.hh"
#include "cpu/thread_context.hh"
#include "params/X86FsWorkload.hh"
#include "sim/os_kernel.hh"
#include "sim/kernel_workload.hh"
namespace X86ISA
{
@@ -79,7 +79,7 @@ const Addr MMIORegionPhysAddr = 0xffff0000;
void installSegDesc(ThreadContext *tc, SegmentRegIndex seg,
SegDescriptor desc, bool longmode);
class FsWorkload : public OsKernel
class FsWorkload : public KernelWorkload
{
public:
typedef X86FsWorkloadParams Params;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -99,7 +99,7 @@ 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")
workload = Param.Workload(NULL, "Operating system kernel")
init_param = Param.UInt64(0, "numerical value to pass into simulator")
readfile = Param.String("", "file to read startup script from")
symbolfile = Param.String("", "file to get the symbols from")

View File

@@ -28,9 +28,14 @@ from m5.SimObject import SimObject
from m5.objects.SimpleMemory import *
class OsKernel(SimObject):
type = 'OsKernel'
cxx_header = "sim/os_kernel.hh"
class Workload(SimObject):
type = 'Workload'
cxx_header = "sim/workload.hh"
abstract = True
class KernelWorkload(Workload):
type = 'KernelWorkload'
cxx_header = "sim/kernel_workload.hh"
object_file = Param.String("", "File that contains the kernel code")
extras = VectorParam.String([], "Additional object files to load")

View File

@@ -35,6 +35,7 @@
#include "cpu/pc_event.hh"
#include "sim/eventq_impl.hh"
#include "sim/global_event.hh"
#include "sim/kernel_workload.hh"
#include "sim/sim_events.hh"
#include "sim/sim_exit.hh"
#include "sim/system.hh"

View File

@@ -25,59 +25,52 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "sim/os_kernel.hh"
#include "sim/kernel_workload.hh"
#include "base/loader/object_file.hh"
#include "base/loader/symtab.hh"
#include "debug/Loader.hh"
#include "params/OsKernel.hh"
#include "params/KernelWorkload.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)
KernelWorkload::KernelWorkload(const Params &p) : Workload(&p), _params(p),
_loadAddrMask(p.load_addr_mask), _loadAddrOffset(p.load_addr_offset),
kernelSymtab(new SymbolTable), commandLine(p.command_line)
{
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);
kernelObj = createObjectFile(params().object_file);
inform("kernel located at: %s", params().object_file);
fatal_if(!obj, "Could not load kernel file %s", params().object_file);
fatal_if(!kernelObj,
"Could not load kernel file %s", params().object_file);
image = obj->buildImage();
image = kernelObj->buildImage();
start = image.minAddr();
end = image.maxAddr();
entry = obj->entryPoint();
_start = image.minAddr();
_end = image.maxAddr();
// 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);
// 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;
});
image.move([this](Addr a) {
return (a & _loadAddrMask) + _loadAddrOffset;
});
// load symbols
fatal_if(!obj->loadGlobalSymbols(symtab),
"Could not load kernel symbols.");
// load symbols
fatal_if(!kernelObj->loadGlobalSymbols(kernelSymtab),
"Could not load kernel symbols.");
fatal_if(!obj->loadLocalSymbols(symtab),
"Could not load kernel local symbols.");
fatal_if(!kernelObj->loadLocalSymbols(kernelSymtab),
"Could not load kernel local symbols.");
fatal_if(!obj->loadGlobalSymbols(debugSymbolTable),
"Could not load kernel symbols.");
fatal_if(!kernelObj->loadGlobalSymbols(debugSymbolTable),
"Could not load kernel symbols.");
fatal_if(!obj->loadLocalSymbols(debugSymbolTable),
"Could not load kernel local symbols.");
}
fatal_if(!kernelObj->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()
@@ -97,42 +90,36 @@ OsKernel::OsKernel(const Params &p) : SimObject(&p), _params(p),
}
}
Addr
OsKernel::fixFuncEventAddr(Addr addr)
KernelWorkload::~KernelWorkload()
{
return system->fixFuncEventAddr(addr);
}
OsKernel::~OsKernel()
{
delete symtab;
delete kernelSymtab;
}
void
OsKernel::initState()
KernelWorkload::initState()
{
auto &phys_mem = system->physProxy;
/**
* Load the kernel code into memory.
*/
auto mapper = [this](Addr a) {
return (a & loadAddrMask) + loadAddrOffset;
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)),
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));
_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 start = %#x\n", _start);
DPRINTF(Loader, "Kernel end = %#x\n", _end);
DPRINTF(Loader, "Kernel entry = %#x\n", kernelObj->entryPoint());
DPRINTF(Loader, "Kernel loaded...\n");
}
@@ -151,21 +138,19 @@ OsKernel::initState()
}
void
OsKernel::serialize(CheckpointOut &cp) const
KernelWorkload::serialize(CheckpointOut &cp) const
{
symtab->serialize("symtab", cp);
serializeSymtab(cp);
kernelSymtab->serialize("symtab", cp);
}
void
OsKernel::unserialize(CheckpointIn &cp)
KernelWorkload::unserialize(CheckpointIn &cp)
{
symtab->unserialize("symtab", cp);
unserializeSymtab(cp);
kernelSymtab->unserialize("symtab", cp);
}
OsKernel *
OsKernelParams::create()
KernelWorkload *
KernelWorkloadParams::create()
{
return new OsKernel(*this);
return new KernelWorkload(*this);
}

View File

@@ -25,114 +25,83 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __SIM_OS_KERNEL_HH__
#define __SIM_OS_KERNEL_HH__
#ifndef __SIM_KERNEL_WORKLOAD_HH__
#define __SIM_KERNEL_WORKLOAD_HH__
#include "base/loader/memory_image.hh"
#include "base/loader/symtab.hh"
#include "params/OsKernel.hh"
#include "sim/sim_object.hh"
#include <string>
#include <vector>
#include "base/loader/object_file.hh"
#include "base/types.hh"
#include "params/KernelWorkload.hh"
#include "sim/workload.hh"
class ObjectFile;
class SymbolTable;
class System;
class OsKernel : public SimObject
class KernelWorkload : public Workload
{
public:
using Params = OsKernelParams;
using Params = KernelWorkloadParams;
protected:
const Params &_params;
Addr fixFuncEventAddr(Addr);
public:
OsKernel(const Params &p);
~OsKernel();
const Params &params() { return _params; }
void initState() override;
const std::string commandLine;
void serialize(CheckpointOut &cp) const override;
void unserialize(CheckpointIn &cp) override;
System *system = nullptr;
ObjectFile *obj = nullptr;
SymbolTable *symtab = nullptr;
MemoryImage image;
Addr start = 0;
Addr end = MaxAddr;
Addr entry = 0;
/** Mask that should be anded for binary/symbol loading.
* This allows one two different OS requirements for the same ISA to be
* handled. Some OSes are compiled for a virtual address and need to be
* loaded into physical memory that starts at address 0, while other
* bare metal tools generate images that start at address 0.
*/
Addr loadAddrMask;
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;
Addr _loadAddrOffset;
Addr _start, _end;
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)
ObjectFile *kernelObj = nullptr;
SymbolTable *kernelSymtab = nullptr;
const std::string commandLine;
public:
const Params &params() const { return _params; }
Addr start() const { return _start; }
Addr end() const { return _end; }
Addr loadAddrMask() const { return _loadAddrMask; }
Addr loadAddrOffset() const { return _loadAddrOffset; }
KernelWorkload(const Params &p);
~KernelWorkload();
Addr getEntry() const override { return kernelObj->entryPoint(); }
ObjectFile::Arch getArch() const override { return kernelObj->getArch(); }
const SymbolTable *
symtab(ThreadContext *tc) override
{
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;
return kernelSymtab;
}
template <class T>
T *
addFuncEvent(const SymbolTable *symtab, const char *lbl)
bool
insertSymbol(Addr address, const std::string &symbol)
{
return addFuncEvent<T>(symtab, lbl, lbl);
return kernelSymtab->insert(address, symbol);
}
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;
}
/** @} */
void initState() override;
void serialize(CheckpointOut &cp) const override;
void unserialize(CheckpointIn &cp) override;
/** @{ */
/**
@@ -153,37 +122,18 @@ class OsKernel : public SimObject
T *
addKernelFuncEvent(const char *lbl, Args... args)
{
return addFuncEvent<T>(symtab, lbl, std::forward<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>(symtab, lbl, std::forward<Args>(args)...));
if (!e)
panic("Failed to find kernel symbol '%s'", lbl);
T *e = addFuncEvent<T>(kernelSymtab, lbl, std::forward<Args>(args)...);
panic_if(!e, "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__
#endif // __SIM_KERNEL_WORKLOAD_HH__

View File

@@ -217,7 +217,7 @@ loadsymbol(ThreadContext *tc)
if (!to_number(address, addr))
continue;
if (!tc->getSystemPtr()->workload->symtab->insert(addr, symbol))
if (!tc->getSystemPtr()->workload->insertSymbol(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()->workload->symtab->insert(addr,symbol);
tc->getSystemPtr()->workload->insertSymbol(addr, symbol);
debugSymbolTable->insert(addr,symbol);
}

View File

@@ -60,10 +60,10 @@
#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"
#include "sim/workload.hh"
class BaseRemoteGDB;
class KvmVM;
@@ -211,7 +211,7 @@ class System : public SimObject, public PCEventScope
PortProxy physProxy;
/** OS kernel */
OsKernel *workload = nullptr;
Workload *workload = nullptr;
public:
/**

View File

@@ -1,6 +1,5 @@
/*
* Copyright (c) 2018 TU Dresden
* All rights reserved
* Copyright 2019 Google Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -26,25 +25,13 @@
* 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 "sim/workload.hh"
#include "arch/riscv/system.hh"
#include "params/BareMetalRiscvSystem.hh"
#include "params/Workload.hh"
#include "sim/system.hh"
class BareMetalRiscvSystem : public RiscvSystem
Addr
Workload::fixFuncEventAddr(Addr addr)
{
protected:
ObjectFile* bootloader;
public:
typedef BareMetalRiscvSystemParams Params;
BareMetalRiscvSystem(Params *p);
~BareMetalRiscvSystem();
// initialize the system
virtual void initState();
};
#endif // __ARCH_RISCV_BARE_METAL_SYSTEM_HH__
return system->fixFuncEventAddr(addr);
}

102
src/sim/workload.hh Normal file
View File

@@ -0,0 +1,102 @@
/*
* 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_WORKLOAD_HH__
#define __SIM_WORKLOAD_HH__
#include "base/loader/object_file.hh"
#include "base/loader/symtab.hh"
#include "params/Workload.hh"
#include "sim/sim_object.hh"
class System;
class ThreadContext;
class Workload : public SimObject
{
protected:
Addr fixFuncEventAddr(Addr);
public:
using SimObject::SimObject;
System *system = nullptr;
virtual Addr getEntry() const = 0;
virtual ObjectFile::Arch getArch() const = 0;
virtual const SymbolTable *symtab(ThreadContext *tc) = 0;
virtual bool insertSymbol(Addr address, const std::string &symbol) = 0;
/** @{ */
/**
* 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;
}
/** @} */
};
#endif // __SIM_WORKLOAD_HH__