diff options
Diffstat (limited to 'os/boot/pc/mbr.s')
| -rw-r--r-- | os/boot/pc/mbr.s | 259 |
1 files changed, 259 insertions, 0 deletions
diff --git a/os/boot/pc/mbr.s b/os/boot/pc/mbr.s new file mode 100644 index 00000000..fb299584 --- /dev/null +++ b/os/boot/pc/mbr.s @@ -0,0 +1,259 @@ +/* + * Hard disc boot block. Loaded at 0x7C00, relocates to 0x0600: + * 8a mbr.s; 8l -o mbr -l -H3 -T0x0600 mbr.8 + */ +#include "x16.h" +#include "mem.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'; |
