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..8bb35ccd17 100644 --- a/src/arch/riscv/linux/fs_workload.cc +++ b/src/arch/riscv/linux/fs_workload.cc @@ -75,5 +75,125 @@ 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; + + inform("Loaded bootloader \'%s\' at 0x%llx\n", + params().bootloader_filename, + bootloader_addr_offset); + } else { + inform("Bootloader is not specified.\n"); + } +} + +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; + + inform("Loaded kernel \'%s\' at 0x%llx\n", + params().kernel_filename, + kernel_paddr_offset); + } else { + inform("Kernel is not specified.\n"); + } +} + + +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; + + 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"); + } +} + +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 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 d0000daffa..450fcb7866 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) @@ -432,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