123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309 |
- /*
- * Bootstrap loader decompressor. Starts at 0x10000 (where pbs puts it)
- * or 0x7c00 (where pxe puts it) and memmoves kernel (immediately following)
- * into standard kernel location.
- */
- #include "mem.h"
- #include "/sys/src/boot/pc/x16.h"
- #undef BIOSCALL /* we don't know what evil the bios gets up to */
- #define BIOSCALL(b) INT $(b); CLI
- #define CMPL(r0, r1) BYTE $0x66; CMP(r0, r1)
- #define LLI(i, rX) BYTE $0x66; /* i -> rX */ \
- BYTE $(0xB8+rX); \
- LONG $i;
- #define CPUID BYTE $0x0F; BYTE $0xA2 /* CPUID, argument in AX */
- #define WBINVD BYTE $0x0F; BYTE $0x09
- TEXT origin(SB), $0
- /*
- * turn off interrupts
- */
- CLI
- /*
- * 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
- LWI(0, rAX) /* always put stack in first 64k */
- MTSR(rAX, rSS)
- LWI(origin(SB), rSP) /* set the stack pointer */
- LWI(0x2401, rAX) /* enable a20 line */
- BIOSCALL(0x15)
- XORL AX, AX
- MOVB $0x03, AL
- // LWI(3, rAX)
- INT $0x10 /* set video mode in AL */
- /*
- * Check for CGA mode.
- */
- _cgastart:
- LWI(0x0F00, rAX) /* get current video mode in AL */
- BIOSCALL(0x10)
- ANDI(0x007F, rAX)
- SUBI(0x0003, rAX) /* is it mode 3? */
- JEQ _cgamode3
- LWI(0x0003, rAX) /* turn on text mode 3 */
- BIOSCALL(0x10)
- _cgamode3:
- LWI(_hello(SB), rSI)
- CALL _cgaputs(SB)
- LLI(BIOSTABLES, rAX) /* tables in low memory, not after end */
- OPSIZE; ANDL $~(BY2PG-1), AX
- OPSIZE; SHRL $4, AX
- SW(rAX, _ES(SB))
- CLR(rDI)
- SW(rDI, _DI(SB))
- MTSR(rAX, rES)
-
- /*
- * Check for APM1.2 BIOS support.
- */
- LWI(0x5304, rAX) /* disconnect anyone else */
- CLR(rBX)
- BIOSCALL(0x15)
- JCS _apmfail
- LWI(0x5303, rAX) /* connect */
- CLR(rBX)
- CLC
- BIOSCALL(0x15)
- JCC _apmpush
- _apmfail:
- LW(_ES(SB), rAX) /* no support */
- MTSR(rAX, rES)
- LW(_DI(SB), rDI)
- JCS _apmend
- _apmpush:
- OPSIZE; PUSHR(rSI) /* save returned APM data on stack */
- OPSIZE; PUSHR(rBX)
- PUSHR(rDI)
- PUSHR(rDX)
- PUSHR(rCX)
- PUSHR(rAX)
- LW(_ES(SB), rAX)
- MTSR(rAX, rES)
- LW(_DI(SB), rDI)
- LWI(0x5041, rAX) /* first 4 bytes are APM\0 */
- STOSW
- LWI(0x004D, rAX)
- STOSW
- LWI(8, rCX) /* pop the saved APM data */
- _apmpop:
- POPR(rAX)
- STOSW
- LOOP _apmpop
- _apmend:
- /*
- * Try to retrieve the 0xE820 memory map.
- * This is weird because some BIOS do not seem to preserve
- * ES/DI on failure. Consequently they may not be valid
- * at _e820end:.
- */
- SW(rDI, _DI(SB)) /* save DI */
- CLR(rAX) /* write terminator */
- STOSW
- STOSW
- CLR(rBX)
- PUSHR(rBX) /* keep loop count on stack */
- /* BX is the continuation value */
- _e820loop:
- POPR(rAX)
- INC(rAX)
- PUSHR(rAX) /* doesn't affect FLAGS */
- CMPI(32, rAX) /* mmap[32+1] in C code */
- JGT _e820pop
- LLI(20, rCX) /* buffer size */
- LLI(0x534D4150, rDX) /* signature - ASCII "SMAP" */
- LLI(0x0000E820, rAX) /* function code */
- BIOSCALL(0x15) /* writes 20 bytes at (es,di) */
- JCS _e820pop /* some kind of error */
- LLI(0x534D4150, rDX)
- CMPL(rDX, rAX) /* verify correct BIOS version */
- JNE _e820pop
- LLI(20, rDX)
- CMPL(rDX, rCX) /* verify correct count */
- JNE _e820pop
- SUBI(4, rDI) /* overwrite terminator */
- LWI(0x414D, rAX) /* first 4 bytes are "MAP\0" */
- STOSW
- LWI(0x0050, rAX)
- STOSW
- ADDI(20, rDI) /* bump to next entry */
- SW(rDI, _DI(SB)) /* save DI */
- CLR(rAX) /* write terminator */
- STOSW
- STOSW
- OR(rBX, rBX) /* zero if last entry */
- JNE _e820loop
- _e820pop:
- POPR(rAX) /* loop count */
- LW(_DI(SB), rDI)
- CLR(rAX)
- MTSR(rAX, rES)
- _e820end:
- /*
- * goto protected mode
- */
- /* MOVL loadgdtptr(SB),GDTR /**/
- BYTE $0x0f
- BYTE $0x01
- BYTE $0x16
- WORD $loadgdtptr(SB)
- DELAY
- LWI(1, rAX)
- /* MOV AX,MSW */
- BYTE $0x0F; BYTE $0x01; BYTE $0xF0
- /*
- * clear prefetch queue (weird code to avoid optimizations)
- */
- DELAY
- /*
- * set all segs
- */
- /* MOVW $KDSEL,AX /**/
- BYTE $0xc7
- BYTE $0xc0
- WORD $KDSEL
- MOVW AX,DS
- MOVW AX,SS
- MOVW AX,ES
- MOVW AX,FS
- MOVW AX,GS
- MOVW $(20*1024*1024-4), SP /* new stack pointer */
- DELAY
- /* god only knows what the damned bios has been up to... */
- CLI
- /* jump to C (main) */
- /* JMPFAR KESEL:$main(SB) /**/
- BYTE $0x66
- BYTE $0xEA
- LONG $_main(SB)
- WORD $KESEL
- /* output a cheery wee message (rSI) */
- TEXT _cgaputs(SB), $0
- //_cgaputs:
- CLR(rBX)
- _cgaputsloop:
- LODSB
- ORB(rAL, rAL)
- JEQ _cgaend
- LBI(0x0E,rAH)
- BIOSCALL(0x10)
- JMP _cgaputsloop
- _cgaend:
- RET
- TEXT _hello(SB), $0
- BYTE $'\r'; BYTE $'\n'
- BYTE $'9'; BYTE $'b'; BYTE $'o'; BYTE $'o'
- BYTE $'t'; BYTE $' '
- BYTE $'\z'
- /* offset into bios tables using segment ES. stos? use (es,di) */
- TEXT _DI(SB), $0
- LONG $0
- /* segment address of bios tables (BIOSTABLES >> 4) */
- TEXT _ES(SB), $0
- LONG $0
- /*
- * pointer to initial gdt
- */
- TEXT loadgdtptr(SB),$0
- WORD $(4*8)
- LONG $loadgdt(SB)
- /*
- * gdt to get us to 32-bit/segmented/unpaged mode
- */
- TEXT loadgdt(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)
- /* exec segment descriptor for 4 gigabytes (PL 0) 16-bit */
- LONG $(0xFFFF)
- LONG $(SEGG|(0xF<<16)|SEGP|SEGPL(0)|SEGEXEC|SEGR)
- /*
- * output a byte
- */
- TEXT outb(SB),$0
- MOVL p+0(FP),DX
- MOVL b+4(FP),AX
- OUTB
- RET
- /*
- * input a byte
- */
- TEXT inb(SB),$0
- MOVL p+0(FP),DX
- XORL AX,AX
- INB
- RET
- TEXT mb586(SB), $0
- XORL AX, AX
- CPUID
- RET
- TEXT wbinvd(SB), $0
- WBINVD
- RET
- TEXT splhi(SB),$0
- PUSHFL
- POPL AX
- CLI
- RET
|