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 21KB

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