summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/include/arch/ppc.H35
-rw-r--r--src/include/kernel/cpu.H24
-rw-r--r--src/include/kernel/cpumgr.H25
-rw-r--r--src/include/kernel/syscalls.H3
-rw-r--r--src/include/sys/misc.h21
-rw-r--r--src/kernel/cpumgr.C16
-rw-r--r--src/kernel/syscall.C36
-rw-r--r--src/lib/cxxtest_stub.C11
-rw-r--r--src/lib/makefile3
-rw-r--r--src/lib/syscall_misc.C10
-rw-r--r--src/makefile8
-rw-r--r--src/usr/initservice/extinitsvc/extinitsvc.C17
-rw-r--r--src/usr/initservice/extinitsvc/extinitsvc.H11
13 files changed, 202 insertions, 18 deletions
diff --git a/src/include/arch/ppc.H b/src/include/arch/ppc.H
index a87f339f2..7c19fdf16 100644
--- a/src/include/arch/ppc.H
+++ b/src/include/arch/ppc.H
@@ -185,4 +185,39 @@ inline void icbi(void* _ptr)
asm volatile("icbi 0, %0" : : "b" (ptr) : "memory");
}
+ALWAYS_INLINE
+inline void doze()
+{
+ asm volatile("doze");
+}
+
+ALWAYS_INLINE
+inline void setScratch0Spr(uint64_t _data)
+{
+ // Write to SPRC(276) to select the register
+ // 0x20 selects SCRATCH 0 SPR
+ // Write to SPRD(277) to write the data
+ // TODO This is per P7 Pervasive Spec. Is this the same for Salerno/Venice?
+ register uint64_t address = 0x20;
+ register uint64_t data = _data;
+ asm volatile("mtspr 276, %0\n"
+ "isync\n"
+ "mtspr 277, %1" :: "r" (address), "r" (data));
+}
+
+ALWAYS_INLINE
+inline uint64_t getScratch0Spr()
+{
+ // Write to SPRC(276) to select the register
+ // 0x20 selects SCRATCH 0 SPR
+ // Read from SPRD(277) to get the data
+ // TODO This is per P7 Pervasive Spec. Is this the same for Salerno/Venice?
+ register uint64_t address = 0x20;
+ register uint64_t data = 0;
+ asm volatile("mtspr 276, %1\n"
+ "isync\n"
+ "mfspr %0, 277" : "=r" (data) : "r" (address));
+ return data;
+}
+
#endif
diff --git a/src/include/kernel/cpu.H b/src/include/kernel/cpu.H
index 8f6fedb69..2e2a4b8e4 100644
--- a/src/include/kernel/cpu.H
+++ b/src/include/kernel/cpu.H
@@ -21,21 +21,27 @@ class Scheduler;
*/
struct cpu_t
{
- /** Stack to use while in kernel mode. */
+ /** Stack to use while in kernel mode. */
void* kernel_stack;
- /** ID of the CPU (PIR value) */
+
+ /** ID of the CPU (PIR value) */
cpuid_t cpu;
-
- /** Pointer to the scheduler for this CPU (may not be unique) */
+
+ /** If the CPU is the master */
+ bool master;
+
+ /** Pointer to the scheduler for this CPU (may not be unique) */
Scheduler* scheduler;
- /** Location for scheduler to store per-CPU data, currently used
- * for the local run-queue for processor affinity.
- */
+
+ /** Location for scheduler to store per-CPU data, currently used
+ * for the local run-queue for processor affinity.
+ */
void* scheduler_extra;
- /** Pointer to the idle task for this CPU */
+
+ /** Pointer to the idle task for this CPU */
task_t* idle_task;
- /** XSCOM mutex to serialize access per CPU */
+ /** XSCOM mutex to serialize access per CPU */
mutex_t xscom_mutex;
};
diff --git a/src/include/kernel/cpumgr.H b/src/include/kernel/cpumgr.H
index 6ba4bfee1..4416e5815 100644
--- a/src/include/kernel/cpumgr.H
+++ b/src/include/kernel/cpumgr.H
@@ -14,14 +14,29 @@ class CpuManager
* task structure in SPRG3.
*/
static cpu_t* getCurrentCPU();
- static cpu_t* getCpu(size_t i) { return cv_cpus[i]; };
+ static cpu_t* getCpu(size_t i) { return cv_cpus[i]; }
static void init();
static void init_slave_smp(cpu_t*);
+ /** @fn requestShutdown
+ * Requests that all CPUs shutdown
+ */
+ static void requestShutdown(uint64_t i_status);
+
+ /** @fn isShutdownRequested
+ * Returns if a shutdown of all CPUs was requested
+ */
+ static bool isShutdownRequested() { return cv_shutdown_requested; }
+
+ /** @fn getShutdownStatus
+ * Returns the status code that needs to be posted during shutdown
+ */
+ static uint32_t getShutdownStatus() { return cv_shutdown_status; }
+
protected:
CpuManager();
- ~CpuManager() {};
+ ~CpuManager() {}
/** @fn startCPU
* Starts the requested CPU. Default of -1 implies current CPU.
@@ -33,6 +48,12 @@ class CpuManager
static cpu_t* cv_cpus[MAXCPUS]; // Need to be able to access this
// from start.S to get initial stacks
// of secondary cpus / threads.
+
+ // If a shutdown of all CPUs is requested
+ static bool cv_shutdown_requested;
+
+ // The status code that needs to be posted during shutdown
+ static uint64_t cv_shutdown_status;
};
#endif
diff --git a/src/include/kernel/syscalls.H b/src/include/kernel/syscalls.H
index 26e2bdf75..6473f12b6 100644
--- a/src/include/kernel/syscalls.H
+++ b/src/include/kernel/syscalls.H
@@ -56,6 +56,9 @@ namespace Systemcalls
/** futex_wake() */
FUTEX_WAKE,
+ /** shutdown() */
+ MISC_SHUTDOWN,
+
SYSCALL_MAX
};
diff --git a/src/include/sys/misc.h b/src/include/sys/misc.h
new file mode 100644
index 000000000..8e963ad2e
--- /dev/null
+++ b/src/include/sys/misc.h
@@ -0,0 +1,21 @@
+#ifndef __SYS_MISC_H
+#define __SYS_MISC_H
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/** @fn shutdown()
+ * @brief Shutdown all CPUs (hardware threads)
+ * @param[in] i_status The status code to post
+ */
+void shutdown(uint64_t i_status);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/kernel/cpumgr.C b/src/kernel/cpumgr.C
index 27417ef0d..7be1cf2dc 100644
--- a/src/kernel/cpumgr.C
+++ b/src/kernel/cpumgr.C
@@ -11,6 +11,8 @@
#include <sys/sync.h>
cpu_t* CpuManager::cv_cpus[CpuManager::MAXCPUS] = { NULL };
+bool CpuManager::cv_shutdown_requested = false;
+uint64_t CpuManager::cv_shutdown_status = 0;
CpuManager::CpuManager()
{
@@ -34,6 +36,12 @@ void CpuManager::init_slave_smp(cpu_t* cpu)
Singleton<CpuManager>::instance().startSlaveCPU(cpu);
}
+void CpuManager::requestShutdown(uint64_t i_status)
+{
+ cv_shutdown_requested = true;
+ cv_shutdown_status = i_status;
+}
+
void CpuManager::startCPU(ssize_t i)
{
bool currentCPU = false;
@@ -55,6 +63,14 @@ void CpuManager::startCPU(ssize_t i)
// Initialize CPU.
cpu->cpu = i;
+ if (currentCPU)
+ {
+ cpu->master = true;
+ }
+ else
+ {
+ cpu->master = false;
+ }
cpu->scheduler = &Singleton<Scheduler>::instance();
cpu->scheduler_extra = NULL;
cpu->kernel_stack =
diff --git a/src/kernel/syscall.C b/src/kernel/syscall.C
index 85252a408..bccccac03 100644
--- a/src/kernel/syscall.C
+++ b/src/kernel/syscall.C
@@ -13,9 +13,29 @@
extern "C"
void kernel_execute_decrementer()
{
- Scheduler* s = CpuManager::getCurrentCPU()->scheduler;
+ cpu_t* c = CpuManager::getCurrentCPU();
+ Scheduler* s = c->scheduler;
TimeManager::checkReleaseTasks(s);
s->returnRunnable();
+
+ if (CpuManager::isShutdownRequested())
+ {
+ // Shutdown was requested
+ if (c->master)
+ {
+ // Write the shutdown status to Scratch SPR 0
+ uint64_t status = CpuManager::getShutdownStatus();
+ printk("Shutdown Requested. Status = 0x%lx\n", status);
+ setScratch0Spr(status);
+ }
+
+ // Make the thread doze
+ while(1)
+ {
+ doze();
+ }
+ }
+
s->setNextRunnable();
}
@@ -39,6 +59,7 @@ namespace Systemcalls
void TimeNanosleep(task_t*);
void FutexWait(task_t *t);
void FutexWake(task_t *t);
+ void Shutdown(task_t *t);
syscall syscalls[] =
{
@@ -63,6 +84,8 @@ namespace Systemcalls
&FutexWait,
&FutexWake,
+
+ &Shutdown,
};
};
@@ -322,4 +345,15 @@ namespace Systemcalls
TASK_SETRTN(t,started);
}
+ /**
+ * Shutdown all CPUs
+ * @param[in] t: The current task
+ */
+ void Shutdown(task_t * t)
+ {
+ uint64_t status = static_cast<uint64_t>(TASK_GETARG0(t));
+ CpuManager::requestShutdown(status);
+ TASK_SETRTN(t, 0);
+ }
+
};
diff --git a/src/lib/cxxtest_stub.C b/src/lib/cxxtest_stub.C
new file mode 100644
index 000000000..cbc98baee
--- /dev/null
+++ b/src/lib/cxxtest_stub.C
@@ -0,0 +1,11 @@
+#include <stdint.h>
+
+namespace CxxTest
+{
+
+// This variable is to allow a code in a binary image not containing the
+// testcase modules to query the number of failed tests
+uint64_t g_FailedTests = 0;
+
+}
+
diff --git a/src/lib/makefile b/src/lib/makefile
index 86735cf22..d4c4f70cb 100644
--- a/src/lib/makefile
+++ b/src/lib/makefile
@@ -2,6 +2,7 @@ ROOTPATH = ../..
OBJS = string.o stdlib.o assert.o stdio.o
OBJS += syscall_stub.o syscall_task.o syscall_msg.o
-OBJS += syscall_mmio.o syscall_time.o sync.o
+OBJS += syscall_mmio.o syscall_time.o sync.o syscall_misc.o
+OBJS += cxxtest_stub.o
include ${ROOTPATH}/config.mk
diff --git a/src/lib/syscall_misc.C b/src/lib/syscall_misc.C
new file mode 100644
index 000000000..6a4ad1845
--- /dev/null
+++ b/src/lib/syscall_misc.C
@@ -0,0 +1,10 @@
+#include <sys/misc.h>
+#include <sys/syscall.h>
+
+using namespace Systemcalls;
+
+void shutdown(uint64_t i_status)
+{
+ _syscall1(MISC_SHUTDOWN, reinterpret_cast<void*>(i_status));
+}
+
diff --git a/src/makefile b/src/makefile
index af3c07589..8f2ecd0b3 100644
--- a/src/makefile
+++ b/src/makefile
@@ -9,11 +9,13 @@ BASE_OBJECTS = console.o spinlock.o string.o stdlib.o assert.o stdio.o \
DIRECT_BOOT_OBJECTS = start.o kernel.o taskmgr.o cpumgr.o syscall.o \
scheduler.o exception.o vmmmgr.o timemgr.o \
- syscall_stub.o syscall_task.o \
+ syscall_stub.o syscall_task.o syscall_misc.o \
syscall_msg.o syscall_mmio.o syscall_time.o \
init_main.o vfs_main.o sync.o futexmgr.o \
ptmgr.o
+STUB_TESTCASE_OBJECT = cxxtest_stub.o
+
RUNTIME_OBJECTS =
BASE_MODULES = trace errl devicefw scom xscom initservice taskargs
@@ -27,12 +29,12 @@ TESTCASE_MODULES = cxxtest testerrl testdevicefw testsyslib \
RELOCATABLE_IMAGE_LDFLAGS = -pie --export-dynamic
-hbicore_OBJECTS = ${BASE_OBJECTS} ${DIRECT_BOOT_OBJECTS}
+hbicore_OBJECTS = ${BASE_OBJECTS} ${DIRECT_BOOT_OBJECTS} ${STUB_TESTCASE_OBJECT}
hbicore_MODULES = ${BASE_MODULES} ${EXTENDED_MODULES} ${DIRECT_BOOT_MODULES}
hbicore_EXTENDED_MODULES =
hbicore_LIDNUMBER = 80f00100
-hbicore_test_OBJECTS = ${hbicore_OBJECTS}
+hbicore_test_OBJECTS = ${BASE_OBJECTS} ${DIRECT_BOOT_OBJECTS}
hbicore_test_MODULES = ${hbicore_MODULES} ${TESTCASE_MODULES}
hbicore_test_EXTENDED_MODULES =
diff --git a/src/usr/initservice/extinitsvc/extinitsvc.C b/src/usr/initservice/extinitsvc/extinitsvc.C
index 3d9ab6441..916ea31ed 100644
--- a/src/usr/initservice/extinitsvc/extinitsvc.C
+++ b/src/usr/initservice/extinitsvc/extinitsvc.C
@@ -10,6 +10,9 @@
#include <sys/vfs.h>
#include <sys/task.h>
#include <sys/sync.h>
+#include <sys/misc.h>
+#include <sys/time.h>
+#include <usr/cxxtest/TestSuite.H>
#include <trace/interface.H>
#include <errl/errlentry.H>
@@ -190,6 +193,20 @@ void ExtInitSvc::init( void *i_ptr )
TRACDCOMP( g_trac_initsvc,
EXIT_MRK "Unit Tests finished.");
+ // Shutdown all CPUs
+
+ // TODO. Current code does not wait for UTs to finish. Add a delay for now
+ // This will be fixed soon.
+ nanosleep(2, 0);
+
+ uint64_t l_shutdownStatus = SHUTDOWN_STATUS_GOOD;
+
+ if (CxxTest::g_FailedTests)
+ {
+ l_shutdownStatus = SHUTDOWN_STATUS_UT_FAILED;
+ }
+
+ shutdown(l_shutdownStatus);
// return to _start(), which may end the task or die.
return;
diff --git a/src/usr/initservice/extinitsvc/extinitsvc.H b/src/usr/initservice/extinitsvc/extinitsvc.H
index aa4ef6bc6..a50b790ed 100644
--- a/src/usr/initservice/extinitsvc/extinitsvc.H
+++ b/src/usr/initservice/extinitsvc/extinitsvc.H
@@ -33,8 +33,15 @@ namespace INITSERVICE
/******************************************************************************/
// Typedef/Enumerations
/******************************************************************************/
-
-
+/**
+ * @enum ShutdownStatus
+ */
+enum ShutdownStatus
+{
+ SHUTDOWN_STATUS_GOOD = 0x01230000,
+ SHUTDOWN_STATUS_UT_FAILED = 0x01230001,
+ SHUTDOWN_STATUS_ISTEP_FAILED = 0x01230002,
+};
/******************************************************************************/
// ExtInitSvc Class
OpenPOWER on IntegriCloud