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