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.

romprefix.S 19KB

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