mbr.s 6.1 KB

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