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