#include "mem.h" #define KB 1024 #define MB (1024*1024) /* * Some machine instructions not handled by 8[al]. */ #define DELAY BYTE $0xEB; BYTE $0x00 /* JMP .+2 */ #define FARJUMP(s, o) BYTE $0xEA; /* far jump to ptr32:16 */\ LONG $o; WORD $s #define NOP BYTE $0x90 #define HLT BYTE $0xF4 /* * Macro for calculating offset within the page directory base. * Note that this is assembler-specific hence the '<<2'. */ #define PDO(a) (((((a))>>22) & 0x03FF)<<2) /* * May enter here either from the 16-bit real-mode startup or * from other 32-bit protected mode code. For the latter case must * make sure the GDT is set as it would be by the 16-bit code: * disable interrupts; * load the GDT with the table in _gdt32p; * load all the data segments * load the code segment via a far jump. */ TEXT _start32p(SB), $0 /* if distance to _start32p32 changes, update the offset after 0xEB. */ // jmp .+32 (_start32p32). BYTE $0xEB; BYTE $(2+3*2*4+2+4) NOP; NOP TEXT _gdt32p(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 _gdtptr32p(SB), $0 WORD $(3*8) LONG $_gdt32p-KZERO(SB) _start32p32: CLI MOVL AX, _multibootheader+(48-KZERO)(SB) MOVL BX, _multibootheader+(52-KZERO)(SB) MOVL $_gdtptr32p-KZERO(SB), AX MOVL (AX), GDTR MOVL $KDSEL, AX MOVW AX, DS MOVW AX, ES MOVW AX, FS MOVW AX, GS MOVW AX, SS DELAY FARJUMP(KESEL, _start32pg-KZERO(SB)) /* * Make the basic page tables for processor 0. Eight pages are needed for * the basic set: * a page directory, 5 pages pf page tables for mapping the first 20MB of * physical memory, a single physical and virtual page for the Mach structure, * and a page to be used later for the GDT. * * The remaining PTEs will be allocated later when memory is sized. * Could clear BSS here too when clearing the space for the tables, * but that would violate the separation of church and state. * The first aligned page after end[] was used for passing BIOS parameters * by the real-mode startup, now it's BIOSTABLES. */ TEXT _start32pg(SB), $0 /* CHECK alignment (16) */ DELAY MOVL $end-KZERO(SB), DX /* clear pages for the tables etc. */ /* start must be page aligned, skip boot params page */ ADDL $(2*BY2PG-1), DX ANDL $~(BY2PG-1), DX /* * zero mach page & gdt in low memory */ MOVL $(CPU0MACH-KZERO), DI XORL AX, AX MOVL $(2*BY2PG), CX /* mach (phys & virt) & gdt */ SHRL $2, CX CLD REP; STOSL /* zero mach & gdt pages */ /* * zero pdb and pte for low memory */ MOVL DX, DI /* first page after end & boot params */ XORL AX, AX MOVL $((1+LOWPTEPAGES)*BY2PG), CX /* pdb, n pte */ SHRL $2, CX CLD REP; STOSL /* zero pdb & pte pages */ /* * populate pdb for low memory (20MB) */ MOVL DX, AX /* bootstrap processor PDB (page 0) */ MOVL DX, DI /* save it for later */ MOVL $(PTEWRITE|PTEVALID), BX/* page permissions */ ADDL $BY2PG, DX /* -> PA of first page of page table (page 1) */ ADDL $PDO(KZERO), AX /* page directory offset for KZERO */ MOVL DX, (AX) /* PTE's for KZERO */ ORL BX, (AX) /* should be LOWPTEPAGES-1 repetitions of this fragment */ ADDL $BY2PG, DX /* -> PA of second page of page table (page 2) */ ADDL $4, AX /* page dir. offset for KZERO+4MB */ MOVL DX, (AX) /* PTE's for KZERO */ ORL BX, (AX) ADDL $BY2PG, DX /* -> PA of third page of page table (page 3) */ ADDL $4, AX /* page dir. offset for KZERO+8MB */ MOVL DX, (AX) /* PTE's for KZERO */ ORL BX, (AX) ADDL $BY2PG, DX /* -> PA of fourth page of page table (page 4) */ ADDL $4, AX /* page dir. offset for KZERO+12MB */ MOVL DX, (AX) /* PTE's for KZERO */ ORL BX, (AX) ADDL $BY2PG, DX /* -> PA of fifth page of page table (page 5) */ ADDL $4, AX /* page dir. offset for KZERO+16MB */ MOVL DX, (AX) /* PTE's for KZERO */ ORL BX, (AX) /* * populate page tables for low memory */ MOVL DI, AX ADDL $BY2PG, AX /* PA of first page of page table */ MOVL $(MemMin/BY2PG), CX _setpte: MOVL BX, (AX) ADDL $(1< PA of Mach structure */ MOVL $CPU0MACH, BX /* VA of Mach structure */ SHRL $10, BX /* create offset into PTEs */ ANDL $(0x3FF<<2), BX ADDL BX, AX /* PTE offset for Mach structure */ MOVL DX, (AX) /* create PTE for Mach */ MOVL $(PTEWRITE|PTEVALID), BX/* page permissions */ ORL BX, (AX) /* * Now ready to use the new map. Initialise CR0 (assume the BIOS gets * it mostly correct for this processor type w.r.t. caches and FPU). * It is necessary on some processors to follow mode switching * with a JMP instruction to clear the prefetch queues. * The instruction to switch modes and the following jump instruction * should be identity-mapped; to this end double map KZERO at * virtual 0 and undo the mapping once virtual nirvana has been attained. * If paging is already on, don't load CR3 before setting CR0, in which * case most of this is a NOP and the 2nd load of CR3 actually does * the business. */ MOVL DI, CX /* load address of PDB */ /* double-map first 20 MB, since we are running at 7 or 9 MB */ /* should be LOWPTEPAGES repetitions */ MOVL PDO(KZERO)(CX), DX /* double-map KZERO at 0 */ MOVL DX, PDO(0)(CX) MOVL PDO(KZERO+4*MB)(CX), DX MOVL DX, PDO(4*MB)(CX) MOVL PDO(KZERO+8*MB)(CX), DX MOVL DX, PDO(8*MB)(CX) MOVL PDO(KZERO+12*MB)(CX), DX MOVL DX, PDO(12*MB)(CX) MOVL PDO(KZERO+16*MB)(CX), DX MOVL DX, PDO(16*MB)(CX) MOVL CR0, DX MOVL DX, AX ANDL $PG, AX /* check paging not already on */ JNE _nocr3load MOVL CX, CR3 /* paging off, safe to load cr3 */ _nocr3load: ORL $(PG|0x10000), DX /* PG|WP */ ANDL $~0x6000000A, DX /* ~(CD|NW|TS|MP) */ MOVL $_startpg(SB), AX TESTL $KZERO, AX /* want to run protected or virtual? */ JEQ _to32v /* protected */ MOVL DX, CR0 /* turn on paging */ JMP* AX /* headfirst into the new world */ TEXT _startpg(SB), $0 // MOVL $0, PDO(0)(CX) /* undo double-map of KZERO at 0 */ MOVL CX, CR3 /* load and flush the mmu */ _to32v: MOVL $_start32v(SB), AX JMP* AX /* into the dorkness */