arch-riscv: Add bootloader+kernel workload (#390)
Aims to boot OpenSBI + Linux kernel.
This commit is contained in:
@@ -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"
|
||||
)
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user