Update gPXE syslinux-3.72-pre8
authorH. Peter Anvin <hpa@zytor.com>
Thu, 25 Sep 2008 20:46:43 +0000 (13:46 -0700)
committerH. Peter Anvin <hpa@zytor.com>
Thu, 25 Sep 2008 20:46:43 +0000 (13:46 -0700)
Update gPXE to:

gpxe-for-syslinux 0a1f463e8b3218803b42cd3940e90a7678de0b3e
gpxe upstream 3392cfa7df58a5662417f25226cf75dedabeb750

Signed-off-by: H. Peter Anvin <hpa@zytor.com>
20 files changed:
gpxe/src/arch/i386/core/relocate.c
gpxe/src/arch/i386/drivers/net/undirom.c
gpxe/src/arch/i386/firmware/pcbios/e820mangler.S
gpxe/src/arch/i386/firmware/pcbios/fakee820.c [new file with mode: 0644]
gpxe/src/arch/i386/firmware/pcbios/hidemem.c
gpxe/src/arch/i386/firmware/pcbios/memmap.c
gpxe/src/arch/i386/include/fakee820.h [new file with mode: 0644]
gpxe/src/arch/i386/interface/pxe/pxe_call.c
gpxe/src/arch/i386/prefix/romprefix.S
gpxe/src/core/settings.c
gpxe/src/core/uri.c
gpxe/src/crypto/axtls/bigint.h
gpxe/src/drivers/infiniband/arbel.c
gpxe/src/drivers/infiniband/hermon.c
gpxe/src/drivers/net/phantom/phantom.c
gpxe/src/include/gpxe/dhcp.h
gpxe/src/include/gpxe/uri.h
gpxe/src/interface/pxe/pxe_loader.c
gpxe/src/net/tcp/iscsi.c
gpxe/src/net/udp/dhcp.c

index 39d00b0..aa58ad6 100644 (file)
@@ -93,11 +93,16 @@ __cdecl void relocate ( struct i386_all_regs *ix86 ) {
                        /* If last byte that might be used (r_end-1)
                         * is in an odd megabyte, round down r_end to
                         * the top of the next even megabyte.
+                        *
+                        * Make sure that we don't accidentally wrap
+                        * r_end below 0.
                         */
-                       r_end = ( r_end - 1 ) & ~0xfffff;
-                       DBG ( "...end truncated to %lx "
-                             "(avoid ending in odd megabyte)\n",
-                             r_end );
+                       if ( r_end >= 1 ) {
+                               r_end = ( r_end - 1 ) & ~0xfffff;
+                               DBG ( "...end truncated to %lx "
+                                     "(avoid ending in odd megabyte)\n",
+                                     r_end );
+                       }
                } else if ( ( r_end - size ) & 0x100000 ) {
                        /* If the last byte that might be used
                         * (r_end-1) is in an even megabyte, but the
@@ -108,7 +113,7 @@ __cdecl void relocate ( struct i386_all_regs *ix86 ) {
                         * Make sure that we don't accidentally wrap
                         * r_end below 0.
                         */
-                       if ( r_end > 0x100000 ) {
+                       if ( r_end >= 0x100000 ) {
                                r_end = ( r_end - 0x100000 ) & ~0xfffff;
                                DBG ( "...end truncated to %lx "
                                      "(avoid starting in odd megabyte)\n",
index f977a55..d40fcd3 100644 (file)
@@ -188,9 +188,9 @@ static void undirom_probe_all_roms ( void ) {
 
        DBG ( "Scanning for PXE expansion ROMs\n" );
 
-       /* Scan through expansion ROM region at 2kB intervals */
+       /* Scan through expansion ROM region at 512 byte intervals */
        for ( rom_segment = 0xc000 ; rom_segment < 0x10000 ;
-             rom_segment += 0x80 ) {
+             rom_segment += 0x20 ) {
                undirom_probe ( rom_segment );
        }
 
index 3c4cf21..ad773f7 100644 (file)
@@ -245,10 +245,19 @@ get_underlying_e820:
        pushl   %ebx
        pushl   %ecx
        pushl   %edx
+       pushw   %es
+       pushw   %di
+       pushw   %ds
+       popw    %es
+       movw    $underlying_e820_cache, %di
+       movl    $20, %ecx
        movl    underlying_e820_ebx, %ebx
        stc
        pushfw
        lcall   *%cs:int15_vector
+       popw    %di
+       popw    %es
+       /* Check for error return from underlying e820 call */
        jc      1f /* CF set: error */
        cmpl    $SMAP, %eax
        je      2f /* 'SMAP' missing: error */
@@ -262,25 +271,6 @@ get_underlying_e820:
        popl    %ecx
        popl    %ebx
        popl    %eax
-       /* Copy result to cache */
-       pushw   %es
-       pushw   %fs
-       pushw   %si
-       pushw   %di
-       pushw   %cx
-       pushw   %es
-       popw    %fs
-       movw    %di, %si
-       pushw   %ds
-       popw    %es
-       movw    $underlying_e820_cache, %di
-       movw    $20, %cx
-       fs rep movsb
-       popw    %cx
-       popw    %di
-       popw    %si
-       popw    %fs
-       popw    %es
        /* Mark cache as containing this result */
        incw    underlying_e820_index
 
diff --git a/gpxe/src/arch/i386/firmware/pcbios/fakee820.c b/gpxe/src/arch/i386/firmware/pcbios/fakee820.c
new file mode 100644 (file)
index 0000000..e171edf
--- /dev/null
@@ -0,0 +1,90 @@
+/* Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <realmode.h>
+#include <biosint.h>
+
+/** Assembly routine in inline asm */
+extern void int15_fakee820();
+
+/** Original INT 15 handler */
+static struct segoff __text16 ( real_int15_vector );
+#define real_int15_vector __use_text16 ( real_int15_vector )
+
+/** An INT 15,e820 memory map entry */
+struct e820_entry {
+       /** Start of region */
+       uint64_t start;
+       /** Length of region */
+       uint64_t len;
+       /** Type of region */
+       uint32_t type;
+} __attribute__ (( packed ));
+
+#define E820_TYPE_RAM          1 /**< Normal memory */
+#define E820_TYPE_RSVD         2 /**< Reserved and unavailable */
+#define E820_TYPE_ACPI         3 /**< ACPI reclaim memory */
+#define E820_TYPE_NVS          4 /**< ACPI NVS memory */
+
+/** Fake e820 map */
+static struct e820_entry __text16_array ( e820map, [] ) __used = {
+       { 0x00000000ULL, ( 0x000a0000ULL - 0x00000000ULL ), E820_TYPE_RAM },
+       { 0x00100000ULL, ( 0xcfb50000ULL - 0x00100000ULL ), E820_TYPE_RAM },
+       { 0xcfb50000ULL, ( 0xcfb64000ULL - 0xcfb50000ULL ), E820_TYPE_RSVD },
+       { 0xcfb64000ULL, ( 0xcfb66000ULL - 0xcfb64000ULL ), E820_TYPE_RSVD },
+       { 0xcfb66000ULL, ( 0xcfb85c00ULL - 0xcfb66000ULL ), E820_TYPE_ACPI },
+       { 0xcfb85c00ULL, ( 0xd0000000ULL - 0xcfb85c00ULL ), E820_TYPE_RSVD },
+       { 0xe0000000ULL, ( 0xf0000000ULL - 0xe0000000ULL ), E820_TYPE_RSVD },
+       { 0xfe000000ULL, (0x100000000ULL - 0xfe000000ULL ), E820_TYPE_RSVD },
+       {0x100000000ULL, (0x230000000ULL -0x100000000ULL ), E820_TYPE_RAM },
+};
+#define e820map __use_text16 ( e820map )
+
+void fake_e820 ( void ) {
+       __asm__ __volatile__ (
+               TEXT16_CODE ( "\nint15_fakee820:\n\t"
+                             "pushfw\n\t"
+                             "cmpl $0xe820, %%eax\n\t"
+                             "jne 99f\n\t"
+                             "cmpl $0x534d4150, %%edx\n\t"
+                             "jne 99f\n\t"
+                             "pushaw\n\t"
+                             "leaw e820map(%%bx), %%si\n\t"
+                             "cs rep movsb\n\t"
+                             "popaw\n\t"
+                             "movl %%edx, %%eax\n\t"
+                             "addl $20, %%ebx\n\t"
+                             "cmpl %0, %%ebx\n\t"
+                             "jne 1f\n\t"
+                             "xorl %%ebx,%%ebx\n\t"
+                             "\n1:\n\t"
+                             "popfw\n\t"
+                             "clc\n\t"
+                             "lret $2\n\t"
+                             "\n99:\n\t"
+                             "popfw\n\t"
+                             "ljmp *%%cs:real_int15_vector\n\t" )
+               : : "i" ( sizeof ( e820map ) ) );
+
+       hook_bios_interrupt ( 0x15, ( unsigned int ) int15_fakee820,
+                             &real_int15_vector );
+}
+
+void unfake_e820 ( void ) {
+       unhook_bios_interrupt ( 0x15, ( unsigned int ) int15_fakee820,
+                               &real_int15_vector );
+}
index 2e74d3b..c9df7bd 100644 (file)
 #include <realmode.h>
 #include <biosint.h>
 #include <basemem.h>
+#include <fakee820.h>
 #include <gpxe/init.h>
 #include <gpxe/memmap.h>
 #include <gpxe/hidemem.h>
 
+/** Set to true if you want to test a fake E820 map */
+#define FAKE_E820 0
+
 /** Alignment for hidden memory regions */
 #define ALIGN_HIDDEN 4096   /* 4kB page alignment should be enough */
 
@@ -64,6 +68,10 @@ extern struct segoff __text16 ( int15_vector );
 /* The linker defines these symbols for us */
 extern char _text[];
 extern char _end[];
+extern char _text16_size[];
+#define _text16_size ( ( unsigned int ) _text16_size )
+extern char _data16_size[];
+#define _data16_size ( ( unsigned int ) _data16_size )
 
 /**
  * Hide region of memory from system memory map
@@ -123,16 +131,46 @@ void hide_text ( void ) {
  */
 static void hide_etherboot ( void ) {
        struct memory_map memmap;
+       unsigned int rm_ds_top;
+       unsigned int rm_cs_top;
+       unsigned int fbms;
 
        /* Dump memory map before mangling */
        DBG ( "Hiding gPXE from system memory map\n" );
        get_memmap ( &memmap );
 
+       /* Hook in fake E820 map, if we're testing one */
+       if ( FAKE_E820 ) {
+               DBG ( "Hooking in fake E820 map\n" );
+               fake_e820();
+               get_memmap ( &memmap );
+       }
+
        /* Initialise the hidden regions */
        hide_basemem();
        hide_umalloc ( virt_to_phys ( _text ), virt_to_phys ( _text ) );
        hide_text();
 
+       /* Some really moronic BIOSes bring up the PXE stack via the
+        * UNDI loader entry point and then don't bother to unload it
+        * before overwriting the code and data segments.  If this
+        * happens, we really don't want to leave INT 15 hooked,
+        * because that will cause any loaded OS to die horribly as
+        * soon as it attempts to fetch the system memory map.
+        *
+        * We use a heuristic to guess whether or not we are being
+        * loaded sensibly.
+        */
+       rm_cs_top = ( ( ( rm_cs << 4 ) + _text16_size + 1024 - 1 ) >> 10 );
+       rm_ds_top = ( ( ( rm_ds << 4 ) + _data16_size + 1024 - 1 ) >> 10 );
+       fbms = get_fbms();
+       if ( ( rm_cs_top < fbms ) && ( rm_ds_top < fbms ) ) {
+               DBG ( "Detected potentially unsafe UNDI load at CS=%04x "
+                     "DS=%04x FBMS=%dkB\n", rm_cs, rm_ds, fbms );
+               DBG ( "Disabling INT 15 memory hiding\n" );
+               return;
+       }
+
        /* Hook INT 15 */
        hook_bios_interrupt ( 0x15, ( unsigned int ) int15,
                              &int15_vector );
@@ -167,6 +205,10 @@ static void unhide_etherboot ( int flags __unused ) {
         */
        unhook_bios_interrupt ( 0x15, ( unsigned int ) int15,
                                &int15_vector );
+
+       /* Unhook fake E820 map, if used */
+       if ( FAKE_E820 )
+               unfake_e820();
 }
 
 /** Hide Etherboot startup function */
index fc0d36a..e6d6428 100644 (file)
@@ -86,9 +86,20 @@ static unsigned int extmemsize_e801 ( void ) {
        }
 
        extmem = ( extmem_1m_to_16m_k + ( extmem_16m_plus_64k * 64 ) );
-       DBG ( "INT 15,e801 extended memory size %d+64*%d=%d kB [100000,%x)\n",
-             extmem_1m_to_16m_k, extmem_16m_plus_64k, extmem,
-             ( 0x100000 + ( extmem * 1024 ) ) );
+       DBG ( "INT 15,e801 extended memory size %d+64*%d=%d kB "
+             "[100000,%llx)\n", extmem_1m_to_16m_k, extmem_16m_plus_64k,
+             extmem, ( 0x100000 + ( ( ( uint64_t ) extmem ) * 1024 ) ) );
+
+       /* Sanity check.  Some BIOSes report the entire 4GB address
+        * space as available, which cannot be correct (since that
+        * would leave no address space available for 32-bit PCI
+        * BARs).
+        */
+       if ( extmem == ( 0x400000 - 0x400 ) ) {
+               DBG ( "INT 15,e801 reported whole 4GB; assuming insane\n" );
+               return 0;
+       }
+
        return extmem;
 }
 
@@ -186,6 +197,28 @@ static int meme820 ( struct memory_map *memmap ) {
                }
        } while ( next != 0 );
 
+       /* Sanity checks.  Some BIOSes report complete garbage via INT
+        * 15,e820 (especially at POST time), despite passing the
+        * signature checks.  We currently check for a base memory
+        * region (starting at 0) and at least one high memory region
+        * (starting at 0x100000).
+        */
+       if ( memmap->count < 2 ) {
+               DBG ( "INT 15,e820 returned only %d regions; assuming "
+                     "insane\n", memmap->count );
+               return -EINVAL;
+       }
+       if ( memmap->regions[0].start != 0 ) {
+               DBG ( "INT 15,e820 region 0 starts at %llx (expected 0); "
+                     "assuming insane\n", memmap->regions[0].start );
+               return -EINVAL;
+       }
+       if ( memmap->regions[1].start != 0x100000 ) {
+               DBG ( "INT 15,e820 region 1 starts at %llx (expected 100000); "
+                     "assuming insane\n", memmap->regions[0].start );
+               return -EINVAL;
+       }
+
        return 0;
 }
 
diff --git a/gpxe/src/arch/i386/include/fakee820.h b/gpxe/src/arch/i386/include/fakee820.h
new file mode 100644 (file)
index 0000000..f1fe8af
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef _FAKEE820_H
+#define _FAKEE820_H
+
+extern void fake_e820 ( void );
+extern void unfake_e820 ( void );
+
+#endif /* _FAKEE820_H */
index 3ccb7fb..7122c4e 100644 (file)
@@ -440,6 +440,7 @@ int pxe_start_nbp ( void ) {
        __asm__ __volatile__ ( REAL_CODE ( "pushw %%cx\n\t"
                                           "pushw %%ax\n\t"
                                           "movw %%cx, %%es\n\t"
+                                          "sti\n\t"
                                           "lcall $0, $0x7c00\n\t"
                                           "addw $4, %%sp\n\t" )
                               : "=a" ( rc ), "=b" ( discard_b ),
index f9b9e16..872fbf5 100644 (file)
@@ -6,6 +6,8 @@
  * table so using a noticeable amount of stack space is a no-no.
  */
 
+#include <config/general.h>
+
 #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 PNP_GET_BBS_VERSION 0x60
 #define PMM_ALLOCATE 0x0000
 
+/* ROM banner timeout.  Based on the configurable BANNER_TIMEOUT in
+ * config.h, but converted to a number of (18Hz) timer ticks, and
+ * doubled to allow for BIOSes that switch video modes immediately
+ * beforehand, so rendering the message almost invisible to the user.
+ */
+#define ROM_BANNER_TIMEOUT ( 2 * ( 18 * BANNER_TIMEOUT ) / 10 )
+
        .text
        .code16
        .arch i386
@@ -145,8 +154,6 @@ init:
        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
@@ -317,51 +324,23 @@ no_pmm:
        movw    $init_message_prompt, %si
        xorw    %di, %di
        call    print_message
-       /* Empty the keyboard buffer before waiting for input */
-empty_keyboard_buffer:
-       movb    $0x01, %ah
-       int     $0x16
-       jz      1f
-       xorw    %ax, %ax
-       int     $0x16
-       jmp     empty_keyboard_buffer
-1:     /* Wait for up to 3s for a key press */
-       movw    $(18 * 3), %cx  /* Approx 3s worth of timer ticks */
-wait_for_key:
-       decw    %cx
-       jz      no_key_pressed
-       /* Wait for timer tick to be updated */
-       movl    %fs:(0x6c), %eax
-1:     pushf
-       sti
-       hlt
+       /* Wait for Ctrl-B */
+       movw    $0xff02, %bx
+       call    wait_for_key
+       /* Clear prompt */
+       pushf
+       movw    $clear_message, %si
+       xorw    %di, %di
+       call    print_message
        popf
-       cmpl    %fs:(0x6c), %eax
-       je      1b
-       /* Check to see if a key was pressed */
-       movb    $0x01, %ah
-       int     $0x16
-       jz      wait_for_key
-       /* Check to see if key was Ctrl-B */
-       cmpb    $0x02, %al
-       je      1f
-       /* Key was not Ctrl-B: remove from buffer and stop waiting */
-       xorw    %ax, %ax
-       int     $0x16
-       jmp     no_key_pressed
-1:     /* Key was Ctrl-B: leave in keyboard buffer and invoke gPXE.
-        * The keypress will be picked up by the initial shell
-        * prompt, and we will drop into a shell.
+       jnz     1f
+       /* Ctrl-B was pressed: invoke gPXE.  The keypress will be
+        * picked up by the initial shell prompt, and we will drop
+        * into a shell.
         */
        pushw   %cs
        call    exec
-no_key_pressed:
-
-       /* Print blank lines to terminate messages */
-       movw    $init_message_end, %si
-       xorw    %di, %di
-       call    print_message
-
+1:
        /* Restore registers */
        popw    %gs
        popw    %fs
@@ -395,9 +374,9 @@ init_message_int19:
 init_message_prompt:
        .asciz  "\nPress Ctrl-B to configure gPXE..."
        .size   init_message_prompt, . - init_message_prompt
-init_message_end:
-       .asciz  "\n\n\n"
-       .size   init_message_end, . - init_message_end
+clear_message:
+       .asciz  "\r                                     \n\n"
+       .size   clear_message, . - clear_message
 
 /* ROM image location
  *
@@ -436,24 +415,52 @@ bev_entry:
 /* INT19 entry point
  *
  * Called via the hooked INT 19 if we detected a non-PnP BIOS.  We
- * attempt to return via the original INT 19 vector (if we were able to
- * store it).
+ * attempt to return via the original INT 19 vector (if we were able
+ * to store it).
  */
 int19_entry:
        pushw   %cs
+       popw    %ds
+       /* Prompt user to press B to boot */
+       movw    $int19_message_prompt, %si
+       xorw    %di, %di
+       call    print_message
+       movw    $prodstr, %si
+       call    print_message
+       movw    $int19_message_dots, %si
+       call    print_message
+       movw    $0xdf42, %bx
+       call    wait_for_key
+       pushf
+       movw    $clear_message, %si
+       xorw    %di, %di
+       call    print_message
+       popf
+       jnz     1f
+       /* Leave keypress in buffer and start gPXE.  The keypress will
+        * cause the usual initial Ctrl-B prompt to be skipped.
+        */
+       pushw   %cs
        call    exec
+1:     /* Try to call original INT 19 vector */
        movl    %cs:orig_int19, %eax
        testl   %eax, %eax
-       je      1f
-       /* Chain to original INT 19 vector */
+       je      2f
        ljmp    *%cs:orig_int19
-1:     /* No chained vector: issue INT 18 as a last resort */
+2:     /* No chained vector: issue INT 18 as a last resort */
        int     $0x18
        .size   int19_entry, . - int19_entry
 orig_int19:
        .long   0
        .size   orig_int19, . - orig_int19
 
+int19_message_prompt:
+       .asciz  "Press B to boot from "
+       .size   int19_message_prompt, . - int19_message_prompt
+int19_message_dots:
+       .asciz  "..."
+       .size   int19_message_dots, . - int19_message_dots
+       
 /* Execute as a boot device
  *
  */
@@ -560,3 +567,67 @@ undiloader:
        popl    %esi
        lret
        .size undiloader, . - undiloader
+
+/* Wait for key press specified by %bl (masked by %bh)
+ *
+ * Used by init and INT19 code when prompting user.  If the specified
+ * key is pressed, it is left in the keyboard buffer.
+ *
+ * Returns with ZF set iff specified key is pressed.
+ */
+wait_for_key:
+       /* Preserve registers */
+       pushw   %cx
+       pushw   %ax
+1:     /* Empty the keyboard buffer before waiting for input */
+       movb    $0x01, %ah
+       int     $0x16
+       jz      2f
+       xorw    %ax, %ax
+       int     $0x16
+       jmp     1b
+2:     /* Wait for a key press */
+       movw    $ROM_BANNER_TIMEOUT, %cx
+3:     decw    %cx
+       js      99f             /* Exit with ZF clear */
+       /* Wait for timer tick to be updated */
+       call    wait_for_tick
+       /* Check to see if a key was pressed */
+       movb    $0x01, %ah
+       int     $0x16
+       jz      3b
+       /* Check to see if key was the specified key */
+       andb    %bh, %al
+       cmpb    %al, %bl
+       je      99f             /* Exit with ZF set */
+       /* Not the specified key: remove from buffer and stop waiting */
+       pushfw
+       xorw    %ax, %ax
+       int     $0x16
+       popfw                   /* Exit with ZF clear */
+99:    /* Restore registers and return */
+       popw    %ax
+       popw    %cx
+       ret
+       .size wait_for_key, . - wait_for_key
+
+/* Wait for timer tick
+ *
+ * Used by wait_for_key
+ */
+wait_for_tick:
+       pushl   %eax
+       pushw   %fs
+       movw    $0x40, %ax
+       movw    %ax, %fs
+       movl    %fs:(0x6c), %eax
+1:     pushf
+       sti
+       hlt
+       popf
+       cmpl    %fs:(0x6c), %eax
+       je      1b
+       popw    %fs
+       popl    %eax
+       ret
+       .size wait_for_tick, . - wait_for_tick
index e660ae7..a1299ee 100644 (file)
@@ -28,6 +28,7 @@
 #include <gpxe/vsprintf.h>
 #include <gpxe/dhcp.h>
 #include <gpxe/uuid.h>
+#include <gpxe/uri.h>
 #include <gpxe/settings.h>
 
 /** @file
@@ -746,6 +747,58 @@ struct setting_type setting_type_string __setting_type = {
 };
 
 /**
+ * Parse and store value of URI-encoded string setting
+ *
+ * @v settings         Settings block
+ * @v setting          Setting to store
+ * @v value            Formatted setting data
+ * @ret rc             Return status code
+ */
+static int storef_uristring ( struct settings *settings,
+                             struct setting *setting,
+                             const char *value ) {
+       char buf[ strlen ( value ) + 1 ]; /* Decoding never expands string */
+       size_t len;
+
+       len = uri_decode ( value, buf, sizeof ( buf ) );
+       return store_setting ( settings, setting, buf, len );
+}
+
+/**
+ * Fetch and format value of URI-encoded string setting
+ *
+ * @v settings         Settings block, or NULL to search all blocks
+ * @v setting          Setting to fetch
+ * @v buf              Buffer to contain formatted value
+ * @v len              Length of buffer
+ * @ret len            Length of formatted value, or negative error
+ */
+static int fetchf_uristring ( struct settings *settings,
+                             struct setting *setting,
+                             char *buf, size_t len ) {
+       size_t raw_len;
+
+       /* We need to always retrieve the full raw string to know the
+        * length of the encoded string.
+        */
+       raw_len = fetch_setting ( settings, setting, NULL, 0 );
+       {
+               char raw_buf[ raw_len + 1 ];
+       
+               fetch_string_setting ( settings, setting, raw_buf,
+                                      sizeof ( raw_buf ) );
+               return uri_encode ( raw_buf, buf, len );
+       }
+}
+
+/** A URI-encoded string setting type */
+struct setting_type setting_type_uristring __setting_type = {
+       .name = "uristring",
+       .storef = storef_uristring,
+       .fetchf = fetchf_uristring,
+};
+
+/**
  * Parse and store value of IPv4 address setting
  *
  * @v settings         Settings block
index 3b3cf85..cf2b071 100644 (file)
@@ -26,6 +26,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <libgen.h>
+#include <ctype.h>
 #include <gpxe/vsprintf.h>
 #include <gpxe/uri.h>
 
@@ -381,3 +382,80 @@ struct uri * resolve_uri ( struct uri *base_uri,
        free ( tmp_path );
        return new_uri;
 }
+
+/**
+ * Test for unreserved URI characters
+ *
+ * @v c                        Character to test
+ * @ret is_unreserved  Character is an unreserved character
+ */
+static int is_unreserved_uri_char ( int c ) {
+       /* According to RFC3986, the unreserved character set is
+        *
+        * A-Z a-z 0-9 - _ . ~
+        */
+       return ( isupper ( c ) || islower ( c ) || isdigit ( c ) ||
+                ( c == '-' ) || ( c == '_' ) ||
+                ( c == '.' ) || ( c == '~' ) );
+}
+
+/**
+ * URI-encode string
+ *
+ * @v raw_string       String to be URI-encoded
+ * @v buf              Buffer to contain encoded string
+ * @v len              Length of buffer
+ * @ret len            Length of encoded string (excluding NUL)
+ */
+size_t uri_encode ( const char *raw_string, char *buf, size_t len ) {
+       ssize_t remaining = len;
+       size_t used;
+       unsigned char c;
+
+       if ( len )
+               buf[0] = '\0';
+
+       while ( ( c = *(raw_string++) ) ) {
+               if ( is_unreserved_uri_char ( c ) ) {
+                       used = ssnprintf ( buf, remaining, "%c", c );
+               } else {
+                       used = ssnprintf ( buf, remaining, "%%%02X", c );
+               }
+               buf += used;
+               remaining -= used;
+       }
+
+       return ( len - remaining );
+}
+
+/**
+ * Decode URI-encoded string
+ *
+ * @v encoded_string   URI-encoded string
+ * @v buf              Buffer to contain decoded string
+ * @v len              Length of buffer
+ * @ret len            Length of decoded string (excluding NUL)
+ */
+size_t uri_decode ( const char *encoded_string, char *buf, size_t len ) {
+       ssize_t remaining = len;
+       char hexbuf[3];
+       char *hexbuf_end;
+       unsigned char c;
+
+       if ( len )
+               buf[0] = '\0';
+
+       while ( *encoded_string ) {
+               if ( *encoded_string == '%' ) {
+                       encoded_string++;
+                       snprintf ( hexbuf, sizeof ( hexbuf ), "%s",
+                                  encoded_string );
+                       c = strtoul ( hexbuf, &hexbuf_end, 16 );
+                       encoded_string += ( hexbuf_end - hexbuf );
+               } else {
+                       c = *(encoded_string++);
+               }
+               ssnprintf ( buf++, remaining--, "%c", c );
+       }
+       return ( len - remaining );
+}
index 5a13c5a..f9a3c70 100644 (file)
@@ -19,8 +19,6 @@
 #ifndef BIGINT_HEADER
 #define BIGINT_HEADER
 
-#include "config.h"
-
 /* enable features based on a 'super-set' capbaility. */
 #if defined(CONFIG_SSL_FULL_MODE) 
 #define CONFIG_SSL_ENABLE_CLIENT
index 2aced77..0c18083 100644 (file)
@@ -1714,7 +1714,7 @@ static int arbel_start_firmware ( struct arbel *arbel ) {
 
        /* Allocate firmware pages and map firmware area */
        fw_size = ( fw_pages * 4096 );
-       arbel->firmware_area = umalloc ( fw_size );
+       arbel->firmware_area = umalloc ( fw_size * 2 );
        if ( ! arbel->firmware_area ) {
                rc = -ENOMEM;
                goto err_alloc_fa;
index 439974e..9716aba 100644 (file)
@@ -1684,7 +1684,7 @@ static int hermon_start_firmware ( struct hermon *hermon ) {
 
        /* Allocate firmware pages and map firmware area */
        fw_size = ( fw_pages * HERMON_PAGE_SIZE );
-       hermon->firmware_area = umalloc ( fw_size );
+       hermon->firmware_area = umalloc ( fw_size * 2 );
        if ( ! hermon->firmware_area ) {
                rc = -ENOMEM;
                goto err_alloc_fa;
index 5644c96..6c7d1fc 100644 (file)
@@ -1673,6 +1673,17 @@ static int phantom_init_cmdpeg ( struct phantom_nic *phantom ) {
        uint32_t cmdpeg_state;
        uint32_t last_cmdpeg_state = 0;
 
+       /* Check for a previous initialisation.  This could have
+        * happened if, for example, the BIOS used the UNDI API to
+        * drive the NIC prior to a full PXE boot.
+        */
+       cmdpeg_state = phantom_readl ( phantom, UNM_NIC_REG_CMDPEG_STATE );
+       if ( cmdpeg_state == UNM_NIC_REG_CMDPEG_STATE_INITIALIZE_ACK ) {
+               DBGC ( phantom, "Phantom %p command PEG already initialized\n",
+                      phantom );
+               return 0;
+       }
+
        /* If this was a cold boot, check that the hardware came up ok */
        cold_boot = phantom_readl ( phantom, UNM_CAM_RAM_COLD_BOOT );
        if ( cold_boot == UNM_CAM_RAM_COLD_BOOT_MAGIC ) {
@@ -1692,8 +1703,6 @@ static int phantom_init_cmdpeg ( struct phantom_nic *phantom ) {
        phantom_writel ( phantom, 0, UNM_CAM_RAM_COLD_BOOT );
 
        /* Set port modes */
-       phantom_writel ( phantom, UNM_CAM_RAM_PORT_MODE_AUTO_NEG,
-                        UNM_CAM_RAM_PORT_MODE );
        phantom_writel ( phantom, UNM_CAM_RAM_PORT_MODE_AUTO_NEG_1G,
                         UNM_CAM_RAM_WOL_PORT_MODE );
 
index c5ed0ea..e89503d 100644 (file)
@@ -102,6 +102,7 @@ struct dhcp_packet;
 
 /** DHCP message type */
 #define DHCP_MESSAGE_TYPE 53
+#define DHCPNONE 0
 #define DHCPDISCOVER 1
 #define DHCPOFFER 2
 #define DHCPREQUEST 3
index 514bc47..37f3aac 100644 (file)
@@ -135,5 +135,7 @@ extern char * resolve_path ( const char *base_path,
 extern struct uri * resolve_uri ( struct uri *base_uri,
                                  struct uri *relative_uri );
 extern void churi ( struct uri *uri );
+extern size_t uri_encode ( const char *raw_string, char *buf, size_t len );
+extern size_t uri_decode ( const char *encoded_string, char *buf, size_t len );
 
 #endif /* _GPXE_URI_H */
index f815bc2..d228a36 100644 (file)
  */
 PXENV_EXIT_t undi_loader ( struct s_UNDI_LOADER *undi_loader ) {
 
-       DBG ( "[PXENV_UNDI_LOADER to CS %04x DS %04x]",
-             undi_loader->UNDI_CS, undi_loader->UNDI_DS );
-
        /* Perform one-time initialisation (e.g. heap) */
        initialise();
 
+       DBG ( "[PXENV_UNDI_LOADER to CS %04x DS %04x]",
+             undi_loader->UNDI_CS, undi_loader->UNDI_DS );
+
        /* Set up PXE data structures */
        pxe_init_structures();
 
index a67415b..01a4658 100644 (file)
@@ -1886,7 +1886,7 @@ static struct iscsi_string_setting iscsi_string_settings[] = {
        {
                .setting = &hostname_setting,
                .string = &iscsi_default_initiator_iqn,
-               .prefix = "iqn.2000-09.org.etherboot:",
+               .prefix = "iqn.2000-01.org.etherboot:",
        },
 };
 
index 5fcd56e..ab751cd 100644 (file)
@@ -65,7 +65,8 @@ static const uint8_t dhcp_op[] = {
 
 /** Raw option data for options common to all DHCP requests */
 static uint8_t dhcp_request_options_data[] = {
-       DHCP_MAX_MESSAGE_SIZE, DHCP_WORD ( ETH_MAX_MTU ),
+       DHCP_MAX_MESSAGE_SIZE,
+       DHCP_WORD ( ETH_MAX_MTU - 20 /* IP header */ - 8 /* UDP header */ ),
        DHCP_CLIENT_ARCHITECTURE, DHCP_WORD ( 0 ),
        DHCP_CLIENT_NDI, DHCP_OPTION ( 1 /* UNDI */ , 2, 1 /* v2.1 */ ),
        DHCP_VENDOR_CLASS_ID,
@@ -128,7 +129,7 @@ struct dhcp_client_uuid {
  */
 static inline const char * dhcp_msgtype_name ( unsigned int msgtype ) {
        switch ( msgtype ) {
-       case 0:                 return "BOOTP"; /* Non-DHCP packet */
+       case DHCPNONE:          return "BOOTP"; /* Non-DHCP packet */
        case DHCPDISCOVER:      return "DHCPDISCOVER";
        case DHCPOFFER:         return "DHCPOFFER";
        case DHCPREQUEST:       return "DHCPREQUEST";
@@ -685,7 +686,7 @@ static void dhcp_store_dhcpoffer ( struct dhcp_session *dhcp,
  */
 static void dhcp_rx_dhcpoffer ( struct dhcp_session *dhcp,
                                struct dhcp_settings *dhcpoffer ) {
-       struct in_addr server_id;
+       struct in_addr server_id = { 0 };
        char vci[9]; /* "PXEClient" */
        int len;
        uint8_t ignore_proxy = 0;
@@ -697,7 +698,7 @@ static void dhcp_rx_dhcpoffer ( struct dhcp_session *dhcp,
             != sizeof ( server_id ) ) {
                DBGC ( dhcp, "DHCP %p received DHCPOFFER %p missing server "
                       "identifier\n", dhcp, dhcpoffer );
-               return;
+               /* Could be a valid BOOTP offer; do not abort processing */
        }
 
        /* If there is an IP address, it's a normal DHCPOFFER */
@@ -714,7 +715,8 @@ static void dhcp_rx_dhcpoffer ( struct dhcp_session *dhcp,
         */
        len = dhcppkt_fetch ( &dhcpoffer->dhcppkt, DHCP_VENDOR_CLASS_ID,
                              vci, sizeof ( vci ) );
-       if ( ( len >= ( int ) sizeof ( vci ) ) &&
+       if ( ( server_id.s_addr != 0 ) &&
+            ( len >= ( int ) sizeof ( vci ) ) &&
             ( strncmp ( "PXEClient", vci, sizeof ( vci ) ) == 0 ) ) {
                DBGC ( dhcp, "DHCP %p received DHCPOFFER %p from %s is a "
                       "ProxyDHCPOFFER\n",
@@ -924,12 +926,12 @@ static int dhcp_deliver_iob ( struct xfer_interface *xfer,
        /* Handle packet based on current state */
        switch ( dhcp->state ) {
        case DHCP_STATE_DISCOVER:
-               if ( ( msgtype == DHCPOFFER ) &&
+               if ( ( ( msgtype == DHCPOFFER ) || ( msgtype == DHCPNONE ) ) &&
                     ( src_port == htons ( BOOTPS_PORT ) ) )
                        dhcp_rx_dhcpoffer ( dhcp, dhcpset );
                break;
        case DHCP_STATE_REQUEST:
-               if ( ( msgtype == DHCPACK ) &&
+               if ( ( ( msgtype == DHCPACK ) || ( msgtype == DHCPNONE ) ) &&
                     ( src_port == htons ( BOOTPS_PORT ) ) )
                        dhcp_rx_dhcpack ( dhcp, dhcpset );
                break;