Charles.Forsyth20060303644188019 years agoHistory
953 lines · 23.3 KB · Assembly
RawDownload
#include "mem.h" #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 WBINVD		BYTE $0x0F; BYTE $0x09#define HLT		BYTE $0xF4 /* * 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 _start0x80100020(SB), $0	MOVL	$_start0x00100020(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	$_start0x80100020-KZERO(SB)	/* load_addr */	LONG	$edata-KZERO(SB)		/* load_end_addr */	LONG	$end-KZERO(SB)			/* bss_end_addr */	LONG	$_start0x80100020-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 0x00100020, the physical address of the virtual kernel entry point of 0x80100020 * Make the basic page tables for processor 0. Four pages are needed for the basic set: * a page directory, a page table for mapping the first 4MB of physical memory to KZERO, * and 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 _start0x00100020(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 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 0x80000000 */	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(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 /* * Port I/O. *	in[bsl]		input a byte|short|long *	ins[bsl]	input a string of bytes|shorts|longs *	out[bsl]	output a byte|short|long *	outs[bsl]	output a string of bytes|shorts|longs */TEXT inb(SB), $0	MOVL	port+0(FP), DX	XORL	AX, AX	INB	RET TEXT insb(SB), $0	MOVL	port+0(FP), DX	MOVL	address+4(FP), DI	MOVL	count+8(FP), CX	CLD	REP;	INSB	RET TEXT ins(SB), $0	MOVL	port+0(FP), DX	XORL	AX, AX	OP16;	INL	RET TEXT inss(SB), $0	MOVL	port+0(FP), DX	MOVL	address+4(FP), DI	MOVL	count+8(FP), CX	CLD	REP;	OP16; INSL	RET TEXT inl(SB), $0	MOVL	port+0(FP), DX	INL	RET TEXT insl(SB), $0	MOVL	port+0(FP), DX	MOVL	address+4(FP), DI	MOVL	count+8(FP), CX	CLD	REP;	INSL	RET TEXT outb(SB), $0	MOVL	port+0(FP), DX	MOVL	byte+4(FP), AX	OUTB	RET TEXT outsb(SB), $0	MOVL	port+0(FP), DX	MOVL	address+4(FP), SI	MOVL	count+8(FP), CX	CLD	REP;	OUTSB	RET TEXT outs(SB), $0	MOVL	port+0(FP), DX	MOVL	short+4(FP), AX	OP16;	OUTL	RET TEXT outss(SB), $0	MOVL	port+0(FP), DX	MOVL	address+4(FP), SI	MOVL	count+8(FP), CX	CLD	REP;	OP16; OUTSL	RET TEXT outl(SB), $0	MOVL	port+0(FP), DX	MOVL	long+4(FP), AX	OUTL	RET TEXT outsl(SB), $0	MOVL	port+0(FP), DX	MOVL	address+4(FP), SI	MOVL	count+8(FP), CX	CLD	REP;	OUTSL	RET /* there's a macro in fns.h but libinterp can't see it */TEXT getcallerpc(SB), $0	MOVL	a+0(FP), AX	RET /* * Read/write various system registers. * CR4 and the 'model specific registers' should only be read/written * after it has been determined the processor supports them */TEXT lgdt(SB), $0				/* GDTR - global descriptor table */	MOVL	gdtptr+0(FP), AX	MOVL	(AX), GDTR	RET TEXT lidt(SB), $0				/* IDTR - interrupt descriptor table */	MOVL	idtptr+0(FP), AX	MOVL	(AX), IDTR	RET TEXT ltr(SB), $0				/* TR - task register */	MOVL	tptr+0(FP), AX	MOVW	AX, TASK	RET TEXT getcr0(SB), $0				/* CR0 - processor control */	MOVL	CR0, AX	RET TEXT getcr2(SB), $0				/* CR2 - page fault linear address */	MOVL	CR2, AX	RET TEXT getcr3(SB), $0				/* CR3 - page directory base */	MOVL	CR3, AX	RET TEXT putcr3(SB), $0	MOVL	cr3+0(FP), AX	MOVL	AX, CR3	RET TEXT getcr4(SB), $0				/* CR4 - extensions */	MOVL	CR4, AX	RET TEXT putcr4(SB), $0	MOVL	cr4+0(FP), AX	MOVL	AX, CR4	RET TEXT _cycles(SB), $0				/* time stamp counter; cycles since power up */	RDTSC	MOVL	vlong+0(FP), CX			/* &vlong */	MOVL	AX, 0(CX)			/* lo */	MOVL	DX, 4(CX)			/* hi */	RET TEXT rdmsr(SB), $0				/* model-specific register */	MOVL	index+0(FP), CX	RDMSR	MOVL	vlong+4(FP), CX			/* &vlong */	MOVL	AX, 0(CX)			/* lo */	MOVL	DX, 4(CX)			/* hi */	RET	TEXT wrmsr(SB), $0	MOVL	index+0(FP), CX	MOVL	lo+4(FP), AX	MOVL	hi+8(FP), DX	WRMSR	RET TEXT wbinvd(SB), $0	WBINVD	RET TEXT	rdtsc32(SB), $0	CPUID	RDTSC	RET /* * Try to determine the CPU type which requires fiddling with EFLAGS. * If the Id bit can be toggled then the CPUID instruction can be used * to determine CPU identity and features. First have to check if it's * a 386 (Ac bit can't be set). If it's not a 386 and the Id bit can't be * toggled then it's an older 486 of some kind. * *	cpuid(id[], &ax, &dx); */TEXT cpuid(SB), $0	MOVL	$0x240000, AX	PUSHL	AX	POPFL					/* set Id|Ac */ 	PUSHFL	POPL	BX				/* retrieve value */ 	MOVL	$0, AX	PUSHL	AX	POPFL					/* clear Id|Ac, EFLAGS initialised */ 	PUSHFL	POPL	AX				/* retrieve value */	XORL	BX, AX	TESTL	$0x040000, AX			/* Ac */	JZ	_cpu386				/* can't set this bit on 386 */	TESTL	$0x200000, AX			/* Id */	JZ	_cpu486				/* can't toggle this bit on some 486 */ 	MOVL	$0, AX	CPUID	MOVL	id+0(FP), BP	MOVL	BX, 0(BP)			/* "Genu" "Auth" "Cyri" */	MOVL	DX, 4(BP)			/* "ineI" "enti" "xIns" */	MOVL	CX, 8(BP)			/* "ntel" "cAMD" "tead" */ 	MOVL	$1, AX	CPUID	JMP	_cpuid _cpu486:	MOVL	$0x400, AX	MOVL	$0, DX	JMP	_cpuid _cpu386:	MOVL	$0x300, AX	MOVL	$0, DX _cpuid:	MOVL	ax+4(FP), BP	MOVL	AX, 0(BP)	MOVL	dx+8(FP), BP	MOVL	DX, 0(BP)	RET /* * Basic timing loop to determine CPU frequency. */TEXT aamloop(SB), $0	MOVL	count+0(FP), CX_aamloop:	AAM	LOOP	_aamloop	RET /* * Floating point. * Note: the encodings for the FCLEX, FINIT, FSAVE, FSTCW, FSENV and FSTSW * instructions do NOT have the WAIT prefix byte (i.e. they act like their * FNxxx variations) so WAIT instructions must be explicitly placed in the * code as necessary. */#define	FPOFF(l)							;\	MOVL	CR0, AX 					 	;\	ANDL	$0xC, AX			/* EM, TS */	 	;\	CMPL	AX, $0x8					 	;\	JEQ 	l						 	;\	WAIT							 	;\l:								 	;\	MOVL	CR0, AX							;\	ANDL	$~0x4, AX			/* EM=0 */		;\	ORL	$0x28, AX			/* NE=1, TS=1 */	;\	MOVL	AX, CR0 #define	FPON								;\	MOVL	CR0, AX							;\	ANDL	$~0xC, AX			/* EM=0, TS=0 */	;\	MOVL	AX, CR0	TEXT fpoff(SB), $0				/* disable */	FPOFF(l1)	RET TEXT fpinit(SB), $0				/* enable and init */	FPON	FINIT	WAIT	/* setfcr(FPPDBL|FPRNR|FPINVAL|FPZDIV|FPOVFL) */	/* note that low 6 bits are masks, not enables, on this chip */	PUSHW	$0x0232	FLDCW	0(SP)	POPW	AX	WAIT	RET TEXT fpsave(SB), $0				/* save state and disable */	MOVL	p+0(FP), AX	FSAVE	0(AX)	/* no WAIT */	FPOFF(l2)	RET TEXT fprestore(SB), $0				/* enable and restore state */	FPON	MOVL	p+0(FP), AX

Lines 1–500 of 953.