1319 lines · 29.7 KB · Assembly
RawDownload
#include "mem.h"#include "/sys/src/boot/pc/x16.h"#undef DELAY #define PADDR(a)	((a) & ~KZERO)#define KADDR(a)	(KZERO|(a)) /* * Some machine instructions not handled by 8[al]. */#define OP16		BYTE $0x66#define DELAY		BYTE $0xEB; BYTE $0x00	/* JMP .+2 */#define CPUID		BYTE $0x0F; BYTE $0xA2	/* CPUID, argument in AX */#define WRMSR		BYTE $0x0F; BYTE $0x30	/* WRMSR, argument in AX/DX (lo/hi) */#define RDTSC 		BYTE $0x0F; BYTE $0x31	/* RDTSC, result in AX/DX (lo/hi) */#define RDMSR		BYTE $0x0F; BYTE $0x32	/* RDMSR, result in AX/DX (lo/hi) */#define HLT		BYTE $0xF4#define INVLPG	BYTE $0x0F; BYTE $0x01; BYTE $0x39	/* INVLPG (%ecx) */#define WBINVD	BYTE $0x0F; BYTE $0x09#define FXSAVE		BYTE $0x0f; BYTE $0xae; BYTE $0x00  /* SSE FP save */#define FXRSTOR		BYTE $0x0f; BYTE $0xae; BYTE $0x08  /* SSE FP restore */ /* * 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) /* * For backwards compatiblity with 9load - should go away when 9load is changed * 9load currently sets up the mmu, however the first 16MB of memory is identity * mapped, so behave as if the mmu was not setup */TEXT _startKADDR(SB), $0	MOVL	$_startPADDR(SB), AX	ANDL	$~KZERO, AX	JMP*	AX /* * Must be 4-byte aligned. */TEXT _multibootheader(SB), $0	LONG	$0x1BADB002			/* magic */	LONG	$0x00010003			/* flags */	LONG	$-(0x1BADB002 + 0x00010003)	/* checksum */	LONG	$_multibootheader-KZERO(SB)	/* header_addr */	LONG	$_startKADDR-KZERO(SB)		/* load_addr */	LONG	$edata-KZERO(SB)		/* load_end_addr */	LONG	$end-KZERO(SB)			/* bss_end_addr */	LONG	$_startKADDR-KZERO(SB)		/* entry_addr */	LONG	$0				/* mode_type */	LONG	$0				/* width */	LONG	$0				/* height */	LONG	$0				/* depth */ /* * In protected mode with paging turned off and segment registers setup * to linear map all memory. Entered via a jump to PADDR(entry), * the physical address of the virtual kernel entry point of KADDR(entry). * Make the basic page tables for processor 0. Six pages are needed for * the basic set: *	a page directory; *	page tables for mapping the first 8MB of physical memory to KZERO; *	a page for the GDT; *	virtual and physical pages for mapping the Mach structure. * The remaining PTEs will be allocated later when memory is sized. * An identity mmu map is also needed for the switch to virtual mode. * This identity mapping is removed once the MMU is going and the JMP has * been made to virtual memory. */TEXT _startPADDR(SB), $0	CLI					/* make sure interrupts are off */ 	/* set up the gdt so we have sane plan 9 style gdts. */	MOVL	$tgdtptr(SB), AX	ANDL	$~KZERO, AX	MOVL	(AX), GDTR	MOVW	$1, AX	MOVW	AX, MSW 	/* clear prefetch queue (weird code to avoid optimizations) */	DELAY 	/* set segs to something sane (avoid traps later) */	MOVW	$(1<<3), AX	MOVW	AX, DS	MOVW	AX, SS	MOVW	AX, ES	MOVW	AX, FS	MOVW	AX, GS /*	JMP	$(2<<3):$mode32bit(SB) /**/	 BYTE	$0xEA	 LONG	$mode32bit-KZERO(SB)	 WORD	$(2<<3) /* *  gdt to get us to 32-bit/segmented/unpaged mode */TEXT tgdt(SB), $0 	/* null descriptor */	LONG	$0	LONG	$0 	/* data segment descriptor for 4 gigabytes (PL 0) */	LONG	$(0xFFFF)	LONG	$(SEGG|SEGB|(0xF<<16)|SEGP|SEGPL(0)|SEGDATA|SEGW) 	/* exec segment descriptor for 4 gigabytes (PL 0) */	LONG	$(0xFFFF)	LONG	$(SEGG|SEGD|(0xF<<16)|SEGP|SEGPL(0)|SEGEXEC|SEGR) /* *  pointer to initial gdt *  Note the -KZERO which puts the physical address in the gdtptr.  *  that's needed as we start executing in physical addresses.  */TEXT tgdtptr(SB), $0	WORD	$(3*8)	LONG	$tgdt-KZERO(SB) TEXT m0rgdtptr(SB), $0	WORD	$(NGDT*8-1)	LONG	$(CPU0GDT-KZERO) TEXT m0gdtptr(SB), $0	WORD	$(NGDT*8-1)	LONG	$CPU0GDT TEXT m0idtptr(SB), $0	WORD $(256*8-1)	LONG $IDTADDR TEXT mode32bit(SB), $0	/* At this point, the GDT setup is done. */ 	MOVL	$PADDR(CPU0PDB), DI		/* clear 4 pages for the tables etc. */	XORL	AX, AX	MOVL	$(4*BY2PG), CX	SHRL	$2, CX 	CLD	REP;	STOSL 	MOVL	$PADDR(CPU0PDB), AX	ADDL	$PDO(KZERO), AX			/* page directory offset for KZERO */	MOVL	$PADDR(CPU0PTE), (AX)		/* PTE's for KZERO */	MOVL	$(PTEWRITE|PTEVALID), BX	/* page permissions */	ORL	BX, (AX) 	ADDL	$4, AX	MOVL	$PADDR(CPU0PTE1), (AX)		/* PTE's for KZERO+4MB */	MOVL	$(PTEWRITE|PTEVALID), BX	/* page permissions */	ORL	BX, (AX) 	MOVL	$PADDR(CPU0PTE), AX		/* first page of page table */	MOVL	$1024, CX			/* 1024 pages in 4MB */_setpte:	MOVL	BX, (AX)	ADDL	$(1<<PGSHIFT), BX	ADDL	$4, AX	LOOP	_setpte 	MOVL	$PADDR(CPU0PTE1), AX		/* second page of page table */	MOVL	$1024, CX			/* 1024 pages in 4MB */_setpte1:	MOVL	BX, (AX)	ADDL	$(1<<PGSHIFT), BX	ADDL	$4, AX	LOOP	_setpte1 	MOVL	$PADDR(CPU0PTE), AX	ADDL	$PTO(MACHADDR), AX		/* page table entry offset for MACHADDR */	MOVL	$PADDR(CPU0MACH), (AX)		/* PTE for Mach */	MOVL	$(PTEWRITE|PTEVALID), BX	/* page permissions */	ORL	BX, (AX) /* * Now ready to use the new map. Make sure the processor options are what is wanted. * It is necessary on some processors to immediately follow mode switching with a JMP instruction * to clear the prefetch queues. */	MOVL	$PADDR(CPU0PDB), CX		/* load address of page directory */	MOVL	(PDO(KZERO))(CX), DX		/* double-map KZERO at 0 */	MOVL	DX, (PDO(0))(CX)	MOVL	CX, CR3	DELAY					/* JMP .+2 */ 	MOVL	CR0, DX	ORL	$0x80010000, DX			/* PG|WP */	ANDL	$~0x6000000A, DX		/* ~(CD|NW|TS|MP) */ 	MOVL	$_startpg(SB), AX		/* this is a virtual address */	MOVL	DX, CR0				/* turn on paging */	JMP*	AX				/* jump to the virtual nirvana */ /* * Basic machine environment set, can clear BSS and create a stack. * The stack starts at the top of the page containing the Mach structure. * The x86 architecture forces the use of the same virtual address for * each processor's Mach structure, so the global Mach pointer 'm' can * be initialised here. */TEXT _startpg(SB), $0	MOVL	$0, (PDO(0))(CX)		/* undo double-map of KZERO at 0 */	MOVL	CX, CR3				/* load and flush the mmu */ _clearbss:	MOVL	$edata(SB), DI	XORL	AX, AX	MOVL	$end(SB), CX	SUBL	DI, CX				/* end-edata bytes */	SHRL	$2, CX				/* end-edata doublewords */ 	CLD	REP;	STOSL				/* clear BSS */ 	MOVL	$MACHADDR, SP	MOVL	SP, m(SB)			/* initialise global Mach pointer */	MOVL	$0, 0(SP)			/* initialise m->machno */  	ADDL	$(MACHSIZE-4), SP		/* initialise stack */ /* * Need to do one final thing to ensure a clean machine environment, * clear the EFLAGS register, which can only be done once there is a stack. */	MOVL	$0, AX	PUSHL	AX	POPFL 	CALL	main(SB) /* * Park a processor. Should never fall through a return from main to here, * should only be called by application processors when shutting down. */TEXT idle(SB), $0_idle:	STI	HLT	JMP	_idle /* * Save registers. */TEXT saveregs(SB), $0	/* appease 8l */	SUBL $32, SP	POPL AX	POPL AX	POPL AX	POPL AX	POPL AX	POPL AX	POPL AX	POPL AX		PUSHL	AX	PUSHL	BX	PUSHL	CX	PUSHL	DX	PUSHL	BP	PUSHL	DI	PUSHL	SI	PUSHFL 	XCHGL	32(SP), AX	/* swap return PC and saved flags */	XCHGL	0(SP), AX	XCHGL	32(SP), AX	RET TEXT restoreregs(SB), $0	/* appease 8l */	PUSHL	AX	PUSHL	AX	PUSHL	AX	PUSHL	AX	PUSHL	AX	PUSHL	AX	PUSHL	AX	PUSHL	AX	ADDL	$32, SP		XCHGL	32(SP), AX	/* swap return PC and saved flags */	XCHGL	0(SP), AX	XCHGL	32(SP), AX 	POPFL	POPL	SI	POPL	DI	POPL	BP	POPL	DX	POPL	CX	POPL	BX	POPL	AX	RET /* * Assumed to be in protected mode at time of call. * Switch to real mode, execute an interrupt, and * then switch back to protected mode.   * * Assumes: * *	- no device interrupts are going to come in *	- 0-16MB is identity mapped in page tables *	- realmode() has copied us down from 0x100000 to 0x8000 *	- can use code segment 0x0800 in real mode *		to get at l.s code *	- l.s code is less than 1 page */#define RELOC	(RMCODE-KTZERO) TEXT realmodeidtptr(SB), $0	WORD	$(4*256-1)	LONG	$0 TEXT realmode0(SB), $0	CALL	saveregs(SB) 	/* switch to low code address */	LEAL	physcode-KZERO(SB), AX	JMP *AX TEXT physcode(SB), $0 	/* switch to low stack */	MOVL	SP, AX	MOVL	$0x7C00, SP	PUSHL	AX 	/* change gdt to physical pointer */	MOVL	m0rgdtptr-KZERO(SB), GDTR 	/* load IDT with real-mode version*/	MOVL	realmodeidtptr-KZERO(SB), IDTR 	/* edit INT $0x00 instruction below */	MOVL	$(RMUADDR-KZERO+48), AX	/* &rmu.trap */	MOVL	(AX), AX	MOVB	AX, realmodeintrinst+(-KZERO+1+RELOC)(SB) 	/* disable paging */	MOVL	CR0, AX	ANDL	$0x7FFFFFFF, AX	MOVL	AX, CR0	/* JMP .+2 to clear prefetch queue*/	BYTE $0xEB; BYTE $0x00 	/* jump to 16-bit code segment *//*	JMPFAR	SELECTOR(KESEG16, SELGDT, 0):$again16bit(SB) /**/	 BYTE	$0xEA	 LONG	$again16bit-KZERO(SB)	 WORD	$SELECTOR(KESEG16, SELGDT, 0) TEXT again16bit(SB), $0	/*	 * Now in 16-bit compatibility mode.	 * These are 32-bit instructions being interpreted	 * as 16-bit instructions.  I'm being lazy and	 * not using the macros because I know when	 * the 16- and 32-bit instructions look the same	 * or close enough.	 */ 	/* disable protected mode and jump to real mode cs */	OPSIZE; MOVL CR0, AX	OPSIZE; XORL BX, BX	OPSIZE; INCL BX	OPSIZE; XORL BX, AX	OPSIZE; MOVL AX, CR0 	/* JMPFAR 0x0800:now16real */	 BYTE $0xEA	 WORD	$now16real-KZERO(SB)	 WORD	$0x0800 TEXT now16real(SB), $0	/* copy the registers for the bios call */	LWI(0x0000, rAX)	MOVW	AX,SS	LWI(RMUADDR, rBP)		/* offsets are in Ureg */	LXW(44, xBP, rAX)	MOVW	AX, DS	LXW(40, xBP, rAX)	MOVW	AX, ES 	OPSIZE; LXW(0, xBP, rDI)	OPSIZE; LXW(4, xBP, rSI)	OPSIZE; LXW(16, xBP, rBX)	OPSIZE; LXW(20, xBP, rDX)	OPSIZE; LXW(24, xBP, rCX)	OPSIZE; LXW(28, xBP, rAX) 	CLC TEXT realmodeintrinst(SB), $0	INT $0x00	CLI			/* who knows what evil the bios got up to */ 	/* save the registers after the call */ 	LWI(0x7bfc, rSP)	OPSIZE; PUSHFL	OPSIZE; PUSHL AX 	LWI(0, rAX)	MOVW	AX,SS	LWI(RMUADDR, rBP)		OPSIZE; SXW(rDI, 0, xBP)	OPSIZE; SXW(rSI, 4, xBP)	OPSIZE; SXW(rBX, 16, xBP)	OPSIZE; SXW(rDX, 20, xBP)	OPSIZE; SXW(rCX, 24, xBP)	OPSIZE; POPL AX	OPSIZE; SXW(rAX, 28, xBP) 	MOVW	DS, AX	OPSIZE; SXW(rAX, 44, xBP)	MOVW	ES, AX	OPSIZE; SXW(rAX, 40, xBP) 	OPSIZE; POPL AX	OPSIZE; SXW(rAX, 64, xBP)	/* flags */ 	/* re-enter protected mode and jump to 32-bit code */	OPSIZE; MOVL $1, AX	OPSIZE; MOVL AX, CR0	/*	JMPFAR	SELECTOR(KESEG, SELGDT, 0):$again32bit(SB) /**/	 OPSIZE	 BYTE $0xEA	 LONG	$again32bit-KZERO(SB)	 WORD	$SELECTOR(KESEG, SELGDT, 0) TEXT again32bit(SB), $0	MOVW	$SELECTOR(KDSEG, SELGDT, 0),AX	MOVW	AX,DS	MOVW	AX,SS	MOVW	AX,ES	MOVW	AX,FS	MOVW	AX,GS 	/* enable paging and jump to kzero-address code */	MOVL	CR0, AX	ORL	$0x80010000, AX	/* PG|WP */	MOVL	AX, CR0	LEAL	again32kzero(SB), AX	JMP*	AX TEXT again32kzero(SB), $0	/* breathe a sigh of relief - back in 32-bit protected mode */ 	/* switch to old stack */		PUSHL	AX	/* match popl below for 8l */	MOVL	$0x7BFC, SP	POPL	SP 	/* restore idt */	MOVL	m0idtptr(SB),IDTR 	/* restore gdt */	MOVL	m0gdtptr(SB), GDTR 	CALL	restoreregs(SB)	RET /* * BIOS32. */TEXT bios32call(SB), $0	MOVL	ci+0(FP), BP	MOVL	0(BP), AX	MOVL	4(BP), BX	MOVL	8(BP), CX	MOVL	12(BP), DX	MOVL	16(BP), SI	MOVL	20(BP), DI	PUSHL	BP 	MOVL	12(SP), BP			/* ptr */	BYTE $0xFF; BYTE $0x5D; BYTE $0x00	/* CALL FAR 0(BP) */ 	POPL	BP	MOVL	DI, 20(BP)	MOVL	SI, 16(BP)	MOVL	DX, 12(BP)	MOVL	CX, 8(BP)	MOVL	BX, 4(BP)	MOVL	AX, 0(BP) 	XORL	AX, AX

Lines 1–500 of 1319.