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

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