1/* 2 * Partition Boot Sector. Loaded at 0x7C00: 3 * 8a pbsraw.s; 8l -o pbsraw -l -H3 -T0x7C00 pbsraw.8 4 * Will load the target at LOADSEG*16+LOADOFF, so the target 5 * should be probably be loaded with LOADOFF added to the 6 * -Taddress. 7 * If LOADSEG is a multiple of 64KB and LOADOFF is 0 then 8 * targets larger than 64KB can be loaded. 9 * 10 * This code is uses Enhanced BIOS Services for Disc Drives and 11 * can be used with discs up to 137GB in capacity. 12 * 13 * It relies on the _startlba, _filesz and _sectsz containing the start lba of 14 * the loader and filesz to contain the size of the file and the sector size. 15 * The sector size can be probably detected by the bios. 16 */ 17#include "x16.h" 18 19#define LOADSEG (0x10000/16) /* where to load code (64KB) */ 20#define LOADOFF 0 21 22/* 23 * Data is kept on the stack, indexed by rBP. 24 */ 25#define Xdap 0x00 /* disc address packet */ 26#define Xrootsz 0x10 /* file data area */ 27#define Xdrive 0x12 /* boot drive, passed by BIOS or MBR */ 28#define Xtotal 0x14 /* sum of allocated data above */ 29 30TEXT _magic(SB), $0 31 BYTE $0xEB; BYTE $0x3C; /* jmp .+ 0x3C (_start0x3E) */ 32 BYTE $0x90 /* nop */ 33TEXT _startlba(SB), $0 34 BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00 35TEXT _filesz(SB), $0 36 BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00 37TEXT _sectsz(SB), $0 38 BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00 39TEXT _pad(SB), $0 40 BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00 41 BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00 42 BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00 43 BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00 44 BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00 45 BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00 46 BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00 47 BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00 48 BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00 49 BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00 50 BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00 51 BYTE $0x00; BYTE $0x00; BYTE $0x00 52 53_start0x3E: 54 CLI 55 CLR(rAX) 56 MTSR(rAX, rSS) /* 0000 -> rSS */ 57 MTSR(rAX, rDS) /* 0000 -> rDS, source segment */ 58 MTSR(rAX, rES) 59 LWI(_magic-Xtotal(SB), rSP) 60 MW(rSP, rBP) /* set the indexed-data pointer */ 61 62 SBPB(rDL, Xdrive) /* save the boot drive */ 63 64 /* booting from a CD starts us at 7C0:0. Move to 0:7C00 */ 65 PUSHR(rAX) 66 LWI(_nxt(SB), rAX) 67 PUSHR(rAX) 68 BYTE $0xCB /* FAR RET */ 69 70TEXT _nxt(SB), $0 71 STI 72 73 LWI(confidence(SB), rSI) /* for that warm, fuzzy feeling */ 74 CALL16(BIOSputs(SB)) 75 76 LBI(0x41, rAH) /* check extensions present */ 77 LWI(0x55AA, rBX) 78 LXB(Xdrive, xBP, rDL) /* drive */ 79 BIOSCALL(0x13) /* CF set on failure */ 80 JCS _jmp00 81 CMPI(0xAA55, rBX) 82 JNE _jmp00 83 ANDI(0x0001, rCX) 84 JNE _jmp01 85 86_jmp00: 87 CALL16(buggery(SB)) 88 89_jmp01: 90 SBPWI(0x0010, Xdap+0) /* reserved + packet size */ 91 SBPW(rCX, Xdap+2) /* reserved + # of blocks to transfer */ 92 93 DEC(rCX) 94 SBPW(rCX, Xdap+12) 95 SBPW(rCX, Xdap+14) 96 97 CALL16(dreset(SB)) 98 99_jmp02: 100 CLR(rBX) /* a handy value */ 101 102 LW(_startlba(SB), rAX) 103 LW(_startlba+2(SB), rDX) 104 CALL16(printDXAX(SB)) 105 PUSHR(rAX) 106 PUSHR(rDX) 107 LW(_filesz(SB), rAX) 108 LW(_filesz+2(SB), rDX) 109 CALL16(printDXAX(SB)) 110 111 MW(rAX, rCX) 112 POPR(rDX) 113 POPR(rAX) 114 115 LWI(LOADSEG, rBX) /* address to load into (seg+offset) */ 116 MTSR(rBX, rES) /* seg */ 117 LWI(LOADOFF, rBX) /* offset */ 118 119_readboot: 120 CALL16(BIOSread(SB)) /* read the sector */ 121 122 LW(_sectsz(SB), rDI) /* bump addresses/counts */ 123 ADD(rDI, rBX) 124 JCC _incsecno 125 126 MFSR(rES, rDI) /* next 64KB segment */ 127 ADDI(0x1000, rDI) 128 MTSR(rDI, rES) 129 130_incsecno: 131 CLR(rDI) 132 INC(rAX) 133 ADC(rDI, rDX) 134 LOOP _readboot 135 136 LWI(LOADSEG, rDI) /* set rDS for loaded code */ 137 MTSR(rDI, rDS) 138 FARJUMP16(LOADSEG, LOADOFF) /* no deposit, no return */ 139 140TEXT buggery(SB), $0 141 LWI(error(SB), rSI) 142 CALL16(BIOSputs(SB)) 143 144_wait: 145 CLR(rAX) /* wait for almost any key */ 146 BIOSCALL(0x16) 147 148_reset: 149 CLR(rBX) /* set ES segment for BIOS area */ 150 MTSR(rBX, rES) 151 152 LWI(0x0472, rBX) /* warm-start code address */ 153 LWI(0x1234, rAX) /* warm-start code */ 154 POKEW /* MOVW AX, ES:[BX] */ 155 156 FARJUMP16(0xFFFF, 0x0000) /* reset */ 157 158/* 159 * Read a sector from a disc. On entry: 160 * rDX:rAX sector number 161 * rES:rBX buffer address 162 */ 163TEXT BIOSread(SB), $0 164 LWI(5, rDI) /* retry count (ATAPI ZIPs suck) */ 165_retry: 166 PUSHA /* may be trashed by BIOSCALL */ 167 168 SBPW(rBX, Xdap+4) /* transfer buffer :offset */ 169 MFSR(rES, rDI) /* transfer buffer seg: */ 170 SBPW(rDI, Xdap+6) 171 SBPW(rAX, Xdap+8) /* LBA (64-bits) */ 172 SBPW(rDX, Xdap+10) 173 174 MW(rBP, rSI) /* disk address packet */ 175 LBI(0x42, rAH) /* extended read */ 176 LBPB(Xdrive, rDL) /* form drive */ 177 BIOSCALL(0x13) /* CF set on failure */ 178 JCC _BIOSreadret 179 180 POPA 181 DEC(rDI) /* too many retries? */ 182 JEQ _ioerror 183 184 CALL16(dreset(SB)) 185 JMP _retry 186 187_ioerror: 188 LWI(ioerror(SB), rSI) 189 CALL16(BIOSputs(SB)) 190 JMP _wait 191 192_BIOSreadret: 193 POPA 194 RET 195 196TEXT dreset(SB), $0 197 PUSHA 198 CLR(rAX) /* rAH == 0 == reset disc system */ 199 LBPB(Xdrive, rDL) 200 BIOSCALL(0x13) 201 ORB(rAH, rAH) /* status (0 == success) */ 202 POPA 203 JNE _ioerror 204 RET 205 206TEXT printsharp(SB), $0 207 LWI(sharp(SB), rSI) 208_doprint: 209 CALL16(BIOSputs(SB)) 210 RET 211 212TEXT printspace(SB), $0 213 LWI(space(SB), rSI) 214 JMP _doprint 215 216TEXT printnl(SB), $0 217 LWI(nl(SB), rSI) 218 JMP _doprint 219 220/* 221 * Output a string to the display. 222 * String argument is in rSI. 223 */ 224TEXT BIOSputs(SB), $0 225 PUSHA 226 CLR(rBX) 227_BIOSputs: 228 LODSB 229 ORB(rAL, rAL) 230 JEQ _BIOSputsret 231 232 LBI(0x0E, rAH) 233 BIOSCALL(0x10) 234 JMP _BIOSputs 235 236_BIOSputsret: 237 POPA 238 RET 239 240/* 241 * Output a register to the display. 242 */ 243TEXT printAX(SB), $0 244 PUSHR(rAX) 245 PUSHR(rBX) 246 PUSHR(rCX) 247 PUSHR(rDI) 248 249 LWI(4, rCX) 250 LWI(numbuf+4(SB), rSI) 251 252_nextchar: 253 DEC(rSI) 254 MW(rAX, rBX) 255 ANDI(0x000F, rBX) 256 ADDI(0x30, rBX) /* 0x30 = '0' */ 257 CMPI(0x39, rBX) /* 0x39 = '9' */ 258 JLE _dowrite 259 ADDI(0x07, rBX) /* 0x07 = 'A'-(1+'9')*/ 260 261_dowrite: 262 SXB(rBL, 0, xSI) 263 SHRI(4, rAX) 264 265 DEC(rCX) 266 JNE _nextchar 267 268 LWI(numbuf(SB), rSI) 269 CALL16(BIOSputs(SB)) 270 271 POPR(rDI) 272 POPR(rCX) 273 POPR(rBX) 274 POPR(rAX) 275 276 CALL16(printspace(SB)) 277 RET 278 279TEXT printDXAX(SB), $0 280 PUSHR(rAX) 281 MW(rDX, rAX) 282 CALL16(printAX(SB)) 283 POPR(rAX) 284 CALL16(printAX(SB)) 285 RET 286 287TEXT printBX(SB), $0 288 PUSHR(rAX) 289 MW(rBX, rAX) 290 CALL16(printAX(SB)) 291 POPR(rAX) 292 RET 293 294TEXT error(SB), $0 295 BYTE $'E'; 296 297TEXT ioerror(SB), $0 298 BYTE $'I'; 299 300TEXT nl(SB), $0 301 BYTE $'\r'; 302 BYTE $'\n'; 303 BYTE $'\z'; 304 305TEXT numbuf(SB), $0 306 BYTE $'X'; BYTE $'X'; BYTE $'X'; BYTE $'X'; 307 BYTE $'\z'; 308 309TEXT space(SB), $0 310 BYTE $' '; 311 BYTE $'\z'; 312 313TEXT sharp(SB), $0 314 BYTE $'#'; BYTE $'\z'; 315 316/* "PBSR..." */ 317TEXT confidence(SB), $0 318 BYTE $'P'; BYTE $'B'; BYTE $'S'; BYTE $'R'; 319 BYTE $'.'; BYTE $'.'; BYTE $'.'; 320 BYTE $'\z'; 321