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 18KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766
  1. FILE_LICENCE ( GPL2_OR_LATER )
  2. #define PXENV_UNDI_SHUTDOWN 0x0005
  3. #define PXENV_UNDI_GET_NIC_TYPE 0x0012
  4. #define PXENV_UNDI_GET_IFACE_INFO 0x0013
  5. #define PXENV_STOP_UNDI 0x0015
  6. #define PXENV_UNLOAD_STACK 0x0070
  7. #define PXE_HACK_EB54 0x0001
  8. .text
  9. .arch i386
  10. .org 0
  11. .code16
  12. #include <undi.h>
  13. #define STACK_MAGIC ( 'L' + ( 'R' << 8 ) + ( 'E' << 16 ) + ( 'T' << 24 ) )
  14. #define EB_MAGIC_1 ( 'E' + ( 't' << 8 ) + ( 'h' << 16 ) + ( 'e' << 24 ) )
  15. #define EB_MAGIC_2 ( 'r' + ( 'b' << 8 ) + ( 'o' << 16 ) + ( 'o' << 24 ) )
  16. /*****************************************************************************
  17. * Entry point: set operating context, print welcome message
  18. *****************************************************************************
  19. */
  20. .section ".prefix", "ax", @progbits
  21. .globl _pxe_start
  22. _pxe_start:
  23. jmp $0x7c0, $1f
  24. 1:
  25. /* Preserve registers for possible return to PXE */
  26. pushfl
  27. pushal
  28. pushw %gs
  29. pushw %fs
  30. pushw %es
  31. pushw %ds
  32. /* Store magic word on PXE stack and remember PXE %ss:esp */
  33. pushl $STACK_MAGIC
  34. movw %ss, %cs:pxe_ss
  35. movl %esp, %cs:pxe_esp
  36. /* Set up segments */
  37. movw %cs, %ax
  38. movw %ax, %ds
  39. movw $0x40, %ax /* BIOS data segment access */
  40. movw %ax, %fs
  41. /* Set up stack just below 0x7c00 */
  42. xorw %ax, %ax
  43. movw %ax, %ss
  44. movl $0x7c00, %esp
  45. /* Clear direction flag, for the sake of sanity */
  46. cld
  47. /* Print welcome message */
  48. movw $10f, %si
  49. xorw %di, %di
  50. call print_message
  51. .section ".prefix.data", "aw", @progbits
  52. 10: .asciz "PXE->EB:"
  53. .previous
  54. /*****************************************************************************
  55. * Find us a usable !PXE or PXENV+ entry point
  56. *****************************************************************************
  57. */
  58. detect_pxe:
  59. /* Plan A: !PXE pointer from the stack */
  60. lgsl pxe_esp, %ebp /* %gs:%bp -> original stack */
  61. lesw %gs:52(%bp), %bx
  62. call is_valid_ppxe
  63. je have_ppxe
  64. /* Plan B: PXENV+ pointer from initial ES:BX */
  65. movw %gs:32(%bp),%bx
  66. movw %gs:8(%bp),%es
  67. call is_valid_pxenv
  68. je have_pxenv
  69. /* Plan C: PXENV+ structure via INT 1Ah */
  70. movw $0x5650, %ax
  71. int $0x1a
  72. jc 1f
  73. cmpw $0x564e, %ax
  74. jne 1f
  75. call is_valid_pxenv
  76. je have_pxenv
  77. 1:
  78. /* Plan D: scan base memory for !PXE */
  79. call memory_scan_ppxe
  80. je have_ppxe
  81. /* Plan E: scan base memory for PXENV+ */
  82. call memory_scan_pxenv
  83. jne stack_not_found
  84. have_pxenv:
  85. movw %bx, pxenv_offset
  86. movw %es, pxenv_segment
  87. cmpw $0x201, %es:6(%bx) /* API version >= 2.01 */
  88. jb 1f
  89. cmpb $0x2c, %es:8(%bx) /* ... and structure long enough */
  90. jb 2f
  91. lesw %es:0x28(%bx), %bx /* Find !PXE from PXENV+ */
  92. call is_valid_ppxe
  93. je have_ppxe
  94. 2:
  95. call memory_scan_ppxe /* We are *supposed* to have !PXE... */
  96. je have_ppxe
  97. 1:
  98. lesw pxenv_segoff, %bx /* Nope, we're stuck with PXENV+ */
  99. /* Record entry point and UNDI segments */
  100. pushl %es:0x0a(%bx) /* Entry point */
  101. pushw %es:0x24(%bx) /* UNDI code segment */
  102. pushw %es:0x26(%bx) /* UNDI code size */
  103. pushw %es:0x20(%bx) /* UNDI data segment */
  104. pushw %es:0x22(%bx) /* UNDI data size */
  105. /* Print "PXENV+ at <address>" */
  106. movw $10f, %si
  107. jmp check_have_stack
  108. .section ".prefix.data", "aw", @progbits
  109. 10: .asciz " PXENV+ at "
  110. .previous
  111. have_ppxe:
  112. movw %bx, ppxe_offset
  113. movw %es, ppxe_segment
  114. pushl %es:0x10(%bx) /* Entry point */
  115. pushw %es:0x30(%bx) /* UNDI code segment */
  116. pushw %es:0x36(%bx) /* UNDI code size */
  117. pushw %es:0x28(%bx) /* UNDI data segment */
  118. pushw %es:0x2e(%bx) /* UNDI data size */
  119. /* Print "!PXE at <address>" */
  120. movw $10f, %si
  121. jmp check_have_stack
  122. .section ".prefix.data", "aw", @progbits
  123. 10: .asciz " !PXE at "
  124. .previous
  125. is_valid_ppxe:
  126. cmpl $0x45585021, %es:(%bx)
  127. jne 1f
  128. movzbw %es:4(%bx), %cx
  129. cmpw $0x58, %cx
  130. jae is_valid_checksum
  131. 1:
  132. ret
  133. is_valid_pxenv:
  134. cmpl $0x4e455850, %es:(%bx)
  135. jne 1b
  136. cmpw $0x2b56, %es:4(%bx)
  137. jne 1b
  138. movzbw %es:8(%bx), %cx
  139. cmpw $0x28, %cx
  140. jb 1b
  141. is_valid_checksum:
  142. pushw %ax
  143. movw %bx, %si
  144. xorw %ax, %ax
  145. 2:
  146. es lodsb
  147. addb %al, %ah
  148. loopw 2b
  149. popw %ax
  150. ret
  151. memory_scan_ppxe:
  152. movw $is_valid_ppxe, %dx
  153. jmp memory_scan_common
  154. memory_scan_pxenv:
  155. movw $is_valid_pxenv, %dx
  156. memory_scan_common:
  157. movw %fs:(0x13), %ax
  158. shlw $6, %ax
  159. decw %ax
  160. 1: incw %ax
  161. cmpw $( 0xa000 - 1 ), %ax
  162. ja 2f
  163. movw %ax, %es
  164. xorw %bx, %bx
  165. call *%dx
  166. jne 1b
  167. 2: ret
  168. /*****************************************************************************
  169. * Sanity check: we must have an entry point
  170. *****************************************************************************
  171. */
  172. check_have_stack:
  173. /* Save common values pushed onto the stack */
  174. popl undi_data_segoff
  175. popl undi_code_segoff
  176. popl entry_segoff
  177. /* Print have !PXE/PXENV+ message; structure pointer in %es:%bx */
  178. call print_message
  179. call print_segoff
  180. movb $( ',' ), %al
  181. call print_character
  182. /* Check for entry point */
  183. movl entry_segoff, %eax
  184. testl %eax, %eax
  185. jnz 99f
  186. /* No entry point: print message and skip everything else */
  187. stack_not_found:
  188. movw $10f, %si
  189. call print_message
  190. jmp finished
  191. .section ".prefix.data", "aw", @progbits
  192. 10: .asciz " No PXE stack found!\n"
  193. .previous
  194. 99:
  195. /*****************************************************************************
  196. * Calculate base memory usage by UNDI
  197. *****************************************************************************
  198. */
  199. find_undi_basemem_usage:
  200. movw undi_code_segment, %ax
  201. movw undi_code_size, %bx
  202. movw undi_data_segment, %cx
  203. movw undi_data_size, %dx
  204. cmpw %ax, %cx
  205. ja 1f
  206. xchgw %ax, %cx
  207. xchgw %bx, %dx
  208. 1: /* %ax:%bx now describes the lower region, %cx:%dx the higher */
  209. shrw $6, %ax /* Round down to nearest kB */
  210. movw %ax, undi_fbms_start
  211. addw $0x0f, %dx /* Round up to next segment */
  212. shrw $4, %dx
  213. addw %dx, %cx
  214. addw $((1024 / 16) - 1), %cx /* Round up to next kB */
  215. shrw $6, %cx
  216. movw %cx, undi_fbms_end
  217. /*****************************************************************************
  218. * Print information about detected PXE stack
  219. *****************************************************************************
  220. */
  221. print_structure_information:
  222. /* Print entry point */
  223. movw $10f, %si
  224. call print_message
  225. les entry_segoff, %bx
  226. call print_segoff
  227. .section ".prefix.data", "aw", @progbits
  228. 10: .asciz " entry point at "
  229. .previous
  230. /* Print UNDI code segment */
  231. movw $10f, %si
  232. call print_message
  233. les undi_code_segoff, %bx
  234. call print_segoff
  235. .section ".prefix.data", "aw", @progbits
  236. 10: .asciz "\n UNDI code segment "
  237. .previous
  238. /* Print UNDI data segment */
  239. movw $10f, %si
  240. call print_message
  241. les undi_data_segoff, %bx
  242. call print_segoff
  243. .section ".prefix.data", "aw", @progbits
  244. 10: .asciz ", data segment "
  245. .previous
  246. /* Print UNDI memory usage */
  247. movw $10f, %si
  248. call print_message
  249. movw undi_fbms_start, %ax
  250. call print_word
  251. movb $( '-' ), %al
  252. call print_character
  253. movw undi_fbms_end, %ax
  254. call print_word
  255. movw $20f, %si
  256. call print_message
  257. .section ".prefix.data", "aw", @progbits
  258. 10: .asciz " ("
  259. 20: .asciz "kB)\n"
  260. .previous
  261. /*****************************************************************************
  262. * Determine physical device
  263. *****************************************************************************
  264. */
  265. get_physical_device:
  266. /* Issue PXENV_UNDI_GET_NIC_TYPE */
  267. movw $PXENV_UNDI_GET_NIC_TYPE, %bx
  268. call pxe_call
  269. jnc 1f
  270. call print_pxe_error
  271. jmp no_physical_device
  272. 1: /* Determine physical device type */
  273. movb ( pxe_parameter_structure + 0x02 ), %al
  274. cmpb $2, %al
  275. je pci_physical_device
  276. jmp no_physical_device
  277. pci_physical_device:
  278. /* Record PCI bus:dev.fn and vendor/device IDs */
  279. movl ( pxe_parameter_structure + 0x03 ), %eax
  280. movl %eax, pci_vendor
  281. movw ( pxe_parameter_structure + 0x0b ), %ax
  282. movw %ax, pci_busdevfn
  283. movw $10f, %si
  284. call print_message
  285. call print_pci_busdevfn
  286. jmp 99f
  287. .section ".prefix.data", "aw", @progbits
  288. 10: .asciz " UNDI device is PCI "
  289. .previous
  290. no_physical_device:
  291. /* No device found, or device type not understood */
  292. movw $10f, %si
  293. call print_message
  294. .section ".prefix.data", "aw", @progbits
  295. 10: .asciz " Unable to determine UNDI physical device"
  296. .previous
  297. 99:
  298. /*****************************************************************************
  299. * Determine interface type
  300. *****************************************************************************
  301. */
  302. get_iface_type:
  303. /* Issue PXENV_UNDI_GET_IFACE_INFO */
  304. movw $PXENV_UNDI_GET_IFACE_INFO, %bx
  305. call pxe_call
  306. jnc 1f
  307. call print_pxe_error
  308. jmp 99f
  309. 1: /* Print interface type */
  310. movw $10f, %si
  311. call print_message
  312. leaw ( pxe_parameter_structure + 0x02 ), %si
  313. call print_message
  314. .section ".prefix.data", "aw", @progbits
  315. 10: .asciz ", type "
  316. .previous
  317. /* Check for "Etherboot" interface type */
  318. cmpl $EB_MAGIC_1, ( pxe_parameter_structure + 0x02 )
  319. jne 99f
  320. cmpl $EB_MAGIC_2, ( pxe_parameter_structure + 0x06 )
  321. jne 99f
  322. movw $10f, %si
  323. call print_message
  324. .section ".prefix.data", "aw", @progbits
  325. 10: .asciz " (workaround enabled)"
  326. .previous
  327. /* Flag Etherboot workarounds as required */
  328. orw $PXE_HACK_EB54, pxe_hacks
  329. 99: movb $0x0a, %al
  330. call print_character
  331. /*****************************************************************************
  332. * Leave NIC in a safe state
  333. *****************************************************************************
  334. */
  335. #ifndef PXELOADER_KEEP_PXE
  336. shutdown_nic:
  337. /* Issue PXENV_UNDI_SHUTDOWN */
  338. movw $PXENV_UNDI_SHUTDOWN, %bx
  339. call pxe_call
  340. jnc 1f
  341. call print_pxe_error
  342. 1:
  343. unload_base_code:
  344. /* Etherboot treats PXENV_UNLOAD_STACK as PXENV_STOP_UNDI, so
  345. * we must not issue this call if the underlying stack is
  346. * Etherboot and we were not intending to issue a PXENV_STOP_UNDI.
  347. */
  348. #ifdef PXELOADER_KEEP_UNDI
  349. testw $PXE_HACK_EB54, pxe_hacks
  350. jnz 99f
  351. #endif /* PXELOADER_KEEP_UNDI */
  352. /* Issue PXENV_UNLOAD_STACK */
  353. movw $PXENV_UNLOAD_STACK, %bx
  354. call pxe_call
  355. jnc 1f
  356. call print_pxe_error
  357. jmp 99f
  358. 1: /* Free base memory used by PXE base code */
  359. movw undi_fbms_start, %ax
  360. movw %fs:(0x13), %bx
  361. call free_basemem
  362. 99:
  363. andw $~( UNDI_FL_INITIALIZED | UNDI_FL_KEEP_ALL ), flags
  364. #endif /* PXELOADER_KEEP_PXE */
  365. /*****************************************************************************
  366. * Unload UNDI driver
  367. *****************************************************************************
  368. */
  369. #ifndef PXELOADER_KEEP_UNDI
  370. unload_undi:
  371. /* Issue PXENV_STOP_UNDI */
  372. movw $PXENV_STOP_UNDI, %bx
  373. call pxe_call
  374. jnc 1f
  375. call print_pxe_error
  376. jmp 99f
  377. 1: /* Free base memory used by UNDI */
  378. movw undi_fbms_end, %ax
  379. movw undi_fbms_start, %bx
  380. call free_basemem
  381. /* Clear UNDI_FL_STARTED */
  382. andw $~UNDI_FL_STARTED, flags
  383. 99:
  384. #endif /* PXELOADER_KEEP_UNDI */
  385. /*****************************************************************************
  386. * Print remaining free base memory
  387. *****************************************************************************
  388. */
  389. print_free_basemem:
  390. movw $10f, %si
  391. call print_message
  392. movw %fs:(0x13), %ax
  393. call print_word
  394. movw $20f, %si
  395. call print_message
  396. .section ".prefix.data", "aw", @progbits
  397. 10: .asciz " "
  398. 20: .asciz "kB free base memory after PXE unload\n"
  399. .previous
  400. /*****************************************************************************
  401. * Exit point
  402. *****************************************************************************
  403. */
  404. finished:
  405. jmp run_ipxe
  406. /*****************************************************************************
  407. * Subroutine: print segment:offset address
  408. *
  409. * Parameters:
  410. * %es:%bx : segment:offset address to print
  411. * %ds:di : output buffer (or %di=0 to print to console)
  412. * Returns:
  413. * %ds:di : next character in output buffer (if applicable)
  414. *****************************************************************************
  415. */
  416. print_segoff:
  417. /* Preserve registers */
  418. pushw %ax
  419. /* Print "<segment>:offset" */
  420. movw %es, %ax
  421. call print_hex_word
  422. movb $( ':' ), %al
  423. call print_character
  424. movw %bx, %ax
  425. call print_hex_word
  426. /* Restore registers and return */
  427. popw %ax
  428. ret
  429. /*****************************************************************************
  430. * Subroutine: print decimal word
  431. *
  432. * Parameters:
  433. * %ax : word to print
  434. * %ds:di : output buffer (or %di=0 to print to console)
  435. * Returns:
  436. * %ds:di : next character in output buffer (if applicable)
  437. *****************************************************************************
  438. */
  439. print_word:
  440. /* Preserve registers */
  441. pushw %ax
  442. pushw %bx
  443. pushw %cx
  444. pushw %dx
  445. /* Build up digit sequence on stack */
  446. movw $10, %bx
  447. xorw %cx, %cx
  448. 1: xorw %dx, %dx
  449. divw %bx, %ax
  450. pushw %dx
  451. incw %cx
  452. testw %ax, %ax
  453. jnz 1b
  454. /* Print digit sequence */
  455. 1: popw %ax
  456. call print_hex_nibble
  457. loop 1b
  458. /* Restore registers and return */
  459. popw %dx
  460. popw %cx
  461. popw %bx
  462. popw %ax
  463. ret
  464. /*****************************************************************************
  465. * Subroutine: zero 1kB block of base memory
  466. *
  467. * Parameters:
  468. * %bx : block to zero (in kB)
  469. * Returns:
  470. * Nothing
  471. *****************************************************************************
  472. */
  473. zero_kb:
  474. /* Preserve registers */
  475. pushw %ax
  476. pushw %cx
  477. pushw %di
  478. pushw %es
  479. /* Zero block */
  480. movw %bx, %ax
  481. shlw $6, %ax
  482. movw %ax, %es
  483. movw $0x400, %cx
  484. xorw %di, %di
  485. xorw %ax, %ax
  486. rep stosb
  487. /* Restore registers and return */
  488. popw %es
  489. popw %di
  490. popw %cx
  491. popw %ax
  492. ret
  493. /*****************************************************************************
  494. * Subroutine: free and zero base memory
  495. *
  496. * Parameters:
  497. * %ax : Desired new free base memory counter (in kB)
  498. * %bx : Expected current free base memory counter (in kB)
  499. * %fs : BIOS data segment (0x40)
  500. * Returns:
  501. * None
  502. *
  503. * The base memory from %bx kB to %ax kB is unconditionally zeroed.
  504. * It will be freed if and only if the expected current free base
  505. * memory counter (%bx) matches the actual current free base memory
  506. * counter in 0x40:0x13; if this does not match then the memory will
  507. * be leaked.
  508. *****************************************************************************
  509. */
  510. free_basemem:
  511. /* Zero base memory */
  512. pushw %bx
  513. 1: cmpw %bx, %ax
  514. je 2f
  515. call zero_kb
  516. incw %bx
  517. jmp 1b
  518. 2: popw %bx
  519. /* Free base memory */
  520. cmpw %fs:(0x13), %bx /* Update FBMS only if "old" value */
  521. jne 1f /* is correct */
  522. 1: movw %ax, %fs:(0x13)
  523. ret
  524. /*****************************************************************************
  525. * Subroutine: make a PXE API call. Works with either !PXE or PXENV+ API.
  526. *
  527. * Parameters:
  528. * %bx : PXE API call number
  529. * %ds:pxe_parameter_structure : Parameters for PXE API call
  530. * Returns:
  531. * %ax : PXE status code (not exit code)
  532. * CF set if %ax is non-zero
  533. *****************************************************************************
  534. */
  535. pxe_call:
  536. /* Preserve registers */
  537. pushw %di
  538. pushw %es
  539. /* Set up registers for PXENV+ API. %bx already set up */
  540. pushw %ds
  541. popw %es
  542. movw $pxe_parameter_structure, %di
  543. /* Set up stack for !PXE API */
  544. pushw %es
  545. pushw %di
  546. pushw %bx
  547. /* Make the API call */
  548. lcall *entry_segoff
  549. /* Reset the stack */
  550. addw $6, %sp
  551. movw pxe_parameter_structure, %ax
  552. clc
  553. testw %ax, %ax
  554. jz 1f
  555. stc
  556. 1: /* Clear direction flag, for the sake of sanity */
  557. cld
  558. /* Restore registers and return */
  559. popw %es
  560. popw %di
  561. ret
  562. /*****************************************************************************
  563. * Subroutine: print PXE API call error message
  564. *
  565. * Parameters:
  566. * %ax : PXE status code
  567. * %bx : PXE API call number
  568. * Returns:
  569. * Nothing
  570. *****************************************************************************
  571. */
  572. print_pxe_error:
  573. pushw %si
  574. movw $10f, %si
  575. call print_message
  576. xchgw %ax, %bx
  577. call print_hex_word
  578. movw $20f, %si
  579. call print_message
  580. xchgw %ax, %bx
  581. call print_hex_word
  582. movw $30f, %si
  583. call print_message
  584. popw %si
  585. ret
  586. .section ".prefix.data", "aw", @progbits
  587. 10: .asciz " UNDI API call "
  588. 20: .asciz " failed: status code "
  589. 30: .asciz "\n"
  590. .previous
  591. /*****************************************************************************
  592. * PXE data structures
  593. *****************************************************************************
  594. */
  595. .section ".prefix.data"
  596. pxe_esp: .long 0
  597. pxe_ss: .word 0
  598. pxe_parameter_structure: .fill 64
  599. undi_code_segoff:
  600. undi_code_size: .word 0
  601. undi_code_segment: .word 0
  602. undi_data_segoff:
  603. undi_data_size: .word 0
  604. undi_data_segment: .word 0
  605. pxe_hacks: .word 0
  606. /* The following fields are part of a struct undi_device */
  607. undi_device:
  608. pxenv_segoff:
  609. pxenv_offset: .word 0
  610. pxenv_segment: .word 0
  611. ppxe_segoff:
  612. ppxe_offset: .word 0
  613. ppxe_segment: .word 0
  614. entry_segoff:
  615. entry_offset: .word 0
  616. entry_segment: .word 0
  617. undi_fbms_start: .word 0
  618. undi_fbms_end: .word 0
  619. pci_busdevfn: .word UNDI_NO_PCI_BUSDEVFN
  620. isapnp_csn: .word UNDI_NO_ISAPNP_CSN
  621. isapnp_read_port: .word UNDI_NO_ISAPNP_READ_PORT
  622. pci_vendor: .word 0
  623. pci_device: .word 0
  624. flags:
  625. .word ( UNDI_FL_INITIALIZED | UNDI_FL_STARTED | UNDI_FL_KEEP_ALL )
  626. .equ undi_device_size, ( . - undi_device )
  627. /*****************************************************************************
  628. * Run iPXE main code
  629. *****************************************************************************
  630. */
  631. .section ".prefix"
  632. run_ipxe:
  633. /* Install iPXE */
  634. call install
  635. /* Set up real-mode stack */
  636. movw %bx, %ss
  637. movw $_estack16, %sp
  638. #ifdef PXELOADER_KEEP_UNDI
  639. /* Copy our undi_device structure to the preloaded_undi variable */
  640. movw %bx, %es
  641. movw $preloaded_undi, %di
  642. movw $undi_device, %si
  643. movw $undi_device_size, %cx
  644. rep movsb
  645. #endif
  646. /* Retrieve PXE %ss:esp */
  647. movw pxe_ss, %di
  648. movl pxe_esp, %ebp
  649. /* Jump to .text16 segment with %ds pointing to .data16 */
  650. movw %bx, %ds
  651. pushw %ax
  652. pushw $1f
  653. lret
  654. .section ".text16", "ax", @progbits
  655. 1:
  656. /* Update the exit hook */
  657. movw %cs, ( pxe_exit_hook + 2 )
  658. /* Run main program */
  659. pushl $main
  660. pushw %cs
  661. call prot_call
  662. popl %ecx /* discard */
  663. /* Uninstall iPXE */
  664. call uninstall
  665. /* Restore PXE stack */
  666. movw %di, %ss
  667. movl %ebp, %esp
  668. /* Jump to hook if applicable */
  669. ljmpw *pxe_exit_hook
  670. .section ".data16", "aw", @progbits
  671. .globl pxe_exit_hook
  672. pxe_exit_hook:
  673. .word exit_ipxe, 0
  674. .previous
  675. exit_ipxe:
  676. /* Check PXE stack magic */
  677. popl %eax
  678. cmpl $STACK_MAGIC, %eax
  679. jne 1f
  680. /* PXE stack OK: return to caller */
  681. popw %ds
  682. popw %es
  683. popw %fs
  684. popw %gs
  685. popal
  686. popfl
  687. xorw %ax, %ax /* Return success */
  688. lret
  689. 1: /* PXE stack corrupt or removed: use INT 18 */
  690. int $0x18
  691. .previous