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

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