ref: f2f46f4a33ee9ccb4f0475163408b8a699ec4f7f
parent: 105625e10b469d4012c148154563007cfa3acc4d
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Sun Mar 16 16:22:59 EDT 2014
pc64: amd64 kernel reboot support
--- a/sys/src/9/pc/dat.h
+++ b/sys/src/9/pc/dat.h
@@ -279,6 +279,7 @@
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;
/*
--- a/sys/src/9/pc/main.c
+++ b/sys/src/9/pc/main.c
@@ -188,6 +188,7 @@
active.machs = 1;
active.exiting = 0;
+ active.rebooting = 0;
}
void
@@ -936,8 +937,7 @@
delay(5*60*1000);
else
delay(10000);
- }else
- delay(1000);
+ }
}
void
@@ -959,6 +959,10 @@
sched();
}
+ lock(&active);
+ active.rebooting = 1;
+ unlock(&active);
+
shutdown(0);
/*
@@ -965,11 +969,11 @@
* 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 @@
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);
}
--- a/sys/src/9/pc/mp.c
+++ b/sys/src/9/pc/mp.c
@@ -622,23 +622,13 @@
{
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 @@
outb(0xCF9, 0x06);
print("can't reset\n");
- for(;;)
- idle();
+ idle();
}
--- 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.
*/
--- a/sys/src/9/pc64/dat.h
+++ b/sys/src/9/pc64/dat.h
@@ -244,6 +244,7 @@
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;
/*
--- 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 @@
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 @@
active.machs = 1;
active.exiting = 0;
+ active.rebooting = 0;
}
@@ -525,8 +556,7 @@
delay(5*60*1000);
else
delay(10000);
- }else
- delay(1000);
+ }
}
void
@@ -537,9 +567,63 @@
}
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);
}
/*
--- a/sys/src/9/pc64/mkfile
+++ b/sys/src/9/pc64/mkfile
@@ -7,6 +7,7 @@
KTZERO=0xffffffff80110000
APBOOTSTRAP=0xffffffff80003000
+REBOOTADDR=0x11000
DEVS=`{rc ../port/mkdevlist $CONF}
@@ -112,7 +113,7 @@
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 @@
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 @@
$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
--- /dev/null
+++ b/sys/src/9/pc64/rebootcode.s
@@ -1,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
--- a/sys/src/9/port/portclock.c
+++ b/sys/src/9/port/portclock.c
@@ -148,10 +148,8 @@
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();
--- a/sys/src/9/port/rebootcmd.c
+++ b/sys/src/9/port/rebootcmd.c
@@ -69,8 +69,16 @@
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;