arch-riscv: Add PCEvent for RISCV FS Workload kernel panic/oops

Inspired by a similar feature in ARM's full system workload, this change adds
an option to halt gem5 simulation if the guest system encounter kernel panic
or kernel oops.

On RiscvISA::BootloaderKernelWorkload, by default, the simulation
will exit upon kernel panic, while kernel oops will not induce simulation halt.
This is because the system will essentially do nop after a kernel panic, while the
system might be still functional after a kernel oops.

Dumping kernel's dmesg is useful for diagonizing the cause of kernel panic, so
ideally, we want to dump the guest's dmesg to the host. However, due to a bug
described in [1], kernel v5.18+ dmesg might not be dumped properly. Hence, the
dmesg will not be dumped to the host.

On RiscvISA::FsLinux, this feature is turned off by default as the symbols from the
official RISC-V kernel resource are stripped from the binary. However, if this feature
is enable, the dmesg will be dumped to the host system.

[1] https://github.com/gem5/gem5/issues/550

Change-Id: I8f52257727a3a789ebf99fdd4dffe5b3d89f1ebf
Signed-off-by: Hoa Nguyen <hn@hnpl.org>
Co-authored-by: Jason Lowe-Power <jason@lowepower.com>
This commit is contained in:
Hoa Nguyen
2023-11-12 10:36:03 +00:00
committed by Jason Lowe-Power
parent 569e21f798
commit cf087d4d11
3 changed files with 145 additions and 1 deletions

View File

@@ -55,6 +55,16 @@ class RiscvLinux(KernelWorkload):
)
dtb_addr = Param.Addr(0x87E00000, "DTB address")
# gem5 event upon guest's kernel panic
# Default to false because when the kernel is compiled into the bootloader
# it will not have symbols
exit_on_kernel_panic = Param.Bool(
False, "Generate gem5 panic upon the guest's kernel panic."
)
exit_on_kernel_oops = Param.Bool(
False, "Generate gem5 panic upon the guest's kernel oops."
)
class RiscvBootloaderKernelWorkload(Workload):
type = "RiscvBootloaderKernelWorkload"
@@ -84,5 +94,28 @@ class RiscvBootloaderKernelWorkload(Workload):
# booting parameters
command_line = Param.String(
"", "Booting arguments, to be passed to the kernel"
"", "Booting arguments, to be passed to the kernel."
)
# gem5 event upon guest's kernel panic
# Note that if the kernel doesn't have symbols there will be a warning and
# gem5 will not exit
exit_on_kernel_panic = Param.Bool(
True, "Generate gem5 exit upon the guest's kernel panic."
)
exit_on_kernel_oops = Param.Bool(
False, "Generate gem5 exit upon the guest's kernel oops."
)
# Note: Duplicated from KernelWorkload for now
on_panic = Param.KernelPanicOopsBehaviour(
"DumpDmesgAndExit",
"Define how gem5 should behave after a Linux Kernel Panic. "
"Handler might not be implemented for all architectures.",
)
on_oops = Param.KernelPanicOopsBehaviour(
"DumpDmesgAndExit",
"Define how gem5 should behave after a Linux Kernel Oops. "
"Handler might not be implemented for all architectures.",
)

View File

@@ -32,7 +32,10 @@
#include "base/loader/dtb_file.hh"
#include "base/loader/object_file.hh"
#include "base/loader/symtab.hh"
#include "cpu/pc_event.hh"
#include "kern/linux/events.hh"
#include "sim/kernel_workload.hh"
#include "sim/sim_exit.hh"
#include "sim/system.hh"
namespace gem5
@@ -75,6 +78,42 @@ FsLinux::initState()
}
}
void
FsLinux::startup()
{
KernelWorkload::startup();
addExitOnKernelPanicEvent();
addExitOnKernelOopsEvent();
}
void
FsLinux::addExitOnKernelPanicEvent()
{
const std::string dmesg_output = name() + ".dmesg";
if (params().exit_on_kernel_panic) {
kernelPanicPcEvent = addKernelFuncEvent<linux::PanicOrOopsEvent>(
"panic", "Kernel panic in simulated system.",
dmesg_output, params().on_panic
);
warn_if(!kernelPanicPcEvent, "Failed to find kernel symbol 'panic'");
}
}
void
FsLinux::addExitOnKernelOopsEvent()
{
const std::string dmesg_output = name() + ".dmesg";
if (params().exit_on_kernel_oops) {
kernelOopsPcEvent = addKernelFuncEvent<linux::PanicOrOopsEvent>(
"oops_exit", "Kernel oops in simulated system.",
dmesg_output, params().on_oops
);
warn_if(!kernelOopsPcEvent,
"Failed to find kernel symbol 'oops_exit'");
}
}
void
BootloaderKernelWorkload::loadBootloaderSymbolTable()
{
@@ -169,6 +208,30 @@ BootloaderKernelWorkload::loadDtb()
}
}
void
BootloaderKernelWorkload::addExitOnKernelPanicEvent()
{
const std::string dmesg_output = name() + ".dmesg";
if (params().exit_on_kernel_panic) {
kernelPanicPcEvent = addFuncEvent<linux::PanicOrOopsEvent>(
kernelSymbolTable, "panic", "Kernel panic in simulated system.",
dmesg_output, params().on_panic
);
}
}
void
BootloaderKernelWorkload::addExitOnKernelOopsEvent()
{
const std::string dmesg_output = name() + ".dmesg";
if (params().exit_on_kernel_oops) {
kernelOopsPcEvent = addFuncEvent<linux::PanicOrOopsEvent>(
kernelSymbolTable, "oops_exit", "Kernel oops in simulated system.",
dmesg_output, params().on_oops
);
}
}
void
BootloaderKernelWorkload::initState()
{
@@ -182,6 +245,15 @@ BootloaderKernelWorkload::initState()
}
}
void
BootloaderKernelWorkload::startup()
{
Workload::startup();
addExitOnKernelPanicEvent();
addExitOnKernelOopsEvent();
}
void
BootloaderKernelWorkload::serialize(CheckpointOut &checkpoint) const
{

View File

@@ -44,11 +44,30 @@ namespace RiscvISA
class FsLinux : public KernelWorkload
{
private:
/**
* Event to halt the simulator if the kernel calls panic() or
* oops_exit()
**/
PCEvent *kernelPanicPcEvent = nullptr;
PCEvent *kernelOopsPcEvent = nullptr;
void addExitOnKernelPanicEvent();
void addExitOnKernelOopsEvent();
public:
PARAMS(RiscvLinux);
FsLinux(const Params &p) : KernelWorkload(p) {}
~FsLinux()
{
if (kernelPanicPcEvent != nullptr) {
delete kernelPanicPcEvent;
}
if (kernelOopsPcEvent != nullptr) {
delete kernelOopsPcEvent;
}
}
void initState() override;
void startup() override;
void
setSystem(System *sys) override
@@ -71,12 +90,21 @@ class BootloaderKernelWorkload: public Workload
loader::SymbolTable bootloaderSymbolTable;
const std::string bootArgs;
/**
* Event to halt the simulator if the kernel calls panic() or
* oops_exit()
**/
PCEvent *kernelPanicPcEvent = nullptr;
PCEvent *kernelOopsPcEvent = nullptr;
private:
void loadBootloaderSymbolTable();
void loadKernelSymbolTable();
void loadBootloader();
void loadKernel();
void loadDtb();
void addExitOnKernelPanicEvent();
void addExitOnKernelOopsEvent();
public:
PARAMS(RiscvBootloaderKernelWorkload);
@@ -87,7 +115,18 @@ class BootloaderKernelWorkload: public Workload
loadKernelSymbolTable();
}
~BootloaderKernelWorkload()
{
if (kernelPanicPcEvent != nullptr) {
delete kernelPanicPcEvent;
}
if (kernelOopsPcEvent != nullptr) {
delete kernelOopsPcEvent;
}
}
void initState() override;
void startup() override;
void
setSystem(System *sys) override