From 12f203c606422979f46a0fb4bea66a00612a317c Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sun, 9 Mar 2008 22:13:07 +0000 Subject: [PATCH 1/5] [PXE] Add PMM support to romprefix.S (untested) ROM initialisation vector now attempts to allocate a 2MB block using PMM. If successful, it copies the ROM image to this block, then shrinks the ROM image to allow for more option ROMs. If unsuccessful, it leaves the ROM as-is. ROM BEV now attempts to return to the BIOS, resorting to INT 18 only if the BIOS stack has been corrupted. --- src/arch/i386/prefix/libprefix.S | 88 ++++++++---- src/arch/i386/prefix/romprefix.S | 232 +++++++++++++++++++++++++------ src/arch/i386/scripts/i386.lds | 2 + 3 files changed, 246 insertions(+), 76 deletions(-) diff --git a/src/arch/i386/prefix/libprefix.S b/src/arch/i386/prefix/libprefix.S index 12cf9184..406dac39 100644 --- a/src/arch/i386/prefix/libprefix.S +++ b/src/arch/i386/prefix/libprefix.S @@ -17,6 +17,10 @@ * */ + .arch i386 + .section ".prefix.lib", "awx", @progbits + .section ".data16", "aw", @progbits + /** * High memory temporary load address * @@ -27,25 +31,18 @@ * We use the start of an even megabyte so that we don't have to worry * about the current state of the A20 line. * - * We use 4MB rather than 2MB because there is at least one commercial - * PXE ROM ("Broadcom UNDI, PXE-2.1 (build 082) v2.0.4") which stores - * data required by the UNDI ROM loader (yes, the ROM loader; that's - * the component which should be impossible to damage short of - * screwing with the MMU) around the 2MB mark. Sadly, this is not a - * joke. - * + * We use 4MB rather than 2MB because some PXE stack / PMM BIOS + * combinations are known to place data required by other UNDI ROMs + * loader around the 2MB mark. */ -#define HIGHMEM_LOADPOINT ( 4 << 20 ) + .globl HIGHMEM_LOADPOINT + .equ HIGHMEM_LOADPOINT, ( 4 << 20 ) /* Image compression enabled */ #define COMPRESS 1 #define CR0_PE 1 - .arch i386 - .section ".prefix.lib", "awx", @progbits - .section ".data16", "aw", @progbits - /**************************************************************************** * pm_call (real-mode near call) * @@ -223,12 +220,15 @@ copy_bytes: * Returns: * %ds:esi : next source address (will be a multiple of 16) * Corrupts: - * %edi, %ecx, %edx + * %ecx, %edx **************************************************************************** */ .section ".prefix.lib" .code16 install_block: + /* Preserve registers */ + pushl %edi + #if COMPRESS /* Decompress source to destination */ call decompress16 @@ -249,6 +249,8 @@ install_block: addl $0xf, %esi andl $~0xf, %esi + /* Restore registers and return */ + popl %edi ret .size install_block, . - install_block @@ -270,6 +272,7 @@ install_block: */ .section ".prefix.lib" .code16 + .globl alloc_basemem alloc_basemem: /* FBMS => %ax as segment address */ movw $0x40, %ax @@ -308,13 +311,14 @@ alloc_basemem: * Returns: * %esi : next source physical address (will be a multiple of 16) * Corrupts: - * %edi, %ecx, %edx + * %ecx, %edx **************************************************************************** */ .section ".prefix.lib" .code16 install_basemem: /* Preserve registers */ + pushl %edi pushw %ds /* Preserve original %esi */ @@ -335,6 +339,7 @@ install_basemem: /* Restore registers */ popw %ds + popl %edi ret .size install_basemem, . - install_basemem @@ -351,7 +356,7 @@ install_basemem: * Returns: * %esi : next source physical address (will be a multiple of 16) * Corrupts: - * %edi, %ecx, %edx + * %ecx, %edx **************************************************************************** */ @@ -376,17 +381,14 @@ install_highmem: /**************************************************************************** * install (real-mode near call) - * install_prealloc (real-mode near call) * * Install all text and data segments. * * Parameters: - * %ax : .text16 segment address (install_prealloc only) - * %bx : .data16 segment address (install_prealloc only) + * none * Returns: - * %ax : .text16 segment address - * %bx : .data16 segment address - * %edi : .text physical address (if applicable) + * %ax : .text16 segment address + * %bx : .data16 segment address * Corrupts: * none **************************************************************************** @@ -395,26 +397,55 @@ install_highmem: .code16 .globl install install: + /* Preserve registers */ + pushl %esi + pushl %edi /* Allocate space for .text16 and .data16 */ call alloc_basemem + /* Image source = %cs:0000 */ + xorl %esi, %esi + /* Image destination = HIGHMEM_LOADPOINT */ + movl $HIGHMEM_LOADPOINT, %edi + /* Install text and data segments */ + call install_prealloc + /* Restore registers and return */ + popl %edi + popl %esi + ret .size install, . - install + +/**************************************************************************** + * install_prealloc (real-mode near call) + * + * Install all text and data segments. + * + * Parameters: + * %ax : .text16 segment address + * %bx : .data16 segment address + * %esi : Image source physical address (or zero for %cs:0000) + * %edi : Decompression temporary area physical address + * Corrupts: + * none + **************************************************************************** + */ + .section ".prefix.lib" + .code16 .globl install_prealloc install_prealloc: /* Save registers */ + pushal pushw %ds pushw %es - pushl %esi - pushl %ecx - pushl %edx /* Sanity: clear the direction flag asap */ cld /* Calculate physical address of payload (i.e. first source) */ - xorl %esi, %esi + testl %esi, %esi + jnz 1f movw %cs, %si shll $4, %esi - addl $_payload_offset, %esi +1: addl $_payload_offset, %esi /* Install .text16 */ movw %ax, %es @@ -440,7 +471,6 @@ install_prealloc: * prior to reading the E820 memory map and relocating * properly. */ - movl $HIGHMEM_LOADPOINT, %edi movl $_textdata_progbits_size, %ecx movl $_textdata_size, %edx pushl %edi @@ -473,11 +503,9 @@ install_prealloc: #endif /* Restore registers */ - popl %edx - popl %ecx - popl %esi popw %es popw %ds + popal ret .size install_prealloc, . - install_prealloc diff --git a/src/arch/i386/prefix/romprefix.S b/src/arch/i386/prefix/romprefix.S index 167641c6..86d76a5d 100644 --- a/src/arch/i386/prefix/romprefix.S +++ b/src/arch/i386/prefix/romprefix.S @@ -6,6 +6,10 @@ * table so using a noticeable amount of stack space is a no-no. */ +#define PNP_SIGNATURE ( '$' + ( 'P' << 8 ) + ( 'n' << 16 ) + ( 'P' << 24 ) ) +#define PMM_SIGNATURE ( '$' + ( 'P' << 8 ) + ( 'M' << 16 ) + ( 'M' << 24 ) ) +#define STACK_MAGIC ( 'L' + ( 'R' << 8 ) + ( 'E' << 16 ) + ( 'T' << 24 ) ) + .text .code16 .arch i386 @@ -15,7 +19,9 @@ romheader: .word 0xAA55 /* BIOS extension signature */ romheader_size: .byte _load_size_sect /* Size in 512-byte blocks */ - jmp init_vector /* Initialisation vector */ + jmp init /* Initialisation vector */ +checksum: + .byte 0 .org 0x16 .word undiheader .org 0x18 @@ -72,7 +78,7 @@ pnpheader: .byte 0x54 /* Device indicator */ .word 0x0000 /* Boot connection vector */ .word 0x0000 /* Disconnect vector */ - .word exec_vector /* Boot execution vector */ + .word bev_entry /* Boot execution vector */ .word 0x0000 /* Reserved */ .word 0x0000 /* Static resource information vector*/ .equ pnpheader_len, . - pnpheader @@ -98,60 +104,180 @@ undiheader: .equ undiheader_len, . - undiheader .size undiheader, . - undiheader -/* Initialisation vector +/* Initialisation (called once during POST) * * 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. */ -init_vector: - pushw %si - cmpw $'$'+'P'*256, %es:0(%di) - jne notpnp - cmpw $'n'+'P'*256, %es:2(%di) - jne notpnp -ispnp: - movw $ispnp_message, %si - jmp 99f -notpnp: +init: + /* Preserve registers, clear direction flag, set %ds=%cs */ + pushaw pushw %ds - pushw $0 - popw %ds + pushw %es + cld pushw %cs - pushw $exec_vector - popl ( 0x19 * 4 ) popw %ds - movw $notpnp_message, %si -99: + /* Print message as early as possible */ + movw $init_message, %si call print_message - movw $0x20, %ax - popw %si - lret - .size init_vector, . - init_vector - -ispnp_message: - .asciz "gPXE detected PnP BIOS\r\n" - .size ispnp_message, . - ispnp_message -notpnp_message: - .asciz "gPXE detected non-PnP BIOS\r\n" - .size notpnp_message, . - notpnp_message - -/* Boot execution vector - *pciheader_size - * 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 */ + /* Check for PnP BIOS */ + cmpl $PNP_SIGNATURE, %es:0(%di) + je ispnp +notpnp: /* Not PnP: hook INT19 */ xorw %ax, %ax - movw %ax, %ss - movw $0x7c00, %sp - + movw %ax, %es + pushw %cs + pushw $int19_entry + popl %es:( 0x19 * 4 ) + jmp 99f +ispnp: /* Is PnP: print PnP message */ + movw $init_message_pnp, %si + call print_message + /* Check for PMM */ + movw $( 0xe000 - 1 ), %di +pmm_scan: + incw %di + jz 99f + movw %di, %es + cmpl $PMM_SIGNATURE, %es:0 + jne pmm_scan + xorw %bx, %bx + xorw %si, %si + movzbw %es:5, %cx +1: es lodsb + addb %al, %bl + loop 1b + jnz pmm_scan + /* PMM found: print PMM message */ + movw $init_message_pmm, %si + 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 */ + lcall %es:*(7) + addw $12, %sp + testw %dx, %dx /* %ax==0 even on success, since align=2MB */ + jnz gotpmm + movw $init_message_pmm_failed, %si + call print_message + jmp 99f +gotpmm: /* 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 + xorl %esi, %esi + movzbl romheader_size, %ecx + shll $9, %ecx + addr32 rep movsb /* PMM presence implies flat real mode */ + movl %edi, decompress_to + /* Shrink ROM and update checksum */ + xorw %bx, %bx + xorw %si, %si + movb $_prefix_size_sect, romheader_size + shlw $9, %cx +1: lodsb + addb %al, %bl + loop 1b + subb %bl, checksum + popal +99: + /* Print CRLF to terminate messages */ + movw $init_message_crlf, %si + call print_message + /* Restore registers */ + 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)" + .size init_message, . - init_message +init_message_pnp: + .asciz " - PnP BIOS detected" + .size init_message_pnp, . - init_message_pnp +init_message_pmm: + .asciz ", using 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_crlf: + .asciz "\r\n" + .size init_message_crlf, . - init_message_crlf + +/* ROM image location + * + * May be either within option ROM space, or within PMM-allocated block. + */ +image_source: + .long 0 + .size image_source, . - image_source +/* Temporary decompression area + * + * May be either at HIGHMEM_LOADPOINT, or within PMM-allocated block. + */ +decompress_to: + .long HIGHMEM_LOADPOINT + .size decompress_to, . - decompress_to + +/* Boot Execution Vector entry point + * + * Called by the PnP BIOS when it wants to boot us. + */ +bev_entry: + pushw %cs + call exec + lret + .size bev_entry, . - bev_entry + +/* INT19 entry point + * + * Called via the hooked INT 19 if we detected a non-PnP BIOS. + */ +int19_entry: + pushw %cs + call exec + /* No real way to return from INT19 */ + int $0x18 + .size int19_entry, . - int19_entry + +/* Execute as a boot device + * + */ +exec: /* Set %ds = %cs */ + pushw %cs + popw %ds + + /* Print message as soon as possible */ movw $exec_message, %si call print_message - call install + /* Store magic word on BIOS stack and remember BIOS %ss:sp */ + pushl $STACK_MAGIC + movw %ss, %dx + movw %sp, %bp + + /* Obtain a reasonably-sized temporary stack */ + xorw %ax, %ax + movw %ax, %ss + movw $0x7c00, %sp + + /* Install gPXE */ + movl image_source, %esi + movl decompress_to, %edi + call alloc_basemem + call install_prealloc /* Set up real-mode stack */ movw %bx, %ss @@ -162,13 +288,23 @@ exec_vector: pushw $1f lret .section ".text16", "awx", @progbits -1: +1: /* Call main() */ pushl $main pushw %cs call prot_call - popl %eax /* discard */ + /* No need to clean up stack; we are about to reload %ss:sp */ + + /* Restore BIOS stack */ + movw %dx, %ss + movw %bp, %sp - /* Boot next device */ + /* Check magic word on BIOS stack */ + popl %eax + cmpl $STACK_MAGIC, %eax + jne 1f + /* BIOS stack OK: return to caller */ + lret +1: /* BIOS stack corrupt: use INT 18 */ int $0x18 .previous @@ -182,6 +318,7 @@ exec_message: */ undiloader: /* Save registers */ + pushl %esi pushl %edi pushw %es pushw %bx @@ -193,6 +330,8 @@ undiloader: pushw %di movw %es:12(%di), %bx movw %es:14(%di), %ax + movl %cs:image_source, %esi + movl %cs:decompress_to, %edi call install_prealloc popw %di /* Call UNDI loader C code */ @@ -208,6 +347,7 @@ undiloader: popw %bx popw %es popl %edi + popl %esi lret .size undiloader, . - undiloader @@ -218,7 +358,7 @@ print_message: pushw %bx pushw %bp movw $0x0007, %bx -1: cs lodsb +1: lodsb testb %al, %al je 2f movb $0x0e, %ah /* write char, tty mode */ diff --git a/src/arch/i386/scripts/i386.lds b/src/arch/i386/scripts/i386.lds index d481db0f..a5a01056 100644 --- a/src/arch/i386/scripts/i386.lds +++ b/src/arch/i386/scripts/i386.lds @@ -257,6 +257,8 @@ SECTIONS { /* * Values calculated to save code from doing it */ + _prefix_size_pgh = ( ( _prefix_size + 15 ) / 16 ); + _prefix_size_sect = ( ( _prefix_size + 511 ) / 512 ); _text16_size_pgh = ( ( _text16_size + 15 ) / 16 ); _data16_size_pgh = ( ( _data16_size + 15 ) / 16 ); From 297002d7bda37b02b722da1915c8db99ad8c857e Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 11 Mar 2008 11:32:19 +0000 Subject: [PATCH 2/5] [prefix] Add printing functions to libprefix.S Move the printing functions from pxeprefix.S into libprefix.S, so they are available for debug from any prefix. --- src/arch/i386/prefix/libprefix.S | 108 +++++++++++++++++++++++++++++++ src/arch/i386/prefix/pxeprefix.S | 106 ------------------------------ src/arch/i386/prefix/romprefix.S | 26 ++------ 3 files changed, 112 insertions(+), 128 deletions(-) diff --git a/src/arch/i386/prefix/libprefix.S b/src/arch/i386/prefix/libprefix.S index 406dac39..bf26358a 100644 --- a/src/arch/i386/prefix/libprefix.S +++ b/src/arch/i386/prefix/libprefix.S @@ -43,6 +43,114 @@ #define CR0_PE 1 +/***************************************************************************** + * Utility function: print character (with LF -> LF,CR translation) + * + * Parameters: + * %al : character to print + * Returns: + * Nothing + * Corrupts: + * %ax + ***************************************************************************** + */ + .section ".prefix.lib" + .code16 + .globl print_character +print_character: + /* Preserve registers */ + pushw %bx + pushw %bp + /* Print character */ + movw $0x0007, %bx /* page 0, attribute 7 (normal) */ + movb $0x0e, %ah /* write char, tty mode */ + cmpb $0x0a, %al /* '\n'? */ + jne 1f + int $0x10 + movb $0x0d, %al +1: int $0x10 + /* Restore registers and return */ + popw %bp + popw %bx + ret + .size print_character, . - print_character + +/***************************************************************************** + * Utility function: print a NUL-terminated string + * + * Parameters: + * %ds:si : string to print + * Returns: + * %ds:si : character after terminating NUL + ***************************************************************************** + */ + .section ".prefix.lib" + .code16 + .globl print_message +print_message: + /* Preserve registers */ + pushw %ax + /* Print string */ +1: lodsb + testb %al, %al + je 2f + call print_character + jmp 1b +2: /* Restore registers and return */ + popw %ax + ret + .size print_message, . - print_message + +/***************************************************************************** + * Utility functions: print hex digit/byte/word/dword + * + * Parameters: + * %al (low nibble) : digit to print + * %al : byte to print + * %ax : word to print + * %eax : dword to print + * Returns: + * Nothing + ***************************************************************************** + */ + .section ".prefix.lib" + .code16 + .globl print_hex_dword +print_hex_dword: + rorl $16, %eax + call print_hex_word + rorl $16, %eax + /* Fall through */ + .size print_hex_dword, . - print_hex_dword + .globl print_hex_word +print_hex_word: + xchgb %al, %ah + call print_hex_byte + xchgb %al, %ah + /* Fall through */ + .size print_hex_word, . - print_hex_word + .globl print_hex_byte +print_hex_byte: + rorb $4, %al + call print_hex_nibble + rorb $4, %al + /* Fall through */ + .size print_hex_byte, . - print_hex_byte + .globl print_hex_nibble +print_hex_nibble: + /* Preserve registers */ + pushw %ax + /* Print digit (technique by Norbert Juffa */ + andb $0x0f, %al + cmpb $10, %al + sbbb $0x69, %al + das + call print_character + /* Restore registers and return */ + popw %ax + ret + .size print_hex_nibble, . - print_hex_nibble + /**************************************************************************** * pm_call (real-mode near call) * diff --git a/src/arch/i386/prefix/pxeprefix.S b/src/arch/i386/prefix/pxeprefix.S index 31b2102f..6a8aeb3a 100644 --- a/src/arch/i386/prefix/pxeprefix.S +++ b/src/arch/i386/prefix/pxeprefix.S @@ -320,112 +320,6 @@ print_free_basemem: finished: jmp run_etherboot -/***************************************************************************** - * Subroutine: print character (with LF -> LF,CR translation) - * - * Parameters: - * %al : character to print - * Returns: - * Nothing - ***************************************************************************** - */ -print_character: - /* Preserve registers */ - pushw %ax - pushw %bx - pushw %bp - /* Print character */ - movw $0x0007, %bx /* page 0, attribute 7 (normal) */ - movb $0x0e, %ah /* write char, tty mode */ - cmpb $0x0a, %al /* '\n'? */ - jne 1f - int $0x10 - movb $0x0d, %al -1: int $0x10 - /* Restore registers and return */ - popw %bp - popw %bx - popw %ax - ret - -/***************************************************************************** - * Subroutine: print a NUL-terminated string - * - * Parameters: - * %ds:%si : string to print - * Returns: - * Nothing - ***************************************************************************** - */ -print_message: - /* Preserve registers */ - pushw %ax - pushw %si - /* Print string */ -1: lodsb - testb %al, %al - je 2f - call print_character - jmp 1b -2: /* Restore registers and return */ - popw %si - popw %ax - ret - -/***************************************************************************** - * Subroutine: print hex digit - * - * Parameters: - * %al (low nibble) : digit to print - * Returns: - * Nothing - ***************************************************************************** - */ -print_hex_nibble: - /* Preserve registers */ - pushw %ax - /* Print digit (technique by Norbert Juffa */ - andb $0x0f, %al - cmpb $10, %al - sbbb $0x69, %al - das - call print_character - /* Restore registers and return */ - popw %ax - ret - -/***************************************************************************** - * Subroutine: print hex byte - * - * Parameters: - * %al : byte to print - * Returns: - * Nothing - ***************************************************************************** - */ -print_hex_byte: - rorb $4, %al - call print_hex_nibble - rorb $4, %al - call print_hex_nibble - ret - -/***************************************************************************** - * Subroutine: print hex word - * - * Parameters: - * %ax : word to print - * Returns: - * Nothing - ***************************************************************************** - */ -print_hex_word: - xchgb %al, %ah - call print_hex_byte - xchgb %al, %ah - call print_hex_byte - ret - /***************************************************************************** * Subroutine: print segment:offset address * diff --git a/src/arch/i386/prefix/romprefix.S b/src/arch/i386/prefix/romprefix.S index 86d76a5d..e67f476b 100644 --- a/src/arch/i386/prefix/romprefix.S +++ b/src/arch/i386/prefix/romprefix.S @@ -180,7 +180,8 @@ gotpmm: /* PMM allocation succeeded: copy ROM to PMM block */ /* Shrink ROM and update checksum */ xorw %bx, %bx xorw %si, %si - movb $_prefix_size_sect, romheader_size + movw $_prefix_size_sect, %cx + movb %cl, romheader_size shlw $9, %cx 1: lodsb addb %al, %bl @@ -213,7 +214,7 @@ init_message_pmm_failed: .asciz " (failed)" .size init_message_pmm_failed, . - init_message_pmm_failed init_message_crlf: - .asciz "\r\n" + .asciz "\n" .size init_message_crlf, . - init_message_crlf /* ROM image location @@ -309,7 +310,7 @@ exec: /* Set %ds = %cs */ .previous exec_message: - .asciz "gPXE starting boot\r\n" + .asciz "gPXE starting boot\n" .size exec_message, . - exec_message /* UNDI loader @@ -350,22 +351,3 @@ undiloader: popl %esi lret .size undiloader, . - undiloader - -/* Utility function: print string - */ -print_message: - pushw %ax - pushw %bx - pushw %bp - movw $0x0007, %bx -1: lodsb - testb %al, %al - je 2f - movb $0x0e, %ah /* write char, tty mode */ - int $0x10 - jmp 1b -2: popw %bp - popw %bx - popw %ax - ret - .size print_message, . - print_message From 9c86a39551f875db844e1298b0093589a2635652 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 11 Mar 2008 12:02:12 +0000 Subject: [PATCH 3/5] [PXE] Improve PnP/BBS detection Use BBS installation check to see if we need to hook INT19 even on a PnP BIOS. Verify that $PnP signature is paragraph-aligned; bochs/qemu BIOS provides a dummy $PnP signature with no valid entry point, and deliberately unaligns the signature to indicate that it is not properly valid. Print message if INT19 is hooked. Attempt to use PMM even if BBS check failed. --- src/arch/i386/prefix/romprefix.S | 68 +++++++++++++++++++++++--------- 1 file changed, 49 insertions(+), 19 deletions(-) diff --git a/src/arch/i386/prefix/romprefix.S b/src/arch/i386/prefix/romprefix.S index e67f476b..c0681607 100644 --- a/src/arch/i386/prefix/romprefix.S +++ b/src/arch/i386/prefix/romprefix.S @@ -9,6 +9,7 @@ #define PNP_SIGNATURE ( '$' + ( 'P' << 8 ) + ( 'n' << 16 ) + ( 'P' << 24 ) ) #define PMM_SIGNATURE ( '$' + ( 'P' << 8 ) + ( 'M' << 16 ) + ( 'M' << 24 ) ) #define STACK_MAGIC ( 'L' + ( 'R' << 8 ) + ( 'E' << 16 ) + ( 'T' << 24 ) ) +#define PNP_GET_BBS_VERSION 0x60 .text .code16 @@ -123,23 +124,41 @@ init: movw $init_message, %si call print_message /* Check for PnP BIOS */ + testw $0x0f, %di /* PnP signature must be aligned - bochs */ + jnz hook_int19 /* uses unalignment to indicate 'fake' PnP. */ cmpl $PNP_SIGNATURE, %es:0(%di) - je ispnp -notpnp: /* Not PnP: hook INT19 */ + jne hook_int19 + /* Is PnP: print PnP message */ + movw $init_message_pnp, %si + call print_message + xchgw %bx, %bx + /* Check for BBS */ + pushw %es:0x1b(%di) /* Real-mode data segment */ + pushw %ds /* &(bbs_version) */ + pushw $bbs_version + pushw $PNP_GET_BBS_VERSION + lcall *%es:0xd(%di) + addw $16, %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: + movw $init_message_int19, %si + call print_message xorw %ax, %ax movw %ax, %es pushw %cs pushw $int19_entry popl %es:( 0x19 * 4 ) - jmp 99f -ispnp: /* Is PnP: print PnP message */ - movw $init_message_pnp, %si - call print_message +hook_bbs: /* Check for PMM */ movw $( 0xe000 - 1 ), %di pmm_scan: incw %di - jz 99f + jz no_pmm movw %di, %es cmpl $PMM_SIGNATURE, %es:0 jne pmm_scan @@ -158,13 +177,13 @@ pmm_scan: pushl $0xffffffff /* No handle */ pushl $( 0x00200000 / 16 ) /* 2MB in paragraphs */ pushw $0x0000 /* pmmAllocate */ - lcall %es:*(7) + lcall *%es:7 addw $12, %sp testw %dx, %dx /* %ax==0 even on success, since align=2MB */ jnz gotpmm movw $init_message_pmm_failed, %si call print_message - jmp 99f + jmp no_pmm gotpmm: /* PMM allocation succeeded: copy ROM to PMM block */ pushal /* PMM presence implies 1kB stack */ movw %ax, %es /* %ax=0 already - see above */ @@ -188,10 +207,10 @@ gotpmm: /* PMM allocation succeeded: copy ROM to PMM block */ loop 1b subb %bl, checksum popal -99: +no_pmm: /* Print CRLF to terminate messages */ - movw $init_message_crlf, %si - call print_message + movw $'\n', %ax + call print_character /* Restore registers */ popw %es popw %ds @@ -202,20 +221,23 @@ gotpmm: /* PMM allocation succeeded: copy ROM to PMM block */ .size init, . - init init_message: - .asciz "gPXE (http://etherboot.org)" + .asciz "gPXE (http://etherboot.org) -" .size init_message, . - init_message init_message_pnp: - .asciz " - PnP BIOS detected" + .asciz " PnP" .size init_message_pnp, . - init_message_pnp +init_message_bbs: + .asciz " BBS" + .size init_message_bbs, . - init_message_bbs init_message_pmm: - .asciz ", using PMM" + .asciz " PMM" .size init_message_pmm, . - init_message_pmm init_message_pmm_failed: - .asciz " (failed)" + .asciz "(failed)" .size init_message_pmm_failed, . - init_message_pmm_failed -init_message_crlf: - .asciz "\n" - .size init_message_crlf, . - init_message_crlf +init_message_int19: + .asciz " INT19" + .size init_message_int19, . - init_message_int19 /* ROM image location * @@ -224,6 +246,7 @@ init_message_crlf: image_source: .long 0 .size image_source, . - image_source + /* Temporary decompression area * * May be either at HIGHMEM_LOADPOINT, or within PMM-allocated block. @@ -232,6 +255,13 @@ decompress_to: .long HIGHMEM_LOADPOINT .size decompress_to, . - decompress_to +/* BBS version + * + * Filled in by BBS BIOS. We ignore the value. + */ +bbs_version: + .word 0 + /* Boot Execution Vector entry point * * Called by the PnP BIOS when it wants to boot us. From 3bf7105cab8001f4a5ca1fc3cfa0cc0bc4e34dd6 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 11 Mar 2008 13:26:46 +0000 Subject: [PATCH 4/5] [prefix] Cope with image source addresses outside base memory When PMM is used, the gPXE image source will no longer be in base memory. Decompression of .text16 and .data16 can therefore no longer be done in real mode. --- src/arch/i386/prefix/libprefix.S | 235 +++++++++++++++---------------- 1 file changed, 114 insertions(+), 121 deletions(-) diff --git a/src/arch/i386/prefix/libprefix.S b/src/arch/i386/prefix/libprefix.S index bf26358a..deea5ab3 100644 --- a/src/arch/i386/prefix/libprefix.S +++ b/src/arch/i386/prefix/libprefix.S @@ -175,13 +175,14 @@ print_hex_nibble: #ifndef KEEP_IT_REAL /* GDT for protected-mode calls */ - .section ".data16" + .section ".prefix.lib" .align 16 +pm_call_vars: gdt: gdt_limit: .word gdt_length - 1 gdt_base: .long 0 .word 0 /* padding */ -pm_cs: /* 16-bit protected-mode code segment */ +pm_cs: /* 16-bit protected-mode code segment */ .equ PM_CS, pm_cs - gdt .word 0xffff, 0 .byte 0, 0x9b, 0x00, 0 @@ -197,18 +198,24 @@ gdt_end: .equ gdt_length, . - gdt .size gdt, . - gdt - .section ".data16" + .section ".prefix.lib" .align 16 pm_saved_gdt: .long 0, 0 .size pm_saved_gdt, . - pm_saved_gdt + .equ pm_call_vars_size, . - pm_call_vars +#define PM_CALL_VAR(x) ( -pm_call_vars_size + ( (x) - pm_call_vars ) ) + .section ".prefix.lib" .code16 pm_call: - /* Preserve registers, flags, GDT, and RM return point */ + /* Preserve registers, flags, and RM return point */ + pushw %bp + movw %sp, %bp + subw $pm_call_vars_size, %sp + andw $0xfff0, %sp pushfl - sgdt pm_saved_gdt pushw %gs pushw %fs pushw %es @@ -217,27 +224,43 @@ pm_call: pushw %cs pushw $99f + /* Set up local variable block, and preserve GDT */ + pushw %cx + pushw %si + pushw %di + pushw %ss + popw %es + movw $pm_call_vars, %si + leaw PM_CALL_VAR(pm_call_vars)(%bp), %di + movw $pm_call_vars_size, %cx + cs rep movsb + popw %di + popw %si + popw %cx + sgdt PM_CALL_VAR(pm_saved_gdt)(%bp) + /* Set up GDT bases */ pushl %eax - pushw %bx + pushl %edi xorl %eax, %eax - movw %ds, %ax + movw %ss, %ax shll $4, %eax - addl $gdt, %eax - movl %eax, gdt_base + movzwl %bp, %edi + leal PM_CALL_VAR(gdt)(%eax, %edi), %eax + movl %eax, PM_CALL_VAR(gdt_base)(%bp) movw %cs, %ax - movw $pm_cs, %bx + movw $PM_CALL_VAR(pm_cs), %di call set_seg_base movw %ss, %ax - movw $pm_ss, %bx + movw $PM_CALL_VAR(pm_ss), %di call set_seg_base - popw %bx + popl %edi popl %eax /* Switch CPU to protected mode and load up segment registers */ pushl %eax cli - lgdt gdt + lgdt PM_CALL_VAR(gdt)(%bp) movl %cr0, %eax orb $CR0_PE, %al movl %eax, %cr0 @@ -273,18 +296,19 @@ pm_call: popw %es popw %fs popw %gs - lgdt pm_saved_gdt + lgdt PM_CALL_VAR(pm_saved_gdt)(%bp) popfl - + movw %bp, %sp + popw %bp ret .size pm_call, . - pm_call set_seg_base: rolw $4, %ax - movw %ax, 2(%bx) - andw $0xfff0, 2(%bx) - movb %al, 4(%bx) - andb $0x0f, 4(%bx) + movw %ax, 2(%bp,%di) + andw $0xfff0, 2(%bp,%di) + movb %al, 4(%bp,%di) + andb $0x0f, 4(%bp,%di) ret .size set_seg_base, . - set_seg_base @@ -301,7 +325,7 @@ set_seg_base: * %ecx : length * Returns: * %ds:esi : next source address - * %ds:esi : next destination address + * %es:edi : next destination address * Corrupts: * None **************************************************************************** @@ -316,27 +340,57 @@ copy_bytes: .size copy_bytes, . - copy_bytes /**************************************************************************** - * install_block (real-mode or 16-bit protected-mode near call) + * install_block (real-mode near call) * * Install block to specified address * * Parameters: - * %ds:esi : source address (must be a multiple of 16) - * %es:edi : destination address + * %esi : source physical address (must be a multiple of 16) + * %edi : destination physical address (must be a multiple of 16) * %ecx : length of (decompressed) data * %edx : total length of block (including any uninitialised data portion) * Returns: - * %ds:esi : next source address (will be a multiple of 16) + * %esi : next source physical address (will be a multiple of 16) * Corrupts: - * %ecx, %edx + * none **************************************************************************** */ .section ".prefix.lib" .code16 install_block: + +#ifdef KEEP_IT_REAL + /* Preserve registers */ + pushw %ds + pushw %es + pushl %ecx pushl %edi + /* Convert %esi and %edi to segment registers */ + shrl $4, %esi + movw %si, %ds + xorw %si, %si + shrl $4, %edi + movw %di, %es + xorw %di, %di + +#else /* KEEP_IT_REAL */ + + /* Call self in protected mode */ + pushw %ax + movw $1f, %ax + call pm_call + popw %ax + ret +1: + /* Preserve registers */ + pushl %ecx + pushl %edi + +#endif /* KEEP_IT_REAL */ + + #if COMPRESS /* Decompress source to destination */ call decompress16 @@ -357,8 +411,28 @@ install_block: addl $0xf, %esi andl $~0xf, %esi - /* Restore registers and return */ + +#ifdef KEEP_IT_REAL + + /* Convert %ds:esi back to a physical address */ + movzwl %ds, %cx + shll $4, %ecx + addl %ecx, %esi + + /* Restore registers */ popl %edi + popl %ecx + popw %es + popw %ds + +#else /* KEEP_IT_REAL */ + + /* Restore registers */ + popl %edi + popl %ecx + +#endif + ret .size install_block, . - install_block @@ -406,87 +480,6 @@ alloc_basemem: ret .size alloc_basemem, . - alloc_basemem -/**************************************************************************** - * install_basemem (real-mode near call) - * - * Install source block into base memory - * - * Parameters: - * %esi : source physical address (must be a multiple of 16) - * %es : destination segment address - * %cx : length of (decompressed) data - * %dx : total length of block (including any uninitialised data portion) - * Returns: - * %esi : next source physical address (will be a multiple of 16) - * Corrupts: - * %ecx, %edx - **************************************************************************** - */ - .section ".prefix.lib" - .code16 -install_basemem: - /* Preserve registers */ - pushl %edi - pushw %ds - - /* Preserve original %esi */ - pushl %esi - - /* Install to specified address */ - shrl $4, %esi - movw %si, %ds - xorw %si, %si - xorl %edi, %edi - movzwl %cx, %ecx - movzwl %dx, %edx - call install_block - - /* Fix up %esi for return */ - popl %ecx - addl %ecx, %esi - - /* Restore registers */ - popw %ds - popl %edi - ret - .size install_basemem, . - install_basemem - -/**************************************************************************** - * install_highmem (real-mode near call) - * - * Install source block into high memory - * - * Parameters: - * %esi : source physical address (must be a multiple of 16) - * %edi : destination physical address - * %ecx : length of (decompressed) data - * %edx : total length of block (including any uninitialised data portion) - * Returns: - * %esi : next source physical address (will be a multiple of 16) - * Corrupts: - * %ecx, %edx - **************************************************************************** - */ - -#ifndef KEEP_IT_REAL - - .section ".prefix.lib" - .code16 -install_highmem: - /* Preserve registers */ - pushw %ax - - /* Install to specified address */ - movw $install_block, %ax - call pm_call - - /* Restore registers */ - popw %ax - ret - .size install_highmem, . - install_highmem - -#endif /* KEEP_IT_REAL */ - /**************************************************************************** * install (real-mode near call) * @@ -555,17 +548,19 @@ install_prealloc: shll $4, %esi 1: addl $_payload_offset, %esi - /* Install .text16 */ - movw %ax, %es - movw $_text16_size, %cx - movw %cx, %dx - call install_basemem - - /* Install .data16 */ - movw %bx, %es - movw $_data16_progbits_size, %cx - movw $_data16_size, %dx - call install_basemem + /* Install .text16 and .data16 */ + pushl %edi + movzwl %ax, %edi + shll $4, %edi + movl $_text16_size, %ecx + movl %ecx, %edx + call install_block /* .text16 */ + movzwl %bx, %edi + shll $4, %edi + movl $_data16_progbits_size, %ecx + movl $_data16_size, %edx + call install_block /* .data16 */ + popl %edi /* Set up %ds for access to .data16 */ movw %bx, %ds @@ -581,9 +576,7 @@ install_prealloc: */ movl $_textdata_progbits_size, %ecx movl $_textdata_size, %edx - pushl %edi - call install_highmem - popl %edi + call install_block /* Initialise librm at current location */ movw %ax, (init_librm_vector+2) From 66d9a411f718e7b135da11254c9e0fba9157896f Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 11 Mar 2008 16:08:04 +0000 Subject: [PATCH 5/5] [PXE] PMM now tested and working Minor bugfix: 4 x 2 = 8, not 16 --- src/arch/i386/prefix/romprefix.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/arch/i386/prefix/romprefix.S b/src/arch/i386/prefix/romprefix.S index c0681607..d37cce94 100644 --- a/src/arch/i386/prefix/romprefix.S +++ b/src/arch/i386/prefix/romprefix.S @@ -138,7 +138,7 @@ init: pushw $bbs_version pushw $PNP_GET_BBS_VERSION lcall *%es:0xd(%di) - addw $16, %sp + addw $8, %sp testw %ax, %ax jne hook_int19 movw $init_message_bbs, %si