From 46a9d85215ec91c277c954944d1db64d28c28537 Mon Sep 17 00:00:00 2001 From: Hoa Nguyen Date: Wed, 4 Oct 2023 00:56:48 -0700 Subject: [PATCH 1/4] 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 From e8fd8303fba6bfee3b8abb5cdf08632227e09f1b Mon Sep 17 00:00:00 2001 From: Hoa Nguyen Date: Thu, 5 Oct 2023 23:15:27 -0700 Subject: [PATCH 2/4] stdlib: Add `chosen` node to the device tree of RISC-V board This enables two things, - /chosen/stdout-path is now default to uart@10000000, meaning the linux kernel's boot console will be redirected to uart. - /chosen/bootargs now contains the boot arguments obtained from gem5's library. This allows passing the boot arguments to the linux kernel via the device tree. Change-Id: I53821d85f619e6276da85f41c972c041eaaf3280 Signed-off-by: Hoa Nguyen --- src/python/gem5/components/boards/riscv_board.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/python/gem5/components/boards/riscv_board.py b/src/python/gem5/components/boards/riscv_board.py index 25f1fac562..93dae50244 100644 --- a/src/python/gem5/components/boards/riscv_board.py +++ b/src/python/gem5/components/boards/riscv_board.py @@ -259,6 +259,12 @@ class RiscvBoard(AbstractSystemBoard, KernelDiskWorkload): ) root.append(node) + node = FdtNode(f"chosen") + bootargs = " ".join(self.get_default_kernel_args()) + node.append(FdtPropertyStrings("bootargs", [bootargs])) + node.append(FdtPropertyStrings("stdout-path", ["/uart@10000000"])) + root.append(node) + # See Documentation/devicetree/bindings/riscv/cpus.txt for details. cpus_node = FdtNode("cpus") cpus_state = FdtState(addr_cells=1, size_cells=0) From 3fc6b67974eba4c5785ab2875aae95b61a22ede1 Mon Sep 17 00:00:00 2001 From: Hoa Nguyen Date: Fri, 6 Oct 2023 00:45:21 -0700 Subject: [PATCH 3/4] arch-riscv: Add several inform() to RiscvISA::BootloaderKernelWorkload Signed-off-by: Hoa Nguyen --- src/arch/riscv/linux/fs_workload.cc | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/arch/riscv/linux/fs_workload.cc b/src/arch/riscv/linux/fs_workload.cc index 0cd0e761d2..8bb35ccd17 100644 --- a/src/arch/riscv/linux/fs_workload.cc +++ b/src/arch/riscv/linux/fs_workload.cc @@ -118,6 +118,12 @@ BootloaderKernelWorkload::loadBootloader() system->physProxy ); delete bootloader; + + inform("Loaded bootloader \'%s\' at 0x%llx\n", + params().bootloader_filename, + bootloader_addr_offset); + } else { + inform("Bootloader is not specified.\n"); } } @@ -130,6 +136,12 @@ BootloaderKernelWorkload::loadKernel() system->physProxy ); delete kernel; + + inform("Loaded kernel \'%s\' at 0x%llx\n", + params().kernel_filename, + kernel_paddr_offset); + } else { + inform("Kernel is not specified.\n"); } } @@ -144,9 +156,15 @@ BootloaderKernelWorkload::loadDtb() .write(system->physProxy); delete dtb_file; + inform("Loaded DTB \'%s\' at 0x%llx\n", + params().dtb_filename, + params().dtb_addr); + for (auto *tc: system->threads) { tc->setReg(int_reg::A1, params().dtb_addr); } + } else { + inform("DTB file is not specified.\n"); } } From 6f8b74ece8f75d63d38e68dbcbf9519867fbf6b1 Mon Sep 17 00:00:00 2001 From: Hoa Nguyen Date: Fri, 6 Oct 2023 00:48:12 -0700 Subject: [PATCH 4/4] dev,arch-riscv: Mark gem5's 8250 UART as 16550a compatible 8250 UART is supposed to be compatible to 16550a UART. This enables OpenSBI to print things to UART as OpenSBI only prints if the UART is 16550a compatible [1]. There is a similar change from gem5 gerrit [2] pointing out that this also enables bbl to print things to UART. This is confirmed :) [1] https://github.com/riscv-software-src/opensbi/blob/v1.3.1/lib/utils/serial/fdt_serial_uart8250.c#L29 [2] https://gem5-review.googlesource.com/c/public/gem5/+/68481 Signed-off-by: Hoa Nguyen --- src/dev/serial/Uart.py | 2 +- src/python/gem5/components/boards/riscv_board.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dev/serial/Uart.py b/src/dev/serial/Uart.py index 2ca68b8f12..fb0d91efa4 100644 --- a/src/dev/serial/Uart.py +++ b/src/dev/serial/Uart.py @@ -82,5 +82,5 @@ class RiscvUart8250(Uart8250): node.append(FdtPropertyWords("interrupts", [platform.uart_int_id])) node.append(FdtPropertyWords("clock-frequency", [0x384000])) node.append(FdtPropertyWords("interrupt-parent", state.phandle(plic))) - node.appendCompatible(["ns8250"]) + node.appendCompatible(["ns8250", "ns16550a"]) yield node diff --git a/src/python/gem5/components/boards/riscv_board.py b/src/python/gem5/components/boards/riscv_board.py index 93dae50244..c8e0df78c2 100644 --- a/src/python/gem5/components/boards/riscv_board.py +++ b/src/python/gem5/components/boards/riscv_board.py @@ -438,7 +438,7 @@ class RiscvBoard(AbstractSystemBoard, KernelDiskWorkload): uart_node.append( FdtPropertyWords("interrupt-parent", soc_state.phandle(plic)) ) - uart_node.appendCompatible(["ns8250"]) + uart_node.appendCompatible(["ns8250", "ns16550a"]) soc_node.append(uart_node) # VirtIO MMIO disk node