diff options
Diffstat (limited to 'gpxe/src/arch/i386/prefix/romprefix.S')
-rw-r--r-- | gpxe/src/arch/i386/prefix/romprefix.S | 191 |
1 files changed, 143 insertions, 48 deletions
diff --git a/gpxe/src/arch/i386/prefix/romprefix.S b/gpxe/src/arch/i386/prefix/romprefix.S index 727cffcb..f9b9e169 100644 --- a/gpxe/src/arch/i386/prefix/romprefix.S +++ b/gpxe/src/arch/i386/prefix/romprefix.S @@ -8,8 +8,10 @@ #define PNP_SIGNATURE ( '$' + ( 'P' << 8 ) + ( 'n' << 16 ) + ( 'P' << 24 ) ) #define PMM_SIGNATURE ( '$' + ( 'P' << 8 ) + ( 'M' << 16 ) + ( 'M' << 24 ) ) +#define PCI_SIGNATURE ( 'P' + ( 'C' << 8 ) + ( 'I' << 16 ) + ( ' ' << 24 ) ) #define STACK_MAGIC ( 'L' + ( 'R' << 8 ) + ( 'E' << 16 ) + ( 'T' << 24 ) ) #define PNP_GET_BBS_VERSION 0x60 +#define PMM_ALLOCATE 0x0000 .text .code16 @@ -40,25 +42,31 @@ checksum: pciheader: .ascii "PCIR" /* Signature */ - .word pci_vendor_id /* Vendor ID */ - .word pci_device_id /* Device ID */ - .word 0x0000 /* pointer to vital product data */ + .word pci_vendor_id /* Vendor identification */ + .word pci_device_id /* Device identification */ + .word 0x0000 /* Device list pointer */ .word pciheader_len /* PCI data structure length */ - .byte 0x00 /* PCI data structure revision */ - .byte 0x02 /* Device Base Type code */ - .byte 0x00 /* Device Sub-Type code */ - .byte 0x00 /* Device Interface Type code */ -pciheader_size: .word _load_size_sect /* Image length same as offset 02h */ - .word 0x0001 /* revision level of code/data */ - .byte 0x00 /* code type */ - .byte 0x80 /* Flags (last PCI data structure) */ - .word 0x0000 /* reserved */ + .byte 0x03 /* PCI data structure revision */ + .byte 0x02, 0x00, 0x00 /* Class code */ +pciheader_image_length: + .word _load_size_sect /* Image length */ + .word 0x0001 /* Revision level */ + .byte 0x00 /* Code type */ + .byte 0x80 /* Last image indicator */ +pciheader_runtime_length: + .word _load_size_sect /* Maximum run-time image length */ + .word 0x0000 /* Configuration utility code header */ + .word 0x0000 /* DMTF CLP entry point */ .equ pciheader_len, . - pciheader .size pciheader, . - pciheader .section ".zinfo.fixup", "a" /* Compressor fixup information */ .ascii "SUBW" - .long pciheader_size + .long pciheader_image_length + .long 512 + .long 0 + .ascii "SUBW" + .long pciheader_runtime_length .long 512 .long 0 .previous @@ -76,7 +84,7 @@ pnpheader: .byte 0x02 /* Device base type code */ .byte 0x00 /* Device sub-type code */ .byte 0x00 /* Device interface type code */ - .byte 0x54 /* Device indicator */ + .byte 0xf4 /* Device indicator */ .word 0x0000 /* Boot connection vector */ .word 0x0000 /* Disconnect vector */ .word bev_entry /* Boot execution vector */ @@ -104,7 +112,8 @@ prodstr_separator: prodstr_pci_id: .asciz "xx:xx.x)" /* Filled in by init code */ .size prodstr, . - prodstr - + + .globl undiheader undiheader: .ascii "UNDI" /* Signature */ .byte undiheader_len /* Length of structure */ @@ -115,6 +124,7 @@ undiheader: .word _data16_size /* Stack segment size */ .word _data16_size /* Data segment size */ .word _text16_size /* Code segment size */ + .ascii "PCIR" /* Bus type */ .equ undiheader_len, . - undiheader .size undiheader, . - undiheader @@ -131,29 +141,79 @@ init: pushw %ds pushw %es pushw %fs + pushw %gs cld pushw %cs popw %ds pushw $0x40 popw %fs + + /* Shuffle some registers around. We need %di available for + * the print_xxx functions, and in a register that's + * addressable from %es, so shuffle as follows: + * + * %di (pointer to PnP structure) => %bx + * %bx (runtime segment address, for PCI 3.0) => %gs + */ + movw %bx, %gs movw %di, %bx - xorw %di, %di + /* Print message as early as possible */ movw $init_message, %si + xorw %di, %di call print_message call print_pci_busdevfn + /* Fill in product name string, if possible */ movw $prodstr_pci_id, %di call print_pci_busdevfn movb $' ', prodstr_separator + + /* Print segment address */ + movb $' ', %al xorw %di, %di + call print_character + movw %cs, %ax + call print_hex_word + + /* Check for PCI BIOS version */ + pushl %ebx + pushl %edx + pushl %edi + stc + movw $0xb101, %ax + int $0x1a + jc 1f + cmpl $PCI_SIGNATURE, %edx + jne 1f + testb %ah, %ah + jnz 1f + movw $init_message_pci, %si + xorw %di, %di + call print_message + movb %bh, %al + call print_hex_nibble + movb $'.', %al + call print_character + movb %bl, %al + call print_hex_byte + cmpb $3, %bh + jae 2f +1: /* PCI <3.0: set %gs (runtime segment) = %cs (init-time segment) */ + pushw %cs + popw %gs +2: popl %edi + popl %edx + popl %ebx + /* Check for PnP BIOS */ testw $0x0f, %bx /* PnP signature must be aligned - bochs */ - jnz hook_int19 /* uses unalignment to indicate 'fake' PnP. */ + jnz no_bbs /* uses unalignment to indicate 'fake' PnP. */ cmpl $PNP_SIGNATURE, %es:0(%bx) - jne hook_int19 + jne no_bbs /* Is PnP: print PnP message */ movw $init_message_pnp, %si + xorw %di, %di call print_message /* Check for BBS */ pushw %es:0x1b(%bx) /* Real-mode data segment */ @@ -163,22 +223,25 @@ init: lcall *%es:0xd(%bx) addw $8, %sp testw %ax, %ax - jne hook_int19 - movw $init_message_bbs, %si - call print_message - jmp hook_bbs - /* Not BBS-compliant - must hook INT 19 */ -hook_int19: + je got_bbs +no_bbs: /* Not BBS-compliant - must hook INT 19 */ movw $init_message_int19, %si + xorw %di, %di call print_message xorw %ax, %ax movw %ax, %es pushl %es:( 0x19 * 4 ) popl orig_int19 - pushw %cs + pushw %gs /* %gs contains runtime %cs */ pushw $int19_entry popl %es:( 0x19 * 4 ) -hook_bbs: + jmp bbs_done +got_bbs: /* BBS compliant - no need to hook INT 19 */ + movw $init_message_bbs, %si + xorw %di, %di + call print_message +bbs_done: + /* Check for PMM */ movw $( 0xe000 - 1 ), %bx pmm_scan: @@ -196,26 +259,26 @@ pmm_scan: jnz pmm_scan /* PMM found: print PMM message */ movw $init_message_pmm, %si + xorw %di, %di call print_message /* Try to allocate 2MB block via PMM */ pushw $0x0006 /* Aligned, extended memory */ pushl $0xffffffff /* No handle */ pushl $( 0x00200000 / 16 ) /* 2MB in paragraphs */ - pushw $0x0000 /* pmmAllocate */ + pushw $PMM_ALLOCATE lcall *%es:7 addw $12, %sp + movw %dx, %ax + xorw %di, %di + call print_hex_word + movw %dx, ( image_source + 2 ) testw %dx, %dx /* %ax==0 even on success, since align=2MB */ - jnz gotpmm - movw $init_message_pmm_failed, %si - call print_message - jmp no_pmm -gotpmm: /* PMM allocation succeeded: copy ROM to PMM block */ + jz no_pmm + /* PMM allocation succeeded: copy ROM to PMM block */ pushal /* PMM presence implies 1kB stack */ - movw %ax, %es /* %ax=0 already - see above */ - pushw %dx - pushw %ax - popl %edi - movl %edi, image_source + xorw %ax, %ax + movw %ax, %es + movl image_source, %edi xorl %esi, %esi movzbl romheader_size, %ecx shll $9, %ecx @@ -232,8 +295,27 @@ gotpmm: /* PMM allocation succeeded: copy ROM to PMM block */ loop 1b subb %bl, checksum popal -no_pmm: /* Prompt for POST-time shell */ +no_pmm: + + /* Copy self to option ROM space. Required for PCI3.0, which + * loads us to a temporary location in low memory. Will be a + * no-op for lower PCI versions. + */ + movb $' ', %al + xorw %di, %di + call print_character + movw %gs, %ax + call print_hex_word + movzbw romheader_size, %cx + shlw $9, %cx + movw %ax, %es + xorw %si, %si + xorw %di, %di + cs rep movsb + + /* Prompt for POST-time shell */ movw $init_message_prompt, %si + xorw %di, %di call print_message /* Empty the keyboard buffer before waiting for input */ empty_keyboard_buffer: @@ -274,22 +356,30 @@ wait_for_key: pushw %cs call exec no_key_pressed: + /* Print blank lines to terminate messages */ movw $init_message_end, %si + xorw %di, %di call print_message + /* Restore registers */ + popw %gs popw %fs popw %es popw %ds popaw + /* Indicate boot capability to PnP BIOS, if present */ movw $0x20, %ax lret .size init, . - init init_message: - .asciz "gPXE (http://etherboot.org) - PCI " + .asciz "gPXE (http://etherboot.org) - " .size init_message, . - init_message +init_message_pci: + .asciz " PCI" + .size init_message_pci, . - init_message_pci init_message_pnp: .asciz " PnP" .size init_message_pnp, . - init_message_pnp @@ -299,9 +389,6 @@ init_message_bbs: init_message_pmm: .asciz " PMM" .size init_message_pmm, . - init_message_pmm -init_message_pmm_failed: - .asciz "(failed)" - .size init_message_pmm_failed, . - init_message_pmm_failed init_message_int19: .asciz " INT19" .size init_message_int19, . - init_message_int19 @@ -334,6 +421,7 @@ decompress_to: */ bbs_version: .word 0 + .size bbs_version, . - bbs_version /* Boot Execution Vector entry point * @@ -374,9 +462,11 @@ exec: /* Set %ds = %cs */ popw %ds /* Print message as soon as possible */ - movw $exec_message, %si + movw $prodstr, %si xorw %di, %di call print_message + movw $exec_message, %si + call print_message /* Store magic word on BIOS stack and remember BIOS %ss:sp */ pushl $STACK_MAGIC @@ -424,7 +514,7 @@ exec: /* Set %ds = %cs */ .previous exec_message: - .asciz "Entering gPXE\n" + .asciz " starting execution\n" .size exec_message, . - exec_message /* UNDI loader @@ -435,18 +525,22 @@ undiloader: /* Save registers */ pushl %esi pushl %edi + pushw %ds pushw %es pushw %bx + /* ROM segment address to %ds */ + pushw %cs + popw %ds /* UNDI loader parameter structure address into %es:%di */ movw %sp, %bx - movw %ss:12(%bx), %di - movw %ss:14(%bx), %es + movw %ss:18(%bx), %di + movw %ss:20(%bx), %es /* Install to specified real-mode addresses */ pushw %di movw %es:12(%di), %bx movw %es:14(%di), %ax - movl %cs:image_source, %esi - movl %cs:decompress_to, %edi + movl image_source, %esi + movl decompress_to, %edi call install_prealloc popw %di /* Call UNDI loader C code */ @@ -461,6 +555,7 @@ undiloader: /* Restore registers and return */ popw %bx popw %es + popw %ds popl %edi popl %esi lret |