Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

romprefix.S 19KB

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