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

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