arch-riscv: Add bootloader+kernel workload (#390)

Aims to boot OpenSBI + Linux kernel.
This commit is contained in:
Bobby R. Bruce
2023-10-18 09:17:12 -07:00
committed by GitHub
6 changed files with 226 additions and 3 deletions

View File

@@ -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"
)

View File

@@ -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')

View File

@@ -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

View File

@@ -29,7 +29,10 @@
#ifndef __ARCH_RISCV_LINUX_SYSTEM_HH__
#define __ARCH_RISCV_LINUX_SYSTEM_HH__
#include <string>
#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<RemoteGDB>(
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

View File

@@ -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

View File

@@ -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