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

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