選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

romprefix.S 17KB

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