Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

pxeprefix.S 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701
  1. #define PXENV_UNDI_SHUTDOWN 0x0005
  2. #define PXENV_UNDI_GET_NIC_TYPE 0x0012
  3. #define PXENV_STOP_UNDI 0x0015
  4. #define PXENV_UNLOAD_STACK 0x0070
  5. .text
  6. .arch i386
  7. .org 0
  8. .code16
  9. #include <undi.h>
  10. #define STACK_MAGIC ( 'L' + ( 'R' << 8 ) + ( 'E' << 16 ) + ( 'T' << 24 ) )
  11. /*****************************************************************************
  12. * Entry point: set operating context, print welcome message
  13. *****************************************************************************
  14. */
  15. .section ".prefix", "ax", @progbits
  16. jmp $0x7c0, $1f
  17. 1:
  18. /* Preserve registers for possible return to PXE */
  19. pushfl
  20. pushal
  21. pushw %gs
  22. pushw %fs
  23. pushw %es
  24. pushw %ds
  25. /* Store magic word on PXE stack and remember PXE %ss:esp */
  26. pushl $STACK_MAGIC
  27. movw %ss, %cs:pxe_ss
  28. movl %esp, %cs:pxe_esp
  29. /* Set up segments */
  30. movw %cs, %ax
  31. movw %ax, %ds
  32. movw $0x40, %ax /* BIOS data segment access */
  33. movw %ax, %fs
  34. /* Set up stack just below 0x7c00 */
  35. xorw %ax, %ax
  36. movw %ax, %ss
  37. movl $0x7c00, %esp
  38. /* Clear direction flag, for the sake of sanity */
  39. cld
  40. /* Print welcome message */
  41. movw $10f, %si
  42. xorw %di, %di
  43. call print_message
  44. .section ".prefix.data", "aw", @progbits
  45. 10: .asciz "PXE->EB:"
  46. .previous
  47. /*****************************************************************************
  48. * Find us a usable !PXE or PXENV+ entry point
  49. *****************************************************************************
  50. */
  51. detect_pxe:
  52. /* Plan A: !PXE pointer from the stack */
  53. lgsl pxe_esp, %ebp /* %gs:%bp -> original stack */
  54. lesw %gs:52(%bp), %bx
  55. call is_valid_ppxe
  56. je have_ppxe
  57. /* Plan B: PXENV+ pointer from initial ES:BX */
  58. movw %gs:32(%bp),%bx
  59. movw %gs:8(%bp),%es
  60. call is_valid_pxenv
  61. je have_pxenv
  62. /* Plan C: PXENV+ structure via INT 1Ah */
  63. movw $0x5650, %ax
  64. int $0x1a
  65. jc 1f
  66. cmpw $0x564e, %ax
  67. jne 1f
  68. call is_valid_pxenv
  69. je have_pxenv
  70. 1:
  71. /* Plan D: scan base memory for !PXE */
  72. call memory_scan_ppxe
  73. je have_ppxe
  74. /* Plan E: scan base memory for PXENV+ */
  75. call memory_scan_pxenv
  76. jne stack_not_found
  77. have_pxenv:
  78. movw %bx, pxenv_offset
  79. movw %es, pxenv_segment
  80. cmpw $0x201, %es:6(%bx) /* API version >= 2.01 */
  81. jb 1f
  82. cmpb $0x2c, %es:8(%bx) /* ... and structure long enough */
  83. jb 2f
  84. lesw %es:0x28(%bx), %bx /* Find !PXE from PXENV+ */
  85. call is_valid_ppxe
  86. je have_ppxe
  87. 2:
  88. call memory_scan_ppxe /* We are *supposed* to have !PXE... */
  89. je have_ppxe
  90. 1:
  91. lesw pxenv_segoff, %bx /* Nope, we're stuck with PXENV+ */
  92. /* Record entry point and UNDI segments */
  93. pushl %es:0x0a(%bx) /* Entry point */
  94. popl entry_segoff
  95. pushw %es:0x24(%bx) /* UNDI code segment */
  96. pushw %es:0x26(%bx) /* UNDI code size */
  97. popl undi_code_segoff
  98. pushw %es:0x20(%bx) /* UNDI data segment */
  99. pushw %es:0x22(%bx) /* UNDI data size */
  100. popl undi_data_segoff
  101. /* Print "PXENV+ at <address>" */
  102. movw $10f, %si
  103. call print_message
  104. call print_segoff
  105. movb $( ',' ), %al
  106. call print_character
  107. jmp check_have_stack
  108. .section ".prefix.data", "aw", @progbits
  109. 10: .asciz " PXENV+ at "
  110. .previous
  111. have_ppxe:
  112. movw %bx, ppxe_offset
  113. movw %es, ppxe_segment
  114. pushl %es:0x10(%bx) /* Entry point */
  115. popl entry_segoff
  116. pushw %es:0x30(%bx) /* UNDI code segment */
  117. pushw %es:0x36(%bx) /* UNDI code size */
  118. popl undi_code_segoff
  119. pushw %es:0x28(%bx) /* UNDI data segment */
  120. pushw %es:0x2e(%bx) /* UNDI data size */
  121. popl undi_data_segoff
  122. /* Print "!PXE at <address>" */
  123. movw $10f, %si
  124. call print_message
  125. call print_segoff
  126. movb $( ',' ), %al
  127. call print_character
  128. jmp check_have_stack
  129. .section ".prefix.data", "aw", @progbits
  130. 10: .asciz " !PXE at "
  131. .previous
  132. is_valid_ppxe:
  133. cmpl $0x45585021, %es:(%bx)
  134. jne 1f
  135. movzbw %es:4(%bx), %cx
  136. cmpw $0x58, %cx
  137. jae is_valid_checksum
  138. 1:
  139. ret
  140. is_valid_pxenv:
  141. cmpl $0x4e455850, %es:(%bx)
  142. jne 1b
  143. cmpw $0x2b56, %es:4(%bx)
  144. jne 1b
  145. movzbw %es:8(%bx), %cx
  146. cmpw $0x28, %cx
  147. jb 1b
  148. is_valid_checksum:
  149. pushw %ax
  150. movw %bx, %si
  151. xorw %ax, %ax
  152. 2:
  153. es lodsb
  154. addb %al, %ah
  155. loopw 2b
  156. popw %ax
  157. ret
  158. memory_scan_ppxe:
  159. movw $is_valid_ppxe, %dx
  160. jmp memory_scan_common
  161. memory_scan_pxenv:
  162. movw $is_valid_pxenv, %dx
  163. memory_scan_common:
  164. movw %fs:(0x13), %ax
  165. shlw $6, %ax
  166. decw %ax
  167. 1: incw %ax
  168. cmpw $( 0xa000 - 1 ), %ax
  169. ja 2f
  170. movw %ax, %es
  171. xorw %bx, %bx
  172. call *%dx
  173. jne 1b
  174. 2: ret
  175. /*****************************************************************************
  176. * Sanity check: we must have an entry point
  177. *****************************************************************************
  178. */
  179. check_have_stack:
  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. movb $0x0a, %al
  285. call print_character
  286. jmp 99f
  287. .section ".prefix.data", "aw", @progbits
  288. 10: .asciz " UNDI device is PCI "
  289. .previous
  290. no_physical_device:
  291. /* No device found, or device type not understood */
  292. movw $10f, %si
  293. call print_message
  294. .section ".prefix.data", "aw", @progbits
  295. 10: .asciz " Unable to determine UNDI physical device\n"
  296. .previous
  297. 99:
  298. /*****************************************************************************
  299. * Leave NIC in a safe state
  300. *****************************************************************************
  301. */
  302. #ifndef PXELOADER_KEEP_PXE
  303. shutdown_nic:
  304. /* Issue PXENV_UNDI_SHUTDOWN */
  305. movw $PXENV_UNDI_SHUTDOWN, %bx
  306. call pxe_call
  307. jnc 1f
  308. call print_pxe_error
  309. 1:
  310. unload_base_code:
  311. /* Issue PXENV_UNLOAD_STACK */
  312. movw $PXENV_UNLOAD_STACK, %bx
  313. call pxe_call
  314. jnc 1f
  315. call print_pxe_error
  316. jmp 99f
  317. 1: /* Free base memory used by PXE base code */
  318. movw undi_fbms_start, %ax
  319. movw %fs:(0x13), %bx
  320. call free_basemem
  321. 99:
  322. andw $~( UNDI_FL_INITIALIZED | UNDI_FL_KEEP_ALL ), flags
  323. #endif /* PXELOADER_KEEP_PXE */
  324. /*****************************************************************************
  325. * Unload UNDI driver
  326. *****************************************************************************
  327. */
  328. #ifndef PXELOADER_KEEP_UNDI
  329. unload_undi:
  330. /* Issue PXENV_STOP_UNDI */
  331. movw $PXENV_STOP_UNDI, %bx
  332. call pxe_call
  333. jnc 1f
  334. call print_pxe_error
  335. jmp 99f
  336. 1: /* Free base memory used by UNDI */
  337. movw undi_fbms_end, %ax
  338. movw undi_fbms_start, %bx
  339. call free_basemem
  340. /* Clear UNDI_FL_STARTED */
  341. andw $~UNDI_FL_STARTED, flags
  342. 99:
  343. #endif /* PXELOADER_KEEP_UNDI */
  344. /*****************************************************************************
  345. * Print remaining free base memory
  346. *****************************************************************************
  347. */
  348. print_free_basemem:
  349. movw $10f, %si
  350. call print_message
  351. movw %fs:(0x13), %ax
  352. call print_word
  353. movw $20f, %si
  354. call print_message
  355. .section ".prefix.data", "aw", @progbits
  356. 10: .asciz " "
  357. 20: .asciz "kB free base memory after PXE unload\n"
  358. .previous
  359. /*****************************************************************************
  360. * Exit point
  361. *****************************************************************************
  362. */
  363. finished:
  364. jmp run_gpxe
  365. /*****************************************************************************
  366. * Subroutine: print segment:offset address
  367. *
  368. * Parameters:
  369. * %es:%bx : segment:offset address to print
  370. * %ds:di : output buffer (or %di=0 to print to console)
  371. * Returns:
  372. * %ds:di : next character in output buffer (if applicable)
  373. *****************************************************************************
  374. */
  375. print_segoff:
  376. /* Preserve registers */
  377. pushw %ax
  378. /* Print "<segment>:offset" */
  379. movw %es, %ax
  380. call print_hex_word
  381. movb $( ':' ), %al
  382. call print_character
  383. movw %bx, %ax
  384. call print_hex_word
  385. /* Restore registers and return */
  386. popw %ax
  387. ret
  388. /*****************************************************************************
  389. * Subroutine: print decimal word
  390. *
  391. * Parameters:
  392. * %ax : word to print
  393. * %ds:di : output buffer (or %di=0 to print to console)
  394. * Returns:
  395. * %ds:di : next character in output buffer (if applicable)
  396. *****************************************************************************
  397. */
  398. print_word:
  399. /* Preserve registers */
  400. pushw %ax
  401. pushw %bx
  402. pushw %cx
  403. pushw %dx
  404. /* Build up digit sequence on stack */
  405. movw $10, %bx
  406. xorw %cx, %cx
  407. 1: xorw %dx, %dx
  408. divw %bx, %ax
  409. pushw %dx
  410. incw %cx
  411. testw %ax, %ax
  412. jnz 1b
  413. /* Print digit sequence */
  414. 1: popw %ax
  415. call print_hex_nibble
  416. loop 1b
  417. /* Restore registers and return */
  418. popw %dx
  419. popw %cx
  420. popw %bx
  421. popw %ax
  422. ret
  423. /*****************************************************************************
  424. * Subroutine: zero 1kB block of base memory
  425. *
  426. * Parameters:
  427. * %bx : block to zero (in kB)
  428. * Returns:
  429. * Nothing
  430. *****************************************************************************
  431. */
  432. zero_kb:
  433. /* Preserve registers */
  434. pushw %ax
  435. pushw %cx
  436. pushw %di
  437. pushw %es
  438. /* Zero block */
  439. movw %bx, %ax
  440. shlw $6, %ax
  441. movw %ax, %es
  442. movw $0x400, %cx
  443. xorw %di, %di
  444. xorw %ax, %ax
  445. rep stosb
  446. /* Restore registers and return */
  447. popw %es
  448. popw %di
  449. popw %cx
  450. popw %ax
  451. ret
  452. /*****************************************************************************
  453. * Subroutine: free and zero base memory
  454. *
  455. * Parameters:
  456. * %ax : Desired new free base memory counter (in kB)
  457. * %bx : Expected current free base memory counter (in kB)
  458. * %fs : BIOS data segment (0x40)
  459. * Returns:
  460. * None
  461. *
  462. * The base memory from %bx kB to %ax kB is unconditionally zeroed.
  463. * It will be freed if and only if the expected current free base
  464. * memory counter (%bx) matches the actual current free base memory
  465. * counter in 0x40:0x13; if this does not match then the memory will
  466. * be leaked.
  467. *****************************************************************************
  468. */
  469. free_basemem:
  470. /* Zero base memory */
  471. pushw %bx
  472. 1: cmpw %bx, %ax
  473. je 2f
  474. call zero_kb
  475. incw %bx
  476. jmp 1b
  477. 2: popw %bx
  478. /* Free base memory */
  479. cmpw %fs:(0x13), %bx /* Update FBMS only if "old" value */
  480. jne 1f /* is correct */
  481. 1: movw %ax, %fs:(0x13)
  482. ret
  483. /*****************************************************************************
  484. * Subroutine: make a PXE API call. Works with either !PXE or PXENV+ API.
  485. *
  486. * Parameters:
  487. * %bx : PXE API call number
  488. * %ds:pxe_parameter_structure : Parameters for PXE API call
  489. * Returns:
  490. * %ax : PXE status code (not exit code)
  491. * CF set if %ax is non-zero
  492. *****************************************************************************
  493. */
  494. pxe_call:
  495. /* Preserve registers */
  496. pushw %di
  497. pushw %es
  498. /* Set up registers for PXENV+ API. %bx already set up */
  499. pushw %ds
  500. popw %es
  501. movw $pxe_parameter_structure, %di
  502. /* Set up stack for !PXE API */
  503. pushw %es
  504. pushw %di
  505. pushw %bx
  506. /* Make the API call */
  507. lcall *entry_segoff
  508. /* Reset the stack */
  509. addw $6, %sp
  510. movw pxe_parameter_structure, %ax
  511. clc
  512. testw %ax, %ax
  513. jz 1f
  514. stc
  515. 1: /* Restore registers and return */
  516. popw %es
  517. popw %di
  518. ret
  519. /*****************************************************************************
  520. * Subroutine: print PXE API call error message
  521. *
  522. * Parameters:
  523. * %ax : PXE status code
  524. * %bx : PXE API call number
  525. * Returns:
  526. * Nothing
  527. *****************************************************************************
  528. */
  529. print_pxe_error:
  530. pushw %si
  531. movw $10f, %si
  532. call print_message
  533. xchgw %ax, %bx
  534. call print_hex_word
  535. movw $20f, %si
  536. call print_message
  537. xchgw %ax, %bx
  538. call print_hex_word
  539. movw $30f, %si
  540. call print_message
  541. popw %si
  542. ret
  543. .section ".prefix.data", "aw", @progbits
  544. 10: .asciz " UNDI API call "
  545. 20: .asciz " failed: status code "
  546. 30: .asciz "\n"
  547. .previous
  548. /*****************************************************************************
  549. * PXE data structures
  550. *****************************************************************************
  551. */
  552. .section ".prefix.data"
  553. pxe_esp: .long 0
  554. pxe_ss: .word 0
  555. pxe_parameter_structure: .fill 20
  556. undi_code_segoff:
  557. undi_code_size: .word 0
  558. undi_code_segment: .word 0
  559. undi_data_segoff:
  560. undi_data_size: .word 0
  561. undi_data_segment: .word 0
  562. /* The following fields are part of a struct undi_device */
  563. undi_device:
  564. pxenv_segoff:
  565. pxenv_offset: .word 0
  566. pxenv_segment: .word 0
  567. ppxe_segoff:
  568. ppxe_offset: .word 0
  569. ppxe_segment: .word 0
  570. entry_segoff:
  571. entry_offset: .word 0
  572. entry_segment: .word 0
  573. undi_fbms_start: .word 0
  574. undi_fbms_end: .word 0
  575. pci_busdevfn: .word UNDI_NO_PCI_BUSDEVFN
  576. isapnp_csn: .word UNDI_NO_ISAPNP_CSN
  577. isapnp_read_port: .word UNDI_NO_ISAPNP_READ_PORT
  578. pci_vendor: .word 0
  579. pci_device: .word 0
  580. flags:
  581. .word ( UNDI_FL_INITIALIZED | UNDI_FL_STARTED | UNDI_FL_KEEP_ALL )
  582. .equ undi_device_size, ( . - undi_device )
  583. /*****************************************************************************
  584. * Run gPXE main code
  585. *****************************************************************************
  586. */
  587. .section ".prefix"
  588. run_gpxe:
  589. /* Install gPXE */
  590. call install
  591. /* Set up real-mode stack */
  592. movw %bx, %ss
  593. movw $_estack16, %sp
  594. #ifdef PXELOADER_KEEP_UNDI
  595. /* Copy our undi_device structure to the preloaded_undi variable */
  596. movw %bx, %es
  597. movw $preloaded_undi, %di
  598. movw $undi_device, %si
  599. movw $undi_device_size, %cx
  600. rep movsb
  601. #endif
  602. /* Retrieve PXE %ss:esp */
  603. movw pxe_ss, %di
  604. movl pxe_esp, %ebp
  605. /* Jump to .text16 segment with %ds pointing to .data16 */
  606. movw %bx, %ds
  607. pushw %ax
  608. pushw $1f
  609. lret
  610. .section ".text16", "ax", @progbits
  611. 1:
  612. /* Run main program */
  613. pushl $main
  614. pushw %cs
  615. call prot_call
  616. popl %ecx /* discard */
  617. /* Uninstall gPXE */
  618. call uninstall
  619. /* Restore PXE stack */
  620. movw %di, %ss
  621. movl %ebp, %esp
  622. /* Check PXE stack magic */
  623. popl %eax
  624. cmpl $STACK_MAGIC, %eax
  625. jne 1f
  626. /* PXE stack OK: return to caller */
  627. popw %ds
  628. popw %es
  629. popw %fs
  630. popw %gs
  631. popal
  632. popfl
  633. xorw %ax, %ax /* Return success */
  634. lret
  635. 1: /* PXE stack corrupt or removed: use INT 18 */
  636. int $0x18
  637. .previous