#include "x16.h" #include "mem.h" #ifdef PXE #define PDB 0x90000 /* temporary page tables (24KB) */ #else #define PDB 0x08000 #endif PXE #define NoScreenBlank 1 /*#define ResetDiscs 1*/ TEXT origin(SB), $0 /* * This part of l.s is used only in the boot kernel. * It assumes that we are in real address mode, i.e., * that we look like an 8086. * * Make sure the segments are reasonable. * If we were started directly from the BIOS * (i.e. no MS-DOS) then DS may not be * right. */ MOVW CS, AX MOVW AX, DS #ifdef NoScreenBlank /* * Get the current video mode. If it isn't mode 3, * set text mode 3. * Well, no. Windows95 won't co-operate here so we have * to explicitly set mode 3. */ XORL AX, AX MOVB $0x0F, AH INT $0x10 /* get current video mode in AL */ CMPB AL, $03 JEQ sayhello #endif /* NoScreenBlank */ XORL AX, AX MOVB $0x03, AL INT $0x10 /* set video mode in AL */ sayhello: LWI(hello(SB), rSI) CALL16(biosputs(SB)) #ifdef ResetDiscs XORL AX, AX /* reset disc system */ XORL DX, DX MOVB $0x80, DL INT $0x13 #endif /* ResetDiscs */ #ifdef DOTCOM /* * relocate everything to a half meg and jump there * - looks weird because it is being assembled by a 32 bit * assembler for a 16 bit world * * only b.com does this - not 9load */ MOVL $0,BX INCL BX SHLL $15,BX MOVL BX,CX MOVW BX,ES MOVL $0,SI MOVL SI,DI CLD REP MOVSL /* * Jump to the copied image; * fix up the DS for the new location. */ FARJUMP16(0x8000, _start8000(SB)) TEXT _start8000(SB), $0 MFSR(rCS, rAX) /* fix up DS, ES (0x8000) */ MTSR(rAX, rDS) MTSR(rAX, rES) /* * If we are already in protected mode, have to get back * to real mode before trying any privileged operations * (like going into protected mode...). * Try to reset with a restart vector. */ MFCR(rCR0, rAX) /* are we in protected mode? */ ANDI(0x0001, rAX) JEQ _real CLR(rBX) MTSR(rBX, rES) LWI(0x0467, rBX) /* reset entry point */ LWI(_start8000(SB), rAX) /* offset within segment */ BYTE $0x26 BYTE $0x89 BYTE $0x07 /* MOVW AX, ES:[BX] */ LBI(0x69, rBL) MFSR(rCS, rAX) /* segment */ BYTE $0x26 BYTE $0x89 BYTE $0x07 /* MOVW AX, ES:[BX] */ CLR(rDX) OUTPORTB(0x70, 0x8F) OUTPORTB(0x71, 0x0A) FARJUMP16(0xFFFF, 0x0000) /* reset */ #endif /* DOTCOM */ _real: /* * do things that need to be done in real mode. * the results get written to CONFADDR (0x1200) * in a series of <4-byte-magic-number> * the data length is dependent on the magic number. * * this gets parsed by conf.c:/^readlsconf * * N.B. CALL16 kills rDI, so we can't call anything. */ LWI(0x0000, rAX) MTSR(rAX, rES) LWI(0x1200, rDI) /* * turn off interrupts */ CLI /* * detect APM1.2 bios support */ /* save DI */ SW(rDI, rock(SB)) /* disconnect anyone else */ LWI(0x5304, rAX) LWI(0x0000, rBX) INT $0x15 /* connect */ CLC LWI(0x5303, rAX) LWI(0x0000, rBX) INT $0x15 CLI /* apm put interrupts back? */ JC noapm OPSIZE; PUSHR(rSI) OPSIZE; PUSHR(rBX) PUSHR(rDI) PUSHR(rDX) PUSHR(rCX) PUSHR(rAX) /* put DI, ES back */ LW(rock(SB), rDI) LWI(0x0000, rAX) MTSR(rAX, rES) /* * write APM data. first four bytes are APM\0. */ LWI(0x5041, rAX) STOSW LWI(0x004d, rAX) STOSW LWI(8, rCX) apmmove: POPR(rAX) STOSW LOOP apmmove noapm: /* * end of real mode hacks: write terminator, put ES back. */ LWI(0x0000, rAX) STOSW STOSW MFSR(rCS, rAX) /* fix up ES (0x8000) */ MTSR(rAX, rES) /* * goto protected mode */ /* MOVL tgdtptr(SB),GDTR /**/ BYTE $0x0f BYTE $0x01 BYTE $0x16 WORD $tgdtptr(SB) LWI(1, rAX) /* MOV AX,MSW */ BYTE $0x0F; BYTE $0x01; BYTE $0xF0 /* * clear prefetch queue (weird code to avoid optimizations) */ /* JMP .+2 */ BYTE $0xEB BYTE $0x00 /* * set all segs */ /* MOVW $SELECTOR(1, SELGDT, 0),AX /**/ BYTE $0xc7 BYTE $0xc0 WORD $SELECTOR(1, SELGDT, 0) MOVW AX,DS MOVW AX,SS MOVW AX,ES MOVW AX,FS MOVW AX,GS /* JMPFAR SELECTOR(2, SELGDT, 0):$mode32bit(SB) /**/ BYTE $0x66 BYTE $0xEA LONG $mode32bit-KZERO(SB) WORD $SELECTOR(2, SELGDT, 0) TEXT mode32bit(SB),$0 /* * make a bottom level page table page that maps the first * 16 meg of physical memory */ MOVL $PDB, DI /* clear 6 pages for the tables etc. */ XORL AX, AX MOVL $(6*BY2PG), CX SHRL $2, CX CLD REP; STOSL MOVL $PDB, AX /* phys addr of temporary page table */ MOVL $(4*1024),CX /* pte's per page */ MOVL $((((4*1024)-1)<>1)&0x7FFFFFFF)>>(2*PGSHIFT-1-4))+0)(AX) ADDL $BY2PG,BX MOVL BX,4(AX) MOVL BX,((((KZERO>>1)&0x7FFFFFFF)>>(2*PGSHIFT-1-4))+4)(AX) ADDL $BY2PG,BX MOVL BX,8(AX) MOVL BX,((((KZERO>>1)&0x7FFFFFFF)>>(2*PGSHIFT-1-4))+8)(AX) ADDL $BY2PG,BX MOVL BX,12(AX) MOVL BX,((((KZERO>>1)&0x7FFFFFFF)>>(2*PGSHIFT-1-4))+12)(AX) /* * point processor to top level page & turn on paging * * this produces the apparently harmless "VMX|F(125):468 Dis 0x0:0x0" * message in the VMware log. */ MOVL AX,CR3 MOVL CR0,AX ORL $0X80000000,AX MOVL AX,CR0 /* * use a jump to an absolute location to get the PC into * KZERO. */ LEAL tokzero(SB),AX JMP* AX /* * When we load 9load from DOS, the bootstrap jumps * to the instruction right after `JUMP', which gets * us into kzero. * * The name prevents it from being optimized away. */ TEXT jumplabel(SB), $0 BYTE $'J'; BYTE $'U'; BYTE $'M'; BYTE $'P' LEAL tokzero(SB),AX JMP* AX TEXT tokzero(SB),$0 /* * Clear BSS */ LEAL edata(SB),SI MOVL SI,DI ADDL $4,DI MOVL $0,AX MOVL AX,(SI) LEAL end(SB),CX SUBL DI,CX SHRL $2,CX CLD REP MOVSL /* * stack and mach */ MOVL $mach0(SB),SP MOVL SP,m(SB) MOVL $0,0(SP) ADDL $(MACHSIZE-4),SP /* start stack above machine struct */ CALL main(SB) loop: JMP loop GLOBL mach0+0(SB), $MACHSIZE GLOBL m(SB), $4 /* * 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 */ TEXT tgdtptr(SB),$0 WORD $(3*8) LONG $tgdt-KZERO(SB) /* * Output a string to the display. * String argument is in rSI. */ TEXT biosputs(SB), $0 PUSHA CLR(rBX) _BIOSputs: LODSB ORB(rAL, rAL) JEQ _BIOSputsret LBI(0x0E, rAH) BIOSCALL(0x10) JMP _BIOSputs _BIOSputsret: POPA RET /* * input a byte */ TEXT inb(SB),$0 MOVL p+0(FP),DX XORL AX,AX INB RET /* * input a short from a port */ TEXT ins(SB), $0 MOVL p+0(FP), DX XORL AX, AX OPSIZE; INL RET /* * input a long from a port */ TEXT inl(SB), $0 MOVL p+0(FP), DX XORL AX, AX INL RET /* * output a byte */ TEXT outb(SB),$0 MOVL p+0(FP),DX MOVL b+4(FP),AX OUTB RET /* * output a short to a port */ TEXT outs(SB), $0 MOVL p+0(FP), DX MOVL s+4(FP), AX OPSIZE; OUTL RET /* * output a long to a port */ TEXT outl(SB), $0 MOVL p+0(FP), DX MOVL s+4(FP), AX OUTL RET /* * input a string of bytes from a port */ TEXT insb(SB),$0 MOVL p+0(FP),DX MOVL a+4(FP),DI MOVL c+8(FP),CX CLD; REP; INSB RET /* * input a string of shorts from a port */ TEXT inss(SB),$0 MOVL p+0(FP),DX MOVL a+4(FP),DI MOVL c+8(FP),CX CLD REP; OPSIZE; INSL RET /* * output a string of bytes to a port */ TEXT outsb(SB),$0 MOVL p+0(FP),DX MOVL a+4(FP),SI MOVL c+8(FP),CX CLD; REP; OUTSB RET /* * output a string of shorts to a port */ TEXT outss(SB),$0 MOVL p+0(FP),DX MOVL a+4(FP),SI MOVL c+8(FP),CX CLD REP; OPSIZE; OUTSL RET /* * input a string of longs from a port */ TEXT insl(SB),$0 MOVL p+0(FP),DX MOVL a+4(FP),DI MOVL c+8(FP),CX CLD; REP; INSL RET /* * output a string of longs to a port */ TEXT outsl(SB),$0 MOVL p+0(FP),DX MOVL a+4(FP),SI MOVL c+8(FP),CX CLD; REP; OUTSL RET /* * routines to load/read various system registers */ GLOBL idtptr(SB),$6 TEXT putidt(SB),$0 /* interrupt descriptor table */ MOVL t+0(FP),AX MOVL AX,idtptr+2(SB) MOVL l+4(FP),AX MOVW AX,idtptr(SB) MOVL idtptr(SB),IDTR RET TEXT putcr3(SB),$0 /* top level page table pointer */ MOVL t+0(FP),AX MOVL AX,CR3 RET TEXT getcr0(SB),$0 /* coprocessor bits */ MOVL CR0,AX RET TEXT getcr2(SB),$0 /* fault address */ MOVL CR2,AX RET TEXT getcr3(SB),$0 /* page directory base */ MOVL CR3,AX RET TEXT getcr4(SB), $0 /* CR4 - extensions */ MOVL CR4, AX RET /* * special traps */ TEXT intr0(SB),$0 PUSHL $0 PUSHL $0 JMP intrcommon TEXT intr1(SB),$0 PUSHL $0 PUSHL $1 JMP intrcommon TEXT intr2(SB),$0 PUSHL $0 PUSHL $2 JMP intrcommon TEXT intr3(SB),$0 PUSHL $0 PUSHL $3 JMP intrcommon TEXT intr4(SB),$0 PUSHL $0 PUSHL $4 JMP intrcommon TEXT intr5(SB),$0 PUSHL $0 PUSHL $5 JMP intrcommon TEXT intr6(SB),$0 PUSHL $0 PUSHL $6 JMP intrcommon TEXT intr7(SB),$0 PUSHL $0 PUSHL $7 JMP intrcommon TEXT intr8(SB),$0 PUSHL $8 JMP intrcommon TEXT intr9(SB),$0 PUSHL $0 PUSHL $9 JMP intrcommon TEXT intr10(SB),$0 PUSHL $10 JMP intrcommon TEXT intr11(SB),$0 PUSHL $11 JMP intrcommon TEXT intr12(SB),$0 PUSHL $12 JMP intrcommon TEXT intr13(SB),$0 PUSHL $13 JMP intrcommon TEXT intr14(SB),$0 PUSHL $14 JMP intrcommon TEXT intr15(SB),$0 PUSHL $0 PUSHL $15 JMP intrcommon TEXT intr16(SB),$0 PUSHL $0 PUSHL $16 JMP intrcommon TEXT intr24(SB),$0 PUSHL $0 PUSHL $24 JMP intrcommon TEXT intr25(SB),$0 PUSHL $0 PUSHL $25 JMP intrcommon TEXT intr26(SB),$0 PUSHL $0 PUSHL $26 JMP intrcommon TEXT intr27(SB),$0 PUSHL $0 PUSHL $27 JMP intrcommon TEXT intr28(SB),$0 PUSHL $0 PUSHL $28 JMP intrcommon TEXT intr29(SB),$0 PUSHL $0 PUSHL $29 JMP intrcommon TEXT intr30(SB),$0 PUSHL $0 PUSHL $30 JMP intrcommon TEXT intr31(SB),$0 PUSHL $0 PUSHL $31 JMP intrcommon TEXT intr32(SB),$0 PUSHL $0 PUSHL $32 JMP intrcommon TEXT intr33(SB),$0 PUSHL $0 PUSHL $33 JMP intrcommon TEXT intr34(SB),$0 PUSHL $0 PUSHL $34 JMP intrcommon TEXT intr35(SB),$0 PUSHL $0 PUSHL $35 JMP intrcommon TEXT intr36(SB),$0 PUSHL $0 PUSHL $36 JMP intrcommon TEXT intr37(SB),$0 PUSHL $0 PUSHL $37 JMP intrcommon TEXT intr38(SB),$0 PUSHL $0 PUSHL $38 JMP intrcommon TEXT intr39(SB),$0 PUSHL $0 PUSHL $39 JMP intrcommon TEXT intr64(SB),$0 PUSHL $0 PUSHL $64 JMP intrcommon TEXT intrbad(SB),$0 PUSHL $0 PUSHL $0x1ff JMP intrcommon intrcommon: PUSHL DS PUSHL ES PUSHL FS PUSHL GS PUSHAL MOVL $(KDSEL),AX MOVW AX,DS MOVW AX,ES LEAL 0(SP),AX PUSHL AX CALL trap(SB) POPL AX POPAL POPL GS POPL FS POPL ES POPL DS ADDL $8,SP /* error code and trap type */ IRETL /* * interrupt level is interrupts on or off */ TEXT spllo(SB),$0 PUSHFL POPL AX STI RET TEXT splhi(SB),$0 PUSHFL POPL AX CLI RET TEXT splx(SB),$0 MOVL s+0(FP),AX PUSHL AX POPFL RET /* * do nothing whatsoever till interrupt happens */ TEXT idle(SB),$0 HLT 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); */ #define CPUID BYTE $0x0F; BYTE $0xA2 /* CPUID, argument in AX */ 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 c+0(FP),CX aaml1: AAM LOOP aaml1 RET TEXT hello(SB), $0 BYTE $'P'; BYTE $'l'; BYTE $'a'; BYTE $'n'; BYTE $' '; BYTE $'9'; BYTE $' '; BYTE $'f'; BYTE $'r'; BYTE $'o'; BYTE $'m'; BYTE $' '; BYTE $'B'; BYTE $'e'; BYTE $'l'; BYTE $'l'; BYTE $' '; BYTE $'L'; BYTE $'a'; BYTE $'b'; BYTE $'s'; BYTE $'\r'; BYTE $'\n'; BYTE $'\z'; TEXT rock(SB), $0 BYTE $0; BYTE $0; BYTE $0; BYTE $0;