summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authortmm <tmm@FreeBSD.org>2001-11-06 20:22:18 +0000
committertmm <tmm@FreeBSD.org>2001-11-06 20:22:18 +0000
commit1c8bcc6aa95c42588d7fdb6d205bb74d8871a209 (patch)
tree4b1d2aa8ff7a7337345d885428be0738b9ec0555
parent594c8e829ba40deb4c6ba3f1cac483af55625718 (diff)
downloadFreeBSD-src-1c8bcc6aa95c42588d7fdb6d205bb74d8871a209.zip
FreeBSD-src-1c8bcc6aa95c42588d7fdb6d205bb74d8871a209.tar.gz
Add a special OpenFirmware entry point for terminating the kernel (in
this case, the firmware trap table needs to be restored). Make use of it in cpu_halt() and cpu_reset(), and make cpu_reset() reboot the kernel that was used previously insead of behaving like cpu_halt(). Add a shutdown_final event handler that turns the power off if requested.
-rw-r--r--sys/sparc64/sparc64/db_interface.c5
-rw-r--r--sys/sparc64/sparc64/machdep.c44
-rw-r--r--sys/sparc64/sparc64/support.S24
-rw-r--r--sys/sparc64/sparc64/support.s24
-rw-r--r--sys/sparc64/sparc64/vm_machdep.c26
5 files changed, 120 insertions, 3 deletions
diff --git a/sys/sparc64/sparc64/db_interface.c b/sys/sparc64/sparc64/db_interface.c
index e804dd5..9d00793 100644
--- a/sys/sparc64/sparc64/db_interface.c
+++ b/sys/sparc64/sparc64/db_interface.c
@@ -108,3 +108,8 @@ DB_COMMAND(reboot, db_reboot)
{
cpu_reset();
}
+
+DB_COMMAND(halt, db_halt)
+{
+ cpu_halt();
+}
diff --git a/sys/sparc64/sparc64/machdep.c b/sys/sparc64/sparc64/machdep.c
index 30631c0..aaff3cf 100644
--- a/sys/sparc64/sparc64/machdep.c
+++ b/sys/sparc64/sparc64/machdep.c
@@ -58,6 +58,7 @@
#include <sys/bio.h>
#include <sys/buf.h>
#include <sys/bus.h>
+#include <sys/eventhandler.h>
#include <sys/interrupt.h>
#include <sys/ptrace.h>
#include <sys/signalvar.h>
@@ -86,6 +87,7 @@
#include <machine/fp.h>
#include <machine/intr_machdep.h>
#include <machine/md_var.h>
+#include <machine/ofw_machdep.h>
#include <machine/pmap.h>
#include <machine/pstate.h>
#include <machine/reg.h>
@@ -131,6 +133,7 @@ static struct timecounter tick_tc;
static timecounter_get_t tick_get_timecount;
void sparc64_init(struct bootinfo *bi, ofw_vec_t *vec);
+void sparc64_shutdown_final(void *dummy, int howto);
static void cpu_startup(void *);
SYSINIT(cpu, SI_SUB_CPU, SI_ORDER_FIRST, cpu_startup, NULL);
@@ -171,6 +174,9 @@ cpu_startup(void *arg)
intr_init();
tick_start(clock, tick_hardclock);
+
+ EVENTHANDLER_REGISTER(shutdown_final, sparc64_shutdown_final, NULL,
+ SHUTDOWN_PRI_LAST);
}
unsigned
@@ -477,11 +483,47 @@ sigreturn(struct thread *td, struct sigreturn_args *uap)
return (EJUSTRETURN);
}
+/*
+ * Duplicate OF_exit() with a different firmware call function that restores
+ * the trap table, otherwise a RED state exception is triggered in at least
+ * some firmware versions.
+ */
void
cpu_halt(void)
{
+ static struct {
+ cell_t name;
+ cell_t nargs;
+ cell_t nreturns;
+ } args = {
+ (cell_t)"exit",
+ 0,
+ 0
+ };
+
+ openfirmware_exit(&args);
+}
- OF_exit();
+void
+sparc64_shutdown_final(void *dummy, int howto)
+{
+ static struct {
+ cell_t name;
+ cell_t nargs;
+ cell_t nreturns;
+ } args = {
+ (cell_t)"SUNW,power-off",
+ 0,
+ 0
+ };
+
+ /* Turn the power off? */
+ if ((howto & RB_POWEROFF) != 0)
+ openfirmware_exit(&args);
+ /* In case of halt, return to the firmware */
+ if ((howto & RB_HALT) != 0)
+ cpu_halt();
+
}
int
diff --git a/sys/sparc64/sparc64/support.S b/sys/sparc64/sparc64/support.S
index 14ae775..8def136 100644
--- a/sys/sparc64/sparc64/support.S
+++ b/sys/sparc64/sparc64/support.S
@@ -604,3 +604,27 @@ ENTRY(openfirmware)
ret
restore %o0, %g0, %o0
END(openfirmware)
+
+/*
+ * void ofw_exit(cell_t args[])
+ */
+ENTRY(openfirmware_exit)
+ save %sp, -CCFSZ, %sp
+ flushw
+ wrpr %g0, PIL_TICK, %pil
+ setx ofw_tba, %l7, %l5
+ ldx [%l5], %l5
+ wrpr %l5, 0, %tba ! restore the ofw trap table
+ setx ofw_vec, %l7, %l6
+ ldx [%l6], %l6
+ setx kstack0 + KSTACK_PAGES * PAGE_SIZE - PCB_SIZEOF, %l7, %l0
+ sub %l0, SPOFF, %fp ! setup a stack in a locked page
+ sub %l0, SPOFF + CCFSZ, %sp
+ mov AA_DMMU_PCXR, %l3 ! set context 0
+ stxa %g0, [%l3] ASI_DMMU
+ membar #Sync
+ wrpr %g0, 0, %tl ! force trap level 0
+ call %l6
+ mov %i0, %o0
+ ! never to return
+END(openfirmware_exit)
diff --git a/sys/sparc64/sparc64/support.s b/sys/sparc64/sparc64/support.s
index 14ae775..8def136 100644
--- a/sys/sparc64/sparc64/support.s
+++ b/sys/sparc64/sparc64/support.s
@@ -604,3 +604,27 @@ ENTRY(openfirmware)
ret
restore %o0, %g0, %o0
END(openfirmware)
+
+/*
+ * void ofw_exit(cell_t args[])
+ */
+ENTRY(openfirmware_exit)
+ save %sp, -CCFSZ, %sp
+ flushw
+ wrpr %g0, PIL_TICK, %pil
+ setx ofw_tba, %l7, %l5
+ ldx [%l5], %l5
+ wrpr %l5, 0, %tba ! restore the ofw trap table
+ setx ofw_vec, %l7, %l6
+ ldx [%l6], %l6
+ setx kstack0 + KSTACK_PAGES * PAGE_SIZE - PCB_SIZEOF, %l7, %l0
+ sub %l0, SPOFF, %fp ! setup a stack in a locked page
+ sub %l0, SPOFF + CCFSZ, %sp
+ mov AA_DMMU_PCXR, %l3 ! set context 0
+ stxa %g0, [%l3] ASI_DMMU
+ membar #Sync
+ wrpr %g0, 0, %tl ! force trap level 0
+ call %l6
+ mov %i0, %o0
+ ! never to return
+END(openfirmware_exit)
diff --git a/sys/sparc64/sparc64/vm_machdep.c b/sys/sparc64/sparc64/vm_machdep.c
index a128158..d08cdd9 100644
--- a/sys/sparc64/sparc64/vm_machdep.c
+++ b/sys/sparc64/sparc64/vm_machdep.c
@@ -61,6 +61,7 @@
#include <machine/cpu.h>
#include <machine/frame.h>
#include <machine/md_var.h>
+#include <machine/ofw_machdep.h>
#include <machine/tstate.h>
void
@@ -88,7 +89,9 @@ cpu_fork(struct thread *td1, struct proc *p2, int flags)
return;
td2 = &p2->p_thread;
- pcb = (struct pcb *)(td2->td_kstack + KSTACK_PAGES * PAGE_SIZE) - 1;
+ /* The pcb must be aligned on a 64-byte boundary. */
+ pcb = (struct pcb *)((td2->td_kstack + KSTACK_PAGES * PAGE_SIZE -
+ sizeof(struct pcb)) & ~0x3fUL);
td2->td_pcb = pcb;
/*
@@ -136,7 +139,26 @@ cpu_fork(struct thread *td1, struct proc *p2, int flags)
void
cpu_reset(void)
{
- OF_exit();
+ static char bspec[64] = "";
+ phandle_t chosen;
+ static struct {
+ cell_t name;
+ cell_t nargs;
+ cell_t nreturns;
+ cell_t bootspec;
+ } args = {
+ (cell_t)"boot",
+ 1,
+ 0,
+ (cell_t)bspec
+ };
+ if ((chosen = OF_finddevice("/chosen")) != 0) {
+ if (OF_getprop(chosen, "bootpath", bspec, sizeof(bspec)) == -1)
+ bspec[0] = '\0';
+ bspec[sizeof(bspec) - 1] = '\0';
+ }
+
+ openfirmware_exit(&args);
}
/*
OpenPOWER on IntegriCloud