Subversion Repositories planix.SVN

Rev

Rev 2 | Blame | Compare with Previous | Last modification | View Log | RSS feed

/*
 * Hard disc boot block. Loaded at 0x7C00, relocates to 0x0600:
 *      8a mbr.s; 8l -o mbr -l -H3 -T0x0600 mbr.8
 */
#include "x16.h"

/*#define FLOPPY        1               /* test on a floppy */
#define TRACE(C)        PUSHA;\
                        CLR(rBX);\
                        MOVB $C, AL;\
                        LBI(0x0E, rAH);\
                        BIOSCALL(0x10);\
                        POPA

/*
 * We keep data on the stack, indexed by BP.
 */
#define Xdap            0x00            /* disc address packet */
#define Xtable          0x10            /* partition table entry */
#define Xdrive          0x12            /* starting disc */
#define Xtotal          0x14            /* sum of allocated data above */

/*
 * Start: loaded at 0000:7C00, relocate to 0000:0600.
 * Boot drive is in rDL.
 */
TEXT _start(SB), $0
        CLI
        CLR(rAX)
        MTSR(rAX, rSS)                  /* 0000 -> rSS */
        LWI((0x7C00-Xtotal), rSP)       /* 7Bxx -> rSP */
        MW(rSP, rBP)                    /* set the indexed-data pointer */

        MTSR(rAX, rDS)                  /* 0000 -> rDS, source segment */
        LWI(0x7C00, rSI)                /* 7C00 -> rSI, source offset */
        MTSR(rAX, rES)                  /* 0000 -> rES, destination segment */
        LWI(0x600, rDI)                 /* 0600 -> rDI, destination offset */
        LWI(0x100, rCX)                 /* 0100 -> rCX, loop count (words) */

        CLD
        REP; MOVSL                      /* MOV DS:[(E)SI] -> ES:[(E)DI] */

        FARJUMP16(0x0000, _start0600(SB))

TEXT _start0600(SB), $0
#ifdef FLOPPY
        LBI(0x80, rDL)
#else
        CLRB(rAL)                       /* some systems pass 0 */
        CMPBR(rAL, rDL)
        JNE _save
        LBI(0x80, rDL)
#endif /* FLOPPY */
_save:
        SXB(rDL, Xdrive, xBP)           /* save disc */

        LWI(confidence(SB), rSI)        /* for that warm, fuzzy feeling */
        CALL16(BIOSputs(SB))

        LWI(_start+0x01BE(SB), rSI)     /* address of partition table */
        LWI(0x04, rCX)                  /* 4 entries in table */
        LBI(0x80, rAH)                  /* active entry value */
        CLRB(rAL)                       /* inactive entry value */

_activeloop0:
        LXB(0x00, xSI, rBL)             /* get active entry from table */
        CMPBR(rBL, rAH)                 /* is this an active entry? */
        JEQ _active

        CMPBR(rBL, rAL)                 /* if not active it should be 0 */
        JNE _invalidMBR

        ADDI(0x10, rSI)                 /* next table entry */
        DEC(rCX)
        JNE _activeloop0

        LWI(noentry(SB), rSI)
        CALL16(buggery(SB))

_active:
        MW(rSI, rDI)                    /* save table address */

_activeloop1:
        ADDI(0x10, rSI)                 /* next table entry */
        DEC(rCX)
        JEQ _readsector

        LXB(0x00, xSI, rBL)             /* get active entry from table */
        CMPBR(rBL, rAH)                 /* is this an active entry? */
        JNE _activeloop1                /* should only be one active */

_invalidMBR:
        LWI(invalidMBR(SB), rSI)
        CALL16(buggery(SB))

_readsector:
        LBI(0x41, rAH)                  /* check extensions present */
        LWI(0x55AA, rBX)
        LXB(Xdrive, xBP, rDL)           /* drive */
        BIOSCALL(0x13)                  /* CF set on failure */
        JCS _readsector2
        CMPI(0xAA55, rBX)
        JNE _readsector2
        ANDI(0x0001, rCX)
        JEQ _readsector2

_readsector42:
        SBPBI(0x10, Xdap+0)             /* packet size */
        SBPBI(0x00, Xdap+1)             /* reserved */
        SBPBI(0x01, Xdap+2)             /* number of blocks to transfer */
        SBPBI(0x00, Xdap+3)             /* reserved */
        SBPWI(0x7C00, Xdap+4)           /* transfer buffer :offset */
        SBPWI(0x0000, Xdap+6)           /* transfer buffer seg: */
        LXW(0x08, xDI, rAX)             /* LBA (64-bits) */
        SBPW(rAX, Xdap+8)
        LXW(0x0A, xDI, rAX)
        SBPW(rAX, Xdap+10)
        SBPWI(0x0000, Xdap+12)
        SBPWI(0x0000, Xdap+14)

        MW(rBP, rSI)                    /* disk address packet */
        LBI(0x42, rAH)                  /* extended read */
        BIOSCALL(0x13)                  /* CF set on failure */
        JCC _readsectorok

        LWI(ioerror(SB), rSI)
        CALL16(buggery(SB))

/*
 * Read a sector from a disc using the traditional BIOS call.
 * For BIOSCALL(0x13/AH=0x02):
 *   rAH        0x02
 *   rAL        number of sectors to read (1)
 *   rCH        low 8 bits of cylinder
 *   rCL        high 2 bits of cylinder (7-6), sector (5-0)
 *   rDH        head
 *   rDL        drive
 *   rES:rBX    buffer address
 */
_readsector2:
        LXB(0x01, xDI, rDH)             /* head */
        LXW(0x02, xDI, rCX)             /* save active cylinder/sector */

        LWI(0x0201, rAX)                /* read one sector */
        LXB(Xdrive, xBP, rDL)           /* drive */
        LWI(0x7C00, rBX)                /* buffer address (rES already OK) */
        BIOSCALL(0x13)                  /* CF set on failure */
        JCC _readsectorok

        LWI(ioerror(SB), rSI)
        CALL16(buggery(SB))

_readsectorok:
        LWI(0x7C00, rBX)                /* buffer address (rES already OK) */
        LXW(0x1FE, xBX, rAX)
        CMPI(0xAA55, rAX)
        JNE _bbnotok

        /*
         * Jump to the loaded PBS.
         * rDL and rSI should still contain the drive
         * and partition table pointer respectively.
         */
        MW(rDI, rSI)
        FARJUMP16(0x0000, 0x7C00)

_bbnotok:
        LWI(invalidPBS(SB), rSI)

TEXT buggery(SB), $0
        CALL16(BIOSputs(SB))
        LWI(reboot(SB), rSI)
        CALL16(BIOSputs(SB))

_wait:
        CLR(rAX)                        /* wait for any key */
        BIOSCALL(0x16)

_reset:
        CLR(rBX)                        /* set ES segment for BIOS area */
        MTSR(rBX, rES)

        LWI(0x0472, rBX)                /* warm-start code address */
        LWI(0x1234, rAX)                /* warm-start code */
        POKEW                           /* MOVW AX, ES:[BX] */

        FARJUMP16(0xFFFF, 0x0000)       /* reset */

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

/* "No active entry in MBR" */
TEXT noentry(SB), $0
        BYTE $'N'; BYTE $'o'; BYTE $' '; BYTE $'a';
        BYTE $'c'; BYTE $'t'; BYTE $'i'; BYTE $'v';
        BYTE $'e'; BYTE $' '; BYTE $'e'; BYTE $'n';
        BYTE $'t'; BYTE $'r'; BYTE $'y'; BYTE $' ';
        BYTE $'i'; BYTE $'n'; BYTE $' '; BYTE $'M';
        BYTE $'B'; BYTE $'R';
        BYTE $'\z';

/* "Invalid MBR" */
TEXT invalidMBR(SB), $0
        BYTE $'I'; BYTE $'n'; BYTE $'v'; BYTE $'a';
        BYTE $'l'; BYTE $'i'; BYTE $'d'; BYTE $' ';
        BYTE $'M'; BYTE $'B'; BYTE $'R';
        BYTE $'\z';

/* "I/O error" */
TEXT ioerror(SB), $0
        BYTE $'I'; BYTE $'/'; BYTE $'O'; BYTE $' ';
        BYTE $'e'; BYTE $'r'; BYTE $'r'; BYTE $'o';
        BYTE $'r';
        BYTE $'\z';

/* "Invalid PBS" */
TEXT invalidPBS(SB), $0
        BYTE $'I'; BYTE $'n'; BYTE $'v'; BYTE $'a';
        BYTE $'l'; BYTE $'i'; BYTE $'d'; BYTE $' ';
        BYTE $'P'; BYTE $'B'; BYTE $'S';
        BYTE $'\z';

/* "\r\nPress almost any key to reboot..." */
TEXT reboot(SB), $0
        BYTE $'\r';BYTE $'\n';
        BYTE $'P'; BYTE $'r'; BYTE $'e'; BYTE $'s';
        BYTE $'s'; BYTE $' '; BYTE $'a'; BYTE $'l'; 
        BYTE $'m'; BYTE $'o'; BYTE $'s'; BYTE $'t';
        BYTE $' '; BYTE $'a'; BYTE $'n'; BYTE $'y';
        BYTE $' '; BYTE $'k'; BYTE $'e'; BYTE $'y';
        BYTE $' '; BYTE $'t'; BYTE $'o'; BYTE $' ';
        BYTE $'r'; BYTE $'e'; BYTE $'b'; BYTE $'o';
        BYTE $'o'; BYTE $'t'; BYTE $'.'; BYTE $'.';
        BYTE $'.';
        BYTE $'\z';

/* "MBR..." */
TEXT confidence(SB), $0
        BYTE $'M'; BYTE $'B'; BYTE $'R'; BYTE $'.';
        BYTE $'.'; BYTE $'.';
        BYTE $'\z';

Generated by GNU Enscript 1.6.6.