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

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