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.

pxeprefix.S 10KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388
  1. #define PXENV_UNDI_CLEANUP 0x02
  2. #define PXENV_UNDI_SHUTDOWN 0x05
  3. #define PXENV_STOP_UNDI 0x15
  4. #define PXENV_UNLOAD_STACK 0x70
  5. #define PXENV_STOP_BASE 0x76
  6. #define PXE_STACK_MAGIC 0x57ac /* 'STac' */
  7. .text
  8. .code16
  9. .arch i386
  10. .org 0
  11. .section ".prefix", "ax", @progbits
  12. /*****************************************************************************
  13. * Entry point: set cs, ds, bp, print welcome message
  14. *****************************************************************************
  15. */
  16. jmp $0x7c0, $code_start
  17. 10: .asciz "PXE->EB "
  18. code_start:
  19. /* Preserve registers for return to PXE stack */
  20. pushfl
  21. pushal
  22. pushw %gs
  23. pushw %fs
  24. pushw %es
  25. pushw %ds
  26. pushw %ss
  27. pushw %cs
  28. pushw $PXE_STACK_MAGIC /* PXE stack magic marker */
  29. /* Set up stack just below 0x7c00 */
  30. pushw %ss
  31. popw %es
  32. movw %sp, %di
  33. xorw %ax, %ax
  34. movw %ax, %ss
  35. movw $0x7c00, %sp
  36. pushw %es /* Save old PXE stack pointer */
  37. pushw %di
  38. /* Set up our other segment registers */
  39. pushw %cs
  40. popw %ds
  41. movw $0x40, %ax /* BIOS data segment access */
  42. movw %ax, %fs
  43. /* Print welcome message */
  44. movw $10b, %si
  45. call print_message
  46. /*****************************************************************************
  47. * Detect type of PXE available (!PXE, PXENV+ or none)
  48. *****************************************************************************
  49. */
  50. detect_pxe:
  51. les %es:54(%di), %di /* !PXE structure */
  52. cmpl $0x45585021, %es:(%di) /* '!PXE' signature */
  53. je detected_pxe
  54. movw $0x5650, %ax
  55. int $0x1a
  56. cmpw $0x564e, %ax
  57. jne detected_nothing
  58. cmpl $0x4e455850, %es:(%bx) /* 'PXEN' signature */
  59. jne detected_nothing
  60. cmpw $0x2b56, %es:4(%bx) /* 'V+' signature */
  61. je detected_pxenv
  62. detected_nothing:
  63. movw $10f, %si
  64. call print_message
  65. jmp finished_with_error
  66. 10: .asciz "No PXE "
  67. detected_pxenv: /* es:bx points to PXENV+ structure */
  68. pushw %es
  69. pushw %bx
  70. pushw %es:0x24(%bx) /* UNDI code segment */
  71. pushw %es:0x26(%bx) /* UNDI code size */
  72. pushw %es:0x20(%bx) /* UNDI data segment */
  73. pushw %es:0x22(%bx) /* UNDI data size */
  74. les %es:0x0a(%bx), %di /* Entry point to %es:%di */
  75. movw $10f, %si
  76. jmp pxe_setup_done
  77. 10: .asciz "PXENV+ "
  78. detected_pxe: /* es:di points to !PXE structure */
  79. pushw %es
  80. pushw %di
  81. pushw %es:0x30(%di) /* UNDI code segment */
  82. pushw %es:0x36(%di) /* UNDI code size */
  83. pushw %es:0x28(%di) /* UNDI data segment */
  84. pushw %es:0x2e(%di) /* UNDI data size */
  85. les %es:0x10(%di), %di /* Entry point to %es:%di */
  86. movw $10f, %si
  87. jmp pxe_setup_done
  88. 10: .asciz "!PXE "
  89. pxe_setup_done:
  90. movw %es, pxe_entry_segment
  91. movw %di, pxe_entry_offset
  92. popw undi_data_size
  93. popw undi_data_segment
  94. popw undi_code_size
  95. popw undi_code_segment
  96. call print_message
  97. popw %di
  98. popw %es /* Exit with %es:%di containing structure address */
  99. /*****************************************************************************
  100. * Print information about located structure
  101. *****************************************************************************
  102. */
  103. print_structure_information:
  104. call print_segoff /* %es:%di contains address of structure */
  105. les pxe_entry_segoff, %di
  106. call print_segoff
  107. les undi_code_segoff, %di
  108. call print_segoff
  109. les undi_data_segoff, %di
  110. call print_segoff
  111. /*****************************************************************************
  112. * Unload PXE base code and UNDI driver
  113. *****************************************************************************
  114. */
  115. #ifdef PXELOADER_KEEP_ALL
  116. xorw %ax, %ax /* Force zero flag to show success */
  117. jmp do_not_free_base_mem /* Skip the unloading */
  118. #endif /* PXELOADER_KEEP_ALL */
  119. unload_pxe:
  120. movw $PXENV_UNLOAD_STACK, %bx
  121. call pxe_call
  122. movw $PXENV_STOP_UNDI, %bx
  123. call pxe_call
  124. pushfw /* Ignore PXENV_UNDI_CLEANUP errors */
  125. movw $PXENV_UNDI_CLEANUP, %bx
  126. call pxe_call
  127. popfw
  128. /* On exit, zero flag is set iff all calls were successful */
  129. /*****************************************************************************
  130. * Free base memory
  131. *****************************************************************************
  132. */
  133. free_base_mem:
  134. jnz do_not_free_base_mem /* Using zero flag from unload_pxe */
  135. movw undi_code_segment, %bx
  136. movw undi_data_segment, %cx
  137. movw undi_code_size, %ax
  138. cmpw %bx, %cx
  139. jb 1f
  140. movw %cx, %bx
  141. movw undi_data_size, %ax
  142. 1: addw $0x0f, %ax /* Round up to next segment */
  143. shrw $4, %ax
  144. addw %bx, %ax /* Highest segment address into %ax */
  145. addw $(1024 / 16 - 1), %ax /* Round up to next kb */
  146. shrw $6, %ax /* New free basemem size in %ax */
  147. movw %fs:(0x13), %bx /* Old free base memory in %bx */
  148. movw %ax, %fs:(0x13) /* Store new free base memory size */
  149. /* Note that zero_mem_loop will also zero out our stack, so make
  150. * sure the stack is empty at this point.
  151. */
  152. movw %ax, %dx
  153. subw %bx, %dx /* numberof kb to zero in %dx */
  154. shlw $6, %bx /* Segment address into %bx */
  155. zero_mem_loop:
  156. movw %bx, %es /* kB boundary into %es:00 */
  157. xorw %ax, %ax
  158. xorw %di, %di
  159. movw $0x400, %cx
  160. rep stosb /* fill kB with zeroes */
  161. addw $(1024 / 16), %bx
  162. decw %dx
  163. jnz zero_mem_loop
  164. /* Will exit here with zero flag set, so no need to set it explicitly
  165. * in order to indicate success.
  166. */
  167. do_not_free_base_mem:
  168. pushfw /* Save success (zero) flag status */
  169. movw %fs:(0x13), %ax /* Free base memory in %ax */
  170. call print_hex_word /* Print free base memory */
  171. popfw /* Restore success (zero) flag */
  172. /*****************************************************************************
  173. * Exit point
  174. * Jump to finished with the zero flag set to indicate success, or to
  175. * finished_with_error to always report an error
  176. *****************************************************************************
  177. */
  178. finished:
  179. movw $10f, %si
  180. jz 1f
  181. finished_with_error:
  182. movw $20f, %si
  183. 1:
  184. call print_message
  185. jmp run_etherboot
  186. 10: .asciz " ok\n"
  187. 20: .asciz " err\n"
  188. /*****************************************************************************
  189. * Subroutine: print character in %al (with LF -> LF,CR translation)
  190. *****************************************************************************
  191. */
  192. print_character:
  193. movw $0x0007, %bx /* page 0, attribute 7 (normal) */
  194. movb $0x0e, %ah /* write char, tty mode */
  195. cmpb $0x0a, %al /* '\n'? */
  196. jne 1f
  197. int $0x10
  198. movb $0x0d, %al
  199. 1: int $0x10
  200. ret
  201. /*****************************************************************************
  202. * Subroutine: print a zero-terminated message starting at %si
  203. *****************************************************************************
  204. */
  205. print_message:
  206. 1: lodsb
  207. testb %al, %al
  208. je 2f
  209. call print_character
  210. jmp 1b
  211. 2: ret
  212. /*****************************************************************************
  213. * Subroutine: print hex word in %ax
  214. *****************************************************************************
  215. */
  216. print_hex_word:
  217. movw $4, %cx
  218. 1:
  219. pushw %ax
  220. shrw $12, %ax
  221. /* Courtesy of Norbert Juffa <norbert.juffa@amd.com> */
  222. cmpb $10, %al
  223. sbbb $0x69, %al
  224. das
  225. call print_character
  226. popw %ax
  227. shlw $4, %ax
  228. loop 1b
  229. ret
  230. /*****************************************************************************
  231. * Subroutine: print segment:offset address in %es:%di
  232. *****************************************************************************
  233. */
  234. print_segoff:
  235. pushw %di
  236. pushw %es
  237. popw %ax
  238. call print_hex_word
  239. movb $0x3a,%al /* ':' */
  240. call print_character
  241. popw %ax
  242. call print_hex_word
  243. movb $0x20, %al /* ' ' */
  244. call print_character
  245. ret
  246. /*****************************************************************************
  247. * Make a PXE API call. Works with either !PXE or PXENV+ API.
  248. * Opcode in %bx. pxe_parameter_structure always used.
  249. * Returns status code (not exit code) in %bx and prints it.
  250. * ORs status code with overall status code in pxe_overall_status, returns
  251. * with zero flag set iff all PXE API calls have been successful.
  252. *****************************************************************************
  253. */
  254. pxe_call:
  255. /* Set up registers for PXENV+ API. %bx already set up */
  256. pushw %ds
  257. popw %es
  258. movw $pxe_parameter_structure, %di
  259. /* Set up stack for !PXE API */
  260. pushw %cs
  261. pushw %di
  262. pushw %bx
  263. /* Make the API call */
  264. lcall *pxe_entry_segoff
  265. /* Reset the stack */
  266. addw $6, %sp
  267. movw pxe_parameter_structure, %ax
  268. pushw %ax
  269. call print_hex_word
  270. movw $0x20, %ax /* ' ' */
  271. call print_character
  272. popw %bx
  273. orw %bx, pxe_overall_status
  274. ret
  275. /*****************************************************************************
  276. * PXE data structures
  277. *****************************************************************************
  278. */
  279. pxe_overall_status: .word 0
  280. pxe_entry_segoff:
  281. pxe_entry_offset: .word 0
  282. pxe_entry_segment: .word 0
  283. undi_code_segoff:
  284. undi_code_size: .word 0
  285. undi_code_segment: .word 0
  286. undi_data_segoff:
  287. undi_data_size: .word 0
  288. undi_data_segment: .word 0
  289. pxe_parameter_structure:
  290. .word 0
  291. .word 0,0,0,0,0
  292. /*****************************************************************************
  293. * Run Etherboot main code
  294. *****************************************************************************
  295. */
  296. run_etherboot:
  297. /* Install Etherboot */
  298. call install
  299. /* Jump to .text16 segment with %ds pointing to .data16*/
  300. movw %bx, %ds
  301. pushw %ax
  302. pushw $1f
  303. lret
  304. .section ".text16", "ax", @progbits
  305. 1:
  306. /* Original PXE stack pointer to es:di. We must hold it in
  307. * registers, because our current stack may be vapourised by
  308. * the time main() returns. (main() will still be able to
  309. * return, because prot_call() transfers the return address to
  310. * the internal stack and back again).
  311. */
  312. popw %di
  313. popw %es
  314. /* Run main program */
  315. pushl $main
  316. pushw %cs
  317. call prot_call
  318. popl %eax /* discard */
  319. /* If original PXE stack is intact, return via PXE, else via INT 18 */
  320. cmpw $PXE_STACK_MAGIC, %es:0(%di)
  321. jne exit_via_int18
  322. exit_via_pxe: /* Stack OK, return to PXE */
  323. movw $exit_via_pxe_message, %si
  324. call print_exit_message
  325. pushw %es /* Restore original PXE stack */
  326. popw %ss
  327. movw %di, %sp
  328. popw %ax /* discard PXE_STACK_MAGIC */
  329. popw %ax /* discard %cs */
  330. popw %ax /* discard %ss */
  331. popw %ds
  332. popw %es
  333. popw %fs
  334. popw %gs
  335. popal
  336. popfl
  337. xorw %ax, %ax /* Return PXENV_STATUS_SUCCESS */
  338. lret
  339. exit_via_int18: /* Stack damaged, do int 18 */
  340. movw $exit_via_int18_message, %si
  341. call print_exit_message
  342. int $0x18
  343. print_exit_message:
  344. movw $0x0007, %bx /* page 0, attribute 7 (normal) */
  345. movb $0x0e, %ah /* write char, tty mode */
  346. 1: lodsb
  347. testb %al, %al
  348. je 2f
  349. int $0x10
  350. jmp 1b
  351. 2: ret
  352. .section ".data16", "aw", @progbits
  353. exit_via_pxe_message:
  354. .asciz "EB->PXE\r\n"
  355. exit_via_int18_message:
  356. .asciz "EB->BIOS\r\n"