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:
parent
9b3b51bcab
commit
4f14099d5f
@ -108,3 +108,8 @@ DB_COMMAND(reboot, db_reboot)
|
||||
{
|
||||
cpu_reset();
|
||||
}
|
||||
|
||||
DB_COMMAND(halt, db_halt)
|
||||
{
|
||||
cpu_halt();
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user