l16r.s 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. /*
  2. * Protected-mode bootstrap, to be jumped to by a Primary Bootstrap Sector.
  3. * Load with -H3 -R4 -T0xNNNNNNNN to get a binary image with no header.
  4. * Note that the processor is in 'real' mode on entry, so care must be taken
  5. * as the assembler assumes protected mode, hence the sometimes weird-looking
  6. * code to assure 16-bit instructions are issued.
  7. */
  8. #include "mem.h"
  9. #include "x16.h"
  10. #define CMPL(r0, r1) BYTE $0x66; CMP(r0, r1)
  11. #define LLI(i, rX) BYTE $0x66; /* i -> rX */ \
  12. BYTE $(0xB8+rX); \
  13. LONG $i;
  14. /*
  15. * Start:
  16. * disable interrupts;
  17. * set all segments;
  18. * create temporary stack.
  19. */
  20. TEXT _start16r(SB), $0
  21. CLI
  22. CLD
  23. MFSR(rCS, rAX)
  24. MTSR(rAX, rDS) /* set the data and stack segments */
  25. //NO MTSR(rAX, rSS)
  26. //NO
  27. //NO LWI(_start16r(SB), rSP) /* set the stack */
  28. /*
  29. * Do any real-mode BIOS calls before going to protected mode.
  30. * Data will be stored at ROUND(end, BY2PG).
  31. */
  32. _biosstart:
  33. /*
  34. * Check for CGA mode.
  35. */
  36. _cgastart:
  37. LWI(0x0F00, rAX) /* get current video mode in AL */
  38. BIOSCALL(0x10)
  39. ANDI(0x007F, rAX)
  40. SUBI(0x0003, rAX) /* is it mode 3? */
  41. JEQ _cgaputs
  42. LWI(0x0003, rAX) /* turn on text mode 3 */
  43. BIOSCALL(0x10)
  44. _cgaputs: /* output a cheery wee message */
  45. LWI(_hello(SB), rSI)
  46. CLR(rBX)
  47. _cgaputsloop:
  48. LODSB
  49. ORB(rAL, rAL)
  50. JEQ _cgaend
  51. LBI(0x0E,rAH)
  52. BIOSCALL(0x10)
  53. JMP _cgaputsloop
  54. _cgaend:
  55. /*
  56. * Reset floppy disc system.
  57. * If successful, make sure the motor is off.
  58. */
  59. _floppystart:
  60. CLR(rAX)
  61. CLR(rDX)
  62. BIOSCALL(0x13)
  63. ORB(rAL, rAL)
  64. JNE _floppyend
  65. OUTPORTB(0x3F2, 0x00) /* turn off motor */
  66. _floppyend:
  67. LLI(end+4095(SB), rAX)
  68. OPSIZE; ANDL $~(BY2PG-1), AX
  69. OPSIZE; SHRL $4, AX
  70. SW(rAX, _ES(SB))
  71. CLR(rDI)
  72. SW(rDI, _DI(SB))
  73. MTSR(rAX, rES)
  74. /*
  75. * Check for APM1.2 BIOS support.
  76. */
  77. _apmstart:
  78. LWI(0x5304, rAX) /* disconnect anyone else */
  79. CLR(rBX)
  80. BIOSCALL(0x15)
  81. LWI(0x5303, rAX) /* connect */
  82. CLR(rBX)
  83. CLC
  84. BIOSCALL(0x15)
  85. JCC _apmpush
  86. LW(_ES(SB), rAX)
  87. MTSR(rAX, rES)
  88. LW(_DI(SB), rDI)
  89. JCS _apmend
  90. _apmpush:
  91. OPSIZE; PUSHR(rSI) /* save returned APM data on stack */
  92. OPSIZE; PUSHR(rBX)
  93. PUSHR(rDI)
  94. PUSHR(rDX)
  95. PUSHR(rCX)
  96. PUSHR(rAX)
  97. LW(_ES(SB), rAX)
  98. MTSR(rAX, rES)
  99. LW(_DI(SB), rDI)
  100. LWI(0x5041, rAX) /* first 4 bytes are APM\0 */
  101. STOSW
  102. LWI(0x004D, rAX)
  103. STOSW
  104. LWI(8, rCX) /* pop the saved APM data */
  105. _apmpop:
  106. POPR(rAX)
  107. STOSW
  108. LOOP _apmpop
  109. _apmend:
  110. /*
  111. * Try to retrieve the 0xE820 memory map.
  112. * This is weird because some BIOS do not seem to preserve
  113. * ES/DI on failure. Consequently they may not be valid
  114. * at _e820end:.
  115. */
  116. _e820start:
  117. SW(rDI, _DI(SB)) /* save DI */
  118. CLR(rAX) /* write terminator */
  119. STOSW
  120. STOSW
  121. CLR(rBX)
  122. PUSHR(rBX) /* keep loop count on stack */
  123. /* BX is the continuation value */
  124. _e820loop:
  125. POPR(rAX)
  126. INC(rAX)
  127. PUSHR(rAX) /* doesn't affect FLAGS */
  128. CMPI(32, rAX)
  129. JGT _e820pop
  130. LLI(20, rCX) /* buffer size */
  131. LLI(0x534D4150, rDX) /* signature - ASCII "SMAP" */
  132. LLI(0x0000E820, rAX) /* function code */
  133. BIOSCALL(0x15)
  134. JCS _e820pop /* some kind of error */
  135. LLI(0x534D4150, rDX)
  136. CMPL(rDX, rAX) /* verify correct BIOS version */
  137. JNE _e820pop
  138. LLI(20, rDX)
  139. CMPL(rDX, rCX) /* verify correct count */
  140. JNE _e820pop
  141. SUBI(4, rDI) /* overwrite terminator */
  142. LWI(0x414D, rAX) /* first 4 bytes are "MAP\0" */
  143. STOSW
  144. LWI(0x0050, rAX)
  145. STOSW
  146. ADDI(20, rDI) /* bump to next entry */
  147. SW(rDI, _DI(SB)) /* save DI */
  148. CLR(rAX) /* write terminator */
  149. STOSW
  150. STOSW
  151. OR(rBX, rBX) /* zero if last entry */
  152. JNE _e820loop
  153. _e820pop:
  154. POPR(rAX) /* loop count */
  155. LW(_DI(SB), rDI)
  156. CLR(rAX)
  157. MTSR(rAX, rES)
  158. _e820end:
  159. _biosend:
  160. /*
  161. * Load a basic GDT to map 4GB, turn on the protected mode bit in CR0,
  162. * set all the segments to point to the new GDT then jump to the 32-bit code.
  163. */
  164. _real:
  165. LGDT(_gdtptr16r(SB)) /* load a basic gdt */
  166. MFCR(rCR0, rAX)
  167. ORI(1, rAX)
  168. MTCR(rAX, rCR0) /* turn on protected mode */
  169. DELAY /* JMP .+2 */
  170. LWI(SELECTOR(1, SELGDT, 0), rAX)/* set all segments */
  171. MTSR(rAX, rDS)
  172. MTSR(rAX, rES)
  173. MTSR(rAX, rFS)
  174. MTSR(rAX, rGS)
  175. MTSR(rAX, rSS)
  176. FARJUMP32(SELECTOR(2, SELGDT, 0), _start32p-KZERO(SB))
  177. /*
  178. * There's no way with 8[al] to make this into local data, hence
  179. * the TEXT definitions. Also, it should be in the same segment as
  180. * the LGDT instruction.
  181. * In real mode only 24-bits of the descriptor are loaded so the
  182. * -KZERO is superfluous for the usual mappings.
  183. * The segments are
  184. * NULL
  185. * DATA 32b 4GB PL0
  186. * EXEC 32b 4GB PL0
  187. * EXEC 16b 4GB PL0
  188. */
  189. TEXT _gdt16r(SB), $0
  190. LONG $0x0000; LONG $0
  191. LONG $0xFFFF; LONG $(SEGG|SEGB|(0xF<<16)|SEGP|SEGPL(0)|SEGDATA|SEGW)
  192. LONG $0xFFFF; LONG $(SEGG|SEGD|(0xF<<16)|SEGP|SEGPL(0)|SEGEXEC|SEGR)
  193. LONG $0xFFFF; LONG $(SEGG |(0xF<<16)|SEGP|SEGPL(0)|SEGEXEC|SEGR)
  194. TEXT _gdtptr16r(SB), $0
  195. WORD $(4*8)
  196. LONG $_gdt16r-KZERO(SB)
  197. TEXT _hello(SB), $0
  198. BYTE $'P'; BYTE $'r'; BYTE $'o'; BYTE $'t';
  199. BYTE $'e'; BYTE $'c'; BYTE $'t'; BYTE $'e';
  200. BYTE $'d'; BYTE $'-'; BYTE $'m'; BYTE $'o';
  201. BYTE $'d'; BYTE $'e'; BYTE $' '; BYTE $'b';
  202. BYTE $'o'; BYTE $'o'; BYTE $'t'; BYTE $'s';
  203. BYTE $'t'; BYTE $'r'; BYTE $'a'; BYTE $'p';
  204. BYTE $'.'; BYTE $'.'; BYTE $'.';
  205. BYTE $'\r';
  206. BYTE $'\n';
  207. BYTE $'\z';
  208. TEXT _DI(SB), $0
  209. BYTE $0; BYTE $0; BYTE $0; BYTE $0;
  210. TEXT _ES(SB), $0
  211. BYTE $0; BYTE $0; BYTE $0; BYTE $0;