From d9c870f6417c7c344e898c5e9d69912f79aa3033 Mon Sep 17 00:00:00 2001 From: Richard Cooper Date: Sat, 2 Dec 2023 01:33:59 +0000 Subject: [PATCH] sim: Rework the Linux Kernel exit events (#639) This patch reworks the Linux Kernel panic and oops events. The code has been re-factored to provide re-usable events that can be applied to all ISAs from the base `KernelWorkload` `SimObject`. At the moment they are installed for the Arm workloads. This update also provides more configuration options that can be specified using the new `KernelPanicOopsBehaviour` enum. The options are applied to the Kernel Workload parameters `on_panic` and `on_oops` which are available to all subclasses of `KernelWorkload`. The main rationale for this reworking is to add the option to cleanly exit the simulation after dumping the Dmesg buffer. Without this option, the simulation would continue running after a Kernel panic. If system components (e.g. a system timer) keep the event queue alive, this causes the simulation to run slowly to the maximum allowed tick. --- src/arch/arm/linux/fs_workload.cc | 29 +++++++++++----------- src/kern/linux/events.cc | 30 +++++++++++----------- src/kern/linux/events.hh | 41 +++++++++---------------------- src/sim/SConscript | 16 ++++++++++-- src/sim/Workload.py | 34 +++++++++++++++++++++++++ 5 files changed, 89 insertions(+), 61 deletions(-) diff --git a/src/arch/arm/linux/fs_workload.cc b/src/arch/arm/linux/fs_workload.cc index 26146ef001..81bc5ae1ca 100644 --- a/src/arch/arm/linux/fs_workload.cc +++ b/src/arch/arm/linux/fs_workload.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2013, 2016, 2020 ARM Limited + * Copyright (c) 2010-2013, 2016, 2020, 2023 Arm Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -228,21 +228,22 @@ FsLinux::startup() } } - const std::string dmesg_output = name() + ".dmesg"; - if (params().panic_on_panic) { - kernelPanic = addKernelFuncEventOrPanic( - "panic", "Kernel panic in simulated kernel", dmesg_output); - } else { - kernelPanic = addKernelFuncEventOrPanic( - "panic", "Kernel panic in simulated kernel", dmesg_output); + const std::string dmesg_output_fname = name() + ".dmesg"; + + kernelPanic = addKernelFuncEvent( + "panic", "Kernel panic in simulated kernel", + dmesg_output_fname, params().on_panic); + if (kernelPanic == nullptr) { + warn("Could not add Kernel Panic event handler. " + "`panic` symbol not found."); } - if (params().panic_on_oops) { - kernelOops = addKernelFuncEventOrPanic( - "oops_exit", "Kernel oops in guest", dmesg_output); - } else { - kernelOops = addKernelFuncEventOrPanic( - "oops_exit", "Kernel oops in guest", dmesg_output); + kernelOops = addKernelFuncEvent( + "oops_exit", "Kernel oops in guest", + dmesg_output_fname, params().on_oops); + if (kernelOops == nullptr) { + warn("Could not add Kernel Oops event handler. " + "`oops_exit` symbol not found."); } // With ARM udelay() is #defined to __udelay diff --git a/src/kern/linux/events.cc b/src/kern/linux/events.cc index 35767596af..721bac8a45 100644 --- a/src/kern/linux/events.cc +++ b/src/kern/linux/events.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2016 ARM Limited + * Copyright (c) 2011, 2016, 2023 Arm Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -49,6 +49,7 @@ #include "kern/linux/helpers.hh" #include "kern/system_events.hh" #include "sim/core.hh" +#include "sim/sim_exit.hh" #include "sim/system.hh" namespace gem5 @@ -58,25 +59,22 @@ namespace linux { void -DmesgDump::process(ThreadContext *tc) +PanicOrOopsEvent::process(ThreadContext *tc) { - inform("Dumping kernel dmesg buffer to %s...\n", fname); - OutputStream *os = simout.create(fname); - dumpDmesg(tc, *os->stream()); - simout.close(os); - warn(descr()); -} -void -KernelPanic::process(ThreadContext *tc) -{ - inform("Dumping kernel dmesg buffer to %s...\n", fname); - OutputStream *os = simout.create(fname); - dumpDmesg(tc, *os->stream()); - simout.close(os); + if (behaviour != KernelPanicOopsBehaviour::Continue) { + inform("Dumping kernel dmesg buffer to %s...\n", fname); + OutputStream *os = simout.create(fname); + dumpDmesg(tc, *os->stream()); + simout.close(os); + } - panic(descr()); + if (behaviour == KernelPanicOopsBehaviour::DumpDmesgAndExit) { + exitSimLoop(descr(), static_cast(1), curTick(), false); + } else if (behaviour == KernelPanicOopsBehaviour::DumpDmesgAndPanic) { + panic(descr()); + } } void diff --git a/src/kern/linux/events.hh b/src/kern/linux/events.hh index 966c1ba075..2f1e60cd28 100644 --- a/src/kern/linux/events.hh +++ b/src/kern/linux/events.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016 ARM Limited + * Copyright (c) 2016, 2023 Arm Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -47,6 +47,7 @@ #include "base/compiler.hh" #include "base/trace.hh" #include "debug/DebugPrintf.hh" +#include "enums/KernelPanicOopsBehaviour.hh" #include "kern/linux/printk.hh" #include "kern/system_events.hh" #include "mem/se_translating_port_proxy.hh" @@ -83,43 +84,25 @@ class DebugPrintk : public Base }; /** - * Dump the guest kernel's dmesg buffer to a file in gem5's output - * directory and print a warning. + * Specify what to do on a Linux Kernel Panic or Oops. * - * @warn This event uses linux::dumpDmesg() and comes with the same + * @warn This event may use linux::dumpDmesg() and comes with the same * limitations. Most importantly, the kernel's address mappings must * be available to the translating proxy. */ -class DmesgDump : public PCEvent +class PanicOrOopsEvent : public PCEvent { protected: std::string fname; + KernelPanicOopsBehaviour behaviour; public: - DmesgDump(PCEventScope *s, const std::string &desc, Addr addr, - const std::string &_fname) : - PCEvent(s, desc, addr), fname(_fname) - {} - void process(ThreadContext *tc) override; -}; - -/** - * Dump the guest kernel's dmesg buffer to a file in gem5's output - * directory and panic. - * - * @warn This event uses linux::dumpDmesg() and comes with the same - * limitations. Most importantly, the kernel's address mappings must - * be available to the translating proxy. - */ -class KernelPanic : public PCEvent -{ - protected: - std::string fname; - - public: - KernelPanic(PCEventScope *s, const std::string &desc, Addr addr, - const std::string &_fname) : - PCEvent(s, desc, addr), fname(_fname) + PanicOrOopsEvent(PCEventScope *s, const std::string &desc, Addr addr, + const std::string &_fname, + const KernelPanicOopsBehaviour _behaviour) + : PCEvent(s, desc, addr) + , fname(_fname) + , behaviour(_behaviour) {} void process(ThreadContext *tc) override; }; diff --git a/src/sim/SConscript b/src/sim/SConscript index 78b06c5b1d..a9216de824 100644 --- a/src/sim/SConscript +++ b/src/sim/SConscript @@ -1,5 +1,16 @@ # -*- mode:python -*- - +# Copyright (c) 2023 Arm Limited +# All rights reserved. +# +# The license below extends only to copyright in the software and shall +# not be construed as granting a license to any other intellectual +# property including but not limited to intellectual property relating +# to a hardware implementation of the functionality of the software +# licensed hereunder. You may use the software subject to the license +# terms below provided that you ensure that this notice is replicated +# unmodified and in its entirety in all distributions of the software, +# modified or unmodified, in source code or in binary form. +# # Copyright (c) 2006 The Regents of The University of Michigan # All rights reserved. # @@ -31,7 +42,8 @@ Import('*') SimObject('ClockedObject.py', sim_objects=['ClockedObject']) SimObject('TickedObject.py', sim_objects=['TickedObject']) SimObject('Workload.py', sim_objects=[ - 'Workload', 'StubWorkload', 'KernelWorkload', 'SEWorkload']) + 'Workload', 'StubWorkload', 'KernelWorkload', 'SEWorkload'], + enums=['KernelPanicOopsBehaviour']) SimObject('Root.py', sim_objects=['Root']) SimObject('ClockDomain.py', sim_objects=[ 'ClockDomain', 'SrcClockDomain', 'DerivedClockDomain']) diff --git a/src/sim/Workload.py b/src/sim/Workload.py index 998c6c13d6..50625e8085 100644 --- a/src/sim/Workload.py +++ b/src/sim/Workload.py @@ -1,3 +1,15 @@ +# Copyright (c) 2023 Arm Limited +# All rights reserved. +# +# The license below extends only to copyright in the software and shall +# not be construed as granting a license to any other intellectual +# property including but not limited to intellectual property relating +# to a hardware implementation of the functionality of the software +# licensed hereunder. You may use the software subject to the license +# terms below provided that you ensure that this notice is replicated +# unmodified and in its entirety in all distributions of the software, +# modified or unmodified, in source code or in binary form. +# # Copyright 2019 Google Inc. # # Redistribution and use in source and binary forms, with or without @@ -62,6 +74,16 @@ class StubWorkload(Workload): ) +class KernelPanicOopsBehaviour(ScopedEnum): + "Define what gem5 should do after a Kernel Panic or Oops." + vals = [ + "Continue", + "DumpDmesgAndContinue", + "DumpDmesgAndExit", + "DumpDmesgAndPanic", + ] + + class KernelWorkload(Workload): type = "KernelWorkload" cxx_header = "sim/kernel_workload.hh" @@ -86,6 +108,18 @@ class KernelWorkload(Workload): command_line = Param.String("a", "boot flags to pass to the kernel") + 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.", + ) + class SEWorkloadMeta(type(Workload)): all_se_workload_classes = []