summaryrefslogtreecommitdiff
path: root/gpxe/src/arch/i386/prefix/romprefix.S
diff options
context:
space:
mode:
Diffstat (limited to 'gpxe/src/arch/i386/prefix/romprefix.S')
-rw-r--r--gpxe/src/arch/i386/prefix/romprefix.S191
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