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.
This commit is contained in:
Thomas Moestl 2001-11-06 20:22:18 +00:00
parent 9b3b51bcab
commit 4f14099d5f
5 changed files with 120 additions and 3 deletions

View File

@ -108,3 +108,8 @@ DB_COMMAND(reboot, db_reboot)
{
cpu_reset();
}
DB_COMMAND(halt, db_halt)
{
cpu_halt();
}

View File

@ -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
};
OF_exit();
openfirmware_exit(&args);
}
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

View File

@ -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)

View File

@ -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)

View File

@ -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);
}
/*