ldecomp.s 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. /*
  2. * Bootstrap loader decompressor. Starts at 0x10000 (where pbs puts it)
  3. * or 0x7c00 (where pxe puts it) and memmoves kernel (immediately following)
  4. * into standard kernel location.
  5. */
  6. #include "mem.h"
  7. #include "/sys/src/boot/pc/x16.h"
  8. #undef BIOSCALL /* we don't know what evil the bios gets up to */
  9. #define BIOSCALL(b) INT $(b); CLI
  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. #define CPUID BYTE $0x0F; BYTE $0xA2 /* CPUID, argument in AX */
  15. #define WBINVD BYTE $0x0F; BYTE $0x09
  16. TEXT origin(SB), $0
  17. /*
  18. * turn off interrupts
  19. */
  20. CLI
  21. /*
  22. * This part of l.s is used only in the boot kernel.
  23. * It assumes that we are in real address mode, i.e.,
  24. * that we look like an 8086.
  25. *
  26. * Make sure the segments are reasonable.
  27. * If we were started directly from the BIOS
  28. * (i.e. no MS-DOS) then DS may not be
  29. * right.
  30. */
  31. MOVW CS, AX
  32. MOVW AX, DS
  33. LWI(0, rAX) /* always put stack in first 64k */
  34. MTSR(rAX, rSS)
  35. LWI(origin(SB), rSP) /* set the stack pointer */
  36. LWI(0x2401, rAX) /* enable a20 line */
  37. BIOSCALL(0x15)
  38. XORL AX, AX
  39. MOVB $0x03, AL
  40. // LWI(3, rAX)
  41. INT $0x10 /* set video mode in AL */
  42. /*
  43. * Check for CGA mode.
  44. */
  45. _cgastart:
  46. LWI(0x0F00, rAX) /* get current video mode in AL */
  47. BIOSCALL(0x10)
  48. ANDI(0x007F, rAX)
  49. SUBI(0x0003, rAX) /* is it mode 3? */
  50. JEQ _cgamode3
  51. LWI(0x0003, rAX) /* turn on text mode 3 */
  52. BIOSCALL(0x10)
  53. _cgamode3:
  54. LWI(_hello(SB), rSI)
  55. CALL _cgaputs(SB)
  56. LLI(BIOSTABLES, rAX) /* tables in low memory, not after end */
  57. OPSIZE; ANDL $~(BY2PG-1), AX
  58. OPSIZE; SHRL $4, AX
  59. SW(rAX, _ES(SB))
  60. CLR(rDI)
  61. SW(rDI, _DI(SB))
  62. MTSR(rAX, rES)
  63. /*
  64. * Check for APM1.2 BIOS support.
  65. */
  66. LWI(0x5304, rAX) /* disconnect anyone else */
  67. CLR(rBX)
  68. BIOSCALL(0x15)
  69. JCS _apmfail
  70. LWI(0x5303, rAX) /* connect */
  71. CLR(rBX)
  72. CLC
  73. BIOSCALL(0x15)
  74. JCC _apmpush
  75. _apmfail:
  76. LW(_ES(SB), rAX) /* no support */
  77. MTSR(rAX, rES)
  78. LW(_DI(SB), rDI)
  79. JCS _apmend
  80. _apmpush:
  81. OPSIZE; PUSHR(rSI) /* save returned APM data on stack */
  82. OPSIZE; PUSHR(rBX)
  83. PUSHR(rDI)
  84. PUSHR(rDX)
  85. PUSHR(rCX)
  86. PUSHR(rAX)
  87. LW(_ES(SB), rAX)
  88. MTSR(rAX, rES)
  89. LW(_DI(SB), rDI)
  90. LWI(0x5041, rAX) /* first 4 bytes are APM\0 */
  91. STOSW
  92. LWI(0x004D, rAX)
  93. STOSW
  94. LWI(8, rCX) /* pop the saved APM data */
  95. _apmpop:
  96. POPR(rAX)
  97. STOSW
  98. LOOP _apmpop
  99. _apmend:
  100. /*
  101. * Try to retrieve the 0xE820 memory map.
  102. * This is weird because some BIOS do not seem to preserve
  103. * ES/DI on failure. Consequently they may not be valid
  104. * at _e820end:.
  105. */
  106. SW(rDI, _DI(SB)) /* save DI */
  107. CLR(rAX) /* write terminator */
  108. STOSW
  109. STOSW
  110. CLR(rBX)
  111. PUSHR(rBX) /* keep loop count on stack */
  112. /* BX is the continuation value */
  113. _e820loop:
  114. POPR(rAX)
  115. INC(rAX)
  116. PUSHR(rAX) /* doesn't affect FLAGS */
  117. CMPI(32, rAX) /* mmap[32+1] in C code */
  118. JGT _e820pop
  119. LLI(20, rCX) /* buffer size */
  120. LLI(0x534D4150, rDX) /* signature - ASCII "SMAP" */
  121. LLI(0x0000E820, rAX) /* function code */
  122. BIOSCALL(0x15) /* writes 20 bytes at (es,di) */
  123. JCS _e820pop /* some kind of error */
  124. LLI(0x534D4150, rDX)
  125. CMPL(rDX, rAX) /* verify correct BIOS version */
  126. JNE _e820pop
  127. LLI(20, rDX)
  128. CMPL(rDX, rCX) /* verify correct count */
  129. JNE _e820pop
  130. SUBI(4, rDI) /* overwrite terminator */
  131. LWI(0x414D, rAX) /* first 4 bytes are "MAP\0" */
  132. STOSW
  133. LWI(0x0050, rAX)
  134. STOSW
  135. ADDI(20, rDI) /* bump to next entry */
  136. SW(rDI, _DI(SB)) /* save DI */
  137. CLR(rAX) /* write terminator */
  138. STOSW
  139. STOSW
  140. OR(rBX, rBX) /* zero if last entry */
  141. JNE _e820loop
  142. _e820pop:
  143. POPR(rAX) /* loop count */
  144. LW(_DI(SB), rDI)
  145. CLR(rAX)
  146. MTSR(rAX, rES)
  147. _e820end:
  148. /*
  149. * goto protected mode
  150. */
  151. /* MOVL loadgdtptr(SB),GDTR /**/
  152. BYTE $0x0f
  153. BYTE $0x01
  154. BYTE $0x16
  155. WORD $loadgdtptr(SB)
  156. DELAY
  157. LWI(1, rAX)
  158. /* MOV AX,MSW */
  159. BYTE $0x0F; BYTE $0x01; BYTE $0xF0
  160. /*
  161. * clear prefetch queue (weird code to avoid optimizations)
  162. */
  163. DELAY
  164. /*
  165. * set all segs
  166. */
  167. /* MOVW $KDSEL,AX /**/
  168. BYTE $0xc7
  169. BYTE $0xc0
  170. WORD $KDSEL
  171. MOVW AX,DS
  172. MOVW AX,SS
  173. MOVW AX,ES
  174. MOVW AX,FS
  175. MOVW AX,GS
  176. MOVW $(20*1024*1024-4), SP /* new stack pointer */
  177. DELAY
  178. /* god only knows what the damned bios has been up to... */
  179. CLI
  180. /* jump to C (main) */
  181. /* JMPFAR KESEL:$main(SB) /**/
  182. BYTE $0x66
  183. BYTE $0xEA
  184. LONG $_main(SB)
  185. WORD $KESEL
  186. /* output a cheery wee message (rSI) */
  187. TEXT _cgaputs(SB), $0
  188. //_cgaputs:
  189. CLR(rBX)
  190. _cgaputsloop:
  191. LODSB
  192. ORB(rAL, rAL)
  193. JEQ _cgaend
  194. LBI(0x0E,rAH)
  195. BIOSCALL(0x10)
  196. JMP _cgaputsloop
  197. _cgaend:
  198. RET
  199. TEXT _hello(SB), $0
  200. BYTE $'\r'; BYTE $'\n'
  201. BYTE $'9'; BYTE $'b'; BYTE $'o'; BYTE $'o'
  202. BYTE $'t'; BYTE $' '
  203. BYTE $'\z'
  204. /* offset into bios tables using segment ES. stos? use (es,di) */
  205. TEXT _DI(SB), $0
  206. LONG $0
  207. /* segment address of bios tables (BIOSTABLES >> 4) */
  208. TEXT _ES(SB), $0
  209. LONG $0
  210. /*
  211. * pointer to initial gdt
  212. */
  213. TEXT loadgdtptr(SB),$0
  214. WORD $(4*8)
  215. LONG $loadgdt(SB)
  216. /*
  217. * gdt to get us to 32-bit/segmented/unpaged mode
  218. */
  219. TEXT loadgdt(SB),$0
  220. /* null descriptor */
  221. LONG $0
  222. LONG $0
  223. /* data segment descriptor for 4 gigabytes (PL 0) */
  224. LONG $(0xFFFF)
  225. LONG $(SEGG|SEGB|(0xF<<16)|SEGP|SEGPL(0)|SEGDATA|SEGW)
  226. /* exec segment descriptor for 4 gigabytes (PL 0) */
  227. LONG $(0xFFFF)
  228. LONG $(SEGG|SEGD|(0xF<<16)|SEGP|SEGPL(0)|SEGEXEC|SEGR)
  229. /* exec segment descriptor for 4 gigabytes (PL 0) 16-bit */
  230. LONG $(0xFFFF)
  231. LONG $(SEGG|(0xF<<16)|SEGP|SEGPL(0)|SEGEXEC|SEGR)
  232. /*
  233. * output a byte
  234. */
  235. TEXT outb(SB),$0
  236. MOVL p+0(FP),DX
  237. MOVL b+4(FP),AX
  238. OUTB
  239. RET
  240. /*
  241. * input a byte
  242. */
  243. TEXT inb(SB),$0
  244. MOVL p+0(FP),DX
  245. XORL AX,AX
  246. INB
  247. RET
  248. TEXT mb586(SB), $0
  249. XORL AX, AX
  250. CPUID
  251. RET
  252. TEXT wbinvd(SB), $0
  253. WBINVD
  254. RET
  255. TEXT splhi(SB),$0
  256. PUSHFL
  257. POPL AX
  258. CLI
  259. RET