diff options
-rw-r--r-- | src/include/arch/ppc.H | 35 | ||||
-rw-r--r-- | src/include/kernel/cpu.H | 24 | ||||
-rw-r--r-- | src/include/kernel/cpumgr.H | 25 | ||||
-rw-r--r-- | src/include/kernel/syscalls.H | 3 | ||||
-rw-r--r-- | src/include/sys/misc.h | 21 | ||||
-rw-r--r-- | src/kernel/cpumgr.C | 16 | ||||
-rw-r--r-- | src/kernel/syscall.C | 36 | ||||
-rw-r--r-- | src/lib/cxxtest_stub.C | 11 | ||||
-rw-r--r-- | src/lib/makefile | 3 | ||||
-rw-r--r-- | src/lib/syscall_misc.C | 10 | ||||
-rw-r--r-- | src/makefile | 8 | ||||
-rw-r--r-- | src/usr/initservice/extinitsvc/extinitsvc.C | 17 | ||||
-rw-r--r-- | src/usr/initservice/extinitsvc/extinitsvc.H | 11 |
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 |