Du kannst nicht mehr als 25 Themen auswählen Themen müssen mit entweder einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

romprefix.S 17KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753
  1. /* At entry, the processor is in 16 bit real mode and the code is being
  2. * executed from an address it was not linked to. Code must be pic and
  3. * 32 bit sensitive until things are fixed up.
  4. *
  5. * Also be very careful as the stack is at the rear end of the interrupt
  6. * table so using a noticeable amount of stack space is a no-no.
  7. */
  8. FILE_LICENCE ( GPL2_OR_LATER )
  9. #include <config/general.h>
  10. #define PNP_SIGNATURE ( '$' + ( 'P' << 8 ) + ( 'n' << 16 ) + ( 'P' << 24 ) )
  11. #define PMM_SIGNATURE ( '$' + ( 'P' << 8 ) + ( 'M' << 16 ) + ( 'M' << 24 ) )
  12. #define PCI_SIGNATURE ( 'P' + ( 'C' << 8 ) + ( 'I' << 16 ) + ( ' ' << 24 ) )
  13. #define STACK_MAGIC ( 'L' + ( 'R' << 8 ) + ( 'E' << 16 ) + ( 'T' << 24 ) )
  14. #define PNP_GET_BBS_VERSION 0x60
  15. #define PMM_ALLOCATE 0x0000
  16. #define PMM_DEALLOCATE 0x0002
  17. /* ROM banner timeout. Based on the configurable BANNER_TIMEOUT in
  18. * config.h, but converted to a number of (18Hz) timer ticks, and
  19. * doubled to allow for BIOSes that switch video modes immediately
  20. * beforehand, so rendering the message almost invisible to the user.
  21. */
  22. #define ROM_BANNER_TIMEOUT ( 2 * ( 18 * BANNER_TIMEOUT ) / 10 )
  23. .text
  24. .code16
  25. .arch i386
  26. .section ".prefix", "ax", @progbits
  27. .org 0x00
  28. romheader:
  29. .word 0xAA55 /* BIOS extension signature */
  30. romheader_size: .byte 0 /* Size in 512-byte blocks */
  31. jmp init /* Initialisation vector */
  32. checksum:
  33. .byte 0
  34. .org 0x16
  35. .word undiheader
  36. .org 0x18
  37. .word pciheader
  38. .org 0x1a
  39. .word pnpheader
  40. .size romheader, . - romheader
  41. .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */
  42. .ascii "ADDB"
  43. .long romheader_size
  44. .long 512
  45. .long 0
  46. .previous
  47. pciheader:
  48. .ascii "PCIR" /* Signature */
  49. .word pci_vendor_id /* Vendor identification */
  50. .word pci_device_id /* Device identification */
  51. .word 0x0000 /* Device list pointer */
  52. .word pciheader_len /* PCI data structure length */
  53. .byte 0x03 /* PCI data structure revision */
  54. .byte 0x02, 0x00, 0x00 /* Class code */
  55. pciheader_image_length:
  56. .word 0 /* Image length */
  57. .word 0x0001 /* Revision level */
  58. .byte 0x00 /* Code type */
  59. .byte 0x80 /* Last image indicator */
  60. pciheader_runtime_length:
  61. .word 0 /* Maximum run-time image length */
  62. .word 0x0000 /* Configuration utility code header */
  63. .word 0x0000 /* DMTF CLP entry point */
  64. .equ pciheader_len, . - pciheader
  65. .size pciheader, . - pciheader
  66. .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */
  67. .ascii "ADDW"
  68. .long pciheader_image_length
  69. .long 512
  70. .long 0
  71. .ascii "ADDW"
  72. .long pciheader_runtime_length
  73. .long 512
  74. .long 0
  75. .previous
  76. pnpheader:
  77. .ascii "$PnP" /* Signature */
  78. .byte 0x01 /* Structure revision */
  79. .byte ( pnpheader_len / 16 ) /* Length (in 16 byte increments) */
  80. .word 0x0000 /* Offset of next header */
  81. .byte 0x00 /* Reserved */
  82. .byte 0x00 /* Checksum */
  83. .long 0x00000000 /* Device identifier */
  84. .word mfgstr /* Manufacturer string */
  85. .word prodstr /* Product name */
  86. .byte 0x02 /* Device base type code */
  87. .byte 0x00 /* Device sub-type code */
  88. .byte 0x00 /* Device interface type code */
  89. .byte 0xf4 /* Device indicator */
  90. .word 0x0000 /* Boot connection vector */
  91. .word 0x0000 /* Disconnect vector */
  92. .word bev_entry /* Boot execution vector */
  93. .word 0x0000 /* Reserved */
  94. .word 0x0000 /* Static resource information vector*/
  95. .equ pnpheader_len, . - pnpheader
  96. .size pnpheader, . - pnpheader
  97. /* Manufacturer string */
  98. mfgstr:
  99. .asciz "http://etherboot.org"
  100. .size mfgstr, . - mfgstr
  101. /* Product string
  102. *
  103. * Defaults to PRODUCT_SHORT_NAME. If the ROM image is writable at
  104. * initialisation time, it will be filled in to include the PCI
  105. * bus:dev.fn number of the card as well.
  106. */
  107. prodstr:
  108. .ascii PRODUCT_SHORT_NAME
  109. prodstr_separator:
  110. .byte 0
  111. .ascii "(PCI "
  112. prodstr_pci_id:
  113. .asciz "xx:xx.x)" /* Filled in by init code */
  114. .size prodstr, . - prodstr
  115. .globl undiheader
  116. undiheader:
  117. .ascii "UNDI" /* Signature */
  118. .byte undiheader_len /* Length of structure */
  119. .byte 0 /* Checksum */
  120. .byte 0 /* Structure revision */
  121. .byte 0,1,2 /* PXE version: 2.1.0 */
  122. .word undiloader /* Offset to loader routine */
  123. .word _data16_memsz /* Stack segment size */
  124. .word _data16_memsz /* Data segment size */
  125. .word _text16_memsz /* Code segment size */
  126. .ascii "PCIR" /* Bus type */
  127. .equ undiheader_len, . - undiheader
  128. .size undiheader, . - undiheader
  129. /* Initialisation (called once during POST)
  130. *
  131. * Determine whether or not this is a PnP system via a signature
  132. * check. If it is PnP, return to the PnP BIOS indicating that we are
  133. * a boot-capable device; the BIOS will call our boot execution vector
  134. * if it wants to boot us. If it is not PnP, hook INT 19.
  135. */
  136. init:
  137. /* Preserve registers, clear direction flag, set %ds=%cs */
  138. pushaw
  139. pushw %ds
  140. pushw %es
  141. pushw %fs
  142. pushw %gs
  143. cld
  144. pushw %cs
  145. popw %ds
  146. /* Shuffle some registers around. We need %di available for
  147. * the print_xxx functions, and in a register that's
  148. * addressable from %es, so shuffle as follows:
  149. *
  150. * %di (pointer to PnP structure) => %bx
  151. * %bx (runtime segment address, for PCI 3.0) => %gs
  152. */
  153. movw %bx, %gs
  154. movw %di, %bx
  155. /* Print message as early as possible */
  156. movw $init_message, %si
  157. xorw %di, %di
  158. call print_message
  159. call print_pci_busdevfn
  160. /* Fill in product name string, if possible */
  161. movw $prodstr_pci_id, %di
  162. call print_pci_busdevfn
  163. movb $( ' ' ), prodstr_separator
  164. /* Print segment address */
  165. movb $( ' ' ), %al
  166. xorw %di, %di
  167. call print_character
  168. movw %cs, %ax
  169. call print_hex_word
  170. /* Check for PCI BIOS version */
  171. pushl %ebx
  172. pushl %edx
  173. pushl %edi
  174. stc
  175. movw $0xb101, %ax
  176. int $0x1a
  177. jc no_pci3
  178. cmpl $PCI_SIGNATURE, %edx
  179. jne no_pci3
  180. testb %ah, %ah
  181. jnz no_pci3
  182. movw $init_message_pci, %si
  183. xorw %di, %di
  184. call print_message
  185. movb %bh, %al
  186. call print_hex_nibble
  187. movb $( '.' ), %al
  188. call print_character
  189. movb %bl, %al
  190. call print_hex_byte
  191. cmpb $3, %bh
  192. jb no_pci3
  193. /* PCI >=3.0: leave %gs as-is if sane */
  194. movw %gs, %ax
  195. cmpw $0xa000, %ax /* Insane if %gs < 0xa000 */
  196. jb pci3_insane
  197. movw %cs, %bx /* Sane if %cs == %gs */
  198. cmpw %bx, %ax
  199. je 1f
  200. movzbw romheader_size, %cx /* Sane if %cs+len <= %gs */
  201. shlw $5, %cx
  202. addw %cx, %bx
  203. cmpw %bx, %ax
  204. jae 1f
  205. movw %cs, %bx /* Sane if %gs+len <= %cs */
  206. addw %cx, %ax
  207. cmpw %bx, %ax
  208. jbe 1f
  209. pci3_insane: /* PCI 3.0 with insane %gs value: print error and ignore %gs */
  210. movb $( '!' ), %al
  211. call print_character
  212. movw %gs, %ax
  213. call print_hex_word
  214. no_pci3:
  215. /* PCI <3.0: set %gs (runtime segment) = %cs (init-time segment) */
  216. pushw %cs
  217. popw %gs
  218. 1: popl %edi
  219. popl %edx
  220. popl %ebx
  221. /* Check for PnP BIOS. Although %es:di should point to the
  222. * PnP BIOS signature on entry, some BIOSes fail to do this.
  223. */
  224. movw $( 0xf000 - 1 ), %bx
  225. pnp_scan:
  226. incw %bx
  227. jz no_pnp
  228. movw %bx, %es
  229. cmpl $PNP_SIGNATURE, %es:0
  230. jne pnp_scan
  231. xorw %dx, %dx
  232. xorw %si, %si
  233. movzbw %es:5, %cx
  234. 1: es lodsb
  235. addb %al, %dl
  236. loop 1b
  237. jnz pnp_scan
  238. /* Is PnP: print PnP message */
  239. movw $init_message_pnp, %si
  240. xorw %di, %di
  241. call print_message
  242. /* Check for BBS */
  243. pushw %es:0x1b /* Real-mode data segment */
  244. pushw %ds /* &(bbs_version) */
  245. pushw $bbs_version
  246. pushw $PNP_GET_BBS_VERSION
  247. lcall *%es:0xd
  248. addw $8, %sp
  249. testw %ax, %ax
  250. je got_bbs
  251. no_pnp: /* Not PnP-compliant - therefore cannot be BBS-compliant */
  252. no_bbs: /* Not BBS-compliant - must hook INT 19 */
  253. movw $init_message_int19, %si
  254. xorw %di, %di
  255. call print_message
  256. xorw %ax, %ax
  257. movw %ax, %es
  258. pushl %es:( 0x19 * 4 )
  259. popl orig_int19
  260. pushw %gs /* %gs contains runtime %cs */
  261. pushw $int19_entry
  262. popl %es:( 0x19 * 4 )
  263. jmp bbs_done
  264. got_bbs: /* BBS compliant - no need to hook INT 19 */
  265. movw $init_message_bbs, %si
  266. xorw %di, %di
  267. call print_message
  268. bbs_done:
  269. /* Check for PMM */
  270. movw $( 0xe000 - 1 ), %bx
  271. pmm_scan:
  272. incw %bx
  273. jz no_pmm
  274. movw %bx, %es
  275. cmpl $PMM_SIGNATURE, %es:0
  276. jne pmm_scan
  277. xorw %dx, %dx
  278. xorw %si, %si
  279. movzbw %es:5, %cx
  280. 1: es lodsb
  281. addb %al, %dl
  282. loop 1b
  283. jnz pmm_scan
  284. /* PMM found: print PMM message */
  285. movw $init_message_pmm, %si
  286. xorw %di, %di
  287. call print_message
  288. /* We have PMM and so a 1kB stack: preserve upper register halves */
  289. pushal
  290. /* Calculate required allocation size in %esi */
  291. movzbl romheader_size, %eax
  292. shll $9, %eax
  293. addl $_textdata_memsz, %eax
  294. orw $0xffff, %ax /* Ensure allocation size is at least 64kB */
  295. bsrl %eax, %ecx
  296. subw $15, %cx /* Round up and convert to 64kB count */
  297. movw $1, %si
  298. shlw %cl, %si
  299. pmm_loop:
  300. /* Try to allocate block via PMM */
  301. pushw $0x0006 /* Aligned, extended memory */
  302. pushl $0xffffffff /* No handle */
  303. movzwl %si, %eax
  304. shll $12, %eax
  305. pushl %eax /* Allocation size in paragraphs */
  306. pushw $PMM_ALLOCATE
  307. lcall *%es:7
  308. addw $12, %sp
  309. /* Abort if allocation fails */
  310. testw %dx, %dx /* %ax==0 even on success, since align>=64kB */
  311. jz pmm_fail
  312. /* If block has A20==1, free block and try again with twice
  313. * the allocation size (and hence alignment).
  314. */
  315. testw $0x0010, %dx
  316. jz got_pmm
  317. pushw %dx
  318. pushw $0
  319. pushw $PMM_DEALLOCATE
  320. lcall *%es:7
  321. addw $6, %sp
  322. addw %si, %si
  323. jmp pmm_loop
  324. got_pmm: /* PMM allocation succeeded */
  325. movw %dx, ( image_source + 2 )
  326. movw %dx, %ax
  327. xorw %di, %di
  328. call print_hex_word
  329. movb $( '@' ), %al
  330. call print_character
  331. movw %si, %ax
  332. call print_hex_byte
  333. pmm_copy:
  334. /* Copy ROM to PMM block */
  335. xorw %ax, %ax
  336. movw %ax, %es
  337. movl image_source, %edi
  338. xorl %esi, %esi
  339. movzbl romheader_size, %ecx
  340. shll $9, %ecx
  341. addr32 rep movsb /* PMM presence implies flat real mode */
  342. movl %edi, decompress_to
  343. /* Shrink ROM */
  344. movb $_prefix_memsz_sect, romheader_size
  345. #ifdef SHRINK_WITHOUT_PMM
  346. jmp pmm_done
  347. pmm_fail:
  348. /* Print marker and copy ourselves to high memory */
  349. movl $HIGHMEM_LOADPOINT, image_source
  350. xorw %di, %di
  351. movb $( '!' ), %al
  352. call print_character
  353. jmp pmm_copy
  354. pmm_done:
  355. #else
  356. pmm_fail:
  357. #endif
  358. /* Restore upper register halves */
  359. popal
  360. no_pmm:
  361. /* Update checksum */
  362. xorw %bx, %bx
  363. xorw %si, %si
  364. movzbw romheader_size, %cx
  365. shlw $9, %cx
  366. 1: lodsb
  367. addb %al, %bl
  368. loop 1b
  369. subb %bl, checksum
  370. /* Copy self to option ROM space. Required for PCI3.0, which
  371. * loads us to a temporary location in low memory. Will be a
  372. * no-op for lower PCI versions.
  373. */
  374. movb $( ' ' ), %al
  375. xorw %di, %di
  376. call print_character
  377. movw %gs, %ax
  378. call print_hex_word
  379. movzbw romheader_size, %cx
  380. shlw $9, %cx
  381. movw %ax, %es
  382. xorw %si, %si
  383. xorw %di, %di
  384. cs rep movsb
  385. /* Prompt for POST-time shell */
  386. movw $init_message_prompt, %si
  387. xorw %di, %di
  388. call print_message
  389. movw $prodstr, %si
  390. call print_message
  391. movw $init_message_dots, %si
  392. call print_message
  393. /* Wait for Ctrl-B */
  394. movw $0xff02, %bx
  395. call wait_for_key
  396. /* Clear prompt */
  397. pushf
  398. xorw %di, %di
  399. call print_kill_line
  400. movw $init_message_done, %si
  401. call print_message
  402. popf
  403. jnz 2f
  404. /* Ctrl-B was pressed: invoke gPXE. The keypress will be
  405. * picked up by the initial shell prompt, and we will drop
  406. * into a shell.
  407. */
  408. pushw %cs
  409. call exec
  410. 2:
  411. /* Restore registers */
  412. popw %gs
  413. popw %fs
  414. popw %es
  415. popw %ds
  416. popaw
  417. /* Indicate boot capability to PnP BIOS, if present */
  418. movw $0x20, %ax
  419. lret
  420. .size init, . - init
  421. /*
  422. * Note to hardware vendors:
  423. *
  424. * If you wish to brand this boot ROM, please do so by defining the
  425. * strings PRODUCT_NAME and PRODUCT_SHORT_NAME in config/general.h.
  426. *
  427. * While nothing in the GPL prevents you from removing all references
  428. * to gPXE or http://etherboot.org, we prefer you not to do so.
  429. *
  430. * If you have an OEM-mandated branding requirement that cannot be
  431. * satisfied simply by defining PRODUCT_NAME and PRODUCT_SHORT_NAME,
  432. * please contact us.
  433. *
  434. * [ Including an ASCII NUL in PRODUCT_NAME is considered to be
  435. * bypassing the spirit of this request! ]
  436. */
  437. init_message:
  438. .ascii "\n"
  439. .ascii PRODUCT_NAME
  440. .ascii "\n"
  441. .asciz "gPXE (http://etherboot.org) - "
  442. .size init_message, . - init_message
  443. init_message_pci:
  444. .asciz " PCI"
  445. .size init_message_pci, . - init_message_pci
  446. init_message_pnp:
  447. .asciz " PnP"
  448. .size init_message_pnp, . - init_message_pnp
  449. init_message_bbs:
  450. .asciz " BBS"
  451. .size init_message_bbs, . - init_message_bbs
  452. init_message_pmm:
  453. .asciz " PMM"
  454. .size init_message_pmm, . - init_message_pmm
  455. init_message_int19:
  456. .asciz " INT19"
  457. .size init_message_int19, . - init_message_int19
  458. init_message_prompt:
  459. .asciz "\nPress Ctrl-B to configure "
  460. .size init_message_prompt, . - init_message_prompt
  461. init_message_dots:
  462. .asciz "..."
  463. .size init_message_dots, . - init_message_dots
  464. init_message_done:
  465. .asciz "\n\n"
  466. .size init_message_done, . - init_message_done
  467. /* ROM image location
  468. *
  469. * May be either within option ROM space, or within PMM-allocated block.
  470. */
  471. image_source:
  472. .long 0
  473. .size image_source, . - image_source
  474. /* Temporary decompression area
  475. *
  476. * May be either at HIGHMEM_LOADPOINT, or within PMM-allocated block.
  477. */
  478. decompress_to:
  479. .long HIGHMEM_LOADPOINT
  480. .size decompress_to, . - decompress_to
  481. /* BBS version
  482. *
  483. * Filled in by BBS BIOS. We ignore the value.
  484. */
  485. bbs_version:
  486. .word 0
  487. .size bbs_version, . - bbs_version
  488. /* Boot Execution Vector entry point
  489. *
  490. * Called by the PnP BIOS when it wants to boot us.
  491. */
  492. bev_entry:
  493. pushw %cs
  494. call exec
  495. lret
  496. .size bev_entry, . - bev_entry
  497. /* INT19 entry point
  498. *
  499. * Called via the hooked INT 19 if we detected a non-PnP BIOS. We
  500. * attempt to return via the original INT 19 vector (if we were able
  501. * to store it).
  502. */
  503. int19_entry:
  504. pushw %cs
  505. popw %ds
  506. /* Prompt user to press B to boot */
  507. movw $int19_message_prompt, %si
  508. xorw %di, %di
  509. call print_message
  510. movw $prodstr, %si
  511. call print_message
  512. movw $int19_message_dots, %si
  513. call print_message
  514. movw $0xdf4e, %bx
  515. call wait_for_key
  516. pushf
  517. xorw %di, %di
  518. call print_kill_line
  519. movw $int19_message_done, %si
  520. call print_message
  521. popf
  522. jz 1f
  523. /* Leave keypress in buffer and start gPXE. The keypress will
  524. * cause the usual initial Ctrl-B prompt to be skipped.
  525. */
  526. pushw %cs
  527. call exec
  528. 1: /* Try to call original INT 19 vector */
  529. movl %cs:orig_int19, %eax
  530. testl %eax, %eax
  531. je 2f
  532. ljmp *%cs:orig_int19
  533. 2: /* No chained vector: issue INT 18 as a last resort */
  534. int $0x18
  535. .size int19_entry, . - int19_entry
  536. orig_int19:
  537. .long 0
  538. .size orig_int19, . - orig_int19
  539. int19_message_prompt:
  540. .asciz "Press N to skip booting from "
  541. .size int19_message_prompt, . - int19_message_prompt
  542. int19_message_dots:
  543. .asciz "..."
  544. .size int19_message_dots, . - int19_message_dots
  545. int19_message_done:
  546. .asciz "\n\n"
  547. .size int19_message_done, . - int19_message_done
  548. /* Execute as a boot device
  549. *
  550. */
  551. exec: /* Set %ds = %cs */
  552. pushw %cs
  553. popw %ds
  554. /* Print message as soon as possible */
  555. movw $prodstr, %si
  556. xorw %di, %di
  557. call print_message
  558. movw $exec_message, %si
  559. call print_message
  560. /* Store magic word on BIOS stack and remember BIOS %ss:sp */
  561. pushl $STACK_MAGIC
  562. movw %ss, %dx
  563. movw %sp, %bp
  564. /* Obtain a reasonably-sized temporary stack */
  565. xorw %ax, %ax
  566. movw %ax, %ss
  567. movw $0x7c00, %sp
  568. /* Install gPXE */
  569. movl image_source, %esi
  570. movl decompress_to, %edi
  571. call alloc_basemem
  572. call install_prealloc
  573. /* Set up real-mode stack */
  574. movw %bx, %ss
  575. movw $_estack16, %sp
  576. /* Jump to .text16 segment */
  577. pushw %ax
  578. pushw $1f
  579. lret
  580. .section ".text16", "awx", @progbits
  581. 1: /* Call main() */
  582. pushl $main
  583. pushw %cs
  584. call prot_call
  585. popl %ecx /* discard */
  586. /* Uninstall gPXE */
  587. call uninstall
  588. /* Restore BIOS stack */
  589. movw %dx, %ss
  590. movw %bp, %sp
  591. /* Check magic word on BIOS stack */
  592. popl %eax
  593. cmpl $STACK_MAGIC, %eax
  594. jne 1f
  595. /* BIOS stack OK: return to caller */
  596. lret
  597. 1: /* BIOS stack corrupt: use INT 18 */
  598. int $0x18
  599. .previous
  600. exec_message:
  601. .asciz " starting execution\n"
  602. .size exec_message, . - exec_message
  603. /* UNDI loader
  604. *
  605. * Called by an external program to load our PXE stack.
  606. */
  607. undiloader:
  608. /* Save registers */
  609. pushl %esi
  610. pushl %edi
  611. pushw %ds
  612. pushw %es
  613. pushw %bx
  614. /* ROM segment address to %ds */
  615. pushw %cs
  616. popw %ds
  617. /* UNDI loader parameter structure address into %es:%di */
  618. movw %sp, %bx
  619. movw %ss:18(%bx), %di
  620. movw %ss:20(%bx), %es
  621. /* Install to specified real-mode addresses */
  622. pushw %di
  623. movw %es:12(%di), %bx
  624. movw %es:14(%di), %ax
  625. movl image_source, %esi
  626. movl decompress_to, %edi
  627. call install_prealloc
  628. popw %di
  629. /* Call UNDI loader C code */
  630. pushl $pxe_loader_call
  631. pushw %cs
  632. pushw $1f
  633. pushw %ax
  634. pushw $prot_call
  635. lret
  636. 1: popw %bx /* discard */
  637. popw %bx /* discard */
  638. /* Restore registers and return */
  639. popw %bx
  640. popw %es
  641. popw %ds
  642. popl %edi
  643. popl %esi
  644. lret
  645. .size undiloader, . - undiloader
  646. /* Wait for key press specified by %bl (masked by %bh)
  647. *
  648. * Used by init and INT19 code when prompting user. If the specified
  649. * key is pressed, it is left in the keyboard buffer.
  650. *
  651. * Returns with ZF set iff specified key is pressed.
  652. */
  653. wait_for_key:
  654. /* Preserve registers */
  655. pushw %cx
  656. pushw %ax
  657. 1: /* Empty the keyboard buffer before waiting for input */
  658. movb $0x01, %ah
  659. int $0x16
  660. jz 2f
  661. xorw %ax, %ax
  662. int $0x16
  663. jmp 1b
  664. 2: /* Wait for a key press */
  665. movw $ROM_BANNER_TIMEOUT, %cx
  666. 3: decw %cx
  667. js 99f /* Exit with ZF clear */
  668. /* Wait for timer tick to be updated */
  669. call wait_for_tick
  670. /* Check to see if a key was pressed */
  671. movb $0x01, %ah
  672. int $0x16
  673. jz 3b
  674. /* Check to see if key was the specified key */
  675. andb %bh, %al
  676. cmpb %al, %bl
  677. je 99f /* Exit with ZF set */
  678. /* Not the specified key: remove from buffer and stop waiting */
  679. pushfw
  680. xorw %ax, %ax
  681. int $0x16
  682. popfw /* Exit with ZF clear */
  683. 99: /* Restore registers and return */
  684. popw %ax
  685. popw %cx
  686. ret
  687. .size wait_for_key, . - wait_for_key
  688. /* Wait for timer tick
  689. *
  690. * Used by wait_for_key
  691. */
  692. wait_for_tick:
  693. pushl %eax
  694. pushw %fs
  695. movw $0x40, %ax
  696. movw %ax, %fs
  697. movl %fs:(0x6c), %eax
  698. 1: pushf
  699. sti
  700. hlt
  701. popf
  702. cmpl %fs:(0x6c), %eax
  703. je 1b
  704. popw %fs
  705. popl %eax
  706. ret
  707. .size wait_for_tick, . - wait_for_tick