summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPatrick Williams <iawillia@us.ibm.com>2012-04-18 16:18:22 -0500
committerA. Patrick Williams III <iawillia@us.ibm.com>2012-04-24 09:52:42 -0500
commitf2dd13f86d803e241b835c5ca2a2a14d583ba01e (patch)
treeb46bd46aa359a19e460f2382bb2127b08d0ec3e6 /src
parentf4e49418fd0743ab0d143f0ab3c505baefe58bfa (diff)
downloadtalos-hostboot-f2dd13f86d803e241b835c5ca2a2a14d583ba01e.tar.gz
talos-hostboot-f2dd13f86d803e241b835c5ca2a2a14d583ba01e.zip
Allow kernel to shutdown-to-payload.
This code is currently unused, due to InitService not having the payload address and the start_host_os IPL step being unimplemented. For testing purposes the 'shutdown' call in initservice.C can be changed to pass a non-zero base address (such as 256MB). RTC: 40871 Change-Id: I0f4b6bae62ede1853aabbcb28082300005e31897 Reviewed-on: http://gfw160.austin.ibm.com:8080/gerrit/926 Reviewed-by: A. Patrick Williams III <iawillia@us.ibm.com> Tested-by: Jenkins Server Reviewed-by: Douglas R. Gilbert <dgilbert@us.ibm.com>
Diffstat (limited to 'src')
-rw-r--r--src/include/kernel/cpumgr.H5
-rw-r--r--src/include/kernel/misc.H5
-rw-r--r--src/include/kernel/ppcconsts.S1
-rw-r--r--src/include/sys/misc.h9
-rw-r--r--src/kernel/cpumgr.C3
-rw-r--r--src/kernel/misc.C40
-rw-r--r--src/kernel/start.S64
-rw-r--r--src/kernel/syscall.C2
-rw-r--r--src/lib/syscall_misc.C9
-rw-r--r--src/usr/initservice/baseinitsvc/initservice.C6
-rw-r--r--src/usr/initservice/baseinitsvc/initservice.H8
11 files changed, 142 insertions, 10 deletions
diff --git a/src/include/kernel/cpumgr.H b/src/include/kernel/cpumgr.H
index 3be17192c..4374d50a0 100644
--- a/src/include/kernel/cpumgr.H
+++ b/src/include/kernel/cpumgr.H
@@ -81,6 +81,11 @@ class CpuManager
*/
static void activateCPU(cpu_t * i_cpu);
+ /** @fn getCpuCount
+ * Return the number of active CPUs.
+ */
+ static size_t getCpuCount() { return cv_cpuCount; }
+
protected:
CpuManager();
diff --git a/src/include/kernel/misc.H b/src/include/kernel/misc.H
index 4be79d641..f04439748 100644
--- a/src/include/kernel/misc.H
+++ b/src/include/kernel/misc.H
@@ -35,5 +35,10 @@ namespace KernelMisc
* @brief Sequence kernel to shutdown and switch to payload.
*/
void shutdown();
+
+ /** @brief Base address (target HRMOR) of the payload. */
+ extern uint64_t g_payload_base;
+ /** @brief Address from base of payload entry-point. */
+ extern uint64_t g_payload_entry;
};
#endif
diff --git a/src/include/kernel/ppcconsts.S b/src/include/kernel/ppcconsts.S
index 6aa53a6cd..89a52a008 100644
--- a/src/include/kernel/ppcconsts.S
+++ b/src/include/kernel/ppcconsts.S
@@ -156,6 +156,7 @@
.set HSPRG1,305
.set HDSISR,306
.set HDEC,310
+ .set HRMOR,313
.set HSRR0,314
.set HSRR1,315
.set HMER,336
diff --git a/src/include/sys/misc.h b/src/include/sys/misc.h
index d07c5afff..fcf88f08a 100644
--- a/src/include/sys/misc.h
+++ b/src/include/sys/misc.h
@@ -49,9 +49,14 @@ extern "C"
#ifdef __HIDDEN_SYSCALL_SHUTDOWN
/** @fn shutdown()
* @brief Shutdown all CPUs (hardware threads)
- * @param[in] i_status The status code to post
+ * @param[in] i_status The status code to post
+ * @param[in] i_payload_base The base address (target HRMOR) of the payload.
+ * @param[in] i_payload_entry The offset from base address of the payload
+ * entry-point.
*/
-extern "C" void shutdown(uint64_t i_status);
+extern "C" void shutdown(uint64_t i_status,
+ uint64_t i_payload_base,
+ uint64_t i_payload_entry);
#endif
/** @enum ProcessorCoreType
diff --git a/src/kernel/cpumgr.C b/src/kernel/cpumgr.C
index 33290ebf1..f995eb543 100644
--- a/src/kernel/cpumgr.C
+++ b/src/kernel/cpumgr.C
@@ -107,8 +107,9 @@ void CpuManager::init_slave_smp(cpu_t* cpu)
void CpuManager::requestShutdown(uint64_t i_status)
{
- cv_shutdown_requested = true;
cv_shutdown_status = i_status;
+ __sync_synchronize();
+ cv_shutdown_requested = true;
}
void CpuManager::startCPU(ssize_t i)
diff --git a/src/kernel/misc.C b/src/kernel/misc.C
index 513844875..74be12de1 100644
--- a/src/kernel/misc.C
+++ b/src/kernel/misc.C
@@ -24,9 +24,17 @@
#include <kernel/cpumgr.H>
#include <kernel/cpuid.H>
#include <kernel/console.H>
+#include <kernel/barrier.H>
+
+extern "C" void kernel_shutdown(size_t, uint64_t, uint64_t) NO_RETURN;
+
namespace KernelMisc
{
+
+ uint64_t g_payload_base = 0;
+ uint64_t g_payload_entry = 0;
+
void shutdown()
{
// Update scratch SPR for shutdown status.
@@ -65,9 +73,37 @@ namespace KernelMisc
// for exactly how this is handled.
MAGIC_INSTRUCTION(MAGIC_SHUTDOWN);
- while(1)
+ // Check for a valid payload address.
+ if ((0 == g_payload_base) && (0 == g_payload_entry))
{
- doze();
+ // We really don't know what we're suppose to do now, so just
+ // sleep all the processors.
+
+ if (c->master)
+ {
+ printk("No payload... doze'ing all threads.\n");
+ }
+
+ while(1)
+ {
+ doze();
+ }
+ }
+ else
+ {
+ static Barrier* l_barrier = new Barrier(CpuManager::getCpuCount());
+
+ if (c->master)
+ {
+ printk("Preparing to enter payload...%lx:%lx\n",
+ g_payload_base, g_payload_entry);
+ }
+
+ l_barrier->wait();
+
+ kernel_shutdown(CpuManager::getCpuCount(),
+ g_payload_base,
+ g_payload_entry);
}
}
};
diff --git a/src/kernel/start.S b/src/kernel/start.S
index c5af8652f..6d0eab195 100644
--- a/src/kernel/start.S
+++ b/src/kernel/start.S
@@ -640,6 +640,67 @@ task_end_stub:
li r4, 0 ;// NULL -> r4 (status value)
sc
+ ;// @fn kernel_shutdown
+ ;// Leave the Hostboot kernel and switch to the payload.
+ ;//
+ ;// This code must first move itself into "EA[0]=1" mode, migrate to a
+ ;// new HRMOR, and then jump to the new code. The migration of the
+ ;// HRMOR must be synchronized, since the HRMOR is a core-shared SPR, so
+ ;// we must first ensure that all threads are in "EA[0]=1" mode.
+ ;//
+ ;// @param[in] r3 - CPU count - Number of active CPUs.
+ ;// @param[in] r4 - Payload Base
+ ;// @param[in] r5 - Payload Entry
+.global kernel_shutdown
+kernel_shutdown:
+ ;// Set R6 to 0x8000000000000000 so we can set "EA[0]=1" for addrs.
+ li r6, 1
+ rotldi r6, r6, 63
+ ;// Retrieve existing HRMOR.
+ mfspr r7, HRMOR
+ ;// Determine physical address of shutdown_barrier.
+ lis r8, kernel_shutdown_barrier@h
+ ori r8, r8, kernel_shutdown_barrier@l
+ or r8, r8, r7 ;// Apply HRMOR.
+ or r8, r8, r6 ;// Apply EA[0] = 1.
+ ;// Determine physical address of EA[0]=1 mode instruction.
+ lis r9, kernel_shutdown_ea0_1_mode@h
+ ori r9, r9, kernel_shutdown_ea0_1_mode@l
+ or r9, r9, r7 ;// Apply HRMOR.
+ or r9, r9, r6 ;// Apply EA[0] = 1.
+ ;// Jump to enter EA[0] = 1
+ mtlr r9
+ blr
+kernel_shutdown_ea0_1_mode:
+ ;// Perform barrier
+ ;// Increment thread count.
+1:
+ ldarx r11, 0, r8
+ addi r11, r11, 1
+ stdcx. r11, 0, r8
+ bne- 1b
+ isync
+ ;// Wait for count to reach CPU count.
+1:
+ or 1,1,1 ;// Drop thread priority
+ ld r11, 0(r8)
+ cmpd cr0, r11, r3
+ bne 1b
+ ;// Instruction barrier to ensure exit.
+ isync
+ or 3,3,3 ;// Increase thread priority
+ ;// Update HRMOR.
+ ;// TODO: There might be more to it than just this, such as clearing
+ ;// ERATs but this works for now in Simics.
+ mtspr HRMOR, r4
+ ;// Set HSRR0 to entry point.
+ mtspr HSRR0, r5
+ ;// Save MSR, move to HSRR1.
+ mfmsr r10
+ mtspr HSRR1, r10
+ ;// TODO: Any updates we need to do to HSRR1/MSR for payload?
+ ;// Jump to entry point. Causes HSRR0 -> NIA, HSSR1 -> MSR.
+ hrfid
STD_INTERRUPT_NOADDR(hype_emu_assist)
@@ -652,6 +713,9 @@ kernel_stack:
kernel_other_thread_spinlock:
.space 8
+kernel_shutdown_barrier:
+ .space 8
+
.global hbi_ImageId
hbi_ImageId:
.space 128
diff --git a/src/kernel/syscall.C b/src/kernel/syscall.C
index 4d723852f..cfcbed860 100644
--- a/src/kernel/syscall.C
+++ b/src/kernel/syscall.C
@@ -604,6 +604,8 @@ namespace Systemcalls
void Shutdown(task_t * t)
{
uint64_t status = static_cast<uint64_t>(TASK_GETARG0(t));
+ KernelMisc::g_payload_base = static_cast<uint64_t>(TASK_GETARG1(t));
+ KernelMisc::g_payload_entry = static_cast<uint64_t>(TASK_GETARG2(t));
CpuManager::requestShutdown(status);
TASK_SETRTN(t, 0);
}
diff --git a/src/lib/syscall_misc.C b/src/lib/syscall_misc.C
index 897012daa..539399b7a 100644
--- a/src/lib/syscall_misc.C
+++ b/src/lib/syscall_misc.C
@@ -27,9 +27,14 @@
using namespace Systemcalls;
-void shutdown(uint64_t i_status)
+void shutdown(uint64_t i_status,
+ uint64_t i_payload_base,
+ uint64_t i_payload_entry)
{
- _syscall1(MISC_SHUTDOWN, reinterpret_cast<void*>(i_status));
+ _syscall3(MISC_SHUTDOWN,
+ reinterpret_cast<void*>(i_status),
+ reinterpret_cast<void*>(i_payload_base),
+ reinterpret_cast<void*>(i_payload_entry));
}
ProcessorCoreType cpu_core_type()
diff --git a/src/usr/initservice/baseinitsvc/initservice.C b/src/usr/initservice/baseinitsvc/initservice.C
index c352d5353..e9b6b25c2 100644
--- a/src/usr/initservice/baseinitsvc/initservice.C
+++ b/src/usr/initservice/baseinitsvc/initservice.C
@@ -610,7 +610,9 @@ void InitService::registerBlock(void* i_vaddr, uint64_t i_size,
}
}
-void InitService::doShutdown(uint64_t i_status)
+void InitService::doShutdown(uint64_t i_status,
+ uint64_t i_payload_base,
+ uint64_t i_payload_entry)
{
int l_rc = 0;
errlHndl_t l_err = NULL;
@@ -643,7 +645,7 @@ void InitService::doShutdown(uint64_t i_status)
}
l_rb_iter++;
}
- shutdown(i_status);
+ shutdown(i_status, i_payload_base, i_payload_entry);
}
} // namespace
diff --git a/src/usr/initservice/baseinitsvc/initservice.H b/src/usr/initservice/baseinitsvc/initservice.H
index d80c5d2ef..8c8badbbd 100644
--- a/src/usr/initservice/baseinitsvc/initservice.H
+++ b/src/usr/initservice/baseinitsvc/initservice.H
@@ -177,10 +177,16 @@ public:
* @brief Perform necessary steps, such as FLUSHing, to registered blocks.
*
* @param[in] i_status - Shutdown status to be passed along on shutdown
+ * @param[in] i_payload_base - The base address (target HRMOR) of the
+ * payload.
+ * @param[in] i_payload_entry - The offset from base address of the
+ * payload entry-point.
*
* @return Nothing
*/
- void doShutdown(uint64_t i_status);
+ void doShutdown(uint64_t i_status,
+ uint64_t i_payload_base = 0,
+ uint64_t i_payload_entry = 0);
protected:
OpenPOWER on IntegriCloud