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

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