259 lines
6.1 KiB
ArmAsm
259 lines
6.1 KiB
ArmAsm
/*
|
|
* 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';
|