📄 l.s
字号:
#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) *//* * 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. 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 _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 $CPU0GDTTEXT m0idtptr(SB), $0 WORD $(256*8-1) LONG $IDTADDRTEXT 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) 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/* * 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 RETTEXT 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 $0TEXT realmode0(SB), $0 CALL saveregs(SB) /* switch to low code address */ LEAL physcode-KZERO(SB), AX JMP *AXTEXT 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 $0x0800TEXT 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) CLCTEXT realmodeintrinst(SB), $0 INT $0x00 /* 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 $0x80000000, AX MOVL AX, CR0 LEAL again32kzero(SB), AX JMP* AXTEXT 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/*/* * 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 invlpg(SB), $0 /* 486+ only */ MOVL va+0(FP), CX INVLPG RETTEXT _cycles(SB), $0 /* time stamp counter */ RDTSC MOVL vlong+0(FP), CX /* &vlong */ MOVL AX, 0(CX) /* lo */ MOVL DX, 4(CX) /* hi */ RETTEXT rdmsr(SB), $0 /* model-specific register */ MOVL index+0(FP), CX RDMSR MOVL vlong+4(FP), CX /* &vlong */ MOVL AX, 0(CX) /* lo */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -