123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299 |
- #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
- /*
- * 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
- /* 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
- JCC _bios32xxret
- INCL AX
- _bios32xxret:
- 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
- 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
- /*
- * 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 putcr0(SB), $0
- MOVL cr0+0(FP), AX
- MOVL AX, CR0
- 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 invlpg(SB), $0
- /* 486+ only */
- MOVL va+0(FP), CX
- INVLPG
- RET
- TEXT wbinvd(SB), $0
- WBINVD
- RET
- TEXT _cycles(SB), $0 /* time stamp counter */
- RDTSC
- MOVL vlong+0(FP), CX /* &vlong */
- MOVL AX, 0(CX) /* lo */
- MOVL DX, 4(CX) /* hi */
- RET
- /*
- * stub for:
- * time stamp counter; low-order 32 bits of 64-bit cycle counter
- * Runs at fasthz/4 cycles per second (m->clkin>>3)
- */
- TEXT lcycles(SB),1,$0
- RDTSC
- 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
- /*
- * 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(fun, regs[4]);
- */
- 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 */
- /* load registers */
- MOVL regs+4(FP), BP
- MOVL fn+0(FP), AX /* cpuid function */
- MOVL 4(BP), BX
- MOVL 8(BP), CX /* typically an index */
- MOVL 12(BP), DX
- CPUID
- JMP _cpuid
- _cpu486:
- MOVL $0x400, AX
- JMP _maybezapax
- _cpu386:
- MOVL $0x300, AX
- _maybezapax:
- CMPL fn+0(FP), $1
- JE _zaprest
- XORL AX, AX
- _zaprest:
- XORL BX, BX
- XORL CX, CX
- XORL DX, DX
- _cpuid:
- MOVL regs+4(FP), BP
- MOVL AX, 0(BP)
- MOVL BX, 4(BP)
- MOVL CX, 8(BP)
- MOVL DX, 12(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
- FRSTOR 0(AX)
- WAIT
- RET
- TEXT fpstatus(SB), $0 /* get floating point status */
- FSTSW AX
- RET
- TEXT fpenv(SB), $0 /* save state without waiting */
- MOVL p+0(FP), AX
- FSTENV 0(AX)
- RET
- TEXT fpclear(SB), $0 /* clear pending exceptions */
- FPON
- FCLEX /* no WAIT */
- FPOFF(l3)
- RET
- /*
- */
- TEXT splhi(SB), $0
- shi:
- PUSHFL
- POPL AX
- TESTL $0x200, AX
- JZ alreadyhi
- MOVL $(MACHADDR+0x04), CX /* save PC in m->splpc */
- MOVL (SP), BX
- MOVL BX, (CX)
- alreadyhi:
- CLI
- RET
- TEXT spllo(SB), $0
- slo:
- PUSHFL
- POPL AX
- TESTL $0x200, AX
- JNZ alreadylo
- MOVL $(MACHADDR+0x04), CX /* clear m->splpc */
- MOVL $0, (CX)
- alreadylo:
- STI
- RET
- TEXT splx(SB), $0
- MOVL s+0(FP), AX
- TESTL $0x200, AX
- JNZ slo
- JMP shi
- TEXT spldone(SB), $0
- RET
- TEXT islo(SB), $0
- PUSHFL
- POPL AX
- ANDL $0x200, AX /* interrupt enable flag */
- RET
- /*
- * Test-And-Set
- */
- TEXT tas(SB), $0
- MOVL $0xDEADDEAD, AX
- MOVL lock+0(FP), BX
- XCHGL AX, (BX) /* lock->key */
- RET
- TEXT _xinc(SB), $0 /* void _xinc(long*); */
- MOVL l+0(FP), AX
- LOCK; INCL 0(AX)
- RET
- TEXT _xdec(SB), $0 /* long _xdec(long*); */
- MOVL l+0(FP), BX
- XORL AX, AX
- LOCK; DECL 0(BX)
- JLT _xdeclt
- JGT _xdecgt
- RET
- _xdecgt:
- INCL AX
- RET
- _xdeclt:
- DECL AX
- RET
- TEXT mb386(SB), $0
- POPL AX /* return PC */
- PUSHFL
- PUSHL CS
- PUSHL AX
- IRETL
- TEXT mb586(SB), $0
- XORL AX, AX
- CPUID
- RET
- TEXT sfence(SB), $0
- BYTE $0x0f
- BYTE $0xae
- BYTE $0xf8
- RET
- TEXT lfence(SB), $0
- BYTE $0x0f
- BYTE $0xae
- BYTE $0xe8
- RET
- TEXT mfence(SB), $0
- BYTE $0x0f
- BYTE $0xae
- BYTE $0xf0
- RET
- TEXT xchgw(SB), $0
- MOVL v+4(FP), AX
- MOVL p+0(FP), BX
- XCHGW AX, (BX)
- RET
- TEXT cmpswap486(SB), $0
- MOVL addr+0(FP), BX
- MOVL old+4(FP), AX
- MOVL new+8(FP), CX
- LOCK
- BYTE $0x0F; BYTE $0xB1; BYTE $0x0B /* CMPXCHGL CX, (BX) */
- JNZ didnt
- MOVL $1, AX
- RET
- didnt:
- XORL AX,AX
- RET
- TEXT mul64fract(SB), $0
- /*
- * Multiply two 64-bit number s and keep the middle 64 bits from the 128-bit result
- * See ../port/tod.c for motivation.
- */
- MOVL r+0(FP), CX
- XORL BX, BX /* BX = 0 */
- MOVL a+8(FP), AX
- MULL b+16(FP) /* a1*b1 */
- MOVL AX, 4(CX) /* r2 = lo(a1*b1) */
- MOVL a+8(FP), AX
- MULL b+12(FP) /* a1*b0 */
- MOVL AX, 0(CX) /* r1 = lo(a1*b0) */
- ADDL DX, 4(CX) /* r2 += hi(a1*b0) */
- MOVL a+4(FP), AX
- MULL b+16(FP) /* a0*b1 */
- ADDL AX, 0(CX) /* r1 += lo(a0*b1) */
- ADCL DX, 4(CX) /* r2 += hi(a0*b1) + carry */
- MOVL a+4(FP), AX
- MULL b+12(FP) /* a0*b0 */
- ADDL DX, 0(CX) /* r1 += hi(a0*b0) */
- ADCL BX, 4(CX) /* r2 += carry */
- RET
- /*
- * label consists of a stack pointer and a PC
- */
- TEXT gotolabel(SB), $0
- MOVL label+0(FP), AX
- MOVL 0(AX), SP /* restore sp */
- MOVL 4(AX), AX /* put return pc on the stack */
- MOVL AX, 0(SP)
- MOVL $1, AX /* return 1 */
- RET
- TEXT setlabel(SB), $0
- MOVL label+0(FP), AX
- MOVL SP, 0(AX) /* store sp */
- MOVL 0(SP), BX /* store return pc */
- MOVL BX, 4(AX)
- MOVL $0, AX /* return 0 */
- RET
- /*
- * Attempt at power saving. -rsc
- */
- TEXT halt(SB), $0
- CLI
- CMPL nrdy(SB), $0
- JEQ _nothingready
- STI
- RET
- _nothingready:
- STI
- HLT
- RET
- /*
- * Interrupt/exception handling.
- * Each entry in the vector table calls either _strayintr or _strayintrx depending
- * on whether an error code has been automatically pushed onto the stack
- * (_strayintrx) or not, in which case a dummy entry must be pushed before retrieving
- * the trap type from the vector table entry and placing it on the stack as part
- * of the Ureg structure.
- * The size of each entry in the vector table (6 bytes) is known in trapinit().
- */
- TEXT _strayintr(SB), $0
- PUSHL AX /* save AX */
- MOVL 4(SP), AX /* return PC from vectortable(SB) */
- JMP intrcommon
- TEXT _strayintrx(SB), $0
- XCHGL AX, (SP) /* swap AX with vectortable CALL PC */
- intrcommon:
- PUSHL DS /* save DS */
- PUSHL $(KDSEL)
- POPL DS /* fix up DS */
- MOVBLZX (AX), AX /* trap type -> AX */
- XCHGL AX, 4(SP) /* exchange trap type with saved AX */
- PUSHL ES /* save ES */
- PUSHL $(KDSEL)
- POPL ES /* fix up ES */
- PUSHL FS /* save the rest of the Ureg struct */
- PUSHL GS
- PUSHAL
- PUSHL SP /* Ureg* argument to trap */
- CALL trap(SB)
- TEXT forkret(SB), $0
- POPL AX
- POPAL
- POPL GS
- POPL FS
- POPL ES
- POPL DS
- ADDL $8, SP /* pop error code and trap type */
- IRETL
- TEXT vectortable(SB), $0
- CALL _strayintr(SB); BYTE $0x00 /* divide error */
- CALL _strayintr(SB); BYTE $0x01 /* debug exception */
- CALL _strayintr(SB); BYTE $0x02 /* NMI interrupt */
- CALL _strayintr(SB); BYTE $0x03 /* breakpoint */
- CALL _strayintr(SB); BYTE $0x04 /* overflow */
- CALL _strayintr(SB); BYTE $0x05 /* bound */
- CALL _strayintr(SB); BYTE $0x06 /* invalid opcode */
- CALL _strayintr(SB); BYTE $0x07 /* no coprocessor available */
- CALL _strayintrx(SB); BYTE $0x08 /* double fault */
- CALL _strayintr(SB); BYTE $0x09 /* coprocessor segment overflow */
- CALL _strayintrx(SB); BYTE $0x0A /* invalid TSS */
- CALL _strayintrx(SB); BYTE $0x0B /* segment not available */
- CALL _strayintrx(SB); BYTE $0x0C /* stack exception */
- CALL _strayintrx(SB); BYTE $0x0D /* general protection error */
- CALL _strayintrx(SB); BYTE $0x0E /* page fault */
- CALL _strayintr(SB); BYTE $0x0F /* */
- CALL _strayintr(SB); BYTE $0x10 /* coprocessor error */
- CALL _strayintrx(SB); BYTE $0x11 /* alignment check */
- CALL _strayintr(SB); BYTE $0x12 /* machine check */
- CALL _strayintr(SB); BYTE $0x13
- CALL _strayintr(SB); BYTE $0x14
- CALL _strayintr(SB); BYTE $0x15
- CALL _strayintr(SB); BYTE $0x16
- CALL _strayintr(SB); BYTE $0x17
- CALL _strayintr(SB); BYTE $0x18
- CALL _strayintr(SB); BYTE $0x19
- CALL _strayintr(SB); BYTE $0x1A
- CALL _strayintr(SB); BYTE $0x1B
- CALL _strayintr(SB); BYTE $0x1C
- CALL _strayintr(SB); BYTE $0x1D
- CALL _strayintr(SB); BYTE $0x1E
- CALL _strayintr(SB); BYTE $0x1F
- CALL _strayintr(SB); BYTE $0x20 /* VectorLAPIC */
- CALL _strayintr(SB); BYTE $0x21
- CALL _strayintr(SB); BYTE $0x22
- CALL _strayintr(SB); BYTE $0x23
- CALL _strayintr(SB); BYTE $0x24
- CALL _strayintr(SB); BYTE $0x25
- CALL _strayintr(SB); BYTE $0x26
- CALL _strayintr(SB); BYTE $0x27
- CALL _strayintr(SB); BYTE $0x28
- CALL _strayintr(SB); BYTE $0x29
- CALL _strayintr(SB); BYTE $0x2A
- CALL _strayintr(SB); BYTE $0x2B
- CALL _strayintr(SB); BYTE $0x2C
- CALL _strayintr(SB); BYTE $0x2D
- CALL _strayintr(SB); BYTE $0x2E
- CALL _strayintr(SB); BYTE $0x2F
- CALL _strayintr(SB); BYTE $0x30
- CALL _strayintr(SB); BYTE $0x31
- CALL _strayintr(SB); BYTE $0x32
- CALL _strayintr(SB); BYTE $0x33
- CALL _strayintr(SB); BYTE $0x34
- CALL _strayintr(SB); BYTE $0x35
- CALL _strayintr(SB); BYTE $0x36
- CALL _strayintr(SB); BYTE $0x37
- CALL _strayintr(SB); BYTE $0x38
- CALL _strayintr(SB); BYTE $0x39
- CALL _strayintr(SB); BYTE $0x3A
- CALL _strayintr(SB); BYTE $0x3B
- CALL _strayintr(SB); BYTE $0x3C
- CALL _strayintr(SB); BYTE $0x3D
- CALL _strayintr(SB); BYTE $0x3E
- CALL _strayintr(SB); BYTE $0x3F
- CALL _syscallintr(SB); BYTE $0x40 /* VectorSYSCALL */
- CALL _strayintr(SB); BYTE $0x41
- CALL _strayintr(SB); BYTE $0x42
- CALL _strayintr(SB); BYTE $0x43
- CALL _strayintr(SB); BYTE $0x44
- CALL _strayintr(SB); BYTE $0x45
- CALL _strayintr(SB); BYTE $0x46
- CALL _strayintr(SB); BYTE $0x47
- CALL _strayintr(SB); BYTE $0x48
- CALL _strayintr(SB); BYTE $0x49
- CALL _strayintr(SB); BYTE $0x4A
- CALL _strayintr(SB); BYTE $0x4B
- CALL _strayintr(SB); BYTE $0x4C
- CALL _strayintr(SB); BYTE $0x4D
- CALL _strayintr(SB); BYTE $0x4E
- CALL _strayintr(SB); BYTE $0x4F
- CALL _strayintr(SB); BYTE $0x50
- CALL _strayintr(SB); BYTE $0x51
- CALL _strayintr(SB); BYTE $0x52
- CALL _strayintr(SB); BYTE $0x53
- CALL _strayintr(SB); BYTE $0x54
- CALL _strayintr(SB); BYTE $0x55
- CALL _strayintr(SB); BYTE $0x56
- CALL _strayintr(SB); BYTE $0x57
- CALL _strayintr(SB); BYTE $0x58
- CALL _strayintr(SB); BYTE $0x59
- CALL _strayintr(SB); BYTE $0x5A
- CALL _strayintr(SB); BYTE $0x5B
- CALL _strayintr(SB); BYTE $0x5C
- CALL _strayintr(SB); BYTE $0x5D
- CALL _strayintr(SB); BYTE $0x5E
- CALL _strayintr(SB); BYTE $0x5F
- CALL _strayintr(SB); BYTE $0x60
- CALL _strayintr(SB); BYTE $0x61
- CALL _strayintr(SB); BYTE $0x62
- CALL _strayintr(SB); BYTE $0x63
- CALL _strayintr(SB); BYTE $0x64
- CALL _strayintr(SB); BYTE $0x65
- CALL _strayintr(SB); BYTE $0x66
- CALL _strayintr(SB); BYTE $0x67
- CALL _strayintr(SB); BYTE $0x68
- CALL _strayintr(SB); BYTE $0x69
- CALL _strayintr(SB); BYTE $0x6A
- CALL _strayintr(SB); BYTE $0x6B
- CALL _strayintr(SB); BYTE $0x6C
- CALL _strayintr(SB); BYTE $0x6D
- CALL _strayintr(SB); BYTE $0x6E
- CALL _strayintr(SB); BYTE $0x6F
- CALL _strayintr(SB); BYTE $0x70
- CALL _strayintr(SB); BYTE $0x71
- CALL _strayintr(SB); BYTE $0x72
- CALL _strayintr(SB); BYTE $0x73
- CALL _strayintr(SB); BYTE $0x74
- CALL _strayintr(SB); BYTE $0x75
- CALL _strayintr(SB); BYTE $0x76
- CALL _strayintr(SB); BYTE $0x77
- CALL _strayintr(SB); BYTE $0x78
- CALL _strayintr(SB); BYTE $0x79
- CALL _strayintr(SB); BYTE $0x7A
- CALL _strayintr(SB); BYTE $0x7B
- CALL _strayintr(SB); BYTE $0x7C
- CALL _strayintr(SB); BYTE $0x7D
- CALL _strayintr(SB); BYTE $0x7E
- CALL _strayintr(SB); BYTE $0x7F
- CALL _strayintr(SB); BYTE $0x80 /* Vector[A]PIC */
- CALL _strayintr(SB); BYTE $0x81
- CALL _strayintr(SB); BYTE $0x82
- CALL _strayintr(SB); BYTE $0x83
- CALL _strayintr(SB); BYTE $0x84
- CALL _strayintr(SB); BYTE $0x85
- CALL _strayintr(SB); BYTE $0x86
- CALL _strayintr(SB); BYTE $0x87
- CALL _strayintr(SB); BYTE $0x88
- CALL _strayintr(SB); BYTE $0x89
- CALL _strayintr(SB); BYTE $0x8A
- CALL _strayintr(SB); BYTE $0x8B
- CALL _strayintr(SB); BYTE $0x8C
- CALL _strayintr(SB); BYTE $0x8D
- CALL _strayintr(SB); BYTE $0x8E
- CALL _strayintr(SB); BYTE $0x8F
- CALL _strayintr(SB); BYTE $0x90
- CALL _strayintr(SB); BYTE $0x91
- CALL _strayintr(SB); BYTE $0x92
- CALL _strayintr(SB); BYTE $0x93
- CALL _strayintr(SB); BYTE $0x94
- CALL _strayintr(SB); BYTE $0x95
- CALL _strayintr(SB); BYTE $0x96
- CALL _strayintr(SB); BYTE $0x97
- CALL _strayintr(SB); BYTE $0x98
- CALL _strayintr(SB); BYTE $0x99
- CALL _strayintr(SB); BYTE $0x9A
- CALL _strayintr(SB); BYTE $0x9B
- CALL _strayintr(SB); BYTE $0x9C
- CALL _strayintr(SB); BYTE $0x9D
- CALL _strayintr(SB); BYTE $0x9E
- CALL _strayintr(SB); BYTE $0x9F
- CALL _strayintr(SB); BYTE $0xA0
- CALL _strayintr(SB); BYTE $0xA1
- CALL _strayintr(SB); BYTE $0xA2
- CALL _strayintr(SB); BYTE $0xA3
- CALL _strayintr(SB); BYTE $0xA4
- CALL _strayintr(SB); BYTE $0xA5
- CALL _strayintr(SB); BYTE $0xA6
- CALL _strayintr(SB); BYTE $0xA7
- CALL _strayintr(SB); BYTE $0xA8
- CALL _strayintr(SB); BYTE $0xA9
- CALL _strayintr(SB); BYTE $0xAA
- CALL _strayintr(SB); BYTE $0xAB
- CALL _strayintr(SB); BYTE $0xAC
- CALL _strayintr(SB); BYTE $0xAD
- CALL _strayintr(SB); BYTE $0xAE
- CALL _strayintr(SB); BYTE $0xAF
- CALL _strayintr(SB); BYTE $0xB0
- CALL _strayintr(SB); BYTE $0xB1
- CALL _strayintr(SB); BYTE $0xB2
- CALL _strayintr(SB); BYTE $0xB3
- CALL _strayintr(SB); BYTE $0xB4
- CALL _strayintr(SB); BYTE $0xB5
- CALL _strayintr(SB); BYTE $0xB6
- CALL _strayintr(SB); BYTE $0xB7
- CALL _strayintr(SB); BYTE $0xB8
- CALL _strayintr(SB); BYTE $0xB9
- CALL _strayintr(SB); BYTE $0xBA
- CALL _strayintr(SB); BYTE $0xBB
- CALL _strayintr(SB); BYTE $0xBC
- CALL _strayintr(SB); BYTE $0xBD
- CALL _strayintr(SB); BYTE $0xBE
- CALL _strayintr(SB); BYTE $0xBF
- CALL _strayintr(SB); BYTE $0xC0
- CALL _strayintr(SB); BYTE $0xC1
- CALL _strayintr(SB); BYTE $0xC2
- CALL _strayintr(SB); BYTE $0xC3
- CALL _strayintr(SB); BYTE $0xC4
- CALL _strayintr(SB); BYTE $0xC5
- CALL _strayintr(SB); BYTE $0xC6
- CALL _strayintr(SB); BYTE $0xC7
- CALL _strayintr(SB); BYTE $0xC8
- CALL _strayintr(SB); BYTE $0xC9
- CALL _strayintr(SB); BYTE $0xCA
- CALL _strayintr(SB); BYTE $0xCB
- CALL _strayintr(SB); BYTE $0xCC
- CALL _strayintr(SB); BYTE $0xCD
- CALL _strayintr(SB); BYTE $0xCE
- CALL _strayintr(SB); BYTE $0xCF
- CALL _strayintr(SB); BYTE $0xD0
- CALL _strayintr(SB); BYTE $0xD1
- CALL _strayintr(SB); BYTE $0xD2
- CALL _strayintr(SB); BYTE $0xD3
- CALL _strayintr(SB); BYTE $0xD4
- CALL _strayintr(SB); BYTE $0xD5
- CALL _strayintr(SB); BYTE $0xD6
- CALL _strayintr(SB); BYTE $0xD7
- CALL _strayintr(SB); BYTE $0xD8
- CALL _strayintr(SB); BYTE $0xD9
- CALL _strayintr(SB); BYTE $0xDA
- CALL _strayintr(SB); BYTE $0xDB
- CALL _strayintr(SB); BYTE $0xDC
- CALL _strayintr(SB); BYTE $0xDD
- CALL _strayintr(SB); BYTE $0xDE
- CALL _strayintr(SB); BYTE $0xDF
- CALL _strayintr(SB); BYTE $0xE0
- CALL _strayintr(SB); BYTE $0xE1
- CALL _strayintr(SB); BYTE $0xE2
- CALL _strayintr(SB); BYTE $0xE3
- CALL _strayintr(SB); BYTE $0xE4
- CALL _strayintr(SB); BYTE $0xE5
- CALL _strayintr(SB); BYTE $0xE6
- CALL _strayintr(SB); BYTE $0xE7
- CALL _strayintr(SB); BYTE $0xE8
- CALL _strayintr(SB); BYTE $0xE9
- CALL _strayintr(SB); BYTE $0xEA
- CALL _strayintr(SB); BYTE $0xEB
- CALL _strayintr(SB); BYTE $0xEC
- CALL _strayintr(SB); BYTE $0xED
- CALL _strayintr(SB); BYTE $0xEE
- CALL _strayintr(SB); BYTE $0xEF
- CALL _strayintr(SB); BYTE $0xF0
- CALL _strayintr(SB); BYTE $0xF1
- CALL _strayintr(SB); BYTE $0xF2
- CALL _strayintr(SB); BYTE $0xF3
- CALL _strayintr(SB); BYTE $0xF4
- CALL _strayintr(SB); BYTE $0xF5
- CALL _strayintr(SB); BYTE $0xF6
- CALL _strayintr(SB); BYTE $0xF7
- CALL _strayintr(SB); BYTE $0xF8
- CALL _strayintr(SB); BYTE $0xF9
- CALL _strayintr(SB); BYTE $0xFA
- CALL _strayintr(SB); BYTE $0xFB
- CALL _strayintr(SB); BYTE $0xFC
- CALL _strayintr(SB); BYTE $0xFD
- CALL _strayintr(SB); BYTE $0xFE
- CALL _strayintr(SB); BYTE $0xFF
|