mbr.s 6.1 KB

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