diff --git a/sys/src/9/pc/dat.h b/sys/src/9/pc/dat.h index a4544debf..5e5b4ea3a 100644 --- a/sys/src/9/pc/dat.h +++ b/sys/src/9/pc/dat.h @@ -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; /* diff --git a/sys/src/9/pc/main.c b/sys/src/9/pc/main.c index 62d6a192a..c947bb816 100644 --- a/sys/src/9/pc/main.c +++ b/sys/src/9/pc/main.c @@ -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); } diff --git a/sys/src/9/pc/mp.c b/sys/src/9/pc/mp.c index 041f94a0c..ead78ae17 100644 --- a/sys/src/9/pc/mp.c +++ b/sys/src/9/pc/mp.c @@ -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(); } diff --git a/sys/src/9/pc/rebootcode.s b/sys/src/9/pc/rebootcode.s index 34ee4ca36..c7d0b1991 100644 --- a/sys/src/9/pc/rebootcode.s +++ b/sys/src/9/pc/rebootcode.s @@ -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. */ diff --git a/sys/src/9/pc64/dat.h b/sys/src/9/pc64/dat.h index 0882634c8..1f5caa736 100644 --- a/sys/src/9/pc64/dat.h +++ b/sys/src/9/pc64/dat.h @@ -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; /* diff --git a/sys/src/9/pc64/main.c b/sys/src/9/pc64/main.c index 4c2e5c803..566d8d5b9 100644 --- a/sys/src/9/pc64/main.c +++ b/sys/src/9/pc64/main.c @@ -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); } /* diff --git a/sys/src/9/pc64/mkfile b/sys/src/9/pc64/mkfile index b09e2cad4..d3f9e7e5f 100644 --- a/sys/src/9/pc64/mkfile +++ b/sys/src/9/pc64/mkfile @@ -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 diff --git a/sys/src/9/pc64/rebootcode.s b/sys/src/9/pc64/rebootcode.s new file mode 100644 index 000000000..7b6d150f1 --- /dev/null +++ b/sys/src/9/pc64/rebootcode.s @@ -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 diff --git a/sys/src/9/port/portclock.c b/sys/src/9/port/portclock.c index 8f56b50c1..0bbbc92f1 100644 --- a/sys/src/9/port/portclock.c +++ b/sys/src/9/port/portclock.c @@ -148,10 +148,8 @@ hzclock(Ureg *ur) if((active.machs&(1<machno)) == 0) return; - if(active.exiting) { - print("someone's exiting\n"); + if(active.exiting) exit(0); - } if(m->machno == 0) checkalarms(); diff --git a/sys/src/9/port/rebootcmd.c b/sys/src/9/port/rebootcmd.c index 6c6adf95b..fb64b2bee 100644 --- a/sys/src/9/port/rebootcmd.c +++ b/sys/src/9/port/rebootcmd.c @@ -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;