Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

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