You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

init.S 8.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. #include "callbacks.h"
  2. .equ CR0_PE, 1
  3. .text
  4. .arch i386
  5. .section ".prefix", "ax", @progbits
  6. #undef CODE16
  7. #if defined(PCBIOS)
  8. #define CODE16
  9. #endif
  10. /* We have two entry points: "conventional" (at the start of the file)
  11. * and "callback" (at _entry, 2 bytes in). The "callback" entry
  12. * should be used if the caller wishes to provide a specific opcode.
  13. * It is equivalent to a call to in_call. Using the "conventional"
  14. * entry point is equivalent to using the "callback" entry point with
  15. * an opcode of EB_OPCODE_MAIN.
  16. *
  17. * Both entry points can be called in either 16-bit real or 32-bit
  18. * protected mode with flat physical addresses. We detect which mode
  19. * the processor is in and call either in_call or rm_in_call as
  20. * appropriate. Note that the mode detection code must therefore be
  21. * capable of doing the same thing in either mode, even though the
  22. * machine code instructions will be interpreted differently.
  23. *
  24. * The decompressor will be invoked if necessary to decompress
  25. * Etherboot before attempting to jump to it.
  26. */
  27. /******************************************************************************
  28. * Entry points and mode detection code
  29. ******************************************************************************
  30. */
  31. .code32
  32. /* "Conventional" entry point: caller provides no opcode */
  33. .globl _start
  34. _start:
  35. /* Set flag to indicate conventional entry point used */
  36. pushl $0 /* "pushw $0" in 16-bit code */
  37. /* Fall through to "callback" entry point */
  38. /* "Callback" entry point */
  39. .globl _entry
  40. _entry:
  41. #ifdef CODE16
  42. /* CPU mode detection code */
  43. pushl %eax /* "pushw %ax" in 16-bit code */
  44. pushw %ax /* "pushl %eax" in 16-bit code */
  45. movl %cr0, %eax /* Test protected mode bit */
  46. testb $CR0_PE, %al
  47. popw %ax /* "popl %eax" in 16-bit code */
  48. popl %eax /* "popw %eax" in 16-bit code */
  49. jz rmode
  50. #endif /* CODE16 */
  51. /******************************************************************************
  52. * Entered in protected mode
  53. ******************************************************************************
  54. */
  55. .code32
  56. pmode:
  57. cmpl $0, 0(%esp) /* Conventional entry point used? */
  58. jne 1f
  59. /* Entered via conventional entry point: set up stack */
  60. xchgl %eax, 4(%esp) /* %eax = return addr, store %eax */
  61. movl %eax, 0(%esp) /* 0(%esp) = return address */
  62. movl $(EB_OPCODE_MAIN|EB_USE_INTERNAL_STACK|EB_SKIP_OPCODE), %eax
  63. xchgl %eax, 4(%esp) /* 4(%esp) = opcode, restore %eax */
  64. 1:
  65. /* Run decompressor if necessary */
  66. pushl %eax
  67. movl $decompress, %eax
  68. testl %eax, %eax
  69. jz 1f
  70. call decompress
  71. 1: popl %eax
  72. /* Make in_call to Etherboot */
  73. jmp _prefix_in_call
  74. /******************************************************************************
  75. * Entered in real mode
  76. ******************************************************************************
  77. */
  78. #ifdef CODE16
  79. .code16
  80. rmode:
  81. pushw %ax /* Padding */
  82. pushw %bp
  83. movw %sp, %bp
  84. cmpw $0, 6(%bp) /* Conventional entry point used? */
  85. jne 1f
  86. /* Entered via conventional entry point: set up stack */
  87. pushw %ax
  88. movw 6(%bp), %ax
  89. movw %ax, 2(%bp) /* Move return address down */
  90. movl $(EB_OPCODE_MAIN|EB_USE_INTERNAL_STACK|EB_SKIP_OPCODE), 4(%bp)
  91. popw %ax
  92. popw %bp
  93. jmp 2f
  94. 1: /* Entered via callback entry point: do nothing */
  95. popw %bp
  96. popw %ax
  97. 2:
  98. /* Preserve registers */
  99. pushw %ds
  100. pushl %eax
  101. /* Run decompressor if necessary. Decompressor is 32-bit
  102. * code, so we must switch to pmode first. Save and restore
  103. * GDT over transition to pmode.
  104. */
  105. movl $decompress, %eax
  106. testl %eax, %eax
  107. jz 1f
  108. pushw %ds
  109. pushw %es
  110. pushw %fs
  111. pushw %gs
  112. subw $8, %sp
  113. pushw %bp
  114. movw %sp, %bp
  115. sgdt 2(%bp)
  116. pushw %ss /* Store params for _prot_to_real */
  117. pushw %cs
  118. call _prefix_real_to_prot
  119. .code32
  120. call decompress
  121. call _prefix_prot_to_real
  122. .code16
  123. popw %ax /* skip */
  124. popw %ax /* skip */
  125. lgdt 2(%bp)
  126. popw %bp
  127. addw $8, %sp
  128. popw %gs
  129. popw %fs
  130. popw %es
  131. popw %ds
  132. 1:
  133. /* Set rm_etherboot_location */
  134. xorl %eax, %eax
  135. movw %cs, %ax
  136. movw %ax, %ds
  137. shll $4, %eax
  138. addl $_prefix_size, %eax
  139. movl %eax, _prefix_rm_etherboot_location
  140. /* Restore registers */
  141. popl %eax
  142. popw %ds
  143. /* Make real-mode in_call to Etherboot */
  144. jmp _prefix_rm_in_call
  145. #endif /* CODE16 */
  146. /******************************************************************************
  147. * Utility routines that can be called by the "prefix".
  148. ******************************************************************************
  149. */
  150. #ifdef CODE16
  151. /* Prelocate code: either to an area at the top of free base memory.
  152. * Switch stacks to use the stack within the resulting
  153. * Etherboot image.
  154. *
  155. * On entry, %cs:0000 must be the start of the prefix: this is used to
  156. * locate the code to be copied.
  157. *
  158. * This routine takes a single word parameter: the number of bytes to
  159. * be transferred from the old stack to the new stack (excluding the
  160. * return address and this parameter itself, which will always be
  161. * copied). If this value is negative, the stacks will not be
  162. * switched.
  163. *
  164. * Control will "return" to the appropriate point in the relocated
  165. * image.
  166. */
  167. #define PRELOC_PRESERVE ( 20 )
  168. #define PRELOC_OFFSET_RETADDR ( PRELOC_PRESERVE )
  169. #define PRELOC_OFFSET_RETADDR_E ( PRELOC_OFFSET_RETADDR + 4 )
  170. #define PRELOC_OFFSET_COPY ( PRELOC_OFFSET_RETADDR_E )
  171. #define PRELOC_OFFSET_COPY_E ( PRELOC_OFFSET_COPY + 2 )
  172. #define PRELOC_ALWAYS_COPY ( PRELOC_OFFSET_COPY_E )
  173. .code16
  174. .globl prelocate
  175. prelocate:
  176. /* Pad to allow for expansion of return address */
  177. pushw %ax
  178. /* Preserve registers */
  179. pushaw
  180. pushw %ds
  181. pushw %es
  182. /* Claim an area of base memory from the BIOS and put the
  183. * payload there.
  184. */
  185. movw $0x40, %bx
  186. movw %bx, %es
  187. movw %es:(0x13), %bx /* FBMS in kb to %ax */
  188. shlw $6, %bx /* ... in paragraphs */
  189. subw $_image_size_pgh, %bx /* Subtract space for image */
  190. shrw $6, %bx /* Round down to nearest kb */
  191. movw %bx, %es:(0x13) /* ...and claim memory from BIOS */
  192. shlw $6, %bx
  193. /* At this point %bx contains the segment address for the
  194. * start of the image (image = prefix + runtime).
  195. */
  196. /* Switch stacks */
  197. movw %ss, %ax
  198. movw %ax, %ds
  199. movw %sp, %si /* %ds:si = current %ss:sp */
  200. movw %ss:PRELOC_OFFSET_COPY(%si), %cx
  201. testw %cx, %cx
  202. js 1f
  203. leaw _stack_offset_pgh(%bx), %ax /* %ax = new %ss */
  204. movw %ax, %es
  205. movw $_stack_size, %di
  206. addw $PRELOC_ALWAYS_COPY, %cx
  207. subw %cx, %di /* %es:di = new %ss:sp */
  208. movw %ax, %ss /* Set new %ss:sp */
  209. movw %di, %sp
  210. cld
  211. rep movsb /* Copy stack contents */
  212. 1:
  213. /* Do the image copy backwards, since if there's overlap with
  214. * a forward copy then it means we're going to get trashed
  215. * during the copy anyway...
  216. */
  217. pushal /* Preserve 32-bit registers */
  218. movw %bx, %es /* Destination base for copy */
  219. pushw %cs
  220. popw %ds /* Source base for copy */
  221. movl $_verbatim_size-1, %ecx /* Offset to last byte */
  222. movl %ecx, %esi
  223. movl %ecx, %edi
  224. incl %ecx /* Length */
  225. std /* Backwards copy of binary */
  226. ADDR32 rep movsb
  227. cld
  228. popal /* Restore 32-bit registers */
  229. /* Store (%bx<<4) as image_basemem to be picked up by
  230. * basemem.c. Also store image_size, since there's no other
  231. * way that we can later know how much memory we allocated.
  232. * (_zfile_size is unavailable when rt2 is linked).
  233. */
  234. pushl %eax
  235. xorl %eax, %eax
  236. movw %bx, %ax
  237. shll $4, %eax
  238. movl %eax, %es:_prefix_image_basemem
  239. movl $_image_size, %es:_prefix_image_basemem_size
  240. popl %eax
  241. /* Expand original near return address into far return to new
  242. * code location.
  243. */
  244. movw %sp, %bp
  245. xchgw %bx, (PRELOC_OFFSET_RETADDR+2)(%bp)
  246. movw %bx, (PRELOC_OFFSET_RETADDR+0)(%bp)
  247. /* Restore registers and return */
  248. popw %es
  249. popw %ds
  250. popaw
  251. lret /* Jump to relocated code */
  252. /* Utility routine to free base memory allocated by prelocate.
  253. * Ensure that said memory is not in use (e.g. for the CPU
  254. * stack) before calling this routine.
  255. */
  256. .globl deprelocate
  257. deprelocate:
  258. /* Claim an area of base memory from the BIOS and put the
  259. * payload there.
  260. */
  261. pushw %ax
  262. pushw %es
  263. movw $0x40, %ax
  264. movw %ax, %es
  265. movw %es:(0x13), %ax /* FBMS in kb to %ax */
  266. shlw $6, %ax /* ... in paragraphs */
  267. addw $_image_size_pgh+0x40-1, %ax /* Add space for image and... */
  268. shrw $6, %ax /* ...round up to nearest kb */
  269. movw %ax, %es:(0x13) /* Give memory back to BIOS */
  270. popw %es
  271. popw %ax
  272. ret
  273. #endif /* CODE16 */