[pxeprefix] Search for the PXE entry points through all methods
authorH. Peter Anvin <hpa@zytor.com>
Wed, 18 Feb 2009 05:56:08 +0000 (21:56 -0800)
committerMichael Brown <mcb30@etherboot.org>
Mon, 23 Feb 2009 02:53:38 +0000 (02:53 +0000)
Search for the PXE entry points (via the !PXE or PXENV+ structures)
through all known combinations of search methods.  Furthermore, if we
find a PXENV+ structure, attempt to use it to find the !PXE structure
if at all possible.

src/arch/i386/prefix/pxeprefix.S

index ee0f4d9..b3b7947 100644 (file)
        pushl   $STACK_MAGIC
        movw    %ss, %cs:pxe_ss
        movl    %esp, %cs:pxe_esp
-       movw    %sp, %bp
-       movl    (10*4+4*2+4)(%bp),%ebp  /* !PXE address */
 
-       /* Set up %ds */
+       /* Set up segments */
        movw    %cs, %ax
        movw    %ax, %ds
-       /* Record PXENV+ and !PXE nominal addresses */
-       movw    %es, pxenv_segment      /* PXENV+ address */
-       movw    %bx, pxenv_offset
-       movl    %ebp, ppxe_segoff       /* !PXE address */
-       /* Set up %es and %fs */
-       movw    %ax, %es
        movw    $0x40, %ax              /* BIOS data segment access */
        movw    %ax, %fs
        /* Set up stack just below 0x7c00 */
        .previous
 
 /*****************************************************************************
- * Verify PXENV+ structure and record parameters of interest
+ * Find us a usable !PXE or PXENV+ entry point
  *****************************************************************************
  */
-detect_pxenv:
-       /* Signature check */
-       les     pxenv_segoff, %bx
-       cmpl    $0x4e455850, %es:(%bx)  /* 'PXEN' signature */
-       jne     no_pxenv
-       cmpw    $0x2b56, %es:4(%bx)     /* 'V+' signature */
-       jne     no_pxenv
+detect_pxe:
+       /* Plan A: !PXE pointer from the stack */
+       lgsl    pxe_esp, %ebp           /* %gs:%bp -> original stack */
+       lesw    %gs:52(%bp), %bx
+       call    is_valid_ppxe
+       je      have_ppxe
+
+       /* Plan B: PXENV+ pointer from initial ES:BX */
+       movw    %gs:32(%bp),%bx
+       movw    %gs:8(%bp),%es
+       call    is_valid_pxenv
+       je      have_pxenv
+
+       /* Plan C: PXENV+ structure via INT 1Ah */
+       movw    $0x5650, %ax
+       int     $0x1a
+       jc      1f
+       cmpw    $0x564e, %ax
+       jne     1f
+       call    is_valid_pxenv
+       je      have_pxenv
+1:
+       /* Plan D: scan base memory for !PXE */
+       call    memory_scan_ppxe
+       je      have_ppxe
+
+       /* Plan E: scan base memory for PXENV+ */
+       call    memory_scan_pxenv
+       jne     stack_not_found
+       
+have_pxenv:
+       movw    %bx, pxenv_offset
+       movw    %es, pxenv_segment
+
+       cmpw    $0x201, %es:6(%bx)      /* API version >= 2.01 */
+       jb      1f
+       cmpb    $0x2c, %es:8(%bx)       /* ... and structure long enough */
+       jb      2f
+
+       lesw    %es:0x28(%bx), %bx      /* Find !PXE from PXENV+ */
+       call    is_valid_ppxe
+       je      have_ppxe
+2:
+       call    memory_scan_ppxe        /* We are *supposed* to have !PXE... */
+       je      have_ppxe
+1:
+       lesw    pxenv_segoff, %bx       /* Nope, we're stuck with PXENV+ */
+
        /* Record entry point and UNDI segments */
        pushl   %es:0x0a(%bx)           /* Entry point */
        popl    entry_segoff
@@ -79,36 +112,22 @@ detect_pxenv:
        pushw   %es:0x20(%bx)           /* UNDI data segment */
        pushw   %es:0x22(%bx)           /* UNDI data size */
        popl    undi_data_segoff
+
        /* Print "PXENV+ at <address>" */
        movw    $10f, %si
        call    print_message
        call    print_segoff
        movb    $( ',' ), %al
        call    print_character
-       jmp     99f
+       jmp     check_have_stack
        .section ".prefix.data", "aw", @progbits
 10:    .asciz  " PXENV+ at "
        .previous
 
-no_pxenv:
-       xorl    %eax, %eax
-       movl    %eax, pxenv_segoff
-       
-99:
-       
-/*****************************************************************************
- * Verify !PXE structure and record parameters of interest
- *****************************************************************************
- */
-detect_ppxe:
-       /* Signature check */
-       les     ppxe_segoff, %bx
-       cmpl    $0x45585021, %es:(%bx)  /* '!PXE' signature */
-       jne     no_ppxe
-       /* Record structure address, entry point, and UNDI segments */
-       pushw   %es
-       popw    ppxe_segment
+have_ppxe:
        movw    %bx, ppxe_offset
+       movw    %es, ppxe_segment
+       
        pushl   %es:0x10(%bx)           /* Entry point */
        popl    entry_segoff
        pushw   %es:0x30(%bx)           /* UNDI code segment */
@@ -123,17 +142,60 @@ detect_ppxe:
        call    print_segoff
        movb    $( ',' ), %al
        call    print_character
-       jmp     99f
+       jmp     check_have_stack
        .section ".prefix.data", "aw", @progbits
 10:    .asciz  " !PXE at "
        .previous
 
-no_ppxe:
-       xorl    %eax, %eax
-       movl    %eax, ppxe_segoff
+is_valid_ppxe:
+       cmpl    $0x45585021, %es:(%bx)
+       jne     1f
+       movzbw  %es:4(%bx), %cx
+       cmpw    $0x58, %cx
+       jae     is_valid_checksum
+1:
+       ret
+       
+is_valid_pxenv:
+       cmpl    $0x4e455850, %es:(%bx)
+       jne     1b
+       cmpw    $0x2b56, %es:4(%bx)
+       jne     1b
+       movzbw  %es:8(%bx), %cx
+       cmpw    $0x28, %cx
+       jb      1b
+       
+is_valid_checksum:
+       pushw   %ax
+       movw    %bx, %si
+       xorw    %ax, %ax
+2:
+       es lodsb
+       addb    %al, %ah
+       loopw   2b
+       popw    %ax
+       ret
+
+memory_scan_ppxe:
+       movw    $is_valid_ppxe, %dx
+       jmp     memory_scan_common
 
-99:
+memory_scan_pxenv:
+       movw    $is_valid_pxenv, %dx
 
+memory_scan_common:
+       movw    %fs:(0x13), %ax
+       shlw    $6, %ax
+       decw    %ax
+1:     incw    %ax
+       cmpw    $( 0xa000 - 1 ), %ax
+       ja      2f
+       movw    %ax, %es
+       xorw    %bx, %bx
+       call    *%dx
+       jne     1b
+2:     ret
+       
 /*****************************************************************************
  * Sanity check: we must have an entry point
  *****************************************************************************
@@ -144,6 +206,7 @@ check_have_stack:
        testl   %eax, %eax
        jnz     99f
        /* No entry point: print message and skip everything else */
+stack_not_found:
        movw    $10f, %si
        call    print_message
        jmp     finished
@@ -529,8 +592,8 @@ print_pxe_error:
  */
        .section ".prefix.data"
 
-pxe_ss:                        .word 0
 pxe_esp:               .long 0
+pxe_ss:                        .word 0
 
 pxe_parameter_structure: .fill 20