diff --git a/src/arch/i386/prefix/romprefix.S b/src/arch/i386/prefix/romprefix.S index 4a5bd2e6..ced0f49c 100644 --- a/src/arch/i386/prefix/romprefix.S +++ b/src/arch/i386/prefix/romprefix.S @@ -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