pbslba.s 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  1. /*
  2. * FAT Partition Boot Sector. Loaded at 0x7C00:
  3. * 8a pbslba.s; 8l -o pbslba -l -H3 -T0x7C00 pbslba.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 _volid field in the FAT header containing
  14. * the LBA of the root directory.
  15. */
  16. #include "x16.h"
  17. #include "mem.h"
  18. #define LOADSEG (0x10000/16) /* where to load code (64KB) */
  19. #define LOADOFF 0
  20. #define DIROFF 0x0200 /* where to read the root directory */
  21. /*
  22. * FAT directory entry.
  23. */
  24. #define Dname 0x00
  25. #define Dnamesz 0x0B
  26. #define Dext 0x08
  27. #define Dattr 0x0B
  28. #define Dtime 0x16
  29. #define Ddate 0x18
  30. #define Dstart 0x1A
  31. #define Dlengthlo 0x1C
  32. #define Dlengthhi 0x1E
  33. #define Dirsz 0x20
  34. /*
  35. * Data is kept on the stack, indexed by rBP.
  36. */
  37. #define Xdap 0x00 /* disc address packet */
  38. #define Xrootsz 0x10 /* file data area */
  39. #define Xdrive 0x12 /* boot drive, passed by BIOS or MBR */
  40. #define Xtotal 0x14 /* sum of allocated data above */
  41. TEXT _magic(SB), $0
  42. BYTE $0xEB; BYTE $0x3C; /* jmp .+ 0x3C (_start0x3E) */
  43. BYTE $0x90 /* nop */
  44. TEXT _version(SB), $0
  45. BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00;
  46. BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00
  47. TEXT _sectsize(SB), $0
  48. BYTE $0x00; BYTE $0x00
  49. TEXT _clustsize(SB), $0
  50. BYTE $0x00
  51. TEXT _nresrv(SB), $0
  52. BYTE $0x00; BYTE $0x00
  53. TEXT _nfats(SB), $0
  54. BYTE $0x00
  55. TEXT _rootsize(SB), $0
  56. BYTE $0x00; BYTE $0x00
  57. TEXT _volsize(SB), $0
  58. BYTE $0x00; BYTE $0x00
  59. TEXT _mediadesc(SB), $0
  60. BYTE $0x00
  61. TEXT _fatsize(SB), $0
  62. BYTE $0x00; BYTE $0x00
  63. TEXT _trksize(SB), $0
  64. BYTE $0x00; BYTE $0x00
  65. TEXT _nheads(SB), $0
  66. BYTE $0x00; BYTE $0x00
  67. TEXT _nhiddenlo(SB), $0
  68. BYTE $0x00; BYTE $0x00
  69. TEXT _nhiddenhi(SB), $0
  70. BYTE $0x00; BYTE $0x00;
  71. TEXT _bigvolsize(SB), $0
  72. BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00;
  73. TEXT _driveno(SB), $0
  74. BYTE $0x00
  75. TEXT _reserved0(SB), $0
  76. BYTE $0x00
  77. TEXT _bootsig(SB), $0
  78. BYTE $0x00
  79. TEXT _volid(SB), $0
  80. BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00;
  81. TEXT _label(SB), $0
  82. BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00;
  83. BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00
  84. BYTE $0x00; BYTE $0x00; BYTE $0x00
  85. TEXT _type(SB), $0
  86. BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00;
  87. BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00;
  88. _start0x3E:
  89. CLI
  90. CLR(rAX)
  91. MTSR(rAX, rSS) /* 0000 -> rSS */
  92. MTSR(rAX, rDS) /* 0000 -> rDS, source segment */
  93. MTSR(rAX, rES)
  94. LWI(_magic-Xtotal(SB), rSP)
  95. MW(rSP, rBP) /* set the indexed-data pointer */
  96. SBPB(rDL, Xdrive) /* save the boot drive */
  97. /* booting from a CD starts us at 7C0:0. Move to 0:7C00 */
  98. PUSHR(rAX)
  99. LWI(_nxt(SB), rAX)
  100. PUSHR(rAX)
  101. BYTE $0xCB /* FAR RET */
  102. TEXT _nxt(SB), $0
  103. STI
  104. LWI(confidence(SB), rSI) /* for that warm, fuzzy feeling */
  105. CALL16(BIOSputs(SB))
  106. LBI(0x41, rAH) /* check extensions present */
  107. LWI(0x55AA, rBX)
  108. LXB(Xdrive, xBP, rDL) /* drive */
  109. BIOSCALL(0x13) /* CF set on failure */
  110. JCS _jmp01
  111. CMPI(0xAA55, rBX)
  112. JNE _jmp01
  113. ANDI(0x0001, rCX)
  114. JEQ _jmp01
  115. /* rCX contains 0x0001 */
  116. SBPWI(0x0010, Xdap+0) /* reserved + packet size */
  117. SBPW(rCX, Xdap+2) /* reserved + # of blocks to transfer */
  118. DEC(rCX)
  119. SBPW(rCX, Xdap+12)
  120. SBPW(rCX, Xdap+14)
  121. CALL16(dreset(SB))
  122. _jmp00:
  123. LW(_volid(SB), rAX) /* Xrootlo */
  124. LW(_volid+2(SB), rDX) /* Xroothi */
  125. LWI(_magic+DIROFF(SB), rBX)
  126. CALL16(BIOSread(SB)) /* read the root directory */
  127. LWI((512/Dirsz), rBX)
  128. LWI(_magic+DIROFF(SB), rDI) /* compare first directory entry */
  129. _cmp00:
  130. PUSHR(rDI) /* save for later if it matches */
  131. LWI(bootfile(SB), rSI)
  132. LWI(Dnamesz, rCX)
  133. REP
  134. CMPSB
  135. POPR(rDI)
  136. JEQ _jmp02
  137. DEC(rBX)
  138. JEQ _jmp01
  139. ADDI(Dirsz, rDI)
  140. JMP _cmp00
  141. _jmp01:
  142. CALL16(buggery(SB))
  143. _jmp02:
  144. CLR(rBX) /* a handy value */
  145. LW(_rootsize(SB), rAX) /* calculate and save Xrootsz */
  146. LWI(Dirsz, rCX)
  147. MUL(rCX)
  148. LW(_sectsize(SB), rCX)
  149. PUSHR(rCX)
  150. DEC(rCX)
  151. ADD(rCX, rAX)
  152. ADC(rBX, rDX)
  153. POPR(rCX) /* _sectsize(SB) */
  154. DIV(rCX)
  155. PUSHR(rAX) /* Xrootsz */
  156. /*
  157. * rDI points to the matching directory entry.
  158. */
  159. LXW(Dstart, xDI, rAX) /* starting sector address */
  160. DEC(rAX) /* that's just the way it is */
  161. DEC(rAX)
  162. LB(_clustsize(SB), rCL)
  163. CLRB(rCH)
  164. MUL(rCX)
  165. LW(_volid(SB), rCX) /* Xrootlo */
  166. ADD(rCX, rAX)
  167. LW(_volid+2(SB), rCX) /* Xroothi */
  168. ADC(rCX, rDX)
  169. POPR(rCX) /* Xrootsz */
  170. ADD(rCX, rAX)
  171. ADC(rBX, rDX)
  172. PUSHR(rAX) /* calculate how many sectors to read */
  173. PUSHR(rDX)
  174. LXW(Dlengthlo, xDI, rAX)
  175. LXW(Dlengthhi, xDI, rDX)
  176. LW(_sectsize(SB), rCX)
  177. PUSHR(rCX)
  178. DEC(rCX)
  179. ADD(rCX, rAX)
  180. ADC(rBX, rDX)
  181. POPR(rCX) /* _sectsize(SB) */
  182. DIV(rCX)
  183. MW(rAX, rCX)
  184. POPR(rDX)
  185. POPR(rAX)
  186. LWI(LOADSEG, rBX) /* address to load into (seg+offset) */
  187. MTSR(rBX, rES) /* seg */
  188. LWI(LOADOFF, rBX) /* offset */
  189. _readboot:
  190. CALL16(BIOSread(SB)) /* read the sector */
  191. LW(_sectsize(SB), rDI) /* bump addresses/counts */
  192. ADD(rDI, rBX)
  193. JCC _incsecno
  194. MFSR(rES, rDI) /* next 64KB segment */
  195. ADDI(0x1000, rDI)
  196. MTSR(rDI, rES)
  197. _incsecno:
  198. CLR(rDI)
  199. INC(rAX)
  200. ADC(rDI, rDX)
  201. LOOP _readboot
  202. LWI(LOADSEG, rDI) /* set rDS for loaded code */
  203. MTSR(rDI, rDS)
  204. FARJUMP16(LOADSEG, LOADOFF) /* no deposit, no return */
  205. TEXT buggery(SB), $0
  206. LWI(error(SB), rSI)
  207. CALL16(BIOSputs(SB))
  208. _wait:
  209. CLR(rAX) /* wait for almost any key */
  210. BIOSCALL(0x16)
  211. _reset:
  212. CLR(rBX) /* set ES segment for BIOS area */
  213. MTSR(rBX, rES)
  214. LWI(0x0472, rBX) /* warm-start code address */
  215. LWI(0x1234, rAX) /* warm-start code */
  216. POKEW /* MOVW AX, ES:[BX] */
  217. FARJUMP16(0xFFFF, 0x0000) /* reset */
  218. /*
  219. * Read a sector from a disc. On entry:
  220. * rDX:rAX sector number
  221. * rES:rBX buffer address
  222. */
  223. TEXT BIOSread(SB), $0
  224. LWI(5, rDI) /* retry count (ATAPI ZIPs suck) */
  225. _retry:
  226. PUSHA /* may be trashed by BIOSCALL */
  227. SBPW(rBX, Xdap+4) /* transfer buffer :offset */
  228. MFSR(rES, rDI) /* transfer buffer seg: */
  229. SBPW(rDI, Xdap+6)
  230. SBPW(rAX, Xdap+8) /* LBA (64-bits) */
  231. SBPW(rDX, Xdap+10)
  232. MW(rBP, rSI) /* disk address packet */
  233. LBI(0x42, rAH) /* extended read */
  234. LBPB(Xdrive, rDL) /* form drive */
  235. BIOSCALL(0x13) /* CF set on failure */
  236. JCC _BIOSreadret
  237. POPA
  238. DEC(rDI) /* too many retries? */
  239. JEQ _ioerror
  240. CALL16(dreset(SB))
  241. JMP _retry
  242. _ioerror:
  243. LWI(ioerror(SB), rSI)
  244. CALL16(BIOSputs(SB))
  245. JMP _wait
  246. _BIOSreadret:
  247. POPA
  248. RET
  249. TEXT dreset(SB), $0
  250. PUSHA
  251. CLR(rAX) /* rAH == 0 == reset disc system */
  252. LBPB(Xdrive, rDL)
  253. BIOSCALL(0x13)
  254. ORB(rAH, rAH) /* status (0 == success) */
  255. POPA
  256. JNE _ioerror
  257. RET
  258. /*
  259. * Output a string to the display.
  260. * String argument is in rSI.
  261. */
  262. TEXT BIOSputs(SB), $0
  263. PUSHA
  264. CLR(rBX)
  265. _BIOSputs:
  266. LODSB
  267. ORB(rAL, rAL)
  268. JEQ _BIOSputsret
  269. LBI(0x0E, rAH)
  270. BIOSCALL(0x10)
  271. JMP _BIOSputs
  272. _BIOSputsret:
  273. POPA
  274. RET
  275. /* "Bad format or I/O error\r\nPress almost any key to reboot..." */
  276. TEXT error(SB), $0
  277. BYTE $'B'; BYTE $'a'; BYTE $'d'; BYTE $' ';
  278. BYTE $'f'; BYTE $'o'; BYTE $'r'; BYTE $'m';
  279. BYTE $'a'; BYTE $'t'; BYTE $' '; BYTE $'o';
  280. BYTE $'r'; BYTE $' ';
  281. /* "I/O error\r\nPress almost any key to reboot..." */
  282. TEXT ioerror(SB), $0
  283. BYTE $'I'; BYTE $'/'; BYTE $'O'; BYTE $' ';
  284. BYTE $'e'; BYTE $'r'; BYTE $'r'; BYTE $'o';
  285. BYTE $'r'; BYTE $'\r';BYTE $'\n';
  286. BYTE $'P'; BYTE $'r'; BYTE $'e'; BYTE $'s';
  287. BYTE $'s'; BYTE $' '; BYTE $'a'; BYTE $' ';
  288. BYTE $'k'; BYTE $'e'; BYTE $'y';
  289. BYTE $' '; BYTE $'t'; BYTE $'o'; BYTE $' ';
  290. BYTE $'r'; BYTE $'e'; BYTE $'b'; BYTE $'o';
  291. BYTE $'o'; BYTE $'t';
  292. BYTE $'.'; BYTE $'.'; BYTE $'.';
  293. BYTE $'\z';
  294. #ifdef USEBCOM
  295. /* "B COM" */
  296. TEXT bootfile(SB), $0
  297. BYTE $'B'; BYTE $' '; BYTE $' '; BYTE $' ';
  298. BYTE $' '; BYTE $' '; BYTE $' '; BYTE $' ';
  299. BYTE $'C'; BYTE $'O'; BYTE $'M';
  300. BYTE $'\z';
  301. #else
  302. /* "9LOAD " */
  303. TEXT bootfile(SB), $0
  304. BYTE $'9'; BYTE $'L'; BYTE $'O'; BYTE $'A';
  305. BYTE $'D'; BYTE $' '; BYTE $' '; BYTE $' ';
  306. BYTE $' '; BYTE $' '; BYTE $' ';
  307. BYTE $'\z';
  308. #endif /* USEBCOM */
  309. /* "PBS..." */
  310. TEXT confidence(SB), $0
  311. BYTE $'P'; BYTE $'B'; BYTE $'S'; BYTE $'2';
  312. BYTE $'.'; BYTE $'.'; BYTE $'.';
  313. BYTE $'\z';