shithub: riscv

Download patch

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;