1/* 2 * Hard disc boot block. Loaded at 0x7C00, relocates to 0x0600: 3 * 8a mbr.s; 8l -o mbr -l -H3 -T0x0600 mbr.8 4 */ 5#include "x16.h" 6 7/*#define FLOPPY 1 /* test on a floppy */ 8#define TRACE(C) PUSHA;\ 9 CLR(rBX);\ 10 MOVB $C, AL;\ 11 LBI(0x0E, rAH);\ 12 BIOSCALL(0x10);\ 13 POPA 14 15/* 16 * We keep data on the stack, indexed by BP. 17 */ 18#define Xdap 0x00 /* disc address packet */ 19#define Xtable 0x10 /* partition table entry */ 20#define Xdrive 0x12 /* starting disc */ 21#define Xtotal 0x14 /* sum of allocated data above */ 22 23/* 24 * Start: loaded at 0000:7C00, relocate to 0000:0600. 25 * Boot drive is in rDL. 26 */ 27TEXT _start(SB), $0 28 CLI 29 CLR(rAX) 30 MTSR(rAX, rSS) /* 0000 -> rSS */ 31 LWI((0x7C00-Xtotal), rSP) /* 7Bxx -> rSP */ 32 MW(rSP, rBP) /* set the indexed-data pointer */ 33 34 MTSR(rAX, rDS) /* 0000 -> rDS, source segment */ 35 LWI(0x7C00, rSI) /* 7C00 -> rSI, source offset */ 36 MTSR(rAX, rES) /* 0000 -> rES, destination segment */ 37 LWI(0x600, rDI) /* 0600 -> rDI, destination offset */ 38 LWI(0x100, rCX) /* 0100 -> rCX, loop count (words) */ 39 40 CLD 41 REP; MOVSL /* MOV DS:[(E)SI] -> ES:[(E)DI] */ 42 43 FARJUMP16(0x0000, _start0600(SB)) 44 45TEXT _start0600(SB), $0 46#ifdef FLOPPY 47 LBI(0x80, rDL) 48#else 49 CLRB(rAL) /* some systems pass 0 */ 50 CMPBR(rAL, rDL) 51 JNE _save 52 LBI(0x80, rDL) 53#endif /* FLOPPY */ 54_save: 55 SXB(rDL, Xdrive, xBP) /* save disc */ 56 57 LWI(confidence(SB), rSI) /* for that warm, fuzzy feeling */ 58 CALL16(BIOSputs(SB)) 59 60 LWI(_start+0x01BE(SB), rSI) /* address of partition table */ 61 LWI(0x04, rCX) /* 4 entries in table */ 62 LBI(0x80, rAH) /* active entry value */ 63 CLRB(rAL) /* inactive entry value */ 64 65_activeloop0: 66 LXB(0x00, xSI, rBL) /* get active entry from table */ 67 CMPBR(rBL, rAH) /* is this an active entry? */ 68 JEQ _active 69 70 CMPBR(rBL, rAL) /* if not active it should be 0 */ 71 JNE _invalidMBR 72 73 ADDI(0x10, rSI) /* next table entry */ 74 DEC(rCX) 75 JNE _activeloop0 76 77 LWI(noentry(SB), rSI) 78 CALL16(buggery(SB)) 79 80_active: 81 MW(rSI, rDI) /* save table address */ 82 83_activeloop1: 84 ADDI(0x10, rSI) /* next table entry */ 85 DEC(rCX) 86 JEQ _readsector 87 88 LXB(0x00, xSI, rBL) /* get active entry from table */ 89 CMPBR(rBL, rAH) /* is this an active entry? */ 90 JNE _activeloop1 /* should only be one active */ 91 92_invalidMBR: 93 LWI(invalidMBR(SB), rSI) 94 CALL16(buggery(SB)) 95 96_readsector: 97 LBI(0x41, rAH) /* check extensions present */ 98 LWI(0x55AA, rBX) 99 LXB(Xdrive, xBP, rDL) /* drive */ 100 BIOSCALL(0x13) /* CF set on failure */ 101 JCS _readsector2 102 CMPI(0xAA55, rBX) 103 JNE _readsector2 104 ANDI(0x0001, rCX) 105 JEQ _readsector2 106 107_readsector42: 108 SBPBI(0x10, Xdap+0) /* packet size */ 109 SBPBI(0x00, Xdap+1) /* reserved */ 110 SBPBI(0x01, Xdap+2) /* number of blocks to transfer */ 111 SBPBI(0x00, Xdap+3) /* reserved */ 112 SBPWI(0x7C00, Xdap+4) /* transfer buffer :offset */ 113 SBPWI(0x0000, Xdap+6) /* transfer buffer seg: */ 114 LXW(0x08, xDI, rAX) /* LBA (64-bits) */ 115 SBPW(rAX, Xdap+8) 116 LXW(0x0A, xDI, rAX) 117 SBPW(rAX, Xdap+10) 118 SBPWI(0x0000, Xdap+12) 119 SBPWI(0x0000, Xdap+14) 120 121 MW(rBP, rSI) /* disk address packet */ 122 LBI(0x42, rAH) /* extended read */ 123 BIOSCALL(0x13) /* CF set on failure */ 124 JCC _readsectorok 125 126 LWI(ioerror(SB), rSI) 127 CALL16(buggery(SB)) 128 129/* 130 * Read a sector from a disc using the traditional BIOS call. 131 * For BIOSCALL(0x13/AH=0x02): 132 * rAH 0x02 133 * rAL number of sectors to read (1) 134 * rCH low 8 bits of cylinder 135 * rCL high 2 bits of cylinder (7-6), sector (5-0) 136 * rDH head 137 * rDL drive 138 * rES:rBX buffer address 139 */ 140_readsector2: 141 LXB(0x01, xDI, rDH) /* head */ 142 LXW(0x02, xDI, rCX) /* save active cylinder/sector */ 143 144 LWI(0x0201, rAX) /* read one sector */ 145 LXB(Xdrive, xBP, rDL) /* drive */ 146 LWI(0x7C00, rBX) /* buffer address (rES already OK) */ 147 BIOSCALL(0x13) /* CF set on failure */ 148 JCC _readsectorok 149 150 LWI(ioerror(SB), rSI) 151 CALL16(buggery(SB)) 152 153_readsectorok: 154 LWI(0x7C00, rBX) /* buffer address (rES already OK) */ 155 LXW(0x1FE, xBX, rAX) 156 CMPI(0xAA55, rAX) 157 JNE _bbnotok 158 159 /* 160 * Jump to the loaded PBS. 161 * rDL and rSI should still contain the drive 162 * and partition table pointer respectively. 163 */ 164 MW(rDI, rSI) 165 FARJUMP16(0x0000, 0x7C00) 166 167_bbnotok: 168 LWI(invalidPBS(SB), rSI) 169 170TEXT buggery(SB), $0 171 CALL16(BIOSputs(SB)) 172 LWI(reboot(SB), rSI) 173 CALL16(BIOSputs(SB)) 174 175_wait: 176 CLR(rAX) /* wait for any key */ 177 BIOSCALL(0x16) 178 179_reset: 180 CLR(rBX) /* set ES segment for BIOS area */ 181 MTSR(rBX, rES) 182 183 LWI(0x0472, rBX) /* warm-start code address */ 184 LWI(0x1234, rAX) /* warm-start code */ 185 POKEW /* MOVW AX, ES:[BX] */ 186 187 FARJUMP16(0xFFFF, 0x0000) /* reset */ 188 189/* 190 * Output a string to the display. 191 * String argument is in rSI. 192 */ 193TEXT BIOSputs(SB), $0 194 PUSHA 195 CLR(rBX) 196_BIOSputs: 197 LODSB 198 ORB(rAL, rAL) 199 JEQ _BIOSputsret 200 201 LBI(0x0E, rAH) 202 BIOSCALL(0x10) 203 JMP _BIOSputs 204 205_BIOSputsret: 206 POPA 207 RET 208 209/* "No active entry in MBR" */ 210TEXT noentry(SB), $0 211 BYTE $'N'; BYTE $'o'; BYTE $' '; BYTE $'a'; 212 BYTE $'c'; BYTE $'t'; BYTE $'i'; BYTE $'v'; 213 BYTE $'e'; BYTE $' '; BYTE $'e'; BYTE $'n'; 214 BYTE $'t'; BYTE $'r'; BYTE $'y'; BYTE $' '; 215 BYTE $'i'; BYTE $'n'; BYTE $' '; BYTE $'M'; 216 BYTE $'B'; BYTE $'R'; 217 BYTE $'\z'; 218 219/* "Invalid MBR" */ 220TEXT invalidMBR(SB), $0 221 BYTE $'I'; BYTE $'n'; BYTE $'v'; BYTE $'a'; 222 BYTE $'l'; BYTE $'i'; BYTE $'d'; BYTE $' '; 223 BYTE $'M'; BYTE $'B'; BYTE $'R'; 224 BYTE $'\z'; 225 226/* "I/O error" */ 227TEXT ioerror(SB), $0 228 BYTE $'I'; BYTE $'/'; BYTE $'O'; BYTE $' '; 229 BYTE $'e'; BYTE $'r'; BYTE $'r'; BYTE $'o'; 230 BYTE $'r'; 231 BYTE $'\z'; 232 233/* "Invalid PBS" */ 234TEXT invalidPBS(SB), $0 235 BYTE $'I'; BYTE $'n'; BYTE $'v'; BYTE $'a'; 236 BYTE $'l'; BYTE $'i'; BYTE $'d'; BYTE $' '; 237 BYTE $'P'; BYTE $'B'; BYTE $'S'; 238 BYTE $'\z'; 239 240/* "\r\nPress almost any key to reboot..." */ 241TEXT reboot(SB), $0 242 BYTE $'\r';BYTE $'\n'; 243 BYTE $'P'; BYTE $'r'; BYTE $'e'; BYTE $'s'; 244 BYTE $'s'; BYTE $' '; BYTE $'a'; BYTE $'l'; 245 BYTE $'m'; BYTE $'o'; BYTE $'s'; BYTE $'t'; 246 BYTE $' '; BYTE $'a'; BYTE $'n'; BYTE $'y'; 247 BYTE $' '; BYTE $'k'; BYTE $'e'; BYTE $'y'; 248 BYTE $' '; BYTE $'t'; BYTE $'o'; BYTE $' '; 249 BYTE $'r'; BYTE $'e'; BYTE $'b'; BYTE $'o'; 250 BYTE $'o'; BYTE $'t'; BYTE $'.'; BYTE $'.'; 251 BYTE $'.'; 252 BYTE $'\z'; 253 254/* "MBR..." */ 255TEXT confidence(SB), $0 256 BYTE $'M'; BYTE $'B'; BYTE $'R'; BYTE $'.'; 257 BYTE $'.'; BYTE $'.'; 258 BYTE $'\z'; 259