Subversion Repositories planix.SVN

Rev

Blame | Last modification | View Log | RSS feed

/*
 * Protected-mode bootstrap, to be jumped to by a Primary Bootstrap Sector.
 * Load with -H3 -R4 -T0xNNNNNNNN to get a binary image with no header.
 * Note that the processor is in 'real' mode on entry, so care must be taken
 * as the assembler assumes protected mode, hence the sometimes weird-looking
 * code to assure 16-bit instructions are issued.
 */
#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;

/*
 * Start:
 *      disable interrupts;
 *      set all segments;
 *      create temporary stack.
 */
TEXT _start16r(SB), $0
        CLI                             /* interrupts off */

        MFSR(rCS, rAX)
        MTSR(rAX, rDS)                  /* set the data segment */

        LWI(0, rAX)                     /* always put stack in first 64k */
        MTSR(rAX, rSS)
        LWI(PXEBASE, rSP)               /* set the stack */

        LWI(0x2401, rAX)                /* enable a20 line */
        BIOSCALL(0x15)

/*
 * Do any real-mode BIOS calls before going to protected mode.
 * Data will be stored at BIOSTABLES, not ROUND(end, BY2PG) as before.
 */

/*
 * 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     _cgaputs

        LWI(0x0003, rAX)                /* turn on text mode 3 */
        BIOSCALL(0x10)

_cgaputs:                               /* output a cheery wee message */
        LWI(_hello(SB), rSI)
        CLR(rBX)
_cgaputsloop:
        LODSB
        ORB(rAL, rAL)
        JEQ     _cgaend

        LBI(0x0E,rAH)
        BIOSCALL(0x10)
        JMP     _cgaputsloop
_cgaend:

/*
 * Reset floppy disc system.
 * If successful, make sure the motor is off.
 */
_floppystart:
        CLR(rAX)
        CLR(rDX)
        BIOSCALL(0x13)
        ORB(rAL, rAL)
        JNE     _floppyend
        OUTPORTB(0x3F2, 0x00)           /* turn off motor */
_floppyend:

        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:

/*
 * Done with BIOS calls for now.  realmode calls may use the BIOS later.
 */

/*
 * Load a basic GDT to map 4GB, turn on the protected mode bit in CR0,
 * set all the segments to point to the new GDT then jump to the 32-bit code.
 */
_real:
        LGDT(_gdtptr16r(SB))            /* load a basic gdt */

        MFCR(rCR0, rAX)
        ORI(1, rAX)
        MTCR(rAX, rCR0)                 /* turn on protected mode */
        DELAY                           /* JMP .+2 */

        LWI(SELECTOR(1, SELGDT, 0), rAX)/* set all segments */
        MTSR(rAX, rDS)
        MTSR(rAX, rES)
        MTSR(rAX, rFS)
        MTSR(rAX, rGS)
        MTSR(rAX, rSS)

        FARJUMP32(SELECTOR(2, SELGDT, 0), _start32p-KZERO(SB))

TEXT _hello(SB), $0
        BYTE $'\r';
        BYTE $'\n';
        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 $'\z';

TEXT _DI(SB), $0
        LONG $0

TEXT _ES(SB), $0
        LONG $0