2
0
mirror of https://github.com/xcat2/xNBA.git synced 2024-12-14 07:11:32 +00:00

Cut out almost all the optional code paths, drastically simplifying the

flow of control through this code.

We now always add PCI and PnP headers even for ISA ROMs; there's no harm
in doing so.

UNDI loader is still missing.
This commit is contained in:
Michael Brown 2006-06-06 15:33:39 +00:00
parent e7eca7b7cb
commit ef37f78cbe

View File

@ -6,412 +6,180 @@
* table so using a noticeable amount of stack space is a no-no.
*/
/* Define DELAYED_INT when NO_DELAYED_INT is not defined.
* This allows positive tests instead of tests that contain
* double negatives, and become confusing.
*/
#ifndef NO_DELAYED_INT
#define DELAYED_INT
#endif
/* We need some unique magic ID, if we defer startup thru the INT18H or INT19H
* handler. This way, we can check if we have already been installed.
*/
#ifndef MAGIC
#define MAGIC 0xE44C
#endif
/* Hook into INT18H or INT19H handler */
#ifdef BOOT_INT18H
#define BOOT_INT 0x18
#else
#define BOOT_INT 0x19
#endif
#define BOOT_INT_VEC BOOT_INT*4
#define SCRATCHVEC 0x300
/* Prefix exit codes. We store these on the stack so that we will
* know how to return control to the BIOS when Etherboot exits.
*/
#define EXIT_VIA_LRET 0x0
#define EXIT_VIA_INT_18 0x1
#define EXIT_VIA_BOOT_INT 0x2
.text
.code16
.arch i386
.org 0
.section ".prefix", "ax", @progbits
_prefix:
.word 0xAA55 /* BIOS extension signature */
size: .byte 0 /* number of 512 byte blocks */
/* = number of 256 word blocks */
/* filled in by makerom program */
jmp over /* skip over checksum */
.byte 0 /* checksum */
jmp legacyentry /* alternate entry point +6 */
/* used by mknbi-rom */
#ifdef PCI_PNP_HEADER
mfgstr:
.asciz "Etherboot"
#ifdef PXE_EXPORT
.org 0x00
romheader:
.word 0xAA55 /* BIOS extension signature */
.byte _rom_size /* Size in 512-byte blocks */
jmp init_vector /* Initialisation vector */
.org 0x16
.word UNDIROMID - _prefix
#endif /* PXE_EXPORT */
.word undiheader
.org 0x18
.word PCI - _prefix
.word PnP - _prefix
.word pciheader
.org 0x1a
.word pnpheader
.size romheader, . - romheader
PCI:
.ascii "PCIR"
.word 0x0000 /* vendor ID, filled in by makerom */
.word 0x0000 /* device ID, filled in by makerom */
.word 0x0000 /* pointer to vital product data */
.word 0x0018 /* 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 */
.word 0x0000 /* Image length same as offset 02h */
.word 0x0001 /* revision level of code/data */
.byte 0x00 /* code type */
.byte 0x80 /* indicator (last PCI data structure) */
.word 0x0000 /* reserved */
pciheader:
.ascii "PCIR" /* Signature */
.word pci_vendor_id /* Vendor ID */
.word pci_device_id /* Device ID */
.word 0x0000 /* pointer to vital product data */
.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 */
.word _rom_size /* 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 */
.equ pciheader_len, . - pciheader
.size pciheader, . - pciheader
PnP:
.ascii "$PnP"
.byte 0x01 /* structure revision */
.byte 0x02 /* length (in 16 byte increments) */
.word 0x0000 /* offset of next header */
.byte 0x00 /* Reserved */
.byte 0x00 /* checksum filled by makerom */
.long 0x00000000 /* Device identifier */
.word mfgstr - _prefix
.word 0x0 /* pointer to product name */
/* filled by makerom */
.byte 0x02 /* Device Base Type code */
.byte 0x00 /* Device Sub-Type code */
.byte 0x00 /* Device Interface Type code */
.byte 0x14 /* device indicator */
.word 0x0000 /* boot connection vector */
.word 0x0000 /* disconnect vector */
.word pnpentry - _prefix
.word 0x0000 /* reserved */
.word 0x0000 /* static resource information vector */
#ifdef PXE_EXPORT
UNDIROMID:
.ascii "UNDI"
.byte UNDIROMID_end - UNDIROMID /* length of structure */
pnpheader:
.ascii "$PnP" /* Signature */
.byte 0x01 /* Structure revision */
.byte ( pnpheader_len / 16 ) /* Length (in 16 byte increments) */
.word 0x0000 /* Offset of next header */
.byte 0x00 /* Reserved */
.byte 0x00 /* Checksum */
.long 0x00000000 /* Device identifier */
.word mfgstr /* Manufacturer string */
.word prodstr /* Product name */
.byte 0x02 /* Device base type code */
.byte 0x00 /* Device sub-type code */
.byte 0x00 /* Device interface type code */
.byte 0x54 /* Device indicator */
.word 0x0000 /* Boot connection vector */
.word 0x0000 /* Disconnect vector */
.word exec_vector /* Boot execution vector */
.word 0x0000 /* Reserved */
.word 0x0000 /* Static resource information vector*/
.equ pnpheader_len, . - pnpheader
.size pnpheader, . - pnpheader
mfgstr:
.asciz "http://etherboot.org"
.size mfgstr, . - mfgstr
prodstr:
.asciz "Etherboot"
.size prodstr, . - prodstr
undiheader:
.ascii "UNDI" /* Signature */
.byte undiheader_len /* Length of structure */
.byte 0 /* Checksum */
.byte 0 /* Structure revision */
.byte 0,1,2 /* PXE version 2.1.0 */
.word UNDILoader - _prefix /* Offset to loader routine */
.word _real_mode_stack_size /* Stack segment size */
.word _real_mode_stack_size /* Data segment size */
.word _pxe_stack_size /* Code segment size */
.ascii "PCIR"
.byte 0,1,2 /* PXE version: 2.1.0 */
.word undiloader /* Offset to loader routine */
.word _data16_size /* Stack segment size */
.word _data16_size /* Data segment size */
.word _text16_size /* Code segment size */
.equ undiheader_len, . - undiheader
.size undiheader, . - undiheader
/* The code segment contains our pxe_stack_t plus the PXE and
* RM callback interfaces. We don't actually use a data
* segment, but we put a nonzero value here to avoid confusing
* things. 16k of stack space should be enough.
*
* When we claim our own memory, we fill out the data segment
* with the address and size of the real-mode stack, so that
* NBPs will free that area of memory for us. When the UNDI
* loader is used to initialise us, we will never need a
* real-mode stack because we will only ever be called via the
* PXE API, hence our stack is already in base memory.
*/
.equ UNDICodeSize, _pxe_stack_size
.equ UNDIDataSize, _real_mode_stack_size
.equ UNDIStackSize, _real_mode_stack_size
UNDIROMID_end:
#endif /* PXE_EXPORT */
#endif /* PCI_PNP_HEADER */
/*
* Explicitly specify DI is wrt ES to avoid problems with some BIOSes
* Discovered by Eric Biederman
* In addition, some BIOSes don't point DI to the string $PnP so
* we need another #define to take care of that.
/* Initialisation vector
*
* Determine whether or not this is a PnP system via a signature
* check. If it is PnP, return to the PnP BIOS indicating that we are
* a boot-capable device; the BIOS will call our boot execution vector
* if it wants to boot us. If it is not PnP, hook INT 19.
*/
over:
#ifdef DEBUG_ROMPREFIX
call print_bcv
#endif
/* Omit this test for ISA cards anyway */
#ifdef PCI_PNP_HEADER
/* Accept old name too for backward compatibility */
#if !defined(BBS_BUT_NOT_PNP_COMPLIANT) && !defined(PNP_BUT_NOT_BBS_COMPLIANT)
cmpw $'$'+'P'*256,%es:0(%di)
init_vector:
pushw %si
cmpw $'$'+'P'*256, %es:0(%di)
jne notpnp
cmpw $'n'+'P'*256,%es:2(%di)
cmpw $'n'+'P'*256, %es:2(%di)
jne notpnp
#endif /* BBS_BUT_NOT_PNP_COMPLIANT */
movw $0x20,%ax
lret
#endif /* PCI_PNP_HEADER */
ispnp:
movw $ispnp_message, %si
jmp 99f
notpnp:
#ifdef DEBUG_ROMPREFIX
call print_notpnp
#endif
#ifdef DELAYED_INT
pushw %ax
pushw %ds
xorw %ax,%ax
movw %ax,%ds /* access first 64kB segment */
movw SCRATCHVEC+4, %ax /* check if already installed */
cmpw $MAGIC, %ax /* check magic word */
jz installed
movw BOOT_INT_VEC, %ax /* hook into INT18H or INT19H */
movw %ax, SCRATCHVEC
movw BOOT_INT_VEC+2, %ax
movw %ax, SCRATCHVEC+2
movw $start_int - _prefix, %ax
movw %ax, BOOT_INT_VEC
movw %cs,%ax
movw %ax, BOOT_INT_VEC+2
movw $MAGIC, %ax /* set magic word */
movw %ax, SCRATCHVEC+4
#ifdef DEBUG_ROMPREFIX
call print_installed
#endif
installed:
pushw $0
popw %ds
popw %ax
movw $0x20,%ax
lret
start_int: /* clobber magic id, so that we will */
#ifdef DEBUG_ROMPREFIX
call print_start_int
#endif
xorw %ax,%ax /* not inadvertendly end up in an */
movw %ax,%ds /* endless loop */
movw %ax, SCRATCHVEC+4
movw SCRATCHVEC+2, %ax /* restore original INT19h handler */
movw %ax, BOOT_INT_VEC+2
movw SCRATCHVEC, %ax
movw %ax, BOOT_INT_VEC
pushl %eax /* padding */
pushw $EXIT_VIA_BOOT_INT
jmp invoke
#endif /* DELAYED_INT */
legacyentry:
#ifdef DEBUG_ROMPREFIX
call print_legacyentry
#endif
pushw $EXIT_VIA_LRET
jmp invoke
#ifdef PCI_PNP_HEADER
pnpentry:
#ifdef DEBUG_ROMPREFIX
call print_bev
#endif
pushl %eax /* padding */
pushw $EXIT_VIA_INT_18
jmp invoke
#endif /* PCI_PNP_HEADER */
invoke:
/* Store ROM segment and size on stack */
pushw %ax
pushw %ds
pushw %cs
movzbw %cs:(size-_prefix), %ax
shlw $9, %ax /* 512-byte blocks */
pushw %ax
/* Relocate to free base memory, switch stacks */
pushw $12 /* Preserve exit code & far ret addr */
call prelocate
/* We are now running in RAM */
popw %ax /* padding */
movw %cs, %ax
movw %ax, %ds
popw %ds:(_prefix_rom+2) /* ROM size */
popw %ds:(_prefix_rom+0) /* ROM segment */
popw %ds /* Original %ds */
popw %ax /* Original %ax */
pushw %ax /* 4-byte alignment */
pushl $8 /* Preserve exit code & far ret addr */
pushw $0 /* Set null return address */
jmp _start
.section ".text16", "ax", @progbits
prefix_exit:
popw %ax /* padding */
popw %ax /* %ax = exit code */
cmpw $EXIT_VIA_LRET, %ax
jne 1f
/* Exit via LRET */
pushw $exec_vector
popl ( 0x19 * 4 )
popw %ds
movw $notpnp_message, %si
99:
call print_message
movw $0x20, %ax
popw %si
lret
1: addw $4, %sp /* Strip padding */
cmpw $EXIT_VIA_BOOT_INT, %ax
jne 2f
/* Exit via int BOOT_INT */
int $BOOT_INT /* Try original vector */
2: /* Exit via int $0x18 */
int $0x18 /* As per BIOS Boot Spec, next dev */
prefix_exit_end:
.size init_vector, . - init_vector
ispnp_message:
.asciz "Etherboot detected PnP BIOS\r\n"
.size ispnp_message, . - ispnp_message
notpnp_message:
.asciz "Etherboot detected non-PnP BIOS\r\n"
.size notpnp_message, . - notpnp_message
/* Boot execution vector
*
* Called by the PnP BIOS when it wants to boot us, or via the hooked
* INT 19 if we detected a non-PnP BIOS.
*/
exec_vector:
/* Obtain a reasonably-sized stack */
xorw %ax, %ax
movw %ax, %ss
movw $0x7c00, %sp
movw $exec_message, %si
call print_message
call install
/* Jump to .text16 segment */
pushw %ax
pushw $1f
lret
.section ".text16", "awx", @progbits
1:
pushl $main
pushw %cs
call prot_call
popl %eax /* discard */
/* Boot next device */
int $0x18
.previous
/* UNDI loader needs to be rewritten to use new mechanism */
#if 0
#ifdef PXE_EXPORT
#define PXENV_UNDI_LOADER 0x104d
.section ".prefix"
UNDILoader:
/* Loader API is different to the usual PXE API; there is no
* opcode on the stack. We arrange the stack to look like a
* normal PXE API call; this makes the Etherboot internals
* cleaner and avoids adding an extra API type just for the
* PXE loader.
*/
pushw %bx
movw %sp, %ax /* Store original %ss:sp */
pushw %ss
pushw %ax
pushl %eax /* Space for loader structure ptr */
pushw %bp
movw %sp, %bp
movw 16(%bp), %ax /* Copy loader structure ptr */
movw %ax, 2(%bp)
movw 18(%bp), %ax
movw %ax, 4(%bp)
popw %bp
pushw $PXENV_UNDI_LOADER /* PXE 'opcode' */
pushl %eax /* dummy return address */
/* Stack now looks like a normal PXE API call */
/* Store ROM segment and size on stack */
pushw %ax
pushw %cs
movzbw %cs:(size-_prefix), %ax
shlw $9, %ax /* 512-byte blocks */
pushw %ax
/* Unpack Etherboot into temporarily claimed base memory */
pushw $20 /* Dummy ret, PXE params, orig ss:sp */
call prelocate
popw %ax /* discard */
popw %cs:(_prefix_rom+2) /* ROM size */
popw %cs:(_prefix_rom+0) /* ROM segment */
popw %ax /* Original %ax */
/* Inhibit automatic deallocation of base memory */
movl $0, %cs:_prefix_image_basemem
/* Make PXE API call to Etherboot */
pushl $0x201 /* PXE API version */
/* Need to USE_INTERNAL_STACK, since we will call relocate() */
pushl $(EB_OPCODE_PXE|EB_USE_INTERNAL_STACK) /* PXE API call type */
call _entry
addw $18, %sp /* discard */
popw %bx /* Restore original %ss:sp */
popw %ss
movw %bx, %sp
popw %bx
call deprelocate
lret $2 /* Skip our PXE 'opcode' */
#endif /* PXE_EXPORT */
#endif /* 0 */
#ifdef DEBUG_ROMPREFIX
.section ".prefix"
print_bcv:
pushw %si
movw $1f-_prefix, %si
call print_message
popw %si
ret
1: .asciz "ROM detected\r\n"
print_bev:
pushw %si
movw $1f-_prefix, %si
call print_message
popw %si
ret
1: .asciz "booting\r\n"
print_notpnp:
pushw %si
movw $1f-_prefix, %si
call print_message
popw %si
ret
1: .asciz ": Non-PnP BIOS detected!\r\n"
print_legacyentry:
pushw %si
movw $1f-_prefix, %si
call print_message
popw %si
ret
1: .asciz "ROM using legacy boot mechanism\r\n"
print_installed:
pushw %si
movw $1f-_prefix, %si
call print_message
popw %si
ret
1: .ascii "hooked boot via INT"
#ifdef BOOT_INT18H
.asciz "18\r\n"
#else
.asciz "19\r\n"
#endif
print_start_int:
pushw %si
movw $1f-_prefix, %si
call print_message
popw %si
ret
1: .asciz "booting via hooked interrupt\r\n"
exec_message:
.asciz "Etherboot starting boot\r\n"
.size exec_message, . - exec_message
/* UNDI loader
*
* Called by an external program to load our PXE stack.
*/
undiloader:
.size undiloader, . - undiloader
/* Utility function: print string
*/
print_message:
pushaw
pushw %ds
pushw %cs
popw %ds
pushw %si
movw $1f-_prefix, %si
call print_string
popw %si
call print_string
popw %ds
popaw
ret
1: .asciz "Etherboot "
print_string:
1: lodsb
testb %al,%al
pushw %ax
pushw %bx
pushw %bp
movw $0x0007, %bx
1: cs lodsb
testb %al, %al
je 2f
movw $0x0007, %bx /* page 0, attribute 7 (normal) */
movb $0x0e, %ah /* write char, tty mode */
int $0x10
jmp 1b
2: ret
#endif
2: popw %bp
popw %bx
popw %ax
ret
.size print_message, . - print_message