diff options
-rw-r--r-- | sys/sparc64/sparc64/db_interface.c | 5 | ||||
-rw-r--r-- | sys/sparc64/sparc64/machdep.c | 44 | ||||
-rw-r--r-- | sys/sparc64/sparc64/support.S | 24 | ||||
-rw-r--r-- | sys/sparc64/sparc64/support.s | 24 | ||||
-rw-r--r-- | sys/sparc64/sparc64/vm_machdep.c | 26 |
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); } /* |