/* 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
* 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",
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 );
}
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 */
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
--- /dev/null
+/* 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 );
+}
#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 */
/* 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
*/
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 );
*/
unhook_bios_interrupt ( 0x15, ( unsigned int ) int15,
&int15_vector );
+
+ /* Unhook fake E820 map, if used */
+ if ( FAKE_E820 )
+ unfake_e820();
}
/** Hide Etherboot startup function */
}
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;
}
}
} 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;
}
--- /dev/null
+#ifndef _FAKEE820_H
+#define _FAKEE820_H
+
+extern void fake_e820 ( void );
+extern void unfake_e820 ( void );
+
+#endif /* _FAKEE820_H */
__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 ),
* 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
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
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
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
*
/* 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
*
*/
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
#include <gpxe/vsprintf.h>
#include <gpxe/dhcp.h>
#include <gpxe/uuid.h>
+#include <gpxe/uri.h>
#include <gpxe/settings.h>
/** @file
};
/**
+ * 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
#include <stdlib.h>
#include <string.h>
#include <libgen.h>
+#include <ctype.h>
#include <gpxe/vsprintf.h>
#include <gpxe/uri.h>
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 );
+}
#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
/* 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;
/* 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;
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 ) {
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 );
/** DHCP message type */
#define DHCP_MESSAGE_TYPE 53
+#define DHCPNONE 0
#define DHCPDISCOVER 1
#define DHCPOFFER 2
#define DHCPREQUEST 3
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 */
*/
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();
{
.setting = &hostname_setting,
.string = &iscsi_default_initiator_iqn,
- .prefix = "iqn.2000-09.org.etherboot:",
+ .prefix = "iqn.2000-01.org.etherboot:",
},
};
/** 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,
*/
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";
*/
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;
!= 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 */
*/
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",
/* 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;