From 46a9d85215ec91c277c954944d1db64d28c28537 Mon Sep 17 00:00:00 2001 From: Hoa Nguyen Date: Wed, 4 Oct 2023 00:56:48 -0700 Subject: [PATCH] arch-riscv: Add bootloader+kernel workload Aims to boot OpenSBI + Linux kernel. Change-Id: I9ee93cc367e8c06bdd0c7ddf43335d32965be14d Signed-off-by: Hoa Nguyen --- src/arch/riscv/RiscvFsWorkload.py | 34 ++++++++++ src/arch/riscv/SConscript | 4 +- src/arch/riscv/linux/fs_workload.cc | 102 ++++++++++++++++++++++++++++ src/arch/riscv/linux/fs_workload.hh | 61 +++++++++++++++++ 4 files changed, 200 insertions(+), 1 deletion(-) diff --git a/src/arch/riscv/RiscvFsWorkload.py b/src/arch/riscv/RiscvFsWorkload.py index 9e158811da..a71dc1acaf 100644 --- a/src/arch/riscv/RiscvFsWorkload.py +++ b/src/arch/riscv/RiscvFsWorkload.py @@ -52,3 +52,37 @@ class RiscvLinux(KernelWorkload): "", "File that contains the Device Tree Blob. Don't use DTB if empty." ) dtb_addr = Param.Addr(0x87E00000, "DTB address") + + +class RiscvBootloaderKernelWorkload(Workload): + type = "RiscvBootloaderKernelWorkload" + cxx_class = "gem5::RiscvISA::BootloaderKernelWorkload" + cxx_header = "arch/riscv/linux/fs_workload.hh" + + bootloader_filename = Param.String( + "", "File that contains the bootloader. Don't use bootloader if empty." + ) + bootloader_addr = Param.Addr( + 0x0, "Where to place the bootloader in memory." + ) + kernel_filename = Param.String( + "", "vmlinux file. Don't use kernel if empty." + ) + kernel_addr = Param.Addr( + 0x80200000, + "Where to place the kernel in memory. Typically, after the first " + "stage of booting is done, the bootloader will jump to where the " + "`start` symbol of the kernel is.", + ) + entry_point = Param.Addr( + 0x80000000, "Where to find the first instruction to execute." + ) + dtb_filename = Param.String( + "", "File that contains the Device Tree Blob. Don't use DTB if empty." + ) + dtb_addr = Param.Addr(0x87E00000, "Where to place the DTB in memory.") + + # booting parameters + boot_args = Param.String( + "", "Booting arguments, to be passed to the kernel" + ) diff --git a/src/arch/riscv/SConscript b/src/arch/riscv/SConscript index 924bba5915..bf40b6eccd 100644 --- a/src/arch/riscv/SConscript +++ b/src/arch/riscv/SConscript @@ -66,7 +66,9 @@ Source('bare_metal/fs_workload.cc', tags='riscv isa') SimObject('PMAChecker.py', sim_objects=['PMAChecker'], tags='riscv isa') SimObject('PMP.py', sim_objects=['PMP'], tags='riscv isa') SimObject('RiscvDecoder.py', sim_objects=['RiscvDecoder'], tags='riscv isa') -SimObject('RiscvFsWorkload.py', sim_objects=['RiscvBareMetal', 'RiscvLinux'], +SimObject('RiscvFsWorkload.py', + sim_objects=['RiscvBareMetal', 'RiscvLinux', + 'RiscvBootloaderKernelWorkload'], tags='riscv isa') SimObject('RiscvInterrupts.py', sim_objects=['RiscvInterrupts'], tags='riscv isa') diff --git a/src/arch/riscv/linux/fs_workload.cc b/src/arch/riscv/linux/fs_workload.cc index 4a4a3812ec..0cd0e761d2 100644 --- a/src/arch/riscv/linux/fs_workload.cc +++ b/src/arch/riscv/linux/fs_workload.cc @@ -75,5 +75,107 @@ FsLinux::initState() } } +void +BootloaderKernelWorkload::loadBootloaderSymbolTable() +{ + if (params().bootloader_filename != "") { + Addr bootloader_paddr_offset = params().bootloader_addr; + bootloader = loader::createObjectFile(params().bootloader_filename); + bootloaderSymbolTable = bootloader->symtab(); + auto renamedBootloaderSymbolTable = \ + bootloaderSymbolTable.offset(bootloader_paddr_offset)->rename( + [](std::string &name) { + name = "bootloader." + name; + } + ); + loader::debugSymbolTable.insert(*renamedBootloaderSymbolTable); + } +} + +void +BootloaderKernelWorkload::loadKernelSymbolTable() +{ + if (params().kernel_filename != "") { + Addr kernel_paddr_offset = params().kernel_addr; + kernel = loader::createObjectFile(params().kernel_filename); + kernelSymbolTable = kernel->symtab(); + auto renamedKernelSymbolTable = \ + kernelSymbolTable.offset(kernel_paddr_offset)->rename( + [](std::string &name) { + name = "kernel." + name; + } + ); + loader::debugSymbolTable.insert(*renamedKernelSymbolTable); + } +} + +void +BootloaderKernelWorkload::loadBootloader() +{ + if (params().bootloader_filename != "") { + Addr bootloader_addr_offset = params().bootloader_addr; + bootloader->buildImage().offset(bootloader_addr_offset).write( + system->physProxy + ); + delete bootloader; + } +} + +void +BootloaderKernelWorkload::loadKernel() +{ + if (params().kernel_filename != "") { + Addr kernel_paddr_offset = params().kernel_addr; + kernel->buildImage().offset(kernel_paddr_offset).write( + system->physProxy + ); + delete kernel; + } +} + + +void +BootloaderKernelWorkload::loadDtb() +{ + if (params().dtb_filename != "") { + auto *dtb_file = new loader::DtbFile(params().dtb_filename); + + dtb_file->buildImage().offset(params().dtb_addr) + .write(system->physProxy); + delete dtb_file; + + for (auto *tc: system->threads) { + tc->setReg(int_reg::A1, params().dtb_addr); + } + } +} + +void +BootloaderKernelWorkload::initState() +{ + loadBootloader(); + loadKernel(); + loadDtb(); + + for (auto *tc: system->threads) { + RiscvISA::Reset().invoke(tc); + tc->activate(); + } +} + +void +BootloaderKernelWorkload::serialize(CheckpointOut &checkpoint) const +{ + bootloaderSymbolTable.serialize("bootloader_symbol_table", checkpoint); + kernelSymbolTable.serialize("kernel_symbol_table", checkpoint); +} + +void +BootloaderKernelWorkload::unserialize(CheckpointIn &checkpoint) +{ + bootloaderSymbolTable.unserialize("bootloader_symbol_table", checkpoint); + kernelSymbolTable.unserialize("kernel_symbol_table", checkpoint); +} + } // namespace RiscvISA } // namespace gem5 diff --git a/src/arch/riscv/linux/fs_workload.hh b/src/arch/riscv/linux/fs_workload.hh index 1dc704d906..a0366a27c4 100644 --- a/src/arch/riscv/linux/fs_workload.hh +++ b/src/arch/riscv/linux/fs_workload.hh @@ -29,7 +29,10 @@ #ifndef __ARCH_RISCV_LINUX_SYSTEM_HH__ #define __ARCH_RISCV_LINUX_SYSTEM_HH__ +#include + #include "arch/riscv/remote_gdb.hh" +#include "params/RiscvBootloaderKernelWorkload.hh" #include "params/RiscvLinux.hh" #include "sim/kernel_workload.hh" @@ -58,6 +61,64 @@ class FsLinux : public KernelWorkload ByteOrder byteOrder() const override { return ByteOrder::little; } }; +class BootloaderKernelWorkload: public Workload +{ + private: + Addr entryPoint = 0; + loader::ObjectFile *kernel = nullptr; + loader::ObjectFile *bootloader = nullptr; + loader::SymbolTable kernelSymbolTable; + loader::SymbolTable bootloaderSymbolTable; + const std::string bootArgs; + + private: + void loadBootloaderSymbolTable(); + void loadKernelSymbolTable(); + void loadBootloader(); + void loadKernel(); + void loadDtb(); + + public: + PARAMS(RiscvBootloaderKernelWorkload); + BootloaderKernelWorkload(const Params &p) + : Workload(p), entryPoint(p.entry_point), bootArgs(p.boot_args) + { + loadBootloaderSymbolTable(); + loadKernelSymbolTable(); + } + + void initState() override; + + void + setSystem(System *sys) override + { + Workload::setSystem(sys); + gdb = BaseRemoteGDB::build( + params().remote_gdb_port, system); + } + + Addr getEntry() const override { return entryPoint; } + + ByteOrder byteOrder() const override { return ByteOrder::little; } + + loader::Arch getArch() const override { return kernel->getArch(); } + + const loader::SymbolTable & + symtab(ThreadContext *tc) override + { + return kernelSymbolTable; + } + + bool + insertSymbol(const loader::Symbol &symbol) override + { + return kernelSymbolTable.insert(symbol); + } + + void serialize(CheckpointOut &checkpoint) const override; + void unserialize(CheckpointIn &checkpoint) override; +}; + } // namespace RiscvISA } // namespace gem5