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