From cf087d4d11155a9d0a7bb33e397678087a6885a8 Mon Sep 17 00:00:00 2001 From: Hoa Nguyen Date: Sun, 12 Nov 2023 10:36:03 +0000 Subject: [PATCH] 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 Co-authored-by: Jason Lowe-Power --- src/arch/riscv/RiscvFsWorkload.py | 35 +++++++++++++- src/arch/riscv/linux/fs_workload.cc | 72 +++++++++++++++++++++++++++++ src/arch/riscv/linux/fs_workload.hh | 39 ++++++++++++++++ 3 files changed, 145 insertions(+), 1 deletion(-) diff --git a/src/arch/riscv/RiscvFsWorkload.py b/src/arch/riscv/RiscvFsWorkload.py index 467d7ec26a..24dff58828 100644 --- a/src/arch/riscv/RiscvFsWorkload.py +++ b/src/arch/riscv/RiscvFsWorkload.py @@ -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.", ) diff --git a/src/arch/riscv/linux/fs_workload.cc b/src/arch/riscv/linux/fs_workload.cc index da1af8d59b..309d324bcb 100644 --- a/src/arch/riscv/linux/fs_workload.cc +++ b/src/arch/riscv/linux/fs_workload.cc @@ -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( + "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( + "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( + 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( + 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 { diff --git a/src/arch/riscv/linux/fs_workload.hh b/src/arch/riscv/linux/fs_workload.hh index 95269e6f93..c5fcd70eb0 100644 --- a/src/arch/riscv/linux/fs_workload.hh +++ b/src/arch/riscv/linux/fs_workload.hh @@ -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