📄 l.s
字号:
#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 RDMSR BYTE $0x0F; BYTE $0x32 /* RDMSR, result in AX/DX (lo/hi) */#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)/* * Entered here from the bootstrap programme possibly via a jump to 0x00100020, so * need to make another jump to set the correct virtual address. * In protected mode with paging turned on, the first 4MB of physical memory mapped * to KZERO and up. */TEXT _start0x00100020(SB),$0 CLI MOVL $_start0x80100020(SB), AX JMP* AX/* * First check if the bootstrap programme left the first 4MB nicely mapped, otherwise * 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, and * virtual and physical pages for mapping the Mach structure. * The remaining PTEs will be allocated later when memory is sized. */TEXT _start0x80100020(SB), $0 MOVL CR3, AX /* check the page directory base */ CMPL AX, $PADDR(CPU0PDB) JEQ _clearbss MOVL $CPU0PDB, DI /* clear 4 pages for the tables etc. */ XORL AX, AX MOVL $(4*BY2PG), CX SHRL $2, CX CLD REP; STOSL MOVL $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 $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 $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 follow mode switching with a JMP instruction * to clear the prefetch queues. * There's a little mystery here - the Pentium Pro appears to need an identity * mmu map for the switch to virtual mode. The manual doesn't say this is necessary * and it isn't required on the Pentium. * To this end double map KZERO at virtual 0 and undo the mapping once virtual * nirvana has been attained. */ MOVL $PADDR(CPU0PDB), CX /* load address of page directory */ MOVL CX, BX MOVL (PDO(KZERO))(BX), DX /* double-map KZERO at 0 */ MOVL DX, (PDO(0))(BX) 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 MOVL DX, CR0 /* turn on paging */ JMP* AX/* * 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 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 */_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 RETTEXT insb(SB), $0 MOVL port+0(FP), DX MOVL address+4(FP), DI MOVL count+8(FP), CX CLD REP; INSB RETTEXT ins(SB), $0 MOVL port+0(FP), DX XORL AX, AX OP16; INL RETTEXT inss(SB), $0 MOVL port+0(FP), DX MOVL address+4(FP), DI MOVL count+8(FP), CX CLD REP; OP16; INSL RETTEXT inl(SB), $0 MOVL port+0(FP), DX INL RETTEXT insl(SB), $0 MOVL port+0(FP), DX MOVL address+4(FP), DI MOVL count+8(FP), CX CLD REP; INSL RETTEXT outb(SB), $0 MOVL port+0(FP), DX MOVL byte+4(FP), AX OUTB RETTEXT outsb(SB),$0 MOVL port+0(FP), DX MOVL address+4(FP), SI MOVL count+8(FP), CX CLD REP; OUTSB RETTEXT outs(SB), $0 MOVL port+0(FP), DX MOVL short+4(FP), AX OP16; OUTL RETTEXT outss(SB), $0 MOVL port+0(FP), DX MOVL address+4(FP), SI MOVL count+8(FP), CX CLD REP; OP16; OUTSL RETTEXT outl(SB), $0 MOVL port+0(FP), DX MOVL long+4(FP), AX OUTL RETTEXT outsl(SB), $0 MOVL port+0(FP), DX MOVL address+4(FP), SI MOVL count+8(FP), CX CLD REP; OUTSL 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 RETTEXT lidt(SB), $0 /* IDTR - interrupt descriptor table */ MOVL idtptr+0(FP), AX MOVL (AX), IDTR RETTEXT ltr(SB), $0 /* TR - task register */ MOVL tptr+0(FP), AX MOVW AX, TASK RETTEXT getcr0(SB), $0 /* CR0 - processor control */ MOVL CR0, AX RETTEXT getcr2(SB), $0 /* CR2 - page fault linear address */ MOVL CR2, AX RETTEXT getcr3(SB), $0 /* CR3 - page directory base */ MOVL CR3, AX RETTEXT putcr3(SB), $0 MOVL cr3+0(FP), AX MOVL AX, CR3 RETTEXT getcr4(SB), $0 /* CR4 - extensions */ MOVL CR4, AX RETTEXT putcr4(SB), $0 MOVL cr4+0(FP), AX MOVL AX, CR4 RETTEXT rdmsr(SB), $0 /* model-specific register */ MOVL index+0(FP), CX RDMSR MOVL vlong+4(FP), CX /* &vlong */ MOVL AX, (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 RETTEXT wbinvd(SB), $0 WBINVD RET/* * Try to determine the CPU type which requires fiddling with EFLAGS. * If the Id bit can be toggled then the CPUID instruciton 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. */#define FPOFF ;\ WAIT ;\ 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 RETTEXT fpinit(SB), $0 /* enable and init */ FPON FINIT WAIT PUSHW $0x033E FLDCW 0(SP) /* ignore underflow/precision, signal others */ POPW AX WAIT RETTEXT fpsave(SB), $0 /* save state and disable */ MOVL p+0(FP), AX FSAVE 0(AX) /* no WAIT */ FPOFF RET
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -