diff options
author | H. Peter Anvin <hpa@zytor.com> | 2008-09-25 13:46:43 -0700 |
---|---|---|
committer | H. Peter Anvin <hpa@zytor.com> | 2008-09-25 13:46:43 -0700 |
commit | 400e2b589e6d0bdd9efee9369feb7d5f5e0958d6 (patch) | |
tree | 5563ff419701da0868ff0da295fb1a6eb44e79ef /gpxe | |
parent | 41e4481d7bb14abf1e53a9b63abce9533c4e66ad (diff) | |
download | syslinux-400e2b589e6d0bdd9efee9369feb7d5f5e0958d6.tar.gz |
Update gPXEsyslinux-3.72-pre8
Update gPXE to:
gpxe-for-syslinux 0a1f463e8b3218803b42cd3940e90a7678de0b3e
gpxe upstream 3392cfa7df58a5662417f25226cf75dedabeb750
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
Diffstat (limited to 'gpxe')
-rw-r--r-- | gpxe/src/arch/i386/core/relocate.c | 15 | ||||
-rw-r--r-- | gpxe/src/arch/i386/drivers/net/undirom.c | 4 | ||||
-rw-r--r-- | gpxe/src/arch/i386/firmware/pcbios/e820mangler.S | 28 | ||||
-rw-r--r-- | gpxe/src/arch/i386/firmware/pcbios/fakee820.c | 90 | ||||
-rw-r--r-- | gpxe/src/arch/i386/firmware/pcbios/hidemem.c | 42 | ||||
-rw-r--r-- | gpxe/src/arch/i386/firmware/pcbios/memmap.c | 39 | ||||
-rw-r--r-- | gpxe/src/arch/i386/include/fakee820.h | 7 | ||||
-rw-r--r-- | gpxe/src/arch/i386/interface/pxe/pxe_call.c | 1 | ||||
-rw-r--r-- | gpxe/src/arch/i386/prefix/romprefix.S | 173 | ||||
-rw-r--r-- | gpxe/src/core/settings.c | 53 | ||||
-rw-r--r-- | gpxe/src/core/uri.c | 78 | ||||
-rw-r--r-- | gpxe/src/crypto/axtls/bigint.h | 2 | ||||
-rw-r--r-- | gpxe/src/drivers/infiniband/arbel.c | 2 | ||||
-rw-r--r-- | gpxe/src/drivers/infiniband/hermon.c | 2 | ||||
-rw-r--r-- | gpxe/src/drivers/net/phantom/phantom.c | 13 | ||||
-rw-r--r-- | gpxe/src/include/gpxe/dhcp.h | 1 | ||||
-rw-r--r-- | gpxe/src/include/gpxe/uri.h | 2 | ||||
-rw-r--r-- | gpxe/src/interface/pxe/pxe_loader.c | 6 | ||||
-rw-r--r-- | gpxe/src/net/tcp/iscsi.c | 2 | ||||
-rw-r--r-- | gpxe/src/net/udp/dhcp.c | 16 |
20 files changed, 479 insertions, 97 deletions
diff --git a/gpxe/src/arch/i386/core/relocate.c b/gpxe/src/arch/i386/core/relocate.c index 39d00b09..aa58ad65 100644 --- a/gpxe/src/arch/i386/core/relocate.c +++ b/gpxe/src/arch/i386/core/relocate.c @@ -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", diff --git a/gpxe/src/arch/i386/drivers/net/undirom.c b/gpxe/src/arch/i386/drivers/net/undirom.c index f977a553..d40fcd35 100644 --- a/gpxe/src/arch/i386/drivers/net/undirom.c +++ b/gpxe/src/arch/i386/drivers/net/undirom.c @@ -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 ); } diff --git a/gpxe/src/arch/i386/firmware/pcbios/e820mangler.S b/gpxe/src/arch/i386/firmware/pcbios/e820mangler.S index 3c4cf21b..ad773f74 100644 --- a/gpxe/src/arch/i386/firmware/pcbios/e820mangler.S +++ b/gpxe/src/arch/i386/firmware/pcbios/e820mangler.S @@ -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 index 00000000..e171edfd --- /dev/null +++ b/gpxe/src/arch/i386/firmware/pcbios/fakee820.c @@ -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 ); +} diff --git a/gpxe/src/arch/i386/firmware/pcbios/hidemem.c b/gpxe/src/arch/i386/firmware/pcbios/hidemem.c index 2e74d3b0..c9df7bd0 100644 --- a/gpxe/src/arch/i386/firmware/pcbios/hidemem.c +++ b/gpxe/src/arch/i386/firmware/pcbios/hidemem.c @@ -19,10 +19,14 @@ #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 */ diff --git a/gpxe/src/arch/i386/firmware/pcbios/memmap.c b/gpxe/src/arch/i386/firmware/pcbios/memmap.c index fc0d36ac..e6d6428e 100644 --- a/gpxe/src/arch/i386/firmware/pcbios/memmap.c +++ b/gpxe/src/arch/i386/firmware/pcbios/memmap.c @@ -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 index 00000000..f1fe8aff --- /dev/null +++ b/gpxe/src/arch/i386/include/fakee820.h @@ -0,0 +1,7 @@ +#ifndef _FAKEE820_H +#define _FAKEE820_H + +extern void fake_e820 ( void ); +extern void unfake_e820 ( void ); + +#endif /* _FAKEE820_H */ diff --git a/gpxe/src/arch/i386/interface/pxe/pxe_call.c b/gpxe/src/arch/i386/interface/pxe/pxe_call.c index 3ccb7fb5..7122c4eb 100644 --- a/gpxe/src/arch/i386/interface/pxe/pxe_call.c +++ b/gpxe/src/arch/i386/interface/pxe/pxe_call.c @@ -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 ), diff --git a/gpxe/src/arch/i386/prefix/romprefix.S b/gpxe/src/arch/i386/prefix/romprefix.S index f9b9e169..872fbf56 100644 --- a/gpxe/src/arch/i386/prefix/romprefix.S +++ b/gpxe/src/arch/i386/prefix/romprefix.S @@ -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 ) ) @@ -13,6 +15,13 @@ #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 diff --git a/gpxe/src/core/settings.c b/gpxe/src/core/settings.c index e660ae7c..a1299ee2 100644 --- a/gpxe/src/core/settings.c +++ b/gpxe/src/core/settings.c @@ -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 diff --git a/gpxe/src/core/uri.c b/gpxe/src/core/uri.c index 3b3cf85b..cf2b071d 100644 --- a/gpxe/src/core/uri.c +++ b/gpxe/src/core/uri.c @@ -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 ); +} diff --git a/gpxe/src/crypto/axtls/bigint.h b/gpxe/src/crypto/axtls/bigint.h index 5a13c5ae..f9a3c70b 100644 --- a/gpxe/src/crypto/axtls/bigint.h +++ b/gpxe/src/crypto/axtls/bigint.h @@ -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 diff --git a/gpxe/src/drivers/infiniband/arbel.c b/gpxe/src/drivers/infiniband/arbel.c index 2aced777..0c180833 100644 --- a/gpxe/src/drivers/infiniband/arbel.c +++ b/gpxe/src/drivers/infiniband/arbel.c @@ -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; diff --git a/gpxe/src/drivers/infiniband/hermon.c b/gpxe/src/drivers/infiniband/hermon.c index 439974eb..9716aba9 100644 --- a/gpxe/src/drivers/infiniband/hermon.c +++ b/gpxe/src/drivers/infiniband/hermon.c @@ -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; diff --git a/gpxe/src/drivers/net/phantom/phantom.c b/gpxe/src/drivers/net/phantom/phantom.c index 5644c96d..6c7d1fc9 100644 --- a/gpxe/src/drivers/net/phantom/phantom.c +++ b/gpxe/src/drivers/net/phantom/phantom.c @@ -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 ); diff --git a/gpxe/src/include/gpxe/dhcp.h b/gpxe/src/include/gpxe/dhcp.h index c5ed0ead..e89503d3 100644 --- a/gpxe/src/include/gpxe/dhcp.h +++ b/gpxe/src/include/gpxe/dhcp.h @@ -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 diff --git a/gpxe/src/include/gpxe/uri.h b/gpxe/src/include/gpxe/uri.h index 514bc479..37f3aac9 100644 --- a/gpxe/src/include/gpxe/uri.h +++ b/gpxe/src/include/gpxe/uri.h @@ -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 */ diff --git a/gpxe/src/interface/pxe/pxe_loader.c b/gpxe/src/interface/pxe/pxe_loader.c index f815bc25..d228a36d 100644 --- a/gpxe/src/interface/pxe/pxe_loader.c +++ b/gpxe/src/interface/pxe/pxe_loader.c @@ -31,12 +31,12 @@ */ 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(); diff --git a/gpxe/src/net/tcp/iscsi.c b/gpxe/src/net/tcp/iscsi.c index a67415b6..01a46584 100644 --- a/gpxe/src/net/tcp/iscsi.c +++ b/gpxe/src/net/tcp/iscsi.c @@ -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:", }, }; diff --git a/gpxe/src/net/udp/dhcp.c b/gpxe/src/net/udp/dhcp.c index 5fcd56ea..ab751cd5 100644 --- a/gpxe/src/net/udp/dhcp.c +++ b/gpxe/src/net/udp/dhcp.c @@ -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; |