code: 9ferno

Download patch

ref: c88203b29aa39982ea701c083bb0d6bb2ea0483b
parent: 8d8022281735dcf8a6c0c2c52568180e1d4ba17c
author: 9ferno <gophone2015@gmail.com>
date: Thu Sep 16 02:52:09 EDT 2021

cleaned up the memory code

--- a/os/pc/devarch.c
+++ b/os/pc/devarch.c
@@ -477,6 +477,10 @@
 	print("cpu%d: %dMHz %s %s (AX %8.8uX CX %8.8uX DX %8.8uX)\n",
 		m->machno, m->cpumhz, m->cpuidid, m->cpuidtype,
 		m->cpuidax, m->cpuidcx, m->cpuiddx);
+	print("	family %d model %d stepping %d tsc %d\n"
+		"	pge %d watchpoint %d\n",
+		m->cpuidfamily, m->cpuidmodel, m->cpuidstepping, m->havetsc,
+		m->havepge, m->havewatchpt8);
 }
 
 /*
--- a/os/pc/mp.c
+++ b/os/pc/mp.c
@@ -197,6 +197,8 @@
 	}
 	else
 		ncpu = MAXMACH;
+	if(sizeof(apbootstrap) > 4*KiB)
+		print("mpinit: sizeof(apbootstrap) 0x%x > 4*KiB -- fix it\n", sizeof(apbootstrap));
 	memmove((void*)APBOOTSTRAP, apbootstrap, sizeof(apbootstrap));
 	for(i=0; i<nelem(mpapic); i++){
 		if((apic = mpapic[i]) == nil)
--- a/os/pc64/apbootstrap.i
+++ b/os/pc64/apbootstrap.i
@@ -1,21 +1,21 @@
 uchar apbootstrap[]={
-0xea,0x30,0x70,0x00,0x00,0x90,0x90,0x90,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0xea,0x30,0x50,0x00,0x00,0x90,0x90,0x90,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,
-0x8c,0xc8,0x8e,0xd8,0x0f,0x01,0x16,0xff,0x70,0x0f,0x20,0xc0,0x83,0xc8,0x01,0x0f,
-0x22,0xc0,0xeb,0x00,0xea,0x49,0x70,0x18,0x00,0x66,0xb8,0x10,0x00,0x8e,0xd8,0x8e,
-0xc0,0x8e,0xe0,0x8e,0xe8,0x8e,0xd0,0x8b,0x05,0x10,0x70,0x00,0x00,0x0f,0x22,0xd8,
+0x8c,0xc8,0x8e,0xd8,0x0f,0x01,0x16,0xfd,0x50,0x0f,0x20,0xc0,0x83,0xc8,0x01,0x0f,
+0x22,0xc0,0xeb,0x00,0xea,0x49,0x50,0x18,0x00,0x66,0xb8,0x10,0x00,0x8e,0xd8,0x8e,
+0xc0,0x8e,0xe0,0x8e,0xe8,0x8e,0xd0,0x8b,0x05,0x10,0x50,0x00,0x00,0x0f,0x22,0xd8,
 0xeb,0x00,0x0f,0x20,0xe0,0x83,0xe0,0xef,0x0d,0xa0,0x00,0x00,0x00,0x0f,0x22,0xe0,
-0xb9,0x80,0x00,0x00,0xc0,0x0f,0x32,0x0b,0x05,0x28,0x70,0x00,0x00,0x0f,0x30,0x0f,
+0xb9,0x80,0x00,0x00,0xc0,0x0f,0x32,0x0b,0x05,0x28,0x50,0x00,0x00,0x0f,0x30,0x0f,
 0x20,0xc2,0x81,0xe2,0xf5,0xff,0xff,0x9f,0x81,0xca,0x00,0x00,0x01,0x80,0x0f,0x22,
-0xc2,0xea,0x98,0x70,0x00,0x00,0x08,0x00,0x48,0xc7,0xc0,0x0f,0x71,0x00,0x80,0x0f,
-0x01,0x10,0x48,0x31,0xc0,0x8e,0xd8,0x8e,0xc0,0x8e,0xe0,0x8e,0xe8,0x8e,0xd0,0x0f,
-0x00,0xd0,0x48,0x8b,0x24,0x25,0x20,0x70,0x00,0x80,0x49,0x89,0xc6,0x49,0x89,0xe7,
-0x48,0x81,0xc4,0x00,0x80,0x00,0x00,0x50,0x9d,0x48,0x8b,0x04,0x25,0x08,0x70,0x00,
-0x80,0x48,0x8b,0x2c,0x25,0x18,0x70,0x00,0x80,0x55,0xff,0xd0,0xf4,0xeb,0xfd,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x00,0x00,0x00,0x9a,0xaf,0x00,0xff,
-0xff,0x00,0x00,0x00,0x92,0xcf,0x00,0xff,0xff,0x00,0x00,0x00,0x9a,0xcf,0x00,0x1f,
-0x00,0xdf,0x70,0x00,0x00,0x1f,0x00,0xdf,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x1f,
-0x00,0xdf,0x70,0x00,0x80,0xff,0xff,0xff,0xff,
+0xc2,0xea,0x98,0x50,0x00,0x00,0x08,0x00,0xb8,0x0d,0x51,0x00,0x00,0x0f,0x01,0x10,
+0x48,0x31,0xc0,0x8e,0xd8,0x8e,0xc0,0x8e,0xe0,0x8e,0xe8,0x8e,0xd0,0x0f,0x00,0xd0,
+0x48,0x8b,0x24,0x25,0x20,0x50,0x00,0x00,0x49,0x89,0xc6,0x49,0x89,0xe7,0x48,0x81,
+0xc4,0x00,0x00,0x01,0x00,0x50,0x9d,0x48,0x8b,0x04,0x25,0x08,0x50,0x00,0x00,0x48,
+0x8b,0x2c,0x25,0x18,0x50,0x00,0x00,0x55,0xff,0xd0,0xf4,0xeb,0xfd,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x00,0x00,0x00,0x9a,0xaf,0x00,0xff,0xff,0x00,
+0x00,0x00,0x92,0xcf,0x00,0xff,0xff,0x00,0x00,0x00,0x9a,0xcf,0x00,0x1f,0x00,0xdd,
+0x50,0x00,0x00,0x1f,0x00,0xdd,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x1f,0x00,0xdd,
+0x50,0x00,0x00,0x00,0x00,0x00,0x00,
 
 };
--- a/os/pc64/apbootstrap.s
+++ b/os/pc64/apbootstrap.s
@@ -1,29 +1,4 @@
-#include "mem.h"
-
-#define NOP		BYTE $0x90		/* NOP */
-#define LGDT(gdtptr)	BYTE $0x0F;		/* LGDT */			\
-			BYTE $0x01; BYTE $0x16;					\
-			WORD $gdtptr
-#define FARJUMP16(s, o)	BYTE $0xEA;		/* far jump to ptr16:16 */	\
-			WORD $o; WORD $s;					\
-			NOP; NOP; NOP
-#define FARJUMP32(s, o)	BYTE $0x66;		/* far jump to ptr32:16 */	\
-			BYTE $0xEA; LONG $o; WORD $s
-
-#define	DELAY		BYTE $0xEB;		/* JMP .+2 */			\
-			BYTE $0x00
-#define INVD		BYTE $0x0F; BYTE $0x08
-#define WBINVD		BYTE $0x0F; BYTE $0x09
-
 /*
- * Macros for calculating offsets within the page directory base
- * and page tables. Note that these are assembler-specific hence
- * the '<<2'.
- */
-#define PDO(a)		(((((a))>>22) & 0x03FF)<<2)
-#define PTO(a)		(((((a))>>12) & 0x03FF)<<2)
-
-/*
  * Start an Application Processor. This must be placed on a 4KB boundary
  * somewhere in the 1st MB of conventional memory (APBOOTSTRAP). However,
  * due to some shortcuts below it's restricted further to within the 1st
@@ -33,19 +8,48 @@
  *   CS limit set to 64KB;
  *   CPL and IP set to 0.
  */
-TEXT apbootstrap(SB), $0
-	FARJUMP16(0, _apbootstrap(SB))
-TEXT _apvector(SB), $0				/* address APBOOTSTRAP+0x08 */
-	LONG $0
-TEXT _appdb(SB), $0				/* address APBOOTSTRAP+0x0C */
-	LONG $0
-TEXT _apapic(SB), $0				/* address APBOOTSTRAP+0x10 */
-	LONG $0
-TEXT _apbootstrap(SB), $0			/* address APBOOTSTRAP+0x14 */
+#include "mem.h"
+
+#define NOP		BYTE $0x90		/* NOP */
+
+#define pFARJMP32(s, o)	BYTE $0xea;		/* far jmp ptr32:16 */	\
+			LONG $o; WORD $s
+#define rFARJMP16(s, o)	BYTE $0xea;		/* far jump ptr16:16 */	\
+			WORD $o; WORD $s;
+#define rFARJMP32(s, o)	BYTE $0x66;		/* far jump ptr32:16 */	\
+			pFARJMP32(s, o)
+
+#define rLGDT(gdtptr)	BYTE $0x0f;		/* LGDT */		\
+			BYTE $0x01; BYTE $0x16;				\
+			WORD $gdtptr
+
+#define rMOVAX(i)	BYTE $0xb8;		/* i -> AX */		\
+			WORD $i;
+
+#define	DELAY		BYTE $0xEB;		/* JMP .+2 */			\
+			BYTE $0x00
+
+MODE $16
+
+TEXT apbootstrap(SB), 1, $-4 
+	rFARJMP16(0, _apbootstrap-KZERO(SB))
+	NOP; NOP; NOP;
+TEXT _apvector(SB), 1, $-4 			/* address APBOOTSTRAP+0x08 */
+	QUAD $0
+TEXT _appml4(SB), 1, $-4 			/* address APBOOTSTRAP+0x10 */
+	QUAD $0
+TEXT _apapic(SB), 1, $-4 			/* address APBOOTSTRAP+0x18 */
+	QUAD $0
+TEXT _apmach(SB), 1, $-4 			/* address APBOOTSTRAP+0x20 */
+	QUAD $0
+TEXT _apefer(SB), 1, $-4
+	QUAD $0x100				/* Long Mode Enable */
+
+TEXT _apbootstrap(SB), 1, $-4 
 	MOVW	CS, AX
 	MOVW	AX, DS				/* initialise DS */
 
-	LGDT(gdtptr(SB))			/* load a basic gdt */
+	rLGDT(_gdtptr32p<>-KZERO(SB))		/* load a basic gdt */
 
 	MOVL	CR0, AX
 	ORL	$1, AX
@@ -52,7 +56,21 @@
 	MOVL	AX, CR0				/* turn on protected mode */
 	DELAY					/* JMP .+2 */
 
-	BYTE $0xB8; WORD $SELECTOR(1, SELGDT, 0)/* MOVW $SELECTOR(1, SELGDT, 0), AX */
+	rFARJMP16(SELECTOR(3, SELGDT, 0), _ap32-KZERO(SB))
+
+/*
+ * Enable and activate Long Mode. From the manual:
+ * 	make sure Page Size Extentions are off, and Page Global
+ *	Extensions and Physical Address Extensions are on in CR4;
+ *	set Long Mode Enable in the Extended Feature Enable MSR;
+ *	set Paging Enable in CR0;
+ *	make an inter-segment jump to the Long Mode code.
+ * It's all in 32-bit mode until the jump is made.
+ */
+MODE $32
+
+TEXT _ap32(SB), 1, $-4
+	MOVW	$SELECTOR(2, SELGDT, 0), AX
 	MOVW	AX, DS
 	MOVW	AX, ES
 	MOVW	AX, FS
@@ -59,52 +77,95 @@
 	MOVW	AX, GS
 	MOVW	AX, SS
 
-	FARJUMP32(SELECTOR(2, SELGDT, 0), _ap32-KZERO(SB))
+	MOVL	_appml4-KZERO(SB), AX	/* physical address of PML4 */
+	MOVL	AX, CR3			/* load the mmu */
+	DELAY
 
+	MOVL	CR4, AX
+	ANDL	$~0x00000010, AX		/* Page Size */
+	ORL	$0x000000A0, AX			/* Page Global, Phys. Address */
+	MOVL	AX, CR4
+
+	MOVL	$0xc0000080, CX			/* Extended Feature Enable */
+	RDMSR
+	ORL	_apefer-KZERO(SB), AX
+	WRMSR
+
+	MOVL	CR0, DX
+	ANDL	$~0x6000000a, DX
+	ORL	$0x80010000, DX			/* Paging Enable, Write Protect */
+	MOVL	DX, CR0
+
+	pFARJMP32(SELECTOR(KESEG, SELGDT, 0), _ap64-KZERO(SB))
+
 /*
- * For Pentiums and higher, the code that enables paging must come from
- * pages that are identity mapped. 
- * To this end double map KZERO at virtual 0 and undo the mapping once virtual
- * nirvana has been obtained.
+ * Long mode. Welcome to 2003.
+ * Jump out of the identity map space;
+ * load a proper long mode GDT;
+ * initialise the stack and call the
+ * C startup code in m->splpc.
  */
-TEXT _ap32(SB), $0
-	MOVL	_appdb-KZERO(SB), CX		/* physical address of PDB */
-	MOVL	(PDO(KZERO))(CX), DX		/* double-map KZERO at 0 */
-	MOVL	DX, (PDO(0))(CX)
-	MOVL	CX, CR3				/* load and flush the mmu */
+MODE $64
 
-	MOVL	CR0, DX
-	ORL	$0x80010000, DX			/* PG|WP */
-	ANDL	$~0x6000000A, DX		/* ~(CD|NW|TS|MP) */
+TEXT _ap64(SB), 1, $-4
+	MOVQ	$_gdtptr64v<>(SB), AX
+	MOVL	(AX), GDTR
 
-	MOVL	$_appg(SB), AX
-	MOVL	DX, CR0				/* turn on paging */
-	JMP*	AX
+	XORQ	AX, AX
+	MOVW	AX, DS				/* not used in long mode */
+	MOVW	AX, ES				/* not used in long mode */
+	MOVW	AX, FS
+	MOVW	AX, GS
+	MOVW	AX, SS				/* not used in long mode */
 
-TEXT _appg(SB), $0
-	MOVL	CX, AX				/* physical address of PDB */
-	ORL	$KZERO, AX
-	MOVL	$0, (PDO(0))(AX)		/* undo double-map of KZERO at 0 */
-	MOVL	CX, CR3				/* load and flush the mmu */
+	MOVW	AX, LDTR
 
-	MOVL	$(MACHADDR+MACHSIZE-4), SP
+	MOVQ	_apmach(SB), SP
 
-	MOVL	$0, AX
-	PUSHL	AX
-	POPFL
+	MOVQ	AX, RUSER			/* up = 0; */
+	MOVQ	SP, RMACH			/* m = apmach */
 
-	MOVL	_apapic(SB), AX
-	MOVL	AX, (SP)
-	MOVL	_apvector(SB), AX
-	CALL*	AX
-_aphalt:
+	ADDQ	$MACHSIZE, SP
+
+	PUSHQ	AX				/* clear flags */
+	POPFQ
+
+	MOVQ	_apvector(SB), AX
+	MOVQ	_apapic(SB), RARG
+	PUSHQ	RARG
+
+	CALL	*AX
+
+_halt:
 	HLT
-	JMP	_aphalt
+	JMP _halt
+	
+TEXT _gdt<>(SB), 1, $-4
+	/* null descriptor */
+	LONG	$0
+	LONG	$0
 
-TEXT gdt(SB), $0
-	LONG $0x0000; LONG $0
-	LONG $0xFFFF; LONG $(SEGG|SEGB|(0xF<<16)|SEGP|SEGPL(0)|SEGDATA|SEGW)
-	LONG $0xFFFF; LONG $(SEGG|SEGD|(0xF<<16)|SEGP|SEGPL(0)|SEGEXEC|SEGR)
-TEXT gdtptr(SB), $0
-	WORD	$(3*8-1)
-	LONG	$gdt-KZERO(SB)
+	/* (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 _gdtptr32p<>(SB), 1, $-4
+	WORD	$(4*8-1)
+	LONG	$_gdt<>-KZERO(SB)
+
+TEXT _gdtptr64p<>(SB), 1, $-4
+	WORD	$(4*8-1)
+	QUAD	$_gdt<>-KZERO(SB)
+
+TEXT _gdtptr64v<>(SB), 1, $-4
+	WORD	$(4*8-1)
+	QUAD	$_gdt<>(SB)
--- a/os/pc64/fns.h
+++ b/os/pc64/fns.h
@@ -161,7 +161,7 @@
 void	poolsizeinit(void);
 void	procsave(Proc*);
 void	procsetup(Proc*);
-void	punmap(uintptr, vlong);
+void	punmap(uintptr, uvlong);
 void	putcr0(u64);
 void	putcr2(u64);
 void	putcr3(u64);
@@ -200,8 +200,8 @@
 void	upareserve(uintptr, u32);
 u64	us2fastticks(u64);
 void	vectortable(void);
-void*	vmap(uintptr, int);
-void	vunmap(void*, int);
+void*	vmap(uintptr, s32);
+void	vunmap(void*, s32);
 void	wbinvd(void);
 s32	wrmsr(ulong, ulong);
 int	xchgw(ushort*, int);
--- a/os/pc64/main.c
+++ b/os/pc64/main.c
@@ -5,6 +5,7 @@
 #include	"fns.h"
 #include	"io.h"
 #include	"ureg.h"
+#include	"rebootcode.i"
 
 #define X86STEPPING(x)	((x) & 0x0F)
 #define X86MODEL(x)	(((x)>>4) & 0x0F)
@@ -142,6 +143,7 @@
 	doc("arch->clockinit");
 	if(arch->clockinit)
 		arch->clockinit();
+	doc("meminit");
 	meminit();			/* builds the conf.mem entries */
 	doc("confinit");
 	confinit();
@@ -151,12 +153,14 @@
 		i8237alloc(); */
 	doc("pcicfginit");
 	pcicfginit();
+	doc("bootscreeninit");
 	bootscreeninit();	/* vga maps pages for the frame buffer TODO bug causes an i8042 system reset in poolsizeinit() */
 	trapinit();
 	printinit();
 	cpuidprint();
+	doc("mmuinit");
 	mmuinit();		/* builds the page tables, lgdt, lidt */
-	print("after mmuinit\n");
+	print("poolsizeinit\n");
 	poolsizeinit();
 	memmapdump();
 	eve = strdup("inferno");
--- a/os/pc64/mem.h
+++ b/os/pc64/mem.h
@@ -43,14 +43,15 @@
 /*
  *  Address spaces. Kernel, sorted by address.
  */
-#define KZERO		(0)			/* with identity mapping, KZERO = 0 */
+#define KZERO		(0ull)			/* with identity mapping, KZERO = 0 */
 /* Leave the 1st MiB to the BIOS (0 to 1MiB-1)
  * From the first MiB to KTZERO is used by the global data tables
  * acid expects plan9 userspace program text at 2MiB. So, having KTZERO at 2MiB
  * 1MiB for l.s data structures  (1 to 2MiB-1)
+ * check the e820 memory map to see the available memory
  */
-#define KDZERO		(0x100000)
-#define KTZERO		(0x200000)
+#define KDZERO		(0x100000ull)
+#define KTZERO		(0x200000ull)
 #define VMAPSIZE  (512ull*GiB)
 
 /*
@@ -57,11 +58,17 @@
  * Fundamental addresses
  */
 #define	CONFADDR	(0x1200ull)		/* info passed from boot loader */
-#define	REBOOTADDR	(0x11000ull)	/* reboot code - physical address */
-#define	APBOOTSTRAP	(KDZERO+ 0x7000ull)	/* AP bootstrap code */
+	/* Both these should be below 1MiB as they are addressed from real
+	 * mode which can address only upto 1MiB.
+	 * check the e820 memory map to figure out the availble memory below
+	 * 1MiB
+	 * The intel manual mentions a 4KiB (0x1000) page for ap bootstrap code
+	 */
+#define	REBOOTADDR	(0x4000ull)	/* reboot code - physical address */
+#define	APBOOTSTRAP	(0x5000ull)	/* Application Processor (AP) bootstrap code */
 #define	IDTADDR		(KDZERO+0x10000ull)	/* idt */
 #define GDTADDR		(KDZERO+0x11000ull)	/* gdt */
-#define	CPU0MACH	(KDZERO+0x12000ull)	/* Mach for bootstrap processor */
+#define	CPU0MACH	(KDZERO+0x12000ull)	/* Mach for bootstrap processor (BSP) */
 #define CPU0END		(KDZERO+0x22000ull)	/* CPU0MACH + (MACHSIZE = 64 KiB = 0x10 000) */
 										/* MACHSIZE includes stack size */
 #define CPU0SP		(KDZERO+0x22000ull)
--- a/os/pc64/memory.c
+++ b/os/pc64/memory.c
@@ -30,13 +30,14 @@
 
 u64	MemMin;		/* set by l.s */
 
-/* TODO just use xspanalloc. I do not know what the memmapalloc() does. It does not seem to work anyway. inferno pc does not use it either? can refactor all this code.
- */
 void*
 rampage(void)
 {
-	uintptr pa;
+	intptr pa;
 
+	/* no need to add page tables with pmap() here as
+	 * mmuinit() has done it for us
+	 */
 	if(conf.mem[0].npage != 0)
 		return xspanalloc(BY2PG, BY2PG, 0);
 
@@ -48,16 +49,20 @@
 	pa = memmapalloc(-1, BY2PG, BY2PG, MemRAM);
 	if(pa == -1)
 		panic("rampage: out of memory\n");
-	DP("rampage returned 0x%p\n", pa);
+	DP("rampage returned 0x%p\n", (void*)pa);
+	DP("rampage pmap base 0x%p size %zd 0x%zx\n",
+		(void*)pa, BY2PG+BY2PG, BY2PG+BY2PG);
+	pmap(pa, PTEGLOBAL|PTEWRITE|PTEVALID, BY2PG+BY2PG);
 	return (void*)pa;
 }
 
+/* maps page tables for the kernel to run */
 static void
 mapkzero(uintptr base, uintptr len, int type)
 {
-	uintptr flags, n;
+	uintptr flags;
 
-	DP("mapkzero base 0x%p len %llud 0x%llux type 0x%x\n",
+	print("mapkzero base 0x%p len %llud 0x%llux type 0x%x\n",
 		base, len, len, type);
 	if(base < MemMin && base+len > MemMin){
 		mapkzero(base, MemMin-base, type);
@@ -65,17 +70,26 @@
 		base = MemMin;
 	}
 
+	/* arbitrarily limiting the page table size while the
+	 * kernel is still booting
+	 */
+	if(base > 1*GiB && type == MemRAM)
+		return;
+	if(base >= MemMin && len > 1*GiB && type == MemRAM){
+		len=2*MemMin;
+	}
 	switch(type){
 	default:
 		return;
 	case MemRAM:
-		if(base < MemMin)
-			return;
 		flags = PTEGLOBAL|PTEWRITE|PTEVALID;
 		break;
 	case MemUMB:
 		flags = PTEGLOBAL|PTEWRITE|PTEUNCACHED|PTEVALID;
 		break;
+	case MemACPI:
+		flags = PTEGLOBAL|PTEVALID;
+		break;
 	}
 	pmap(base, flags, len);
 }
@@ -158,6 +172,22 @@
 	/* Reserve BIOS tables */
 	memmapadd(pa, 1*KB, MemReserved);
 
+	/* Allocate memory to be used for reboot code */
+	len=4*KiB /* sizeof(rebootcode) */;
+	memmapadd(PADDR(PGROUND((uintptr)REBOOTADDR)), len, MemRAM);
+	if(memmapalloc(PADDR(PGROUND((uintptr)REBOOTADDR)), len, BY2PG, MemRAM) == -1){
+		print("lowraminit: could not memmapalloc REBOOTADDR 0x%p len 0x%zd\n",
+			PADDR(PGROUND((uintptr)REBOOTADDR)), len);
+	}
+
+	/* Allocate memory to be used for ap bootstrap code */
+	len=4*KiB /*sizeof(apbootstrap)*/;
+	memmapadd(PADDR(PGROUND((uintptr)APBOOTSTRAP)), len, MemRAM);
+	if(memmapalloc(PADDR(PGROUND((uintptr)APBOOTSTRAP)), len, BY2PG, MemRAM) == -1){
+		print("lowraminit: could not memmapalloc APBOOTSTRAP 0x%p len 0x%zd\n",
+			PADDR(PGROUND((uintptr)APBOOTSTRAP)), len);
+	}
+
 	/* Reserve EBDA */
 	if((pa = ebdaseg()) != 0)
 		memmapadd(pa, 1*KB, MemReserved);
@@ -433,6 +463,28 @@
 	/* RAM needs to be writeback */
 	mtrrexclude(MemRAM, "wb");
 
+	/* do not bother allocating page tables for UPA.
+	 * UPA users call vmap() to do that.
+	 */
+print("e820scan building page tables for the kernel to work\n");
+	for(base = memmapnext(-1, MemRAM); base != -1; base = memmapnext(base, MemRAM)){
+		size = memmapsize(base, BY2PG) & ~(BY2PG-1);
+		if(size != 0)
+				mapkzero(PGROUND(base), size, MemRAM);
+	}
+print("e820scan building page tables after RAM\n");
+	for(base = memmapnext(-1, MemUMB); base != -1; base = memmapnext(base, MemUMB)){
+		size = memmapsize(base, BY2PG) & ~(BY2PG-1);
+		if(size != 0)
+			mapkzero(PGROUND(base), size, MemUMB);
+	}
+print("e820scan building page tables after UMB\n");
+	for(base = memmapnext(-1, MemACPI); base != -1; base = memmapnext(base, MemACPI)){
+		size = memmapsize(base, BY2PG) & ~(BY2PG-1);
+		if(size != 0)
+			mapkzero(PGROUND(base), size, MemACPI);
+	}
+print("e820scan building page tables after ACPI\n");
 	return 0;
 }
 
@@ -593,27 +645,23 @@
 void
 meminit0(void)
 {
-	uintptr prevbase = 0, base, size = 0;
-
 	print("Memory Configuration\n"
-		"\tMemMin 0x%llux end 0x%p KZERO 0x%x KDZERO 0x%x\n"
-		"\tKTZERO 0x%x etext 0x%p\n\tCPU0END 0x%llux\n"
-		"\tPADDR(PGROUND((uintptr)end)) 0x%zux\n"
-		"\tMemMin-PADDR(PGROUND((uintptr)end)) 0x%zux\n",
+		"\tMemMin 0x%llux end 0x%p KZERO 0x%p KDZERO 0x%p\n"
+		"\tKTZERO 0x%p etext 0x%p\n\tCPU0END 0x%p\n"
+		"\tPADDR(PGROUND((uintptr)end)) 0x%p\n"
+		"\tMemMin-PADDR(PGROUND((uintptr)end)) 0x%p\n",
 		MemMin, end, KZERO, KDZERO, KTZERO, etext, (uintptr)CPU0END,
 		PADDR(PGROUND((uintptr)end)), MemMin-PADDR(PGROUND((uintptr)end)));
 	/*
 	 * Add the already mapped memory after the kernel.
-	 */
-	if(MemMin < PADDR(PGROUND((uintptr)end)))
-		panic("kernel too big");
-	memmapadd(PADDR(PGROUND((uintptr)end)), MemMin-PADDR(PGROUND((uintptr)end)), MemRAM);
-
-	/*
 	 * Memory below MemMin is reserved for the kernel.
+	 * From KDZERO to MemMin is the kernel's RAM.
 	 * Also, set the kernel text pages read only
 	 */
-	memreserve(PADDR(KDZERO), PADDR(PGROUND((uintptr)MemMin))-PADDR(KDZERO));
+	if(MemMin < PADDR(PGROUND((uintptr)end)))
+		panic("kernel too big");
+	memmapadd(PADDR(KDZERO), PADDR(PGROUND((uintptr)MemMin))-PADDR(KDZERO), MemRAM);
+	memmapalloc(PADDR(KDZERO), PADDR(PGROUND((uintptr)MemMin))-PADDR(KDZERO), BY2PG, MemRAM);
 	kernelro();
 
 	/*
@@ -645,6 +693,9 @@
 	 */
 	mtrrexclude(MemUMB, "uc");
 	mtrrexclude(MemUPA, "uc");
+
+	/* Reserve RAM below MemMin to avoid being trashed */
+	memreserve(KZERO, MemMin);
 }
 
 /*
--- a/os/pc64/mkfile
+++ b/os/pc64/mkfile
@@ -12,9 +12,9 @@
 #INSTALLDIR=/$OBJTYPE
 
 # must match mem.h
+REBOOTADDR=0x4000
+APBOOTSTRAP=0x5000
 KTZERO=0x200000
-APBOOTSTRAP=0x107000
-REBOOTADDR=0x11000
 
 #end configurable parameters
 
@@ -84,7 +84,7 @@
 clock.$O:	$ROOT/Inferno/$OBJTYPE/include/ureg.h
 devether.$O:	$ROOT/Inferno/$OBJTYPE/include/ureg.h
 fault386.$O:	$ROOT/Inferno/$OBJTYPE/include/ureg.h
-main.$O:	$ROOT/Inferno/$OBJTYPE/include/ureg.h
+main.$O:	$ROOT/Inferno/$OBJTYPE/include/ureg.h rebootcode.i
 trap.$O:	$ROOT/Inferno/$OBJTYPE/include/ureg.h
 
 devether.$O $ETHERS:	etherif.h ../port/netif.h
@@ -99,6 +99,16 @@
 sdiahci.$O:			ahci.h
 
 ether8169.$O:			../port/ethermii.h
+
+$O.rebootcode:		rebootcode.$O
+	$LD -l -R1 -s -o $target -T$REBOOTADDR $prereq
+rebootcode.out:		$O.rebootcode
+	dd -if $prereq(1) -of $target -bs 1 -iseek 40
+
+$O.apbootstrap:		apbootstrap.$O
+	$LD -l -R1 -s -o $target -T$APBOOTSTRAP $prereq
+apbootstrap.out:	$O.apbootstrap
+	dd -if $prereq(1) -of $target -bs 1 -iseek 40
 
 # to be moved to port/interp 
 bench.h:D: ../../module/bench.m
--- a/os/pc64/mmu.c
+++ b/os/pc64/mmu.c
@@ -136,9 +136,7 @@
 
 	/* pre allocate pages */
 	Confmem *cm;
-	ulong np, nt;
 
-	np = 0;
 	for(i=0; i<nelem(conf.mem); i++){
 		cm = &conf.mem[i];
 		if(cm->npage == 0)
@@ -145,7 +143,6 @@
 			continue;
 		DP("i %d base 0x%p npage 0x%d\n", i, cm->base, cm->npage);
 		pmap(cm->base, PTEGLOBAL|PTEWRITE|PTENOEXEC|PTEVALID, cm->npage*BY2PG);
-
 	}
 }
 
@@ -152,6 +149,7 @@
 int
 mmukmapsync(uintptr va)
 {
+USED(va);
 return 0;
 }
 
@@ -158,6 +156,7 @@
 uintptr
 mmukmap(uintptr pa, uintptr va, int size)
 {
+USED(pa, va, size);
 return 0;
 }
 
@@ -172,7 +171,7 @@
  * < cinap_lenrek> vmap() and kmap() are all built ontop of it
  */
 void*
-vmap(uintptr pa, int size)
+vmap(uintptr pa, s32 size)
 {
         int o;
 
@@ -187,13 +186,14 @@
         o = pa & (BY2PG-1);
         pa -= o;
         size += o;
-        pmap(pa, PTEUNCACHED|PTEWRITE|PTENOEXEC|PTEVALID, size);
+        pmap(pa, PTEGLOBAL|PTEUNCACHED|PTEWRITE|PTENOEXEC|PTEVALID, size);
         return (void*)(pa+o);
 }
 
 void
-vunmap(void *va, int size)
+vunmap(void *va, s32 size)
 {
+USED(va, size);
 /* nothing to do */
 }
 
@@ -207,7 +207,6 @@
 mmucreate(uintptr *table, uintptr pa, int level, int index)
 {
 	uintptr *page, flags;
-	MMU *p;
 	
 	DP("mmucreate table 0x%p pa 0x%p level %d index %d\n",
 		table, pa, level, index);
@@ -224,12 +223,12 @@
 uintptr*
 mmuwalk(uintptr* table, uintptr pa, int level, int create)
 {
-	uintptr pte, flags;
+	uintptr pte /*, flags*/;
 	int i, x;
 
 	DP("mmuwalk table 0x%p pa 0x%p level %d create %d\n",
 		table, pa, level, create);
-	flags = PTEWRITE | PTEVALID;
+	/* flags = PTEWRITE | PTEVALID; */
 	x = PTLX(pa, 3);
 	DP("\tpml4 index %d\n", x);
 	for(i = 2; i >= level; i--){
@@ -290,7 +289,7 @@
 		/* reducing complexity, use 4096 byte pages all through */
 		l = 0;
 		z = PGLSZ(0);
-		pte = mmuwalk((uintptr*)PML4ADDR, pa, l, 1);
+		pte = mmuwalk(m->pml4, pa, l, 1);
 		if(pte == nil){
 			panic("pmap: pa=%#p size=%lld", pa, size);
 		}
@@ -304,7 +303,7 @@
 }
 
 void
-punmap(uintptr pa, vlong size)
+punmap(uintptr pa, uvlong size)
 {
 	uintptr *pte;
 	int l;
--- a/os/pc64/screen.c
+++ b/os/pc64/screen.c
@@ -601,7 +601,7 @@
 		nsize = 64*MB;
 	print("vgalinearaddr0 paddr 0x%p size 0x%x %d pmap npaddr 0x%p nsize 0x%x %d\n",
 		paddr, size, size, npaddr, nsize, nsize);
-	pmap(npaddr, PTEGLOBAL|PTEUNCACHED|PTEWRITE|PTENOEXEC|PTEVALID, nsize);
+	vmap(npaddr, nsize);
 	scr->vaddr = (void*)npaddr;
 
 	if(allocupa){
--- a/os/pc64/squidboy.c
+++ b/os/pc64/squidboy.c
@@ -35,7 +35,7 @@
 	uintptr *apbootp, *pml4, *pdp0;
 	Segdesc *gdt;
 	Mach *mach;
-	uchar *p;
+	uchar *p, *q;
 	int i;
 
 	/*
@@ -62,15 +62,14 @@
 	MACHP(mach->machno) = mach;
 
 	/*
-	 * map KZERO (note that we share the KZERO (and VMAP)
+	 * map KZERO (note that we share the KZERO
 	 * PDP between processors.
 	 */
 	pml4[PTLX(KZERO, 3)] = MACHP(0)->pml4[PTLX(KZERO, 3)];
-	/* TODO pml4[PTLX(VMAP, 3)] = MACHP(0)->pml4[PTLX(VMAP, 3)]; */
 
 	/* double map */
 	pml4[0] = PADDR(pdp0) | PTEWRITE|PTEVALID;
-	/* TODO Why do I need this? Why not use the same page tables for all the processors? pdp0[0] = *mmuwalk(KZERO, 2, 0); */
+	pdp0[0] = *mmuwalk(pml4, KZERO, 2, 0);
 
 	/*
 	 * Tell the AP where its kernel vector and pdb are.
--- a/os/port/memmap.c
+++ b/os/port/memmap.c
@@ -234,7 +234,7 @@
 	unlock(&mapalloc);
 }
 
-uintptr
+intptr
 memmapalloc(uintptr addr, uintptr size, uintptr align, u32 type)
 {
 	Mapent *i, *e;
--- a/os/port/portfns.h
+++ b/os/port/portfns.h
@@ -160,7 +160,7 @@
 uintptr		memmapnext(uintptr, u32);
 uintptr		memmapsize(uintptr, uintptr);
 void		memmapadd(uintptr, uintptr, u32);
-uintptr		memmapalloc(uintptr, uintptr, uintptr, u32);
+intptr		memmapalloc(uintptr, uintptr, uintptr, u32);
 void		memmapfree(uintptr, uintptr, u32);
 int			memusehigh(void);
 void		microdelay(int);
--- a/os/port/portmkfile
+++ b/os/port/portmkfile
@@ -146,4 +146,10 @@
 $CONF.root.s $CONF.root.h: $CONF ../init/$INIT.dis ../port/mkroot $ROOTFILES
 	$SHELLNAME ../port/mkroot $CONF
 
+%.i:D:	%.out
+	{echo 'uchar '^$stem^'[]={'
+	 xd -1x <$stem.out |
+		sed -e 's/^[0-9a-f]+ //' -e 's/ ([0-9a-f][0-9a-f])/0x\1,/g'
+	 echo '};'} > $target
+
 %.$O:	$ROOT/Inferno/$OBJTYPE/include/u.h ../port/lib.h mem.h dat.h fns.h io.h ../port/error.h ../port/portdat.h ../port/portfns.h