From 5f2361f3afb5c8d15e0a5f262a0f8a7942084563 Mon Sep 17 00:00:00 2001
From: Andreas Sandberg <Andreas.Sandberg@ARM.com>
Date: Mon, 22 Apr 2013 13:20:31 -0400
Subject: [PATCH] arm: Enable support for triggering a sim panic on kernel
 panics

Add the options 'panic_on_panic' and 'panic_on_oops' to the
LinuxArmSystem SimObject. When these option are enabled, the simulator
panics when the guest kernel panics or oopses. Enable panic on panic
and panic on oops in ARM-based test cases.
---
 src/arch/arm/ArmSystem.py    |  5 +++++
 src/arch/arm/linux/system.cc | 15 +++++++++++++--
 src/arch/arm/linux/system.hh |  8 +++++---
 src/cpu/pc_event.cc          | 12 ++++++++++++
 src/cpu/pc_event.hh          |  7 +++++++
 tests/configs/arm_generic.py |  7 +++++++
 6 files changed, 49 insertions(+), 5 deletions(-)

diff --git a/src/arch/arm/ArmSystem.py b/src/arch/arm/ArmSystem.py
index 763b043dc..b48c2a29d 100644
--- a/src/arch/arm/ArmSystem.py
+++ b/src/arch/arm/ArmSystem.py
@@ -68,3 +68,8 @@ class LinuxArmSystem(ArmSystem):
     early_kernel_symbols = Param.Bool(False,
         "enable early kernel symbol tables before MMU")
     enable_context_switch_stats_dump = Param.Bool(False, "enable stats/task info dumping at context switch boundaries")
+
+    panic_on_panic = Param.Bool(False, "Trigger a gem5 panic if the " \
+                                    "guest kernel panics")
+    panic_on_oops = Param.Bool(False, "Trigger a gem5 panic if the " \
+                                   "guest kernel oopses")
diff --git a/src/arch/arm/linux/system.cc b/src/arch/arm/linux/system.cc
index de4c27d8b..e714cc913 100644
--- a/src/arch/arm/linux/system.cc
+++ b/src/arch/arm/linux/system.cc
@@ -62,11 +62,22 @@ using namespace Linux;
 
 LinuxArmSystem::LinuxArmSystem(Params *p)
     : ArmSystem(p),
-      enableContextSwitchStatsDump(p->enable_context_switch_stats_dump)
+      enableContextSwitchStatsDump(p->enable_context_switch_stats_dump),
+      kernelPanicEvent(NULL), kernelOopsEvent(NULL)
 {
+    if (p->panic_on_panic) {
+        kernelPanicEvent = addKernelFuncEventOrPanic<PanicPCEvent>(
+            "panic", "Kernel panic in simulated kernel");
+    } else {
 #ifndef NDEBUG
-    kernelPanicEvent = addKernelFuncEventOrPanic<BreakPCEvent>("panic");
+        kernelPanicEvent = addKernelFuncEventOrPanic<BreakPCEvent>("panic");
 #endif
+    }
+
+    if (p->panic_on_oops) {
+        kernelOopsEvent = addKernelFuncEventOrPanic<PanicPCEvent>(
+            "oops_exit", "Kernel oops in guest");
+    }
 
     // With ARM udelay() is #defined to __udelay
     uDelaySkipEvent = addKernelFuncEventOrPanic<UDelayEvent>(
diff --git a/src/arch/arm/linux/system.hh b/src/arch/arm/linux/system.hh
index feed8cfaa..008c64429 100644
--- a/src/arch/arm/linux/system.hh
+++ b/src/arch/arm/linux/system.hh
@@ -98,10 +98,12 @@ class LinuxArmSystem : public ArmSystem
     void mapPid(ThreadContext* tc, uint32_t pid);
 
   private:
-#ifndef NDEBUG
     /** Event to halt the simulator if the kernel calls panic()  */
-    BreakPCEvent *kernelPanicEvent;
-#endif
+    PCEvent *kernelPanicEvent;
+
+    /** Event to halt the simulator if the kernel calls oopses  */
+    PCEvent *kernelOopsEvent;
+
     /**
      * PC based event to skip udelay(<time>) calls and quiesce the
      * processor for the appropriate amount of time. This is not functionally
diff --git a/src/cpu/pc_event.cc b/src/cpu/pc_event.cc
index c957fe4d5..837b17e34 100644
--- a/src/cpu/pc_event.cc
+++ b/src/cpu/pc_event.cc
@@ -158,3 +158,15 @@ sched_break_pc(Addr addr)
     }
 
 }
+
+PanicPCEvent::PanicPCEvent(PCEventQueue *q, const std::string &desc, Addr pc)
+    : PCEvent(q, desc, pc)
+{
+}
+
+void
+PanicPCEvent::process(ThreadContext *tc)
+{
+    StringWrap name(tc->getCpuPtr()->name() + ".panic_event");
+    panic(descr());
+}
diff --git a/src/cpu/pc_event.hh b/src/cpu/pc_event.hh
index c73fc3c5a..11fce2ca0 100644
--- a/src/cpu/pc_event.hh
+++ b/src/cpu/pc_event.hh
@@ -146,4 +146,11 @@ void sched_break_pc_sys(System *sys, Addr addr);
 
 void sched_break_pc(Addr addr);
 
+class PanicPCEvent : public PCEvent
+{
+  public:
+    PanicPCEvent(PCEventQueue *q, const std::string &desc, Addr pc);
+    virtual void process(ThreadContext *tc);
+};
+
 #endif // __PC_EVENT_HH__
diff --git a/tests/configs/arm_generic.py b/tests/configs/arm_generic.py
index 95f9b8bd1..1b0e8ee8b 100644
--- a/tests/configs/arm_generic.py
+++ b/tests/configs/arm_generic.py
@@ -62,6 +62,13 @@ class LinuxArmSystemBuilder(object):
         system = FSConfig.makeArmSystem(self.mem_mode,
                                         self.machine_type,
                                         None, False)
+
+        # We typically want the simulator to panic if the kernel
+        # panics or oopses. This prevents the simulator from running
+        # an obviously failed test case until the end of time.
+        system.panic_on_panic = True
+        system.panic_on_oops = True
+
         self.init_system(system)
         return system
 
-- 
2.30.2