Gabe Black has submitted this change. ( https://gem5-review.googlesource.com/c/public/gem5/+/24283 )

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

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.travagl...@arm.com>
Maintainer: Gabe Black <gabebl...@google.com>
Tested-by: kokoro <noreply+kok...@google.com>
---
M configs/common/FSConfig.py
M src/arch/arm/ArmFsWorkload.py
M src/arch/arm/freebsd/fs_workload.cc
M src/arch/arm/fs_workload.cc
M src/arch/arm/fs_workload.hh
M src/arch/arm/linux/fs_workload.cc
M src/arch/arm/stacktrace.cc
M src/arch/arm/system.cc
M src/arch/generic/linux/threadinfo.hh
M src/arch/riscv/RiscvFsWorkload.py
M src/arch/riscv/bare_metal/fs_workload.cc
M src/arch/riscv/bare_metal/fs_workload.hh
D src/arch/riscv/bare_metal/system.cc
M src/arch/riscv/fs_workload.hh
M src/arch/sparc/SparcFsWorkload.py
M src/arch/sparc/fs_workload.cc
M src/arch/sparc/fs_workload.hh
M src/arch/x86/X86FsWorkload.py
M src/arch/x86/fs_workload.cc
M src/arch/x86/fs_workload.hh
M src/arch/x86/stacktrace.cc
M src/cpu/o3/thread_state.hh
M src/cpu/simple_thread.cc
M src/kern/linux/helpers.cc
M src/sim/SConscript
M src/sim/System.py
R src/sim/Workload.py
M src/sim/debug.cc
A src/sim/kernel_workload.cc
A src/sim/kernel_workload.hh
D src/sim/os_kernel.cc
D src/sim/os_kernel.hh
M src/sim/pseudo_inst.cc
M src/sim/system.hh
R src/sim/workload.cc
A src/sim/workload.hh
36 files changed, 562 insertions(+), 572 deletions(-)

Approvals:
  Giacomo Travaglini: Looks good to me, approved
  Gabe Black: Looks good to me, approved
  kokoro: Regressions pass



diff --git a/configs/common/FSConfig.py b/configs/common/FSConfig.py
index a424a30..b3e248e 100644
--- a/configs/common/FSConfig.py
+++ b/configs/common/FSConfig.py
@@ -388,7 +388,7 @@
     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

diff --git a/src/arch/arm/ArmFsWorkload.py b/src/arch/arm/ArmFsWorkload.py
index 459f830..bc27c6d 100644
--- a/src/arch/arm/ArmFsWorkload.py
+++ b/src/arch/arm/ArmFsWorkload.py
@@ -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 @@
         'DTOnly' : -1,
     }

-class ArmFsWorkload(OsKernel):
+class ArmFsWorkload(KernelWorkload):
     type = 'ArmFsWorkload'
     cxx_header = "arch/arm/fs_workload.hh"
     cxx_class = "ArmISA::FsWorkload"
diff --git a/src/arch/arm/freebsd/fs_workload.cc b/src/arch/arm/freebsd/fs_workload.cc
index dbadb4b..4eff04d 100644
--- a/src/arch/arm/freebsd/fs_workload.cc
+++ b/src/arch/arm/freebsd/fs_workload.cc
@@ -81,21 +81,21 @@
     // 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 @@
         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 @@
     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);
     }
 }

diff --git a/src/arch/arm/fs_workload.cc b/src/arch/arm/fs_workload.cc
index 8f40293..50a3213 100644
--- a/src/arch/arm/fs_workload.cc
+++ b/src/arch/arm/fs_workload.cc
@@ -69,9 +69,8 @@
     }
 }

-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 @@
         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 @@
     } 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 *
diff --git a/src/arch/arm/fs_workload.hh b/src/arch/arm/fs_workload.hh
index 6e1af08..d6e375c 100644
--- a/src/arch/arm/fs_workload.hh
+++ b/src/arch/arm/fs_workload.hh
@@ -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 @@
     void returnFromFuncIn(ThreadContext *tc) override;
 };

-class FsWorkload : public OsKernel
+class FsWorkload : public KernelWorkload
 {
   protected:
     /** Bootloaders */
@@ -71,11 +71,6 @@
     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
      * loadAddrOffset).
@@ -99,19 +94,29 @@
         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
diff --git a/src/arch/arm/linux/fs_workload.cc b/src/arch/arm/linux/fs_workload.cc
index fe023cc..65f0675 100644
--- a/src/arch/arm/linux/fs_workload.cc
+++ b/src/arch/arm/linux/fs_workload.cc
@@ -76,8 +76,8 @@
     // 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 @@
     // 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 @@
         }

         dtb_file->buildImage().
-            offset(params()->atags_addr + loadAddrOffset).
+            offset(params()->atags_addr + _loadAddrOffset).
             write(system->physProxy);
         delete dtb_file;
     } else {
@@ -152,7 +152,7 @@
         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 @@
     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 @@
 {
     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 @@
             "__const_udelay", "__const_udelay", 1000, 107374);
     }

-    if (highestELIs64()) {
+    if (getArch() == ObjectFile::Arm64) {
         debugPrintk = addKernelFuncEvent<
             DebugPrintk<SkipFuncLinux64>>("dprintk");
     } else {
diff --git a/src/arch/arm/stacktrace.cc b/src/arch/arm/stacktrace.cc
index b5a9976..df3f6a2 100644
--- a/src/arch/arm/stacktrace.cc
+++ b/src/arch/arm/stacktrace.cc
@@ -45,7 +45,7 @@
 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))
diff --git a/src/arch/arm/system.cc b/src/arch/arm/system.cc
index b03f0f5..dd3b9a5 100644
--- a/src/arch/arm/system.cc
+++ b/src/arch/arm/system.cc
@@ -73,25 +73,21 @@
       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 && (
diff --git a/src/arch/generic/linux/threadinfo.hh b/src/arch/generic/linux/threadinfo.hh
index 9712113..83e41b9 100644
--- a/src/arch/generic/linux/threadinfo.hh
+++ b/src/arch/generic/linux/threadinfo.hh
@@ -47,7 +47,7 @@
     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"); diff --git a/src/arch/riscv/RiscvFsWorkload.py b/src/arch/riscv/RiscvFsWorkload.py
index 5d1db98..93e8fce 100644
--- a/src/arch/riscv/RiscvFsWorkload.py
+++ b/src/arch/riscv/RiscvFsWorkload.py
@@ -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'
diff --git a/src/arch/riscv/bare_metal/fs_workload.cc b/src/arch/riscv/bare_metal/fs_workload.cc
index 5c03128..41fefe9 100644
--- a/src/arch/riscv/bare_metal/fs_workload.cc
+++ b/src/arch/riscv/bare_metal/fs_workload.cc
@@ -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 @@
 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.");
 }
diff --git a/src/arch/riscv/bare_metal/fs_workload.hh b/src/arch/riscv/bare_metal/fs_workload.hh
index 722806d..37bffcf 100644
--- a/src/arch/riscv/bare_metal/fs_workload.hh
+++ b/src/arch/riscv/bare_metal/fs_workload.hh
@@ -47,6 +47,22 @@
     ~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
diff --git a/src/arch/riscv/bare_metal/system.cc b/src/arch/riscv/bare_metal/system.cc
deleted file mode 100644
index 1ca8ed9..0000000
--- a/src/arch/riscv/bare_metal/system.cc
+++ /dev/null
@@ -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);
-}
-
diff --git a/src/arch/riscv/fs_workload.hh b/src/arch/riscv/fs_workload.hh
index aaa9d0f..0fbd717 100644
--- a/src/arch/riscv/fs_workload.hh
+++ b/src/arch/riscv/fs_workload.hh
@@ -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 @@
     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 @@

     // return bare metal checker
     bool isBareMetal() const { return _isBareMetal; }
+
+    Addr getEntry() const override { return _resetVect; }
 };

 } // namespace RiscvISA
diff --git a/src/arch/sparc/SparcFsWorkload.py b/src/arch/sparc/SparcFsWorkload.py
index 6244882..ffc3f2b 100644
--- a/src/arch/sparc/SparcFsWorkload.py
+++ b/src/arch/sparc/SparcFsWorkload.py
@@ -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
diff --git a/src/arch/sparc/fs_workload.cc b/src/arch/sparc/fs_workload.cc
index e0fa8e4..71c3b45 100644
--- a/src/arch/sparc/fs_workload.cc
+++ b/src/arch/sparc/fs_workload.cc
@@ -38,7 +38,7 @@
 void
 FsWorkload::initState()
 {
-    OsKernel::initState();
+    Workload::initState();

     if (system->threadContexts.empty())
         return;
diff --git a/src/arch/sparc/fs_workload.hh b/src/arch/sparc/fs_workload.hh
index 2ffc06a..d97b922 100644
--- a/src/arch/sparc/fs_workload.hh
+++ b/src/arch/sparc/fs_workload.hh
@@ -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
diff --git a/src/arch/x86/X86FsWorkload.py b/src/arch/x86/X86FsWorkload.py
index 3628c94..1a4248f 100644
--- a/src/arch/x86/X86FsWorkload.py
+++ b/src/arch/x86/X86FsWorkload.py
@@ -39,9 +39,9 @@
 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'
diff --git a/src/arch/x86/fs_workload.cc b/src/arch/x86/fs_workload.cc
index c38fc9b..6ad42db 100644
--- a/src/arch/x86/fs_workload.cc
+++ b/src/arch/x86/fs_workload.cc
@@ -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 @@
 void
 FsWorkload::initState()
 {
-    OsKernel::initState();
+    KernelWorkload::initState();

     for (auto *tc: system->threadContexts) {
         X86ISA::InitInterrupt(0).invoke(tc);
@@ -119,9 +119,9 @@
         }
     }

-    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 @@
     cr0.pg = 1;
     tc->setMiscReg(MISCREG_CR0, cr0);

-    tc->pcState(entry);
+    tc->pcState(kernelObj->entryPoint());

     // We should now be in long mode. Yay!

diff --git a/src/arch/x86/fs_workload.hh b/src/arch/x86/fs_workload.hh
index 5b972ec..7080feb 100644
--- a/src/arch/x86/fs_workload.hh
+++ b/src/arch/x86/fs_workload.hh
@@ -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 @@
 void installSegDesc(ThreadContext *tc, SegmentRegIndex seg,
                     SegDescriptor desc, bool longmode);

-class FsWorkload : public OsKernel
+class FsWorkload : public KernelWorkload
 {
   public:
     typedef X86FsWorkloadParams Params;
diff --git a/src/arch/x86/stacktrace.cc b/src/arch/x86/stacktrace.cc
index 64f2d4b..677ab65 100644
--- a/src/arch/x86/stacktrace.cc
+++ b/src/arch/x86/stacktrace.cc
@@ -45,7 +45,7 @@
 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 @@
 StackTrace::dump()
 {
     StringWrap name(tc->getCpuPtr()->name());
-    SymbolTable *symtab = tc->getSystemPtr()->workload->symtab;
+    const SymbolTable *symtab = tc->getSystemPtr()->workload->symtab(tc);

     DPRINTFN("------ Stack ------\n");

diff --git a/src/cpu/o3/thread_state.hh b/src/cpu/o3/thread_state.hh
index b1814db..030dc4b 100644
--- a/src/cpu/o3/thread_state.hh
+++ b/src/cpu/o3/thread_state.hh
@@ -104,7 +104,7 @@

         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);
diff --git a/src/cpu/simple_thread.cc b/src/cpu/simple_thread.cc
index 9e2e55e..ef8e074 100644
--- a/src/cpu/simple_thread.cc
+++ b/src/cpu/simple_thread.cc
@@ -98,7 +98,7 @@
     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);
diff --git a/src/kern/linux/helpers.cc b/src/kern/linux/helpers.cc
index 5598440..548ae0f 100644
--- a/src/kern/linux/helpers.cc
+++ b/src/kern/linux/helpers.cc
@@ -93,7 +93,7 @@
 {
     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;
diff --git a/src/sim/SConscript b/src/sim/SConscript
index 9687796..0057d28 100644
--- a/src/sim/SConscript
+++ b/src/sim/SConscript
@@ -30,7 +30,7 @@

 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('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')
diff --git a/src/sim/System.py b/src/sim/System.py
index 0d1f730..61fbe0e 100644
--- a/src/sim/System.py
+++ b/src/sim/System.py
@@ -99,7 +99,7 @@
     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")
diff --git a/src/sim/OsKernel.py b/src/sim/Workload.py
similarity index 91%
rename from src/sim/OsKernel.py
rename to src/sim/Workload.py
index 93cb74f..1e35abe 100644
--- a/src/sim/OsKernel.py
+++ b/src/sim/Workload.py
@@ -28,9 +28,14 @@

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

     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);
 }

diff --git a/src/sim/system.hh b/src/sim/system.hh
index f9a437b..09ba7b4 100644
--- a/src/sim/system.hh
+++ b/src/sim/system.hh
@@ -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 @@
     PortProxy physProxy;

     /** OS kernel */
-    OsKernel *workload = nullptr;
+    Workload *workload = nullptr;

   public:
     /**
diff --git a/src/arch/riscv/bare_metal/system.hh b/src/sim/workload.cc
similarity index 72%
rename from src/arch/riscv/bare_metal/system.hh
rename to src/sim/workload.cc
index 1f665be..06773f9 100644
--- a/src/arch/riscv/bare_metal/system.hh
+++ b/src/sim/workload.cc
@@ -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);
+}
diff --git a/src/sim/workload.hh b/src/sim/workload.hh
new file mode 100644
index 0000000..2dbcaa0
--- /dev/null
+++ b/src/sim/workload.hh
@@ -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__

--
To view, visit https://gem5-review.googlesource.com/c/public/gem5/+/24283
To unsubscribe, or for help writing mail filters, visit https://gem5-review.googlesource.com/settings

Gerrit-Project: public/gem5
Gerrit-Branch: develop
Gerrit-Change-Id: Idf72615260266d7b4478d20d4035ed5a1e7aa241
Gerrit-Change-Number: 24283
Gerrit-PatchSet: 28
Gerrit-Owner: Gabe Black <gabebl...@google.com>
Gerrit-Reviewer: Brandon Potter <brandon.pot...@amd.com>
Gerrit-Reviewer: Gabe Black <gabebl...@google.com>
Gerrit-Reviewer: Gem5 Cloud Project GCB service account <345032938...@cloudbuild.gserviceaccount.com>
Gerrit-Reviewer: Giacomo Travaglini <giacomo.travagl...@arm.com>
Gerrit-Reviewer: Jason Lowe-Power <power...@gmail.com>
Gerrit-Reviewer: kokoro <noreply+kok...@google.com>
Gerrit-CC: Alexandru Duțu <alexandru.d...@amd.com>
Gerrit-MessageType: merged
_______________________________________________
gem5-dev mailing list -- gem5-dev@gem5.org
To unsubscribe send an email to gem5-dev-le...@gem5.org
%(web_page_url)slistinfo%(cgiext)s/%(_internal_name)s

Reply via email to