pc64: amd64 kernel reboot support

This commit is contained in:
cinap_lenrek 2014-03-16 20:22:59 +01:00
parent 105625e10b
commit f2f46f4a33
10 changed files with 243 additions and 34 deletions

View file

@ -279,6 +279,7 @@ struct
int exiting; /* shutdown */
int ispanic; /* shutdown in response to a panic */
int thunderbirdsarego; /* lets the added processors continue to schedinit */
int rebooting; /* about to rebooting another kernel */
}active;
/*

View file

@ -188,6 +188,7 @@ mach0init(void)
active.machs = 1;
active.exiting = 0;
active.rebooting = 0;
}
void
@ -936,8 +937,7 @@ shutdown(int ispanic)
delay(5*60*1000);
else
delay(10000);
}else
delay(1000);
}
}
void
@ -959,17 +959,21 @@ reboot(void *entry, void *code, ulong size)
sched();
}
lock(&active);
active.rebooting = 1;
unlock(&active);
shutdown(0);
/*
* should be the only processor running now
*/
if (m->machno != 0)
print("on cpu%d (not 0)!\n", m->machno);
iprint("on cpu%d (not 0)!\n", m->machno);
if (active.machs)
print("still have active ap processors!\n");
iprint("still have active ap processors!\n");
print("shutting down...\n");
iprint("shutting down...\n");
delay(200);
splhi();
@ -993,11 +997,9 @@ reboot(void *entry, void *code, ulong size)
f = (void*)REBOOTADDR;
memmove(f, rebootcode, sizeof(rebootcode));
print("rebooting...\n");
/* off we go - never to return */
coherence();
(*f)(PADDR(entry), PADDR(code), size);
(*f)((ulong)entry & ~0xF0000000UL, PADDR(code), size);
}

View file

@ -622,23 +622,13 @@ mpshutdown(void)
{
static Lock shutdownlock;
/*
* To be done...
*/
if(!canlock(&shutdownlock)){
/*
* If this processor received the CTRL-ALT-DEL from
* the keyboard, acknowledge it. Send an INIT to self.
*/
#ifdef FIXTHIS
if(lapicisr(VectorKBD))
lapiceoi(VectorKBD);
#endif /* FIX THIS */
if(active.rebooting || !canlock(&shutdownlock)){
splhi();
arch->introff();
idle();
}
print("apshutdown: active = %#8.8ux\n", active.machs);
print("mpshutdown: active = %#8.8ux\n", active.machs);
delay(1000);
splhi();
@ -666,6 +656,5 @@ mpshutdown(void)
outb(0xCF9, 0x06);
print("can't reset\n");
for(;;)
idle();
idle();
}

View file

@ -1,7 +1,7 @@
#include "mem.h"
/*
* Turn off MMU, then memmory the new kernel to its correct location
* Turn off MMU, then memmove the new kernel to its correct location
* in physical memory. Then jumps the to start of the kernel.
*/

View file

@ -244,6 +244,7 @@ struct
int exiting; /* shutdown */
int ispanic; /* shutdown in response to a panic */
int thunderbirdsarego; /* lets the added processors continue to schedinit */
int rebooting; /* about to rebooting another kernel */
}active;
/*

View file

@ -8,6 +8,7 @@
#include "ureg.h"
#include "init.h"
#include "pool.h"
#include "reboot.h"
/*
* Where configuration info is left for the loaded programme.
@ -133,6 +134,35 @@ getconf(char *name)
return 0;
}
static void
writeconf(void)
{
char *p, *q;
int n;
p = getconfenv();
if(waserror()) {
free(p);
nexterror();
}
/* convert to name=value\n format */
for(q=p; *q; q++) {
q += strlen(q);
*q = '=';
q += strlen(q);
*q = '\n';
}
n = q - p + 1;
if(n >= BOOTARGSLEN)
error("kernel configuration too large");
memset(BOOTLINE, 0, BOOTLINELEN);
memmove(BOOTARGS, p, n);
poperror();
free(p);
}
void
confinit(void)
{
@ -276,6 +306,7 @@ mach0init(void)
active.machs = 1;
active.exiting = 0;
active.rebooting = 0;
}
@ -525,8 +556,7 @@ shutdown(int ispanic)
delay(5*60*1000);
else
delay(10000);
}else
delay(1000);
}
}
void
@ -537,9 +567,63 @@ exit(int ispanic)
}
void
reboot(void*, void*, ulong)
reboot(void *entry, void *code, ulong size)
{
exit(0);
void (*f)(uintptr, uintptr, ulong);
writeconf();
/*
* the boot processor is cpu0. execute this function on it
* so that the new kernel has the same cpu0. this only matters
* because the hardware has a notion of which processor was the
* boot processor and we look at it at start up.
*/
if (m->machno != 0) {
procwired(up, 0);
sched();
}
lock(&active);
active.rebooting = 1;
unlock(&active);
shutdown(0);
/*
* should be the only processor running now
*/
if (m->machno != 0)
iprint("on cpu%d (not 0)!\n", m->machno);
if (active.machs)
iprint("still have active ap processors!\n");
iprint("shutting down...\n");
delay(200);
splhi();
/* turn off buffered serial console */
serialoq = nil;
/* shutdown devices */
chandevshutdown();
arch->introff();
/*
* This allows the reboot code to turn off the page mapping
*/
*mmuwalk(m->pml4, 0, 3, 0) = *mmuwalk(m->pml4, KZERO, 3, 0);
*mmuwalk(m->pml4, 0, 2, 0) = *mmuwalk(m->pml4, KZERO, 2, 0);
mmuflushtlb();
/* setup reboot trampoline function */
f = (void*)REBOOTADDR;
memmove(f, rebootcode, sizeof(rebootcode));
/* off we go - never to return */
coherence();
(*f)((uintptr)entry & ~0xF0000000UL, (uintptr)PADDR(code), size);
}
/*

View file

@ -7,6 +7,7 @@ p=9
KTZERO=0xffffffff80110000
APBOOTSTRAP=0xffffffff80003000
REBOOTADDR=0x11000
DEVS=`{rc ../port/mkdevlist $CONF}
@ -112,7 +113,7 @@ $SDEV: ../port/sd.h
sdiahci.$O: ahci.h
devaoe.$O sdaoe.$O: ../port/aoe.h
main.$O: init.h
main.$O: init.h reboot.h
devusb.$O usbuhci.$O usbohci.$O usbehci.$O: ../port/usb.h
usbehci.$O: usbehci.h uncached.h
@ -131,6 +132,15 @@ init.h:D: ../port/initcode.c ../pc/init9.c
sed -e 's/^[0-9a-f]+ //' -e 's/ ([0-9a-f][0-9a-f])/0x\1,/g'
echo '};'} > init.h
reboot.h: rebootcode.s
$AS rebootcode.s
$LD -l -R1 -s -o reboot.out -T$REBOOTADDR rebootcode.$O
{echo 'uchar rebootcode[]={'
dd -if reboot.out -bs 1 -iseek 40 |
xd -1x |
sed -e 's/^[0-9a-f]+ //' -e 's/ ([0-9a-f][0-9a-f])/0x\1,/g'
echo '};'} > $target
apbootstrap.h: apbootstrap.s
$AS apbootstrap.s
$LD -l -R1 -s -o apbootstrap.out -T$APBOOTSTRAP apbootstrap.$O
@ -147,4 +157,4 @@ acid:V:
$CC -a -w main.c>acid
%.clean:V:
rm -f $stem.c [9bz]$stem [9bz]$stem.gz boot$stem.* apbootstrap.h init.h $PCHEADERS
rm -f $stem.c [9bz]$stem [9bz]$stem.gz boot$stem.* apbootstrap.h reboot.h init.h $PCHEADERS

116
sys/src/9/pc64/rebootcode.s Normal file
View file

@ -0,0 +1,116 @@
#include "mem.h"
MODE $64
/*
* Turn off MMU, then memmove the new kernel to its correct location
* in physical memory. Then jumps the to start of the kernel.
*/
TEXT main(SB), 1, $-4
MOVL RARG, DI /* destination */
MOVL p2+8(FP), SI /* source */
MOVL n+16(FP), BX /* byte count */
/* load zero length idt */
MOVL $_idtptr64p<>(SB), AX
MOVL (AX), IDTR
/* load temporary gdt */
MOVL $_gdtptr64p<>(SB), AX
MOVL (AX), GDTR
/* move stack below destination */
MOVL DI, SP
/* load CS with 32bit code segment */
PUSHQ $SELECTOR(3, SELGDT, 0)
PUSHQ $_warp32<>(SB)
RETFQ
MODE $32
TEXT _warp32<>(SB), 1, $-4
/* load 32bit data segments */
MOVL $SELECTOR(2, SELGDT, 0), AX
MOVW AX, DS
MOVW AX, ES
MOVW AX, FS
MOVW AX, GS
MOVW AX, SS
/* turn off paging */
MOVL CR0, AX
ANDL $0x7fffffff, AX /* ~(PG) */
MOVL AX, CR0
MOVL $0, AX
MOVL AX, CR3
/* disable long mode */
MOVL $0xc0000080, CX /* Extended Feature Enable */
RDMSR
ANDL $0xfffffeff, AX /* Long Mode Disable */
WRMSR
/* diable pae */
MOVL CR4, AX
ANDL $0xffffff5f, AX /* ~(PAE|PGE) */
MOVL AX, CR4
MOVL BX, CX /* byte count */
MOVL DI, AX /* save entry point */
/*
* the source and destination may overlap.
* determine whether to copy forward or backwards
*/
CMPL SI, DI
JGT _forward
MOVL SI, DX
ADDL CX, DX
CMPL DX, DI
JGT _back
_forward:
CLD
REP; MOVSB
_startkernel:
/* jump to entry point */
JMP* AX
_back:
ADDL CX, DI
ADDL CX, SI
SUBL $1, DI
SUBL $1, SI
STD
REP; MOVSB
JMP _startkernel
TEXT _gdt<>(SB), 1, $-4
/* null descriptor */
LONG $0
LONG $0
/* (KESEG) 64 bit long mode exec segment */
LONG $(0xFFFF)
LONG $(SEGL|SEGG|SEGP|(0xF<<16)|SEGPL(0)|SEGEXEC|SEGR)
/* 32 bit data segment descriptor for 4 gigabytes (PL 0) */
LONG $(0xFFFF)
LONG $(SEGG|SEGB|(0xF<<16)|SEGP|SEGPL(0)|SEGDATA|SEGW)
/* 32 bit exec segment descriptor for 4 gigabytes (PL 0) */
LONG $(0xFFFF)
LONG $(SEGG|SEGD|(0xF<<16)|SEGP|SEGPL(0)|SEGEXEC|SEGR)
TEXT _gdtptr64p<>(SB), 1, $-4
WORD $(4*8-1)
QUAD $_gdt<>(SB)
TEXT _idtptr64p<>(SB), 1, $-4
WORD $0
QUAD $0

View file

@ -148,10 +148,8 @@ hzclock(Ureg *ur)
if((active.machs&(1<<m->machno)) == 0)
return;
if(active.exiting) {
print("someone's exiting\n");
if(active.exiting)
exit(0);
}
if(m->machno == 0)
checkalarms();

View file

@ -69,9 +69,17 @@ rebootcmd(int argc, char *argv[])
entry = l2be(exec.entry);
text = l2be(exec.text);
data = l2be(exec.data);
if(magic != AOUT_MAGIC)
if(AOUT_MAGIC == S_MAGIC || AOUT_MAGIC == I_MAGIC){
if(magic != S_MAGIC && magic != I_MAGIC)
error(Ebadexec);
} else if(magic != AOUT_MAGIC)
error(Ebadexec);
/* amd64 extra header */
if(magic == S_MAGIC)
readn(c, &exec, 8);
/* round text out to page boundary */
rtext = PGROUND(entry+text)-entry;
size = rtext + data;