summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.housekeeping3
-rw-r--r--src/arch/x86/core/x86_bigint.c11
-rw-r--r--src/arch/x86/drivers/net/undinet.c11
-rw-r--r--src/arch/x86/image/bzimage.c52
-rw-r--r--src/arch/x86/image/initrd.c1
-rw-r--r--src/arch/x86/include/bits/bigint.h54
-rw-r--r--src/arch/x86/include/initrd.h7
-rw-r--r--src/arch/x86/include/ipxe/cpuid.h3
-rw-r--r--src/arch/x86/interface/pcbios/rtc_entropy.c11
-rw-r--r--src/arch/x86/prefix/unlzma.S2
-rw-r--r--src/config/cloud/aws.ipxe20
-rw-r--r--src/config/cloud/gce.ipxe3
-rw-r--r--src/config/cloud/settings.h2
-rw-r--r--src/config/config.c6
-rw-r--r--src/config/config_archive.c36
-rw-r--r--src/config/general.h3
-rw-r--r--src/core/archive.c138
-rw-r--r--src/core/base64.c2
-rw-r--r--src/core/console.c5
-rw-r--r--src/core/cpio.c85
-rw-r--r--src/core/image.c25
-rw-r--r--src/core/open.c3
-rw-r--r--src/core/string.c17
-rw-r--r--src/crypto/x509.c3
-rw-r--r--src/drivers/net/ath/ath5k/ath5k_eeprom.c3
-rw-r--r--src/drivers/net/bnxt/bnxt.c68
-rw-r--r--src/drivers/net/bnxt/bnxt.h137
-rw-r--r--src/drivers/net/intel.c12
-rw-r--r--src/drivers/net/rdc.c694
-rw-r--r--src/drivers/net/rdc.h194
-rw-r--r--src/drivers/net/realtek.c10
-rw-r--r--src/hci/commands/image_archive_cmd.c105
-rw-r--r--src/hci/commands/nvo_cmd.c57
-rw-r--r--src/hci/readline.c17
-rw-r--r--src/hci/shell.c2
-rw-r--r--src/image/gzip.c167
-rw-r--r--src/image/zlib.c163
-rw-r--r--src/include/endian.h4
-rw-r--r--src/include/ipxe/cpio.h21
-rw-r--r--src/include/ipxe/errfile.h4
-rw-r--r--src/include/ipxe/gzip.h71
-rw-r--r--src/include/ipxe/image.h12
-rw-r--r--src/include/ipxe/rndis.h4
-rw-r--r--src/include/ipxe/zlib.h43
-rw-r--r--src/include/mii.h2
-rw-r--r--src/include/readline/readline.h3
-rw-r--r--src/include/stdio.h2
-rw-r--r--src/include/strings.h2
-rw-r--r--src/include/usr/imgarchive.h16
-rw-r--r--src/interface/efi/efi_file.c378
-rw-r--r--src/interface/efi/efi_pci.c6
-rw-r--r--src/interface/efi/efi_veto.c18
-rw-r--r--src/interface/xen/xenstore.c12
-rw-r--r--src/net/peerdisc.c23
-rw-r--r--src/net/tcp/httpconn.c3
-rw-r--r--src/tests/gzip_test.c160
-rw-r--r--src/tests/string_test.c8
-rw-r--r--src/tests/tests.c2
-rw-r--r--src/tests/x509_test.c1
-rw-r--r--src/tests/zlib_test.c133
-rw-r--r--src/usr/imgarchive.c54
-rw-r--r--src/util/elf2efi.c16
-rwxr-xr-xsrc/util/genfsimg18
63 files changed, 2803 insertions, 345 deletions
diff --git a/src/Makefile.housekeeping b/src/Makefile.housekeeping
index e017c656b..0deb15c10 100644
--- a/src/Makefile.housekeeping
+++ b/src/Makefile.housekeeping
@@ -1167,7 +1167,8 @@ $(BLIB) : $(BLIB_OBJS) $(BLIB_LIST) $(MAKEDEPS)
$(Q)$(RM) $(BLIB)
$(QM)$(ECHO) " [AR] $@"
$(Q)$(AR) rD $@ $(sort $(BLIB_OBJS))
- $(Q)$(OBJCOPY) --prefix-symbols=$(SYMBOL_PREFIX) $@
+ $(Q)$(OBJCOPY) --enable-deterministic-archives \
+ --prefix-symbols=$(SYMBOL_PREFIX) $@
$(Q)$(RANLIB) -D $@
blib : $(BLIB)
diff --git a/src/arch/x86/core/x86_bigint.c b/src/arch/x86/core/x86_bigint.c
index 6413b2fa8..9a25bdad5 100644
--- a/src/arch/x86/core/x86_bigint.c
+++ b/src/arch/x86/core/x86_bigint.c
@@ -75,17 +75,18 @@ void bigint_multiply_raw ( const uint32_t *multiplicand0,
*
* a < 2^{n}, b < 2^{n} => ab < 2^{2n}
*/
- __asm__ __volatile__ ( "mull %4\n\t"
- "addl %%eax, (%5,%2,4)\n\t"
- "adcl %%edx, 4(%5,%2,4)\n\t"
+ __asm__ __volatile__ ( "mull %5\n\t"
+ "addl %%eax, (%6,%2,4)\n\t"
+ "adcl %%edx, 4(%6,%2,4)\n\t"
"\n1:\n\t"
- "adcl $0, 8(%5,%2,4)\n\t"
+ "adcl $0, 8(%6,%2,4)\n\t"
"inc %2\n\t"
/* Does not affect CF */
"jc 1b\n\t"
: "=&a" ( discard_a ),
"=&d" ( discard_d ),
- "=&r" ( index )
+ "=&r" ( index ),
+ "+m" ( *result )
: "0" ( multiplicand_element ),
"g" ( multiplier_element ),
"r" ( result_elements ),
diff --git a/src/arch/x86/drivers/net/undinet.c b/src/arch/x86/drivers/net/undinet.c
index 9b7d6d849..43cb18bfe 100644
--- a/src/arch/x86/drivers/net/undinet.c
+++ b/src/arch/x86/drivers/net/undinet.c
@@ -104,6 +104,13 @@ static union u_PXENV_ANY __bss16 ( undinet_params );
SEGOFF16_t __bss16 ( undinet_entry_point );
#define undinet_entry_point __use_data16 ( undinet_entry_point )
+/* Read TSC in real mode only when profiling */
+#if PROFILING
+#define RDTSC_IF_PROFILING "rdtsc\n\t"
+#else
+#define RDTSC_IF_PROFILING ""
+#endif
+
/** IRQ profiler */
static struct profiler undinet_irq_profiler __profiler =
{ .name = "undinet.irq" };
@@ -288,14 +295,14 @@ static int undinet_call ( struct undi_nic *undinic, unsigned int function,
*/
profile_start ( &profiler->total );
__asm__ __volatile__ ( REAL_CODE ( "pushl %%ebp\n\t" /* gcc bug */
- "rdtsc\n\t"
+ RDTSC_IF_PROFILING
"pushl %%eax\n\t"
"pushw %%es\n\t"
"pushw %%di\n\t"
"pushw %%bx\n\t"
"lcall *undinet_entry_point\n\t"
"movw %%ax, %%bx\n\t"
- "rdtsc\n\t"
+ RDTSC_IF_PROFILING
"addw $6, %%sp\n\t"
"popl %%edx\n\t"
"popl %%ebp\n\t" /* gcc bug */ )
diff --git a/src/arch/x86/image/bzimage.c b/src/arch/x86/image/bzimage.c
index 51498bf95..a782127a1 100644
--- a/src/arch/x86/image/bzimage.c
+++ b/src/arch/x86/image/bzimage.c
@@ -327,32 +327,6 @@ static void bzimage_set_cmdline ( struct image *image,
}
/**
- * Parse standalone image command line for cpio parameters
- *
- * @v image bzImage file
- * @v cpio CPIO header
- * @v cmdline Command line
- */
-static void bzimage_parse_cpio_cmdline ( struct image *image,
- struct cpio_header *cpio,
- const char *cmdline ) {
- char *arg;
- char *end;
- unsigned int mode;
-
- /* Look for "mode=" */
- if ( ( arg = strstr ( cmdline, "mode=" ) ) ) {
- arg += 5;
- mode = strtoul ( arg, &end, 8 /* Octal for file mode */ );
- if ( *end && ( *end != ' ' ) ) {
- DBGC ( image, "bzImage %p strange \"mode=\""
- "terminator '%c'\n", image, *end );
- }
- cpio_set_field ( cpio->c_mode, ( 0100000 | mode ) );
- }
-}
-
-/**
* Align initrd length
*
* @v len Length
@@ -374,11 +348,9 @@ static inline size_t bzimage_align ( size_t len ) {
static size_t bzimage_load_initrd ( struct image *image,
struct image *initrd,
userptr_t address ) {
- char *filename = initrd->cmdline;
- char *cmdline;
+ const char *filename = cpio_name ( initrd );
struct cpio_header cpio;
size_t offset;
- size_t name_len;
size_t pad_len;
/* Do not include kernel image itself as an initrd */
@@ -386,25 +358,7 @@ static size_t bzimage_load_initrd ( struct image *image,
return 0;
/* Create cpio header for non-prebuilt images */
- if ( filename && filename[0] ) {
- cmdline = strchr ( filename, ' ' );
- name_len = ( ( cmdline ? ( ( size_t ) ( cmdline - filename ) )
- : strlen ( filename ) ) + 1 /* NUL */ );
- memset ( &cpio, '0', sizeof ( cpio ) );
- memcpy ( cpio.c_magic, CPIO_MAGIC, sizeof ( cpio.c_magic ) );
- cpio_set_field ( cpio.c_mode, 0100644 );
- cpio_set_field ( cpio.c_nlink, 1 );
- cpio_set_field ( cpio.c_filesize, initrd->len );
- cpio_set_field ( cpio.c_namesize, name_len );
- if ( cmdline ) {
- bzimage_parse_cpio_cmdline ( image, &cpio,
- ( cmdline + 1 /* ' ' */ ));
- }
- offset = ( ( sizeof ( cpio ) + name_len + 0x03 ) & ~0x03 );
- } else {
- offset = 0;
- name_len = 0;
- }
+ offset = cpio_header ( initrd, &cpio );
/* Copy in initrd image body (and cpio header if applicable) */
if ( address ) {
@@ -413,7 +367,7 @@ static size_t bzimage_load_initrd ( struct image *image,
memset_user ( address, 0, 0, offset );
copy_to_user ( address, 0, &cpio, sizeof ( cpio ) );
copy_to_user ( address, sizeof ( cpio ), filename,
- ( name_len - 1 /* NUL (or space) */ ) );
+ cpio_name_len ( initrd ) );
}
DBGC ( image, "bzImage %p initrd %p [%#08lx,%#08lx,%#08lx)"
"%s%s\n", image, initrd, user_to_phys ( address, 0 ),
diff --git a/src/arch/x86/image/initrd.c b/src/arch/x86/image/initrd.c
index 49b959a91..d7b1f5773 100644
--- a/src/arch/x86/image/initrd.c
+++ b/src/arch/x86/image/initrd.c
@@ -29,6 +29,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/uaccess.h>
#include <ipxe/init.h>
#include <ipxe/memblock.h>
+#include <ipxe/cpio.h>
/** @file
*
diff --git a/src/arch/x86/include/bits/bigint.h b/src/arch/x86/include/bits/bigint.h
index 4f1bc87ff..7443d6fdc 100644
--- a/src/arch/x86/include/bits/bigint.h
+++ b/src/arch/x86/include/bits/bigint.h
@@ -25,19 +25,22 @@ typedef uint32_t bigint_element_t;
static inline __attribute__ (( always_inline )) void
bigint_init_raw ( uint32_t *value0, unsigned int size,
const void *data, size_t len ) {
- long pad_len = ( sizeof ( bigint_t ( size ) ) - len );
+ bigint_t ( size ) __attribute__ (( may_alias )) *value =
+ ( ( void * ) value0 );
+ long pad_len = ( sizeof ( *value ) - len );
void *discard_D;
long discard_c;
/* Copy raw data in reverse order, padding with zeros */
__asm__ __volatile__ ( "\n1:\n\t"
- "movb -1(%2,%1), %%al\n\t"
+ "movb -1(%3,%1), %%al\n\t"
"stosb\n\t"
"loop 1b\n\t"
"xorl %%eax, %%eax\n\t"
- "mov %3, %1\n\t"
+ "mov %4, %1\n\t"
"rep stosb\n\t"
- : "=&D" ( discard_D ), "=&c" ( discard_c )
+ : "=&D" ( discard_D ), "=&c" ( discard_c ),
+ "+m" ( *value )
: "r" ( data ), "g" ( pad_len ), "0" ( value0 ),
"1" ( len )
: "eax" );
@@ -53,6 +56,8 @@ bigint_init_raw ( uint32_t *value0, unsigned int size,
static inline __attribute__ (( always_inline )) void
bigint_add_raw ( const uint32_t *addend0, uint32_t *value0,
unsigned int size ) {
+ bigint_t ( size ) __attribute__ (( may_alias )) *value =
+ ( ( void * ) value0 );
long index;
void *discard_S;
long discard_c;
@@ -60,11 +65,11 @@ bigint_add_raw ( const uint32_t *addend0, uint32_t *value0,
__asm__ __volatile__ ( "xor %0, %0\n\t" /* Zero %0 and clear CF */
"\n1:\n\t"
"lodsl\n\t"
- "adcl %%eax, (%3,%0,4)\n\t"
+ "adcl %%eax, (%4,%0,4)\n\t"
"inc %0\n\t" /* Does not affect CF */
"loop 1b\n\t"
: "=&r" ( index ), "=&S" ( discard_S ),
- "=&c" ( discard_c )
+ "=&c" ( discard_c ), "+m" ( *value )
: "r" ( value0 ), "1" ( addend0 ), "2" ( size )
: "eax" );
}
@@ -79,6 +84,8 @@ bigint_add_raw ( const uint32_t *addend0, uint32_t *value0,
static inline __attribute__ (( always_inline )) void
bigint_subtract_raw ( const uint32_t *subtrahend0, uint32_t *value0,
unsigned int size ) {
+ bigint_t ( size ) __attribute__ (( may_alias )) *value =
+ ( ( void * ) value0 );
long index;
void *discard_S;
long discard_c;
@@ -86,11 +93,11 @@ bigint_subtract_raw ( const uint32_t *subtrahend0, uint32_t *value0,
__asm__ __volatile__ ( "xor %0, %0\n\t" /* Zero %0 and clear CF */
"\n1:\n\t"
"lodsl\n\t"
- "sbbl %%eax, (%3,%0,4)\n\t"
+ "sbbl %%eax, (%4,%0,4)\n\t"
"inc %0\n\t" /* Does not affect CF */
"loop 1b\n\t"
: "=&r" ( index ), "=&S" ( discard_S ),
- "=&c" ( discard_c )
+ "=&c" ( discard_c ), "+m" ( *value )
: "r" ( value0 ), "1" ( subtrahend0 ),
"2" ( size )
: "eax" );
@@ -104,15 +111,18 @@ bigint_subtract_raw ( const uint32_t *subtrahend0, uint32_t *value0,
*/
static inline __attribute__ (( always_inline )) void
bigint_rol_raw ( uint32_t *value0, unsigned int size ) {
+ bigint_t ( size ) __attribute__ (( may_alias )) *value =
+ ( ( void * ) value0 );
long index;
long discard_c;
__asm__ __volatile__ ( "xor %0, %0\n\t" /* Zero %0 and clear CF */
"\n1:\n\t"
- "rcll $1, (%2,%0,4)\n\t"
+ "rcll $1, (%3,%0,4)\n\t"
"inc %0\n\t" /* Does not affect CF */
"loop 1b\n\t"
- : "=&r" ( index ), "=&c" ( discard_c )
+ : "=&r" ( index ), "=&c" ( discard_c ),
+ "+m" ( *value )
: "r" ( value0 ), "1" ( size ) );
}
@@ -124,13 +134,15 @@ bigint_rol_raw ( uint32_t *value0, unsigned int size ) {
*/
static inline __attribute__ (( always_inline )) void
bigint_ror_raw ( uint32_t *value0, unsigned int size ) {
+ bigint_t ( size ) __attribute__ (( may_alias )) *value =
+ ( ( void * ) value0 );
long discard_c;
__asm__ __volatile__ ( "clc\n\t"
"\n1:\n\t"
- "rcrl $1, -4(%1,%0,4)\n\t"
+ "rcrl $1, -4(%2,%0,4)\n\t"
"loop 1b\n\t"
- : "=&c" ( discard_c )
+ : "=&c" ( discard_c ), "+m" ( *value )
: "r" ( value0 ), "0" ( size ) );
}
@@ -239,6 +251,8 @@ bigint_max_set_bit_raw ( const uint32_t *value0, unsigned int size ) {
static inline __attribute__ (( always_inline )) void
bigint_grow_raw ( const uint32_t *source0, unsigned int source_size,
uint32_t *dest0, unsigned int dest_size ) {
+ bigint_t ( dest_size ) __attribute__ (( may_alias )) *dest =
+ ( ( void * ) dest0 );
long pad_size = ( dest_size - source_size );
void *discard_D;
void *discard_S;
@@ -246,10 +260,10 @@ bigint_grow_raw ( const uint32_t *source0, unsigned int source_size,
__asm__ __volatile__ ( "rep movsl\n\t"
"xorl %%eax, %%eax\n\t"
- "mov %3, %2\n\t"
+ "mov %4, %2\n\t"
"rep stosl\n\t"
: "=&D" ( discard_D ), "=&S" ( discard_S ),
- "=&c" ( discard_c )
+ "=&c" ( discard_c ), "+m" ( *dest )
: "g" ( pad_size ), "0" ( dest0 ),
"1" ( source0 ), "2" ( source_size )
: "eax" );
@@ -266,13 +280,15 @@ bigint_grow_raw ( const uint32_t *source0, unsigned int source_size,
static inline __attribute__ (( always_inline )) void
bigint_shrink_raw ( const uint32_t *source0, unsigned int source_size __unused,
uint32_t *dest0, unsigned int dest_size ) {
+ bigint_t ( dest_size ) __attribute__ (( may_alias )) *dest =
+ ( ( void * ) dest0 );
void *discard_D;
void *discard_S;
long discard_c;
__asm__ __volatile__ ( "rep movsl\n\t"
: "=&D" ( discard_D ), "=&S" ( discard_S ),
- "=&c" ( discard_c )
+ "=&c" ( discard_c ), "+m" ( *dest )
: "0" ( dest0 ), "1" ( source0 ),
"2" ( dest_size )
: "eax" );
@@ -289,15 +305,19 @@ bigint_shrink_raw ( const uint32_t *source0, unsigned int source_size __unused,
static inline __attribute__ (( always_inline )) void
bigint_done_raw ( const uint32_t *value0, unsigned int size __unused,
void *out, size_t len ) {
+ struct {
+ uint8_t bytes[len];
+ } __attribute__ (( may_alias )) *out_bytes = out;
void *discard_D;
long discard_c;
/* Copy raw data in reverse order */
__asm__ __volatile__ ( "\n1:\n\t"
- "movb -1(%2,%1), %%al\n\t"
+ "movb -1(%3,%1), %%al\n\t"
"stosb\n\t"
"loop 1b\n\t"
- : "=&D" ( discard_D ), "=&c" ( discard_c )
+ : "=&D" ( discard_D ), "=&c" ( discard_c ),
+ "+m" ( *out_bytes )
: "r" ( value0 ), "0" ( out ), "1" ( len )
: "eax" );
}
diff --git a/src/arch/x86/include/initrd.h b/src/arch/x86/include/initrd.h
index ddb3e5a45..2fb9d3d3a 100644
--- a/src/arch/x86/include/initrd.h
+++ b/src/arch/x86/include/initrd.h
@@ -11,13 +11,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/uaccess.h>
-/** Minimum alignment for initrds
- *
- * Some versions of Linux complain about initrds that are not
- * page-aligned.
- */
-#define INITRD_ALIGN 4096
-
/** Minimum free space required to reshuffle initrds
*
* Chosen to avoid absurdly long reshuffling times
diff --git a/src/arch/x86/include/ipxe/cpuid.h b/src/arch/x86/include/ipxe/cpuid.h
index b5403bd9d..3983dfb89 100644
--- a/src/arch/x86/include/ipxe/cpuid.h
+++ b/src/arch/x86/include/ipxe/cpuid.h
@@ -42,6 +42,9 @@ struct x86_features {
/** Hypervisor is present */
#define CPUID_FEATURES_INTEL_ECX_HYPERVISOR 0x80000000UL
+/** TSC is present */
+#define CPUID_FEATURES_INTEL_EDX_TSC 0x00000010UL
+
/** FXSAVE and FXRSTOR are supported */
#define CPUID_FEATURES_INTEL_EDX_FXSR 0x01000000UL
diff --git a/src/arch/x86/interface/pcbios/rtc_entropy.c b/src/arch/x86/interface/pcbios/rtc_entropy.c
index e9e6baa59..e0c175685 100644
--- a/src/arch/x86/interface/pcbios/rtc_entropy.c
+++ b/src/arch/x86/interface/pcbios/rtc_entropy.c
@@ -36,6 +36,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <biosint.h>
#include <pic8259.h>
#include <rtc.h>
+#include <ipxe/cpuid.h>
#include <ipxe/entropy.h>
/** Maximum time to wait for an RTC interrupt, in milliseconds */
@@ -174,8 +175,17 @@ static int rtc_entropy_check ( void ) {
* @ret rc Return status code
*/
static int rtc_entropy_enable ( void ) {
+ struct x86_features features;
int rc;
+ /* Check that TSC is supported */
+ x86_features ( &features );
+ if ( ! ( features.intel.edx & CPUID_FEATURES_INTEL_EDX_TSC ) ) {
+ DBGC ( &rtc_flag, "RTC has no TSC\n" );
+ rc = -ENOTSUP;
+ goto err_no_tsc;
+ }
+
/* Hook ISR and enable RTC interrupts */
rtc_hook_isr();
enable_irq ( RTC_IRQ );
@@ -191,6 +201,7 @@ static int rtc_entropy_enable ( void ) {
rtc_disable_int();
disable_irq ( RTC_IRQ );
rtc_unhook_isr();
+ err_no_tsc:
return rc;
}
diff --git a/src/arch/x86/prefix/unlzma.S b/src/arch/x86/prefix/unlzma.S
index 956eeb24c..979f699ee 100644
--- a/src/arch/x86/prefix/unlzma.S
+++ b/src/arch/x86/prefix/unlzma.S
@@ -44,7 +44,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
*/
.text
- .arch i586
+ .arch i486
.section ".prefix.lib", "ax", @progbits
#ifdef CODE16
diff --git a/src/config/cloud/aws.ipxe b/src/config/cloud/aws.ipxe
index 2c96e3888..6c007398e 100644
--- a/src/config/cloud/aws.ipxe
+++ b/src/config/cloud/aws.ipxe
@@ -3,6 +3,22 @@
echo Amazon EC2 - iPXE boot via user-data
echo CPU: ${cpuvendor} ${cpumodel}
ifstat ||
-dhcp ||
+
+set attempt:int8 1
+:dhcp_retry
+echo DHCP attempt ${attempt}
+dhcp --timeout 5000 && goto dhcp_ok ||
+ifstat ||
+inc attempt
+iseq ${attempt} 10 || goto dhcp_retry
+
+:dhcp_fail
+echo DHCP failed - rebooting
+reboot ||
+exit
+
+:dhcp_ok
route ||
-chain -ar http://169.254.169.254/latest/user-data
+chain -ar http://169.254.169.254/latest/user-data ||
+ifstat ||
+exit
diff --git a/src/config/cloud/gce.ipxe b/src/config/cloud/gce.ipxe
index 88e12b56b..65e2e57dc 100644
--- a/src/config/cloud/gce.ipxe
+++ b/src/config/cloud/gce.ipxe
@@ -5,4 +5,5 @@ echo CPU: ${cpuvendor} ${cpumodel}
ifstat ||
dhcp ||
route ||
-chain -ar http://metadata.google.internal/computeMetadata/v1/instance/attributes/ipxeboot
+chain -ar http://metadata.google.internal/computeMetadata/v1/instance/attributes/ipxeboot ||
+ifstat ||
diff --git a/src/config/cloud/settings.h b/src/config/cloud/settings.h
index 34deeb070..c9d6bdc93 100644
--- a/src/config/cloud/settings.h
+++ b/src/config/cloud/settings.h
@@ -1,4 +1,6 @@
/* It can often be useful to know the CPU on which a cloud instance is
* running (e.g. to isolate problems with Azure AMD instances).
*/
+#if defined ( __i386__ ) || defined ( __x86_64__ )
#define CPUID_SETTINGS
+#endif
diff --git a/src/config/config.c b/src/config/config.c
index 5e7a3ecfd..a81866132 100644
--- a/src/config/config.c
+++ b/src/config/config.c
@@ -182,6 +182,12 @@ REQUIRE_OBJECT ( efi_image );
#ifdef IMAGE_SDI
REQUIRE_OBJECT ( sdi );
#endif
+#ifdef IMAGE_ZLIB
+REQUIRE_OBJECT ( zlib );
+#endif
+#ifdef IMAGE_GZIP
+REQUIRE_OBJECT ( gzip );
+#endif
/*
* Drag in all requested commands
diff --git a/src/config/config_archive.c b/src/config/config_archive.c
new file mode 100644
index 000000000..746fc7e44
--- /dev/null
+++ b/src/config/config_archive.c
@@ -0,0 +1,36 @@
+/*
+ * 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 (at your option) 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <config/general.h>
+
+/** @file
+ *
+ * Archive image configuration
+ *
+ */
+
+PROVIDE_REQUIRING_SYMBOL();
+
+#ifdef IMAGE_ARCHIVE_CMD
+REQUIRE_OBJECT ( image_archive_cmd );
+#endif
diff --git a/src/config/general.h b/src/config/general.h
index 9b21f1271..2d15f500a 100644
--- a/src/config/general.h
+++ b/src/config/general.h
@@ -117,6 +117,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#define IMAGE_PNG /* PNG image support */
#define IMAGE_DER /* DER image support */
#define IMAGE_PEM /* PEM image support */
+//#define IMAGE_ZLIB /* ZLIB image support */
+//#define IMAGE_GZIP /* GZIP image support */
/*
* Command-line commands to include
@@ -156,6 +158,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
//#define NTP_CMD /* NTP commands */
//#define CERT_CMD /* Certificate management commands */
//#define IMAGE_MEM_CMD /* Read memory command */
+#define IMAGE_ARCHIVE_CMD /* Archive image management commands */
/*
* ROM-specific options
diff --git a/src/core/archive.c b/src/core/archive.c
new file mode 100644
index 000000000..bb62c7e47
--- /dev/null
+++ b/src/core/archive.c
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2021 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <string.h>
+#include <errno.h>
+#include <ipxe/image.h>
+
+/** @file
+ *
+ * Archive images
+ *
+ */
+
+/**
+ * Extract archive image
+ *
+ * @v image Image
+ * @v name Extracted image name
+ * @v extracted Extracted image to fill in
+ * @ret rc Return status code
+ */
+int image_extract ( struct image *image, const char *name,
+ struct image **extracted ) {
+ char *dot;
+ int rc;
+
+ /* Check that this image can be used to extract an archive image */
+ if ( ! ( image->type && image->type->extract ) ) {
+ rc = -ENOTSUP;
+ goto err_unsupported;
+ }
+
+ /* Allocate new image */
+ *extracted = alloc_image ( image->uri );
+ if ( ! *extracted ) {
+ rc = -ENOMEM;
+ goto err_alloc;
+ }
+
+ /* Set image name */
+ if ( ( rc = image_set_name ( *extracted,
+ ( name ? name : image->name ) ) ) != 0 ) {
+ goto err_set_name;
+ }
+
+ /* Strip any archive or compression suffix from implicit name */
+ if ( ( ! name ) && ( (*extracted)->name ) &&
+ ( ( dot = strrchr ( (*extracted)->name, '.' ) ) != NULL ) ) {
+ *dot = '\0';
+ }
+
+ /* Try extracting archive image */
+ if ( ( rc = image->type->extract ( image, *extracted ) ) != 0 ) {
+ DBGC ( image, "IMAGE %s could not extract image: %s\n",
+ image->name, strerror ( rc ) );
+ goto err_extract;
+ }
+
+ /* Register image */
+ if ( ( rc = register_image ( *extracted ) ) != 0 )
+ goto err_register;
+
+ /* Propagate trust flag */
+ if ( image->flags & IMAGE_TRUSTED )
+ image_trust ( *extracted );
+
+ /* Drop local reference to image */
+ image_put ( *extracted );
+
+ return 0;
+
+ unregister_image ( *extracted );
+ err_register:
+ err_extract:
+ err_set_name:
+ image_put ( *extracted );
+ err_alloc:
+ err_unsupported:
+ return rc;
+}
+
+/**
+ * Extract and execute image
+ *
+ * @v image Image
+ * @ret rc Return status code
+ */
+int image_extract_exec ( struct image *image ) {
+ struct image *extracted;
+ int rc;
+
+ /* Extract image */
+ if ( ( rc = image_extract ( image, NULL, &extracted ) ) != 0 )
+ goto err_extract;
+
+ /* Set image command line */
+ if ( ( rc = image_set_cmdline ( extracted, image->cmdline ) ) != 0 )
+ goto err_set_cmdline;
+
+ /* Set auto-unregister flag */
+ extracted->flags |= IMAGE_AUTO_UNREGISTER;
+
+ /* Tail-recurse into extracted image */
+ return image_exec ( extracted );
+
+ err_set_cmdline:
+ unregister_image ( extracted );
+ err_extract:
+ return rc;
+}
+
+/* Drag in objects via image_extract() */
+REQUIRING_SYMBOL ( image_extract );
+
+/* Drag in archive image formats */
+REQUIRE_OBJECT ( config_archive );
diff --git a/src/core/base64.c b/src/core/base64.c
index e452f7d41..ec11be261 100644
--- a/src/core/base64.c
+++ b/src/core/base64.c
@@ -36,7 +36,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
*
*/
-static const char base64[64] =
+static const char base64[ 64 + 1 /* NUL */ ] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
/**
diff --git a/src/core/console.c b/src/core/console.c
index 7fd00036f..2b90809bf 100644
--- a/src/core/console.c
+++ b/src/core/console.c
@@ -20,11 +20,12 @@ unsigned int console_height = CONSOLE_DEFAULT_HEIGHT;
* Write a single character to each console device
*
* @v character Character to be written
+ * @ret character Character written
*
* The character is written out to all enabled console devices, using
* each device's console_driver::putchar() method.
*/
-void putchar ( int character ) {
+int putchar ( int character ) {
struct console_driver *console;
/* Automatic LF -> CR,LF translation */
@@ -37,6 +38,8 @@ void putchar ( int character ) {
console->putchar )
console->putchar ( character );
}
+
+ return character;
}
/**
diff --git a/src/core/cpio.c b/src/core/cpio.c
index 080c72daf..27aee7581 100644
--- a/src/core/cpio.c
+++ b/src/core/cpio.c
@@ -30,6 +30,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
*/
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
#include <ipxe/cpio.h>
@@ -45,3 +46,87 @@ void cpio_set_field ( char *field, unsigned long value ) {
snprintf ( buf, sizeof ( buf ), "%08lx", value );
memcpy ( field, buf, 8 );
}
+
+/**
+ * Get CPIO image filename
+ *
+ * @v image Image
+ * @ret len CPIO filename length (0 for no filename)
+ */
+size_t cpio_name_len ( struct image *image ) {
+ const char *name = cpio_name ( image );
+ char *sep;
+ size_t len;
+
+ /* Check for existence of CPIO filename */
+ if ( ! name )
+ return 0;
+
+ /* Locate separator (if any) */
+ sep = strchr ( name, ' ' );
+ len = ( sep ? ( ( size_t ) ( sep - name ) ) : strlen ( name ) );
+
+ return len;
+}
+
+/**
+ * Parse CPIO image parameters
+ *
+ * @v image Image
+ * @v cpio CPIO header to fill in
+ */
+static void cpio_parse_cmdline ( struct image *image,
+ struct cpio_header *cpio ) {
+ const char *cmdline;
+ char *arg;
+ char *end;
+ unsigned int mode;
+
+ /* Skip image filename */
+ cmdline = ( cpio_name ( image ) + cpio_name_len ( image ) );
+
+ /* Look for "mode=" */
+ if ( ( arg = strstr ( cmdline, "mode=" ) ) ) {
+ arg += 5;
+ mode = strtoul ( arg, &end, 8 /* Octal for file mode */ );
+ if ( *end && ( *end != ' ' ) ) {
+ DBGC ( image, "CPIO %p strange \"mode=\" "
+ "terminator '%c'\n", image, *end );
+ }
+ cpio_set_field ( cpio->c_mode, ( 0100000 | mode ) );
+ }
+}
+
+/**
+ * Construct CPIO header for image, if applicable
+ *
+ * @v image Image
+ * @v cpio CPIO header to fill in
+ * @ret len Length of magic CPIO header (including filename)
+ */
+size_t cpio_header ( struct image *image, struct cpio_header *cpio ) {
+ size_t name_len;
+ size_t len;
+
+ /* Get filename length */
+ name_len = cpio_name_len ( image );
+
+ /* Images with no filename are assumed to already be CPIO archives */
+ if ( ! name_len )
+ return 0;
+
+ /* Construct CPIO header */
+ memset ( cpio, '0', sizeof ( *cpio ) );
+ memcpy ( cpio->c_magic, CPIO_MAGIC, sizeof ( cpio->c_magic ) );
+ cpio_set_field ( cpio->c_mode, 0100644 );
+ cpio_set_field ( cpio->c_nlink, 1 );
+ cpio_set_field ( cpio->c_filesize, image->len );
+ cpio_set_field ( cpio->c_namesize, ( name_len + 1 /* NUL */ ) );
+ cpio_parse_cmdline ( image, cpio );
+
+ /* Calculate total length */
+ len = ( ( sizeof ( *cpio ) + name_len + 1 /* NUL */ + CPIO_ALIGN - 1 )
+ & ~( CPIO_ALIGN - 1 ) );
+
+ return len;
+}
diff --git a/src/core/image.c b/src/core/image.c
index 9fe77c54c..ce8cf868b 100644
--- a/src/core/image.c
+++ b/src/core/image.c
@@ -176,14 +176,13 @@ int image_set_cmdline ( struct image *image, const char *cmdline ) {
}
/**
- * Set image data
+ * Set image length
*
* @v image Image
- * @v data Image data
* @v len Length of image data
* @ret rc Return status code
*/
-int image_set_data ( struct image *image, userptr_t data, size_t len ) {
+int image_set_len ( struct image *image, size_t len ) {
userptr_t new;
/* (Re)allocate image data */
@@ -191,10 +190,28 @@ int image_set_data ( struct image *image, userptr_t data, size_t len ) {
if ( ! new )
return -ENOMEM;
image->data = new;
+ image->len = len;
+
+ return 0;
+}
+
+/**
+ * Set image data
+ *
+ * @v image Image
+ * @v data Image data
+ * @v len Length of image data
+ * @ret rc Return status code
+ */
+int image_set_data ( struct image *image, userptr_t data, size_t len ) {
+ int rc;
+
+ /* Set image length */
+ if ( ( rc = image_set_len ( image, len ) ) != 0 )
+ return rc;
/* Copy in new image data */
memcpy_user ( image->data, 0, data, 0, len );
- image->len = len;
return 0;
}
diff --git a/src/core/open.c b/src/core/open.c
index c27d8a021..f9198c9d9 100644
--- a/src/core/open.c
+++ b/src/core/open.c
@@ -25,6 +25,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdarg.h>
#include <string.h>
+#include <strings.h>
#include <errno.h>
#include <ipxe/xfer.h>
#include <ipxe/uri.h>
@@ -47,7 +48,7 @@ struct uri_opener * xfer_uri_opener ( const char *scheme ) {
struct uri_opener *opener;
for_each_table_entry ( opener, URI_OPENERS ) {
- if ( strcmp ( scheme, opener->scheme ) == 0 )
+ if ( strcasecmp ( scheme, opener->scheme ) == 0 )
return opener;
}
return NULL;
diff --git a/src/core/string.c b/src/core/string.c
index 188fe0864..9a1b9b72a 100644
--- a/src/core/string.c
+++ b/src/core/string.c
@@ -27,6 +27,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
+#include <strings.h>
#include <ctype.h>
/** @file
@@ -205,11 +206,24 @@ int strncmp ( const char *first, const char *second, size_t max ) {
* @ret diff Difference
*/
int strcasecmp ( const char *first, const char *second ) {
+
+ return strncasecmp ( first, second, ~( ( size_t ) 0 ) );
+}
+
+/**
+ * Compare case-insensitive strings
+ *
+ * @v first First string
+ * @v second Second string
+ * @v max Maximum length to compare
+ * @ret diff Difference
+ */
+int strncasecmp ( const char *first, const char *second, size_t max ) {
const uint8_t *first_bytes = ( ( const uint8_t * ) first );
const uint8_t *second_bytes = ( ( const uint8_t * ) second );
int diff;
- for ( ; ; first_bytes++, second_bytes++ ) {
+ for ( ; max-- ; first_bytes++, second_bytes++ ) {
diff = ( toupper ( *first_bytes ) -
toupper ( *second_bytes ) );
if ( diff )
@@ -217,6 +231,7 @@ int strcasecmp ( const char *first, const char *second ) {
if ( ! *first_bytes )
return 0;
}
+ return 0;
}
/**
diff --git a/src/crypto/x509.c b/src/crypto/x509.c
index 17d8c7a43..1f017eb03 100644
--- a/src/crypto/x509.c
+++ b/src/crypto/x509.c
@@ -25,6 +25,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdlib.h>
#include <string.h>
+#include <strings.h>
#include <errno.h>
#include <assert.h>
#include <ipxe/list.h>
@@ -1464,7 +1465,7 @@ static int x509_check_dnsname ( struct x509_certificate *cert,
/* Compare names */
if ( ! ( ( strlen ( name ) == len ) &&
- ( memcmp ( name, dnsname, len ) == 0 ) ) )
+ ( strncasecmp ( name, dnsname, len ) == 0 ) ) )
return -ENOENT;
if ( name != fullname ) {
diff --git a/src/drivers/net/ath/ath5k/ath5k_eeprom.c b/src/drivers/net/ath/ath5k/ath5k_eeprom.c
index 12519bc59..46f33d1e8 100644
--- a/src/drivers/net/ath/ath5k/ath5k_eeprom.c
+++ b/src/drivers/net/ath/ath5k/ath5k_eeprom.c
@@ -39,6 +39,9 @@ static int ath5k_hw_eeprom_read(struct ath5k_hw *ah, u32 offset, u16 *data)
{
u32 status, timeout;
+ /* Avoid returning uninitialised data on error */
+ *data = 0xffff;
+
/*
* Initialize EEPROM access
*/
diff --git a/src/drivers/net/bnxt/bnxt.c b/src/drivers/net/bnxt/bnxt.c
index b8663c00a..e3876503f 100644
--- a/src/drivers/net/bnxt/bnxt.c
+++ b/src/drivers/net/bnxt/bnxt.c
@@ -23,16 +23,74 @@ static void bnxt_adv_cq_index ( struct bnxt *bp, u16 cnt );
static int bnxt_rx_complete ( struct net_device *dev, struct rx_pkt_cmpl *rx );
void bnxt_link_evt ( struct bnxt *bp, struct hwrm_async_event_cmpl *evt );
+static struct pci_device_id bnxt_nics[] = {
+ PCI_ROM( 0x14e4, 0x16c0, "14e4-16C0", "14e4-16C0", 0 ),
+ PCI_ROM( 0x14e4, 0x16c1, "14e4-16C1", "14e4-16C1", BNXT_FLAG_PCI_VF ),
+ PCI_ROM( 0x14e4, 0x16c8, "14e4-16C8", "14e4-16C8", 0 ),
+ PCI_ROM( 0x14e4, 0x16c9, "14e4-16C9", "14e4-16C9", 0 ),
+ PCI_ROM( 0x14e4, 0x16ca, "14e4-16CA", "14e4-16CA", 0 ),
+ PCI_ROM( 0x14e4, 0x16cc, "14e4-16CC", "14e4-16CC", 0 ),
+ PCI_ROM( 0x14e4, 0x16cd, "14e4-16CD", "14e4-16CD", 0 ),
+ PCI_ROM( 0x14e4, 0x16ce, "14e4-16CE", "14e4-16CE", 0 ),
+ PCI_ROM( 0x14e4, 0x16cf, "14e4-16CF", "14e4-16CF", 0 ),
+ PCI_ROM( 0x14e4, 0x16d0, "14e4-16D0", "14e4-16D0", 0 ),
+ PCI_ROM( 0x14e4, 0x16d1, "14e4-16D1", "14e4-16D1", 0 ),
+ PCI_ROM( 0x14e4, 0x16d2, "14e4-16D2", "14e4-16D2", 0 ),
+ PCI_ROM( 0x14e4, 0x16d4, "14e4-16D4", "14e4-16D4", 0 ),
+ PCI_ROM( 0x14e4, 0x16d5, "14e4-16D5", "14e4-16D5", 0 ),
+ PCI_ROM( 0x14e4, 0x16d6, "14e4-16D6", "14e4-16D6", 0 ),
+ PCI_ROM( 0x14e4, 0x16d7, "14e4-16D7", "14e4-16D7", 0 ),
+ PCI_ROM( 0x14e4, 0x16d8, "14e4-16D8", "14e4-16D8", 0 ),
+ PCI_ROM( 0x14e4, 0x16d9, "14e4-16D9", "14e4-16D9", 0 ),
+ PCI_ROM( 0x14e4, 0x16da, "14e4-16DA", "14e4-16DA", 0 ),
+ PCI_ROM( 0x14e4, 0x16db, "14e4-16DB", "14e4-16DB", 0 ),
+ PCI_ROM( 0x14e4, 0x16dc, "14e4-16DC", "14e4-16DC", BNXT_FLAG_PCI_VF ),
+ PCI_ROM( 0x14e4, 0x16de, "14e4-16DE", "14e4-16DE", 0 ),
+ PCI_ROM( 0x14e4, 0x16df, "14e4-16DF", "14e4-16DF", 0 ),
+ PCI_ROM( 0x14e4, 0x16e0, "14e4-16E0", "14e4-16E0", 0 ),
+ PCI_ROM( 0x14e4, 0x16e2, "14e4-16E2", "14e4-16E2", 0 ),
+ PCI_ROM( 0x14e4, 0x16e3, "14e4-16E3", "14e4-16E3", 0 ),
+ PCI_ROM( 0x14e4, 0x16e4, "14e4-16E4", "14e4-16E4", 0 ),
+ PCI_ROM( 0x14e4, 0x16e7, "14e4-16E7", "14e4-16E7", 0 ),
+ PCI_ROM( 0x14e4, 0x16e8, "14e4-16E8", "14e4-16E8", 0 ),
+ PCI_ROM( 0x14e4, 0x16e9, "14e4-16E9", "14e4-16E9", 0 ),
+ PCI_ROM( 0x14e4, 0x16ea, "14e4-16EA", "14e4-16EA", 0 ),
+ PCI_ROM( 0x14e4, 0x16eb, "14e4-16EB", "14e4-16EB", 0 ),
+ PCI_ROM( 0x14e4, 0x16ec, "14e4-16EC", "14e4-16EC", 0 ),
+ PCI_ROM( 0x14e4, 0x16ed, "14e4-16ED", "14e4-16ED", 0 ),
+ PCI_ROM( 0x14e4, 0x16ee, "14e4-16EE", "14e4-16EE", 0 ),
+ PCI_ROM( 0x14e4, 0x16ef, "14e4-16EF", "14e4-16EF", 0 ),
+ PCI_ROM( 0x14e4, 0x16f0, "14e4-16F0", "14e4-16F0", 0 ),
+ PCI_ROM( 0x14e4, 0x16f1, "14e4-16F1", "14e4-16F1", 0 ),
+ PCI_ROM( 0x14e4, 0x1604, "14e4-1604", "14e4-1604", 0 ),
+ PCI_ROM( 0x14e4, 0x1605, "14e4-1605", "14e4-1605", 0 ),
+ PCI_ROM( 0x14e4, 0x1606, "14e4-1606", "14e4-1606", 0 ),
+ PCI_ROM( 0x14e4, 0x1609, "14e4-1609", "14e4-1609", 0 ),
+ PCI_ROM( 0x14e4, 0x1614, "14e4-1614", "14e4-1614", 0 ),
+ PCI_ROM( 0x14e4, 0xd802, "14e4-D802", "14e4-D802", 0 ),
+ PCI_ROM( 0x14e4, 0xd804, "14e4-D804", "14e4-D804", 0 ),
+ PCI_ROM( 0x14e4, 0x1750, "14e4-1750", "14e4-1750", 0 ),
+ PCI_ROM( 0x14e4, 0x1802, "14e4-1802", "14e4-1802", 0 ),
+ PCI_ROM( 0x14e4, 0x1805, "14e4-1805", "14e4-1805", 0 ),
+ PCI_ROM( 0x14e4, 0x1751, "14e4-1751", "14e4-1751", 0 ),
+ PCI_ROM( 0x14e4, 0x1801, "14e4-1801", "14e4-1801", 0 ),
+ PCI_ROM( 0x14e4, 0x1804, "14e4-1804", "14e4-1804", 0 ),
+ PCI_ROM( 0x14e4, 0x1752, "14e4-1752", "14e4-1752", 0 ),
+ PCI_ROM( 0x14e4, 0x1800, "14e4-1800", "14e4-1800", 0 ),
+ PCI_ROM( 0x14e4, 0x1803, "14e4-1803", "14e4-1803", 0 ),
+ PCI_ROM( 0x14e4, 0x1806, "14e4-1806", "14e4-1806", BNXT_FLAG_PCI_VF ),
+ PCI_ROM( 0x14e4, 0x1807, "14e4-1807", "14e4-1807", BNXT_FLAG_PCI_VF ),
+ PCI_ROM( 0x14e4, 0x1808, "14e4-1808", "14e4-1808", BNXT_FLAG_PCI_VF ),
+ PCI_ROM( 0x14e4, 0x1809, "14e4-1809", "14e4-1809", BNXT_FLAG_PCI_VF ),
+};
+
/**
* Check if Virtual Function
*/
u8 bnxt_is_pci_vf ( struct pci_device *pdev )
{
- u16 i;
-
- for ( i = 0; i < ARRAY_SIZE ( bnxt_vf_nics ); i++ ) {
- if ( pdev->device == bnxt_vf_nics[i] )
- return 1;
+ if ( FLAG_TEST ( pdev->id->driver_data, BNXT_FLAG_PCI_VF ) ) {
+ return 1;
}
return 0;
}
diff --git a/src/drivers/net/bnxt/bnxt.h b/src/drivers/net/bnxt/bnxt.h
index 4cca07bd3..2cbaec5e5 100644
--- a/src/drivers/net/bnxt/bnxt.h
+++ b/src/drivers/net/bnxt/bnxt.h
@@ -51,6 +51,7 @@ union dma_addr64_t {
#define BNXT_FLAG_MULTI_HOST 0x0008
#define BNXT_FLAG_NPAR_MODE 0x0010
#define BNXT_FLAG_ATOMICS_ENABLE 0x0020
+#define BNXT_FLAG_PCI_VF 0x0040
/*******************************************************************************
* Status codes.
******************************************************************************/
@@ -867,140 +868,4 @@ struct bnxt {
FUNC_VF_CFG_REQ_ENABLES_ASYNC_EVENT_CR | \
FUNC_VF_CFG_REQ_ENABLES_DFLT_MAC_ADDR)
-/* Device ID's */
-#define PCI_VID_BCOM 0x14e4
#define CHIP_NUM_57500 0x1750
-
-#define DID_57508 0x1750
-#define DID_57508_MF 0x1802
-#define DID_57508_MF_RDMA 0x1805
-#define DID_57504 0x1751
-#define DID_57504_MF 0x1801
-#define DID_57504_MF_RDMA 0x1804
-#define DID_57502 0x1752
-#define DID_57502_MF 0x1800
-#define DID_57502_MF_RDMA 0x1803
-#define DID_57508_VF 0x1806
-#define DID_57508_VF_RDMA 0x1807
-#define DID_57508_VF_HV 0x1806
-#define DID_57508_VF_RDMA_HV 0x1807
-/* Stratus Device IDs */
-#define DID_57320_1 0x16F0
-#define DID_57320_2 0x16F1
-#define DID_57454_MHB 0x1604
-#define DID_57454_MHB_RDMA 0x1605
-#define DID_57454_VF_RDMA 0x1606
-#define DID_57454_VF 0x1609
-#define DID_57454 0x1614
-#define DID_58802 0xD802
-#define DID_58804 0xD804
-
-#define DID_57417_RDMA_MF 0x16C0
-#define DID_57417_VF_RDMA 0x16c1
-#define DID_57301 0x16C8
-#define DID_57302 0x16C9
-#define DID_57304 0x16CA
-#define DID_57417_MF 0x16CC
-#define DID_58700 0x16CD
-#define DID_57311 0x16CE
-#define DID_57312 0x16CF
-#define DID_57402 0x16D0
-#define DID_57404 0x16D1
-#define DID_57406 0x16D2
-#define DID_57402_MF 0x16D4
-#define DID_57407C 0x16D5
-#define DID_57412 0x16D6
-#define DID_57414 0x16D7
-#define DID_57416C 0x16D8
-#define DID_57417C 0x16D9
-#define DID_57402L 0x16DA
-#define DID_57404L 0x16DB
-#define DID_57417_VF 0x16dc
-#define DID_57412_MF 0x16DE
-#define DID_57314 0x16DF
-#define DID_57317C 0x16E0
-#define DID_57417F 0x16E2
-#define DID_57416F 0x16E3
-#define DID_57317F 0x16E4
-#define DID_57404_MF 0x16E7
-#define DID_57406_MF 0x16E8
-#define DID_57407F 0x16E9
-#define DID_57407_MF 0x16EA
-#define DID_57412_RDMA_MF 0x16EB
-#define DID_57414_MF 0x16EC
-#define DID_57414_RDMA_MF 0x16ED
-#define DID_57416_MF 0x16EE
-#define DID_57416_RDMA_MF 0x16EF
-
-static struct pci_device_id bnxt_nics[] = {
- PCI_ROM(PCI_VID_BCOM, DID_57417_RDMA_MF, "14e4-16C0", "14e4-16C0", 0),
- PCI_ROM(PCI_VID_BCOM, DID_57417_VF_RDMA, "14e4-16C1", "14e4-16C1", 0),
- PCI_ROM(PCI_VID_BCOM, DID_57301, "14e4-16C8", "14e4-16C8", 0),
- PCI_ROM(PCI_VID_BCOM, DID_57302, "14e4-16C9", "14e4-16C9", 0),
- PCI_ROM(PCI_VID_BCOM, DID_57304, "14e4-16CA", "14e4-16CA", 0),
- PCI_ROM(PCI_VID_BCOM, DID_57417_MF, "14e4-16CC", "14e4-16CC", 0),
- PCI_ROM(PCI_VID_BCOM, DID_58700, "14e4-16CD", "14e4-16CD", 0),
- PCI_ROM(PCI_VID_BCOM, DID_57311, "14e4-16CE", "14e4-16CE", 0),
- PCI_ROM(PCI_VID_BCOM, DID_57312, "14e4-16CF", "14e4-16CF", 0),
- PCI_ROM(PCI_VID_BCOM, DID_57402, "14e4-16D0", "14e4-16D0", 0),
- PCI_ROM(PCI_VID_BCOM, DID_57404, "14e4-16D1", "14e4-16D1", 0),
- PCI_ROM(PCI_VID_BCOM, DID_57406, "14e4-16D2", "14e4-16D2", 0),
- PCI_ROM(PCI_VID_BCOM, DID_57402_MF, "14e4-16D4", "14e4-16D4", 0),
- PCI_ROM(PCI_VID_BCOM, DID_57407C, "14e4-16D5", "14e4-16D5", 0),
- PCI_ROM(PCI_VID_BCOM, DID_57412, "14e4-16D6", "14e4-16D6", 0),
- PCI_ROM(PCI_VID_BCOM, DID_57414, "14e4-16D7", "14e4-16D7", 0),
- PCI_ROM(PCI_VID_BCOM, DID_57416C, "14e4-16D8", "14e4-16D8", 0),
- PCI_ROM(PCI_VID_BCOM, DID_57417C, "14e4-16D9", "14e4-16D9", 0),
- PCI_ROM(PCI_VID_BCOM, DID_57402L, "14e4-16DA", "14e4-16DA", 0),
- PCI_ROM(PCI_VID_BCOM, DID_57404L, "14e4-16DB", "14e4-16DB", 0),
- PCI_ROM(PCI_VID_BCOM, DID_57417_VF, "14e4-16DC", "14e4-16DC", 0),
- PCI_ROM(PCI_VID_BCOM, DID_57412_MF, "14e4-16DE", "14e4-16DE", 0),
- PCI_ROM(PCI_VID_BCOM, DID_57314, "14e4-16DF", "14e4-16DF", 0),
- PCI_ROM(PCI_VID_BCOM, DID_57317C, "14e4-16E0", "14e4-16E0", 0),
- PCI_ROM(PCI_VID_BCOM, DID_57417F, "14e4-16E2", "14e4-16E2", 0),
- PCI_ROM(PCI_VID_BCOM, DID_57416F, "14e4-16E3", "14e4-16E3", 0),
- PCI_ROM(PCI_VID_BCOM, DID_57317F, "14e4-16E4", "14e4-16E4", 0),
- PCI_ROM(PCI_VID_BCOM, DID_57404_MF, "14e4-16E7", "14e4-16E7", 0),
- PCI_ROM(PCI_VID_BCOM, DID_57406_MF, "14e4-16E8", "14e4-16E8", 0),
- PCI_ROM(PCI_VID_BCOM, DID_57407F, "14e4-16E9", "14e4-16E9", 0),
- PCI_ROM(PCI_VID_BCOM, DID_57407_MF, "14e4-16EA", "14e4-16EA", 0),
- PCI_ROM(PCI_VID_BCOM, DID_57412_RDMA_MF, "14e4-16EB", "14e4-16EB", 0),
- PCI_ROM(PCI_VID_BCOM, DID_57414_MF, "14e4-16EC", "14e4-16EC", 0),
- PCI_ROM(PCI_VID_BCOM, DID_57414_RDMA_MF, "14e4-16ED", "14e4-16ED", 0),
- PCI_ROM(PCI_VID_BCOM, DID_57416_MF, "14e4-16EE", "14e4-16EE", 0),
- PCI_ROM(PCI_VID_BCOM, DID_57416_RDMA_MF, "14e4-16EF", "14e4-16EF", 0),
-
- PCI_ROM(PCI_VID_BCOM, DID_57320_1, "14e4-16F0", "14e4-16F0", 0),
- PCI_ROM(PCI_VID_BCOM, DID_57320_2, "14e4-16F1", "14e4-16F1", 0),
- PCI_ROM(PCI_VID_BCOM, DID_57454_MHB, "14e4-1604", "14e4-1604", 0),
- PCI_ROM(PCI_VID_BCOM, DID_57454_MHB_RDMA, "14e4-1605", "14e4-1605", 0),
- PCI_ROM(PCI_VID_BCOM, DID_57454_VF_RDMA, "14e4-1606", "14e4-1606", 0),
- PCI_ROM(PCI_VID_BCOM, DID_57454_VF, "14e4-1609", "14e4-1609", 0),
- PCI_ROM(PCI_VID_BCOM, DID_57454, "14e4-1614", "14e4-1614", 0),
- PCI_ROM(PCI_VID_BCOM, DID_58802, "14e4-D802", "14e4-D802", 0),
- PCI_ROM(PCI_VID_BCOM, DID_58804, "14e4-D804", "14e4-D804", 0),
-
- PCI_ROM(PCI_VID_BCOM, DID_57508, "14e4-1750", "14e4-1750", 0),
- PCI_ROM(PCI_VID_BCOM, DID_57508_MF, "14e4-1802", "14e4-1802", 0),
- PCI_ROM(PCI_VID_BCOM, DID_57508_MF_RDMA, "14e4-1805", "14e4-1805", 0),
- PCI_ROM(PCI_VID_BCOM, DID_57504, "14e4-1751", "14e4-1751", 0),
- PCI_ROM(PCI_VID_BCOM, DID_57504_MF, "14e4-1801", "14e4-1801", 0),
- PCI_ROM(PCI_VID_BCOM, DID_57504_MF_RDMA, "14e4-1804", "14e4-1804", 0),
- PCI_ROM(PCI_VID_BCOM, DID_57502, "14e4-1752", "14e4-1752", 0),
- PCI_ROM(PCI_VID_BCOM, DID_57502_MF, "14e4-1800", "14e4-1800", 0),
- PCI_ROM(PCI_VID_BCOM, DID_57502_MF_RDMA, "14e4-1803", "14e4-1803", 0),
- PCI_ROM(PCI_VID_BCOM, DID_57508_VF, "14e4-1806", "14e4-1806", 0),
- PCI_ROM(PCI_VID_BCOM, DID_57508_VF_RDMA, "14e4-1807", "14e4-1807", 0),
- PCI_ROM(PCI_VID_BCOM, DID_57508_VF_HV, "14e4-1808", "14e4-1808", 0),
- PCI_ROM(PCI_VID_BCOM,
- DID_57508_VF_RDMA_HV, "14e4-1809", "14e4-1809", 0),
-};
-
-static u16 bnxt_vf_nics[] = {
- DID_57508_VF,
- DID_57508_VF_RDMA,
- DID_57508_VF_HV,
- DID_57508_VF_RDMA_HV,
- DID_57417_VF,
- DID_57417_VF_RDMA,
-};
diff --git a/src/drivers/net/intel.c b/src/drivers/net/intel.c
index 83492961f..ea3ebf68d 100644
--- a/src/drivers/net/intel.c
+++ b/src/drivers/net/intel.c
@@ -1025,6 +1025,12 @@ static struct pci_device_id intel_nics[] = {
PCI_ROM ( 0x8086, 0x043a, "dh8900cc-f", "DH8900CC Fiber", 0 ),
PCI_ROM ( 0x8086, 0x043c, "dh8900cc-b", "DH8900CC Backplane", 0 ),
PCI_ROM ( 0x8086, 0x0440, "dh8900cc-s", "DH8900CC SFP", 0 ),
+ PCI_ROM ( 0x8086, 0x0d4c, "i219lm-11", "I219-LM (11)", INTEL_I219 ),
+ PCI_ROM ( 0x8086, 0x0d4d, "i219v-11", "I219-V (11)", INTEL_I219 ),
+ PCI_ROM ( 0x8086, 0x0d4e, "i219lm-10", "I219-LM (10)", INTEL_I219 ),
+ PCI_ROM ( 0x8086, 0x0d4f, "i219v-10", "I219-V (10)", INTEL_I219 ),
+ PCI_ROM ( 0x8086, 0x0d53, "i219lm-12", "I219-LM (12)", INTEL_I219 ),
+ PCI_ROM ( 0x8086, 0x0d55, "i219v-12", "I219-V (12)", INTEL_I219 ),
PCI_ROM ( 0x8086, 0x1000, "82542-f", "82542 (Fiber)", 0 ),
PCI_ROM ( 0x8086, 0x1001, "82543gc-f", "82543GC (Fiber)", 0 ),
PCI_ROM ( 0x8086, 0x1004, "82543gc", "82543GC (Copper)", 0 ),
@@ -1161,6 +1167,12 @@ static struct pci_device_id intel_nics[] = {
PCI_ROM ( 0x8086, 0x15e1, "i219lm-9", "I219-LM (9)", INTEL_I219 ),
PCI_ROM ( 0x8086, 0x15e2, "i219v-9", "I219-V (9)", INTEL_I219 ),
PCI_ROM ( 0x8086, 0x15e3, "i219lm-5", "I219-LM (5)", INTEL_I219 ),
+ PCI_ROM ( 0x8086, 0x15f4, "i219lm-15", "I219-LM (15)", INTEL_I219 ),
+ PCI_ROM ( 0x8086, 0x15f5, "i219v-15", "I219-V (15)", INTEL_I219 ),
+ PCI_ROM ( 0x8086, 0x15f9, "i219lm-14", "I219-LM (14)", INTEL_I219 ),
+ PCI_ROM ( 0x8086, 0x15fa, "i219v-14", "I219-V (14)", INTEL_I219 ),
+ PCI_ROM ( 0x8086, 0x15fb, "i219lm-13", "I219-LM (13)", INTEL_I219 ),
+ PCI_ROM ( 0x8086, 0x15fc, "i219v-13", "I219-V (13)", INTEL_I219 ),
PCI_ROM ( 0x8086, 0x1f41, "i354", "I354", INTEL_NO_ASDE ),
PCI_ROM ( 0x8086, 0x294c, "82566dc-2", "82566DC-2", 0 ),
PCI_ROM ( 0x8086, 0x2e6e, "cemedia", "CE Media Processor", 0 ),
diff --git a/src/drivers/net/rdc.c b/src/drivers/net/rdc.c
new file mode 100644
index 000000000..c3239c002
--- /dev/null
+++ b/src/drivers/net/rdc.c
@@ -0,0 +1,694 @@
+/*
+ * Copyright (C) 2021 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 (at your option) 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <byteswap.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/ethernet.h>
+#include <ipxe/if_ether.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/malloc.h>
+#include <ipxe/pci.h>
+#include "rdc.h"
+
+/** @file
+ *
+ * RDC R6040 network driver
+ *
+ */
+
+/******************************************************************************
+ *
+ * Device reset
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Reset hardware
+ *
+ * @v rdc RDC device
+ * @ret rc Return status code
+ */
+static int rdc_reset ( struct rdc_nic *rdc ) {
+ unsigned int i;
+
+ /* Reset NIC */
+ writew ( RDC_MCR1_RST, rdc->regs + RDC_MCR1 );
+
+ /* Wait for reset to complete */
+ for ( i = 0 ; i < RDC_RESET_MAX_WAIT_MS ; i++ ) {
+
+ /* Check for reset completion */
+ if ( readw ( rdc->regs + RDC_MCR1 ) & RDC_MCR1_RST ) {
+ mdelay ( 1 );
+ continue;
+ }
+
+ /* Reset internal state machine */
+ writew ( RDC_MACSM_RST, rdc->regs + RDC_MACSM );
+ writew ( 0, rdc->regs + RDC_MACSM );
+ mdelay ( RDC_MACSM_RESET_DELAY_MS );
+
+ return 0;
+ }
+
+ DBGC ( rdc, "RDC %p timed out waiting for reset\n", rdc );
+ return -ETIMEDOUT;
+}
+
+/******************************************************************************
+ *
+ * MII interface
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Read from MII register
+ *
+ * @v mdio MII interface
+ * @v phy PHY address
+ * @v reg Register address
+ * @ret value Data read, or negative error
+ */
+static int rdc_mii_read ( struct mii_interface *mdio, unsigned int phy,
+ unsigned int reg ) {
+ struct rdc_nic *rdc = container_of ( mdio, struct rdc_nic, mdio );
+ uint16_t mmdio;
+ unsigned int i;
+
+ /* Initiate read */
+ mmdio = ( RDC_MMDIO_MIIRD | RDC_MMDIO_PHYAD ( phy ) |
+ RDC_MMDIO_REGAD ( reg ) );
+ writew ( mmdio, rdc->regs + RDC_MMDIO );
+
+ /* Wait for read to complete */
+ for ( i = 0 ; i < RDC_MII_MAX_WAIT_US ; i++ ) {
+
+ /* Check for read completion */
+ if ( readw ( rdc->regs + RDC_MMDIO ) & RDC_MMDIO_MIIRD ) {
+ udelay ( 1 );
+ continue;
+ }
+
+ /* Return register value */
+ return ( readw ( rdc->regs + RDC_MMRD ) );
+ }
+
+ DBGC ( rdc, "RDC %p timed out waiting for MII read\n", rdc );
+ return -ETIMEDOUT;
+}
+
+/**
+ * Write to MII register
+ *
+ * @v mdio MII interface
+ * @v phy PHY address
+ * @v reg Register address
+ * @v data Data to write
+ * @ret rc Return status code
+ */
+static int rdc_mii_write ( struct mii_interface *mdio, unsigned int phy,
+ unsigned int reg, unsigned int data ) {
+ struct rdc_nic *rdc = container_of ( mdio, struct rdc_nic, mdio );
+ uint16_t mmdio;
+ unsigned int i;
+
+ /* Initiate write */
+ mmdio = ( RDC_MMDIO_MIIWR | RDC_MMDIO_PHYAD ( phy ) |
+ RDC_MMDIO_REGAD ( reg ) );
+ writew ( data, rdc->regs + RDC_MMWD );
+ writew ( mmdio, rdc->regs + RDC_MMDIO );
+
+ /* Wait for write to complete */
+ for ( i = 0 ; i < RDC_MII_MAX_WAIT_US ; i++ ) {
+
+ /* Check for write completion */
+ if ( readw ( rdc->regs + RDC_MMDIO ) & RDC_MMDIO_MIIWR ) {
+ udelay ( 1 );
+ continue;
+ }
+
+ return 0;
+ }
+
+ DBGC ( rdc, "RDC %p timed out waiting for MII write\n", rdc );
+ return -ETIMEDOUT;
+}
+
+/** RDC MII operations */
+static struct mii_operations rdc_mii_operations = {
+ .read = rdc_mii_read,
+ .write = rdc_mii_write,
+};
+
+/******************************************************************************
+ *
+ * Link state
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Initialise PHY
+ *
+ * @v rdc RDC device
+ * @ret rc Return status code
+ */
+static int rdc_init_phy ( struct rdc_nic *rdc ) {
+ int rc;
+
+ /* Find PHY address */
+ if ( ( rc = mii_find ( &rdc->mii ) ) != 0 ) {
+ DBGC ( rdc, "RDC %p could not find PHY address: %s\n",
+ rdc, strerror ( rc ) );
+ return rc;
+ }
+
+ /* Reset PHY */
+ if ( ( rc = mii_reset ( &rdc->mii ) ) != 0 ) {
+ DBGC ( rdc, "RDC %p could not reset PHY: %s\n",
+ rdc, strerror ( rc ) );
+ return rc;
+ }
+
+ return 0;
+}
+
+/**
+ * Check link state
+ *
+ * @v netdev Network device
+ * @ret rc Return status code
+ */
+static int rdc_check_link ( struct net_device *netdev ) {
+ struct rdc_nic *rdc = netdev->priv;
+ int rc;
+
+ /* Check link state */
+ if ( ( rc = mii_check_link ( &rdc->mii, netdev ) ) != 0 ) {
+ DBGC ( rdc, "RDC %p could not check link: %s\n",
+ rdc, strerror ( rc ) );
+ return rc;
+ }
+
+ return 0;
+}
+
+/******************************************************************************
+ *
+ * Network device interface
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Create descriptor ring
+ *
+ * @v rdc RDC device
+ * @v ring Descriptor ring
+ * @ret rc Return status code
+ */
+static int rdc_create_ring ( struct rdc_nic *rdc, struct rdc_ring *ring ) {
+ size_t len = ( ring->count * sizeof ( ring->desc[0] ) );
+ struct rdc_descriptor *desc;
+ struct rdc_descriptor *next;
+ physaddr_t start;
+ unsigned int i;
+
+ /* Allocate descriptor ring */
+ ring->desc = dma_alloc ( rdc->dma, &ring->map, len, len );
+ if ( ! ring->desc )
+ return -ENOMEM;
+
+ /* Initialise descriptor ring */
+ memset ( ring->desc, 0, len );
+ for ( i = 0 ; i < ring->count ; i++ ) {
+ desc = &ring->desc[i];
+ next = &ring->desc[ ( i + 1 ) & ( ring->count - 1 ) ];
+ desc->next = cpu_to_le32 ( dma ( &ring->map, next ) );
+ }
+
+ /* Program ring address */
+ start = dma ( &ring->map, ring->desc );
+ writew ( ( start >> 0 ), ( rdc->regs + ring->reg + RDC_MxDSA_LO ) );
+ writew ( ( start >> 16 ), ( rdc->regs + ring->reg + RDC_MxDSA_HI ) );
+
+ DBGC ( rdc, "RDC %p ring %#02x is at [%08lx,%08lx)\n",
+ rdc, ring->reg, virt_to_phys ( ring->desc ),
+ ( virt_to_phys ( ring->desc ) + len ) );
+ return 0;
+}
+
+/**
+ * Destroy descriptor ring
+ *
+ * @v rdc RDC device
+ * @v ring Descriptor ring
+ */
+static void rdc_destroy_ring ( struct rdc_nic *rdc, struct rdc_ring *ring ) {
+ size_t len = ( ring->count * sizeof ( ring->desc[0] ) );
+
+ /* Clear ring address */
+ writew ( 0, ( rdc->regs + ring->reg + RDC_MxDSA_LO ) );
+ writew ( 0, ( rdc->regs + ring->reg + RDC_MxDSA_HI ) );
+
+ /* Free descriptors */
+ dma_free ( &ring->map, ring->desc, len );
+ ring->desc = NULL;
+
+ /* Reset ring */
+ ring->prod = 0;
+ ring->cons = 0;
+}
+
+/**
+ * Refill receive descriptor ring
+ *
+ * @v rdc RDC device
+ */
+static void rdc_refill_rx ( struct rdc_nic *rdc ) {
+ struct rdc_descriptor *rx;
+ struct io_buffer *iobuf;
+ unsigned int rx_idx;
+
+ /* Refill ring */
+ while ( ( rdc->rx.prod - rdc->rx.cons ) < RDC_NUM_RX_DESC ) {
+
+ /* Allocate I/O buffer */
+ iobuf = alloc_rx_iob ( RDC_RX_MAX_LEN, rdc->dma );
+ if ( ! iobuf ) {
+ /* Wait for next refill */
+ break;
+ }
+
+ /* Get next receive descriptor */
+ rx_idx = ( rdc->rx.prod++ % RDC_NUM_RX_DESC );
+ rx = &rdc->rx.desc[rx_idx];
+
+ /* Populate receive descriptor */
+ rx->len = cpu_to_le16 ( RDC_RX_MAX_LEN );
+ rx->addr = cpu_to_le32 ( iob_dma ( iobuf ) );
+ wmb();
+ rx->flags = cpu_to_le16 ( RDC_FL_OWNED );
+
+ /* Record I/O buffer */
+ assert ( rdc->rx_iobuf[rx_idx] == NULL );
+ rdc->rx_iobuf[rx_idx] = iobuf;
+
+ DBGC2 ( rdc, "RDC %p RX %d is [%lx,%lx)\n",
+ rdc, rx_idx, virt_to_phys ( iobuf->data ),
+ ( virt_to_phys ( iobuf->data ) + RDC_RX_MAX_LEN ) );
+ }
+}
+
+/**
+ * Open network device
+ *
+ * @v netdev Network device
+ * @ret rc Return status code
+ */
+static int rdc_open ( struct net_device *netdev ) {
+ struct rdc_nic *rdc = netdev->priv;
+ int rc;
+
+ /* Create transmit descriptor ring */
+ if ( ( rc = rdc_create_ring ( rdc, &rdc->tx ) ) != 0 )
+ goto err_create_tx;
+
+ /* Create receive descriptor ring */
+ if ( ( rc = rdc_create_ring ( rdc, &rdc->rx ) ) != 0 )
+ goto err_create_rx;
+
+ /* Program receive buffer length */
+ writew ( RDC_RX_MAX_LEN, rdc->regs + RDC_MRBSR );
+
+ /* Enable transmit and receive */
+ writew ( ( RDC_MCR0_FD | RDC_MCR0_TXEN | RDC_MCR0_PROMISC |
+ RDC_MCR0_RXEN ),
+ rdc->regs + RDC_MCR0 );
+
+ /* Enable PHY status polling */
+ writew ( ( RDC_MPSCCR_EN | RDC_MPSCCR_PHYAD ( rdc->mii.address ) |
+ RDC_MPSCCR_SLOW ),
+ rdc->regs + RDC_MPSCCR );
+
+ /* Fill receive ring */
+ rdc_refill_rx ( rdc );
+
+ /* Update link state */
+ rdc_check_link ( netdev );
+
+ return 0;
+
+ rdc_destroy_ring ( rdc, &rdc->rx );
+ err_create_rx:
+ rdc_destroy_ring ( rdc, &rdc->tx );
+ err_create_tx:
+ return rc;
+}
+
+/**
+ * Close network device
+ *
+ * @v netdev Network device
+ */
+static void rdc_close ( struct net_device *netdev ) {
+ struct rdc_nic *rdc = netdev->priv;
+ unsigned int i;
+
+ /* Disable NIC */
+ writew ( 0, rdc->regs + RDC_MCR0 );
+
+ /* Destroy receive descriptor ring */
+ rdc_destroy_ring ( rdc, &rdc->rx );
+
+ /* Discard any unused receive buffers */
+ for ( i = 0 ; i < RDC_NUM_RX_DESC ; i++ ) {
+ if ( rdc->rx_iobuf[i] )
+ free_rx_iob ( rdc->rx_iobuf[i] );
+ rdc->rx_iobuf[i] = NULL;
+ }
+
+ /* Destroy transmit descriptor ring */
+ rdc_destroy_ring ( rdc, &rdc->tx );
+}
+
+/**
+ * Transmit packet
+ *
+ * @v netdev Network device
+ * @v iobuf I/O buffer
+ * @ret rc Return status code
+ */
+static int rdc_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) {
+ struct rdc_nic *rdc = netdev->priv;
+ struct rdc_descriptor *tx;
+ unsigned int tx_idx;
+ int rc;
+
+ /* Get next transmit descriptor */
+ if ( ( rdc->tx.prod - rdc->tx.cons ) >= RDC_NUM_TX_DESC ) {
+ DBGC ( rdc, "RDC %p out of transmit descriptors\n", rdc );
+ return -ENOBUFS;
+ }
+ tx_idx = ( rdc->tx.prod % RDC_NUM_TX_DESC );
+ tx = &rdc->tx.desc[tx_idx];
+
+ /* Pad to minimum length */
+ iob_pad ( iobuf, ETH_ZLEN );
+
+ /* Map I/O buffer */
+ if ( ( rc = iob_map_tx ( iobuf, rdc->dma ) ) != 0 )
+ return rc;
+
+ /* Update producer index */
+ rdc->tx.prod++;
+
+ /* Populate transmit descriptor */
+ tx->len = cpu_to_le16 ( iob_len ( iobuf ) );
+ tx->addr = cpu_to_le32 ( iob_dma ( iobuf ) );
+ wmb();
+ tx->flags = cpu_to_le16 ( RDC_FL_OWNED );
+ wmb();
+
+ /* Notify card that there are packets ready to transmit */
+ writew ( RDC_MTPR_TM2TX, rdc->regs + RDC_MTPR );
+
+ return 0;
+}
+
+/**
+ * Poll for completed packets
+ *
+ * @v netdev Network device
+ */
+static void rdc_poll_tx ( struct net_device *netdev ) {
+ struct rdc_nic *rdc = netdev->priv;
+ struct rdc_descriptor *tx;
+ unsigned int tx_idx;
+
+ /* Check for completed packets */
+ while ( rdc->tx.cons != rdc->tx.prod ) {
+
+ /* Get next transmit descriptor */
+ tx_idx = ( rdc->tx.cons % RDC_NUM_TX_DESC );
+ tx = &rdc->tx.desc[tx_idx];
+
+ /* Stop if descriptor is still in use */
+ if ( tx->flags & cpu_to_le16 ( RDC_FL_OWNED ) )
+ return;
+ DBGC2 ( rdc, "RDC %p TX %d complete\n", rdc, tx_idx );
+
+ /* Complete transmit descriptor */
+ rdc->tx.cons++;
+ netdev_tx_complete_next ( netdev );
+ }
+}
+
+/**
+ * Poll for received packets
+ *
+ * @v netdev Network device
+ */
+static void rdc_poll_rx ( struct net_device *netdev ) {
+ struct rdc_nic *rdc = netdev->priv;
+ struct rdc_descriptor *rx;
+ struct io_buffer *iobuf;
+ unsigned int rx_idx;
+ size_t len;
+
+ /* Check for received packets */
+ while ( rdc->rx.cons != rdc->rx.prod ) {
+
+ /* Get next receive descriptor */
+ rx_idx = ( rdc->rx.cons % RDC_NUM_RX_DESC );
+ rx = &rdc->rx.desc[rx_idx];
+
+ /* Stop if descriptor is still in use */
+ if ( rx->flags & cpu_to_le16 ( RDC_FL_OWNED ) )
+ return;
+
+ /* Populate I/O buffer */
+ iobuf = rdc->rx_iobuf[rx_idx];
+ rdc->rx_iobuf[rx_idx] = NULL;
+ len = le16_to_cpu ( rx->len );
+ iob_put ( iobuf, len );
+ iob_unput ( iobuf, 4 /* strip CRC */ );
+
+ /* Hand off to network stack */
+ if ( rx->flags & cpu_to_le16 ( RDC_FL_OK ) ) {
+ DBGC2 ( rdc, "RDC %p RX %d complete (length %zd)\n",
+ rdc, rx_idx, len );
+ netdev_rx ( netdev, iobuf );
+ } else {
+ DBGC2 ( rdc, "RDC %p RX %d error (length %zd, "
+ "flags %#04x)\n", rdc, rx_idx, len,
+ le16_to_cpu ( rx->flags ) );
+ netdev_rx_err ( netdev, iobuf, -EIO );
+ }
+ rdc->rx.cons++;
+ }
+}
+
+/**
+ * Poll for completed and received packets
+ *
+ * @v netdev Network device
+ */
+static void rdc_poll ( struct net_device *netdev ) {
+ struct rdc_nic *rdc = netdev->priv;
+ uint16_t misr;
+
+ /* Check for (and acknowledge) interrupts */
+ misr = readw ( rdc->regs + RDC_MISR );
+
+ /* Poll for TX completions, if applicable */
+ if ( misr & RDC_MIRQ_TX )
+ rdc_poll_tx ( netdev );
+
+ /* Poll for RX completions, if applicable */
+ if ( misr & RDC_MIRQ_RX )
+ rdc_poll_rx ( netdev );
+
+ /* Check link state, if applicable */
+ if ( misr & RDC_MIRQ_LINK )
+ rdc_check_link ( netdev );
+
+ /* Check for unexpected interrupts */
+ if ( misr & ~( RDC_MIRQ_LINK | RDC_MIRQ_TX | RDC_MIRQ_RX_EARLY |
+ RDC_MIRQ_RX_EMPTY | RDC_MIRQ_RX ) ) {
+ DBGC ( rdc, "RDC %p unexpected MISR %#04x\n", rdc, misr );
+ /* Report as a TX error */
+ netdev_tx_err ( netdev, NULL, -ENOTSUP );
+ }
+
+ /* Refill receive ring */
+ rdc_refill_rx ( rdc );
+}
+
+/**
+ * Enable or disable interrupts
+ *
+ * @v netdev Network device
+ * @v enable Interrupts should be enabled
+ */
+static void rdc_irq ( struct net_device *netdev, int enable ) {
+ struct rdc_nic *rdc = netdev->priv;
+ uint16_t mier;
+
+ /* Enable/disable interrupts */
+ mier = ( enable ? ( RDC_MIRQ_LINK | RDC_MIRQ_TX | RDC_MIRQ_RX ) : 0 );
+ writew ( mier, rdc->regs + RDC_MIER );
+}
+
+/** RDC network device operations */
+static struct net_device_operations rdc_operations = {
+ .open = rdc_open,
+ .close = rdc_close,
+ .transmit = rdc_transmit,
+ .poll = rdc_poll,
+ .irq = rdc_irq,
+};
+
+/******************************************************************************
+ *
+ * PCI interface
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Probe PCI device
+ *
+ * @v pci PCI device
+ * @ret rc Return status code
+ */
+static int rdc_probe ( struct pci_device *pci ) {
+ struct net_device *netdev;
+ struct rdc_nic *rdc;
+ union rdc_mac mac;
+ int rc;
+
+ /* Allocate and initialise net device */
+ netdev = alloc_etherdev ( sizeof ( *rdc ) );
+ if ( ! netdev ) {
+ rc = -ENOMEM;
+ goto err_alloc;
+ }
+ netdev_init ( netdev, &rdc_operations );
+ rdc = netdev->priv;
+ pci_set_drvdata ( pci, netdev );
+ netdev->dev = &pci->dev;
+ memset ( rdc, 0, sizeof ( *rdc ) );
+ rdc->dma = &pci->dma;
+ mdio_init ( &rdc->mdio, &rdc_mii_operations );
+ mii_init ( &rdc->mii, &rdc->mdio, 0 );
+ rdc_init_ring ( &rdc->tx, RDC_NUM_TX_DESC, RDC_MTDSA );
+ rdc_init_ring ( &rdc->rx, RDC_NUM_RX_DESC, RDC_MRDSA );
+
+ /* Fix up PCI device */
+ adjust_pci_device ( pci );
+
+ /* Map registers */
+ rdc->regs = pci_ioremap ( pci, pci->membase, RDC_BAR_SIZE );
+ if ( ! rdc->regs ) {
+ rc = -ENODEV;
+ goto err_ioremap;
+ }
+
+ /* Fetch MAC address */
+ mac.mid[0] = cpu_to_le16 ( readw ( rdc->regs + RDC_MID0 ) );
+ mac.mid[1] = cpu_to_le16 ( readw ( rdc->regs + RDC_MID1 ) );
+ mac.mid[2] = cpu_to_le16 ( readw ( rdc->regs + RDC_MID2 ) );
+ memcpy ( netdev->hw_addr, mac.raw, ETH_ALEN );
+
+ /* Reset the NIC */
+ if ( ( rc = rdc_reset ( rdc ) ) != 0 )
+ goto err_reset;
+
+ /* Initialise PHY */
+ if ( ( rc = rdc_init_phy ( rdc ) ) != 0 )
+ goto err_init_phy;
+
+ /* Register network device */
+ if ( ( rc = register_netdev ( netdev ) ) != 0 )
+ goto err_register_netdev;
+
+ /* Set initial link state */
+ rdc_check_link ( netdev );
+
+ return 0;
+
+ unregister_netdev ( netdev );
+ err_register_netdev:
+ err_init_phy:
+ rdc_reset ( rdc );
+ err_reset:
+ iounmap ( rdc->regs );
+ err_ioremap:
+ netdev_nullify ( netdev );
+ netdev_put ( netdev );
+ err_alloc:
+ return rc;
+}
+
+/**
+ * Remove PCI device
+ *
+ * @v pci PCI device
+ */
+static void rdc_remove ( struct pci_device *pci ) {
+ struct net_device *netdev = pci_get_drvdata ( pci );
+ struct rdc_nic *rdc = netdev->priv;
+
+ /* Unregister network device */
+ unregister_netdev ( netdev );
+
+ /* Reset card */
+ rdc_reset ( rdc );
+
+ /* Free network device */
+ iounmap ( rdc->regs );
+ netdev_nullify ( netdev );
+ netdev_put ( netdev );
+}
+
+/** RDC PCI device IDs */
+static struct pci_device_id rdc_nics[] = {
+ PCI_ROM ( 0x17f3, 0x6040, "r6040", "RDC R6040", 0 ),
+};
+
+/** RDC PCI driver */
+struct pci_driver rdc_driver __pci_driver = {
+ .ids = rdc_nics,
+ .id_count = ( sizeof ( rdc_nics ) / sizeof ( rdc_nics[0] ) ),
+ .probe = rdc_probe,
+ .remove = rdc_remove,
+};
diff --git a/src/drivers/net/rdc.h b/src/drivers/net/rdc.h
new file mode 100644
index 000000000..ee1671fdd
--- /dev/null
+++ b/src/drivers/net/rdc.h
@@ -0,0 +1,194 @@
+#ifndef _RDC_H
+#define _RDC_H
+
+/** @file
+ *
+ * RDC R6040 network driver
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <stdint.h>
+#include <ipxe/if_ether.h>
+#include <ipxe/mii.h>
+
+/** RDC BAR size */
+#define RDC_BAR_SIZE 256
+
+/** An RDC descriptor */
+struct rdc_descriptor {
+ /** Flags */
+ uint16_t flags;
+ /** Length */
+ uint16_t len;
+ /** Address */
+ uint32_t addr;
+ /** Next descriptor */
+ uint32_t next;
+ /** Reserved */
+ uint32_t reserved;
+} __attribute__ (( packed ));
+
+/** Descriptor is owned by NIC */
+#define RDC_FL_OWNED 0x8000
+
+/** Packet OK */
+#define RDC_FL_OK 0x4000
+
+/** MAC control register 0 */
+#define RDC_MCR0 0x00
+#define RDC_MCR0_FD 0x8000 /**< Full duplex */
+#define RDC_MCR0_TXEN 0x1000 /**< Transmit enable */
+#define RDC_MCR0_PROMISC 0x0020 /**< Promiscuous mode */
+#define RDC_MCR0_RXEN 0x0002 /**< Receive enable */
+
+/** MAC control register 1 */
+#define RDC_MCR1 0x04
+#define RDC_MCR1_RST 0x0001 /**< MAC reset */
+
+/** Maximum time to wait for reset */
+#define RDC_RESET_MAX_WAIT_MS 10
+
+/** MAC transmit poll command register */
+#define RDC_MTPR 0x14
+#define RDC_MTPR_TM2TX 0x0001 /**< Trigger MAC to transmit */
+
+/** MAC receive buffer size register */
+#define RDC_MRBSR 0x18
+
+/** MAC MDIO control register */
+#define RDC_MMDIO 0x20
+#define RDC_MMDIO_MIIWR 0x4000 /**< MDIO write */
+#define RDC_MMDIO_MIIRD 0x2000 /**< MDIO read */
+#define RDC_MMDIO_PHYAD(x) ( (x) << 8 ) /**< PHY address */
+#define RDC_MMDIO_REGAD(x) ( (x) << 0 ) /**< Register address */
+
+/** Maximum time to wait for an MII read or write */
+#define RDC_MII_MAX_WAIT_US 2048
+
+/** MAC MDIO read data register */
+#define RDC_MMRD 0x24
+
+/** MAC MDIO write data register */
+#define RDC_MMWD 0x28
+
+/** MAC transmit descriptor start address */
+#define RDC_MTDSA 0x2c
+
+/** MAC receive descriptor start address */
+#define RDC_MRDSA 0x34
+
+/** MAC descriptor start address low half */
+#define RDC_MxDSA_LO 0x0
+
+/** MAC descriptor start address low half */
+#define RDC_MxDSA_HI 0x4
+
+/** MAC interrupt status register */
+#define RDC_MISR 0x3c
+#define RDC_MIRQ_LINK 0x0200 /**< Link status changed */
+#define RDC_MIRQ_TX 0x0010 /**< Transmit complete */
+#define RDC_MIRQ_RX_EARLY 0x0008 /**< Receive early interrupt */
+#define RDC_MIRQ_RX_EMPTY 0x0002 /**< Receive descriptor unavailable */
+#define RDC_MIRQ_RX 0x0001 /**< Receive complete */
+
+/** MAC interrupt enable register */
+#define RDC_MIER 0x40
+
+/** MAC address word 0 */
+#define RDC_MID0 0x68
+
+/** MAC address word 1 */
+#define RDC_MID1 0x6a
+
+/** MAC address word 2 */
+#define RDC_MID2 0x6c
+
+/** MAC PHY status change configuration register */
+#define RDC_MPSCCR 0x88
+#define RDC_MPSCCR_EN 0x8000 /**< PHY status change enable */
+#define RDC_MPSCCR_PHYAD(x) ( (x) << 8 ) /**< PHY address */
+#define RDC_MPSCCR_SLOW 0x0007 /**< Poll slowly */
+
+/** MAC state machine register */
+#define RDC_MACSM 0xac
+#define RDC_MACSM_RST 0x0002 /**< Reset state machine */
+
+/** Time to wait after resetting MAC state machine */
+#define RDC_MACSM_RESET_DELAY_MS 10
+
+/** A MAC address */
+union rdc_mac {
+ /** Raw bytes */
+ uint8_t raw[ETH_ALEN];
+ /** MIDx registers */
+ uint16_t mid[ ETH_ALEN / 2 ];
+};
+
+/** A descriptor ring */
+struct rdc_ring {
+ /** Descriptors */
+ struct rdc_descriptor *desc;
+ /** Descriptor ring DMA mapping */
+ struct dma_mapping map;
+ /** Producer index */
+ unsigned int prod;
+ /** Consumer index */
+ unsigned int cons;
+
+ /** Number of descriptors */
+ unsigned int count;
+ /** Start address register 0 */
+ unsigned int reg;
+};
+
+/**
+ * Initialise descriptor ring
+ *
+ * @v ring Descriptor ring
+ * @v count Number of descriptors
+ * @v reg Start address register 0
+ */
+static inline __attribute__ (( always_inline )) void
+rdc_init_ring ( struct rdc_ring *ring, unsigned int count, unsigned int reg ) {
+
+ ring->count = count;
+ ring->reg = reg;
+}
+
+/** Number of transmit descriptors
+ *
+ * This is a policy decision.
+ */
+#define RDC_NUM_TX_DESC 16
+
+/** Number of receive descriptors
+ *
+ * This is a policy decision.
+ */
+#define RDC_NUM_RX_DESC 8
+
+/** Receive buffer length */
+#define RDC_RX_MAX_LEN ( ETH_FRAME_LEN + 4 /* VLAN */ + 4 /* CRC */ )
+
+/** An RDC network card */
+struct rdc_nic {
+ /** Registers */
+ void *regs;
+ /** DMA device */
+ struct dma_device *dma;
+ /** MII interface */
+ struct mii_interface mdio;
+ /** MII device */
+ struct mii_device mii;
+
+ /** Transmit descriptor ring */
+ struct rdc_ring tx;
+ /** Receive descriptor ring */
+ struct rdc_ring rx;
+ /** Receive I/O buffers */
+ struct io_buffer *rx_iobuf[RDC_NUM_RX_DESC];
+};
+
+#endif /* _RDC_H */
diff --git a/src/drivers/net/realtek.c b/src/drivers/net/realtek.c
index 0af3416d5..a43efb68b 100644
--- a/src/drivers/net/realtek.c
+++ b/src/drivers/net/realtek.c
@@ -420,6 +420,16 @@ static int realtek_phy_reset ( struct realtek_nic *rtl ) {
*/
}
+ /* Some cards (e.g. RTL8211B) have a hardware errata that
+ * requires the MII_MMD_DATA register to be cleared before the
+ * link will come up.
+ */
+ if ( ( rc = mii_write ( &rtl->mii, MII_MMD_DATA, 0 ) ) != 0 ) {
+ /* Ignore failures, since the register may not be
+ * present on all PHYs.
+ */
+ }
+
/* Restart autonegotiation */
if ( ( rc = mii_restart ( &rtl->mii ) ) != 0 ) {
DBGC ( rtl, "REALTEK %p could not restart MII: %s\n",
diff --git a/src/hci/commands/image_archive_cmd.c b/src/hci/commands/image_archive_cmd.c
new file mode 100644
index 000000000..a2212aecf
--- /dev/null
+++ b/src/hci/commands/image_archive_cmd.c
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2021 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <getopt.h>
+#include <ipxe/command.h>
+#include <ipxe/parseopt.h>
+#include <usr/imgmgmt.h>
+#include <usr/imgarchive.h>
+
+/** @file
+ *
+ * Archive image commands
+ *
+ */
+
+/** "imgextract" options */
+struct imgextract_options {
+ /** Image name */
+ char *name;
+ /** Keep original image */
+ int keep;
+ /** Download timeout */
+ unsigned long timeout;
+};
+
+/** "imgextract" option list */
+static struct option_descriptor imgextract_opts[] = {
+ OPTION_DESC ( "name", 'n', required_argument,
+ struct imgextract_options, name, parse_string ),
+ OPTION_DESC ( "keep", 'k', no_argument,
+ struct imgextract_options, keep, parse_flag ),
+ OPTION_DESC ( "timeout", 't', required_argument,
+ struct imgextract_options, timeout, parse_timeout ),
+};
+
+/** "imgextract" command descriptor */
+static struct command_descriptor imgextract_cmd =
+ COMMAND_DESC ( struct imgextract_options, imgextract_opts, 1, 1, NULL );
+
+/**
+ * The "imgextract" command
+ *
+ * @v argc Argument count
+ * @v argv Argument list
+ * @ret rc Return status code
+ */
+static int imgextract_exec ( int argc, char **argv ) {
+ struct imgextract_options opts;
+ struct image *image;
+ int rc;
+
+ /* Parse options */
+ if ( ( rc = parse_options ( argc, argv, &imgextract_cmd,
+ &opts ) ) != 0 )
+ goto err_parse;
+
+ /* Acquire image */
+ if ( ( rc = imgacquire ( argv[optind], opts.timeout, &image ) ) != 0 )
+ goto err_acquire;
+
+ /* Extract archive image */
+ if ( ( rc = imgextract ( image, opts.name ) ) != 0 )
+ goto err_extract;
+
+ /* Success */
+ rc = 0;
+
+ err_extract:
+ /* Discard original image unless --keep was specified */
+ if ( ! opts.keep )
+ unregister_image ( image );
+ err_acquire:
+ err_parse:
+ return rc;
+}
+
+/** Archive image commands */
+struct command image_archive_commands[] __command = {
+ {
+ .name = "imgextract",
+ .exec = imgextract_exec,
+ },
+};
diff --git a/src/hci/commands/nvo_cmd.c b/src/hci/commands/nvo_cmd.c
index ac0d60651..6ad7e7428 100644
--- a/src/hci/commands/nvo_cmd.c
+++ b/src/hci/commands/nvo_cmd.c
@@ -100,20 +100,40 @@ static int show_exec ( int argc, char **argv ) {
}
/** "set", "clear", and "read" options */
-struct set_core_options {};
+struct set_core_options {
+ /** Timeout */
+ unsigned long timeout;
+};
/** "set", "clear", and "read" option list */
-static struct option_descriptor set_core_opts[] = {};
+static union {
+ /* "set" takes no options */
+ struct option_descriptor set[0];
+ /* "clear" takes no options */
+ struct option_descriptor clear[0];
+ /* "read" takes --timeout option */
+ struct option_descriptor read[1];
+} set_core_opts = {
+ .read = {
+ OPTION_DESC ( "timeout", 't', required_argument,
+ struct set_core_options, timeout, parse_timeout ),
+ },
+};
/** "set" command descriptor */
static struct command_descriptor set_cmd =
- COMMAND_DESC ( struct set_core_options, set_core_opts, 1, MAX_ARGUMENTS,
- "<setting> <value>" );
+ COMMAND_DESC ( struct set_core_options, set_core_opts.set,
+ 1, MAX_ARGUMENTS, "<setting> <value>" );
+
+/** "clear" command descriptor */
+static struct command_descriptor clear_cmd =
+ COMMAND_DESC ( struct set_core_options, set_core_opts.clear,
+ 1, 1, "<setting>" );
-/** "clear" and "read" command descriptor */
-static struct command_descriptor clear_read_cmd =
- COMMAND_DESC ( struct set_core_options, set_core_opts, 1, 1,
- "<setting>" );
+/** "read" command descriptor */
+static struct command_descriptor read_cmd =
+ COMMAND_DESC ( struct set_core_options, set_core_opts.read,
+ 1, 1, "<setting>" );
/**
* "set", "clear", and "read" command
@@ -127,6 +147,7 @@ static struct command_descriptor clear_read_cmd =
static int set_core_exec ( int argc, char **argv,
struct command_descriptor *cmd,
int ( * get_value ) ( struct named_setting *setting,
+ struct set_core_options *opts,
char **args, char **value ) ) {
struct set_core_options opts;
struct named_setting setting;
@@ -143,7 +164,8 @@ static int set_core_exec ( int argc, char **argv,
goto err_parse_setting;
/* Parse setting value */
- if ( ( rc = get_value ( &setting, &argv[ optind + 1 ], &value ) ) != 0 )
+ if ( ( rc = get_value ( &setting, &opts, &argv[ optind + 1 ],
+ &value ) ) != 0 )
goto err_get_value;
/* Apply default type if necessary */
@@ -170,11 +192,13 @@ static int set_core_exec ( int argc, char **argv,
* Get setting value for "set" command
*
* @v setting Named setting
+ * @v opts Options list
* @v args Remaining arguments
* @ret value Setting value
* @ret rc Return status code
*/
static int set_value ( struct named_setting *setting __unused,
+ struct set_core_options *opts __unused,
char **args, char **value ) {
*value = concat_args ( args );
@@ -200,10 +224,12 @@ static int set_exec ( int argc, char **argv ) {
*
* @v setting Named setting
* @v args Remaining arguments
+ * @v opts Options list
* @ret value Setting value
* @ret rc Return status code
*/
static int clear_value ( struct named_setting *setting __unused,
+ struct set_core_options *opts __unused,
char **args __unused, char **value ) {
*value = NULL;
@@ -218,7 +244,7 @@ static int clear_value ( struct named_setting *setting __unused,
* @ret rc Return status code
*/
static int clear_exec ( int argc, char **argv ) {
- return set_core_exec ( argc, argv, &clear_read_cmd, clear_value );
+ return set_core_exec ( argc, argv, &clear_cmd, clear_value );
}
/**
@@ -226,11 +252,13 @@ static int clear_exec ( int argc, char **argv ) {
*
* @v setting Named setting
* @v args Remaining arguments
+ * @v opts Options list
* @ret value Setting value
* @ret rc Return status code
*/
-static int read_value ( struct named_setting *setting, char **args __unused,
- char **value ) {
+static int read_value ( struct named_setting *setting,
+ struct set_core_options *opts,
+ char **args __unused, char **value ) {
char *existing;
int rc;
@@ -241,7 +269,8 @@ static int read_value ( struct named_setting *setting, char **args __unused,
NULL, &setting->setting, &existing );
/* Read new value */
- if ( ( rc = readline_history ( NULL, existing, NULL, value ) ) != 0 )
+ if ( ( rc = readline_history ( NULL, existing, NULL, opts->timeout,
+ value ) ) != 0 )
goto err_readline;
err_readline:
@@ -257,7 +286,7 @@ static int read_value ( struct named_setting *setting, char **args __unused,
* @ret rc Return status code
*/
static int read_exec ( int argc, char **argv ) {
- return set_core_exec ( argc, argv, &clear_read_cmd, read_value );
+ return set_core_exec ( argc, argv, &read_cmd, read_value );
}
/** "inc" options */
diff --git a/src/hci/readline.c b/src/hci/readline.c
index 83a2e0b90..852c4503a 100644
--- a/src/hci/readline.c
+++ b/src/hci/readline.c
@@ -248,6 +248,7 @@ void history_free ( struct readline_history *history ) {
* @v prompt Prompt string
* @v prefill Prefill string, or NULL for no prefill
* @v history History buffer, or NULL for no history
+ * @v timeout Timeout period, in ticks (0=indefinite)
* @ret line Line read from console (excluding terminating newline)
* @ret rc Return status code
*
@@ -255,7 +256,8 @@ void history_free ( struct readline_history *history ) {
* eventually call free() to release the storage.
*/
int readline_history ( const char *prompt, const char *prefill,
- struct readline_history *history, char **line ) {
+ struct readline_history *history, unsigned long timeout,
+ char **line ) {
char buf[READLINE_MAX];
struct edit_string string;
int key;
@@ -285,8 +287,17 @@ int readline_history ( const char *prompt, const char *prefill,
}
while ( 1 ) {
+
+ /* Get keypress */
+ key = getkey ( timeout );
+ if ( key < 0 ) {
+ rc = -ETIMEDOUT;
+ goto done;
+ }
+ timeout = 0;
+
/* Handle keypress */
- key = edit_string ( &string, getkey ( 0 ) );
+ key = edit_string ( &string, key );
sync_console ( &string );
move_by = 0;
switch ( key ) {
@@ -342,6 +353,6 @@ int readline_history ( const char *prompt, const char *prefill,
char * readline ( const char *prompt ) {
char *line;
- readline_history ( prompt, NULL, NULL, &line );
+ readline_history ( prompt, NULL, NULL, 0, &line );
return line;
}
diff --git a/src/hci/shell.c b/src/hci/shell.c
index 276eb3527..8ecf73a6f 100644
--- a/src/hci/shell.c
+++ b/src/hci/shell.c
@@ -91,7 +91,7 @@ int shell ( void ) {
/* Read and execute commands */
do {
- readline_history ( shell_prompt, NULL, &history, &line );
+ readline_history ( shell_prompt, NULL, &history, 0, &line );
if ( line ) {
rc = system ( line );
free ( line );
diff --git a/src/image/gzip.c b/src/image/gzip.c
new file mode 100644
index 000000000..98376e113
--- /dev/null
+++ b/src/image/gzip.c
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2021 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <stdlib.h>
+#include <errno.h>
+#include <assert.h>
+#include <ipxe/deflate.h>
+#include <ipxe/uaccess.h>
+#include <ipxe/image.h>
+#include <ipxe/zlib.h>
+#include <ipxe/gzip.h>
+
+/** @file
+ *
+ * gzip compressed images
+ *
+ */
+
+/**
+ * Extract gzip image
+ *
+ * @v image Image
+ * @v extracted Extracted image
+ * @ret rc Return status code
+ */
+static int gzip_extract ( struct image *image, struct image *extracted ) {
+ struct gzip_header header;
+ struct gzip_extra_header extra;
+ struct gzip_crc_header crc;
+ struct gzip_footer footer;
+ struct deflate_chunk in;
+ unsigned int strings;
+ size_t offset;
+ size_t len;
+ off_t nul;
+ int rc;
+
+ /* Sanity check */
+ assert ( image->len >= ( sizeof ( header ) + sizeof ( footer ) ) );
+
+ /* Extract footer */
+ len = ( image->len - sizeof ( footer ) );
+ copy_from_user ( &footer, image->data, len, sizeof ( footer ) );
+
+ /* Extract fixed header */
+ copy_from_user ( &header, image->data, 0, sizeof ( header ) );
+ offset = sizeof ( header );
+ assert ( offset <= ( image->len - sizeof ( footer ) ) );
+
+ /* Skip extra header, if present */
+ if ( header.flags & GZIP_FL_EXTRA ) {
+ copy_from_user ( &extra, image->data, offset,
+ sizeof ( extra ) );
+ offset += sizeof ( extra );
+ offset += le16_to_cpu ( extra.len );
+ if ( offset > len ) {
+ DBGC ( image, "GZIP %p overlength extra header\n",
+ image );
+ return -EINVAL;
+ }
+ }
+ assert ( offset <= ( image->len - sizeof ( footer ) ) );
+
+ /* Skip name and/or comment, if present */
+ strings = 0;
+ if ( header.flags & GZIP_FL_NAME )
+ strings++;
+ if ( header.flags & GZIP_FL_COMMENT )
+ strings++;
+ while ( strings-- ) {
+ nul = memchr_user ( image->data, offset, 0, ( len - offset ) );
+ if ( nul < 0 ) {
+ DBGC ( image, "GZIP %p overlength name/comment\n",
+ image );
+ return -EINVAL;
+ }
+ offset = ( nul + 1 /* NUL */ );
+ }
+ assert ( offset <= ( image->len - sizeof ( footer ) ) );
+
+ /* Skip CRC, if present */
+ if ( header.flags & GZIP_FL_HCRC ) {
+ offset += sizeof ( crc );
+ if ( offset > len ) {
+ DBGC ( image, "GZIP %p overlength CRC header\n",
+ image );
+ return -EINVAL;
+ }
+ }
+
+ /* Initialise input chunk */
+ deflate_chunk_init ( &in, userptr_add ( image->data, offset ), 0, len );
+
+ /* Presize extracted image */
+ if ( ( rc = image_set_len ( extracted,
+ le32_to_cpu ( footer.len ) ) ) != 0 ) {
+ DBGC ( image, "GZIP %p could not presize: %s\n",
+ image, strerror ( rc ) );
+ return rc;
+ }
+
+ /* Decompress image (expanding if necessary) */
+ if ( ( rc = zlib_deflate ( DEFLATE_RAW, &in, extracted ) ) != 0 ) {
+ DBGC ( image, "GZIP %p could not decompress: %s\n",
+ image, strerror ( rc ) );
+ return rc;
+ }
+
+ return 0;
+}
+
+/**
+ * Probe gzip image
+ *
+ * @v image gzip image
+ * @ret rc Return status code
+ */
+static int gzip_probe ( struct image *image ) {
+ struct gzip_header header;
+ struct gzip_footer footer;
+
+ /* Sanity check */
+ if ( image->len < ( sizeof ( header ) + sizeof ( footer ) ) ) {
+ DBGC ( image, "GZIP %p image too short\n", image );
+ return -ENOEXEC;
+ }
+
+ /* Check magic header */
+ copy_from_user ( &header.magic, image->data, 0,
+ sizeof ( header.magic ) );
+ if ( header.magic != cpu_to_be16 ( GZIP_MAGIC ) ) {
+ DBGC ( image, "GZIP %p invalid magic\n", image );
+ return -ENOEXEC;
+ }
+
+ return 0;
+}
+
+/** gzip image type */
+struct image_type gzip_image_type __image_type ( PROBE_NORMAL ) = {
+ .name = "gzip",
+ .probe = gzip_probe,
+ .extract = gzip_extract,
+ .exec = image_extract_exec,
+};
diff --git a/src/image/zlib.c b/src/image/zlib.c
new file mode 100644
index 000000000..a42c47e1b
--- /dev/null
+++ b/src/image/zlib.c
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2021 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <stdlib.h>
+#include <errno.h>
+#include <assert.h>
+#include <ipxe/deflate.h>
+#include <ipxe/uaccess.h>
+#include <ipxe/image.h>
+#include <ipxe/zlib.h>
+
+/** @file
+ *
+ * zlib compressed images
+ *
+ */
+
+/**
+ * Extract compressed data to image
+ *
+ * @v format Compression format code
+ * @v in Compressed input chunk
+ * @v extracted Extracted image
+ * @ret rc Return status code
+ */
+int zlib_deflate ( enum deflate_format format, struct deflate_chunk *in,
+ struct image *extracted ) {
+ struct deflate *deflate;
+ struct deflate_chunk out;
+ int rc;
+
+ /* Allocate and initialise decompressor */
+ deflate = zalloc ( sizeof ( *deflate ) );
+ if ( ! deflate ) {
+ rc = -ENOMEM;
+ goto err_alloc;
+ }
+
+ /* Decompress data, (re)allocating if necessary */
+ while ( 1 ) {
+
+ /* (Re)initialise decompressor */
+ deflate_init ( deflate, format );
+
+ /* (Re)initialise input chunk */
+ in->offset = 0;
+
+ /* Initialise output chunk */
+ deflate_chunk_init ( &out, extracted->data, 0, extracted->len );
+
+ /* Decompress data */
+ if ( ( rc = deflate_inflate ( deflate, in, &out ) ) != 0 ) {
+ DBGC ( extracted, "ZLIB %p could not decompress: %s\n",
+ extracted, strerror ( rc ) );
+ goto err_inflate;
+ }
+
+ /* Check that decompression is valid */
+ if ( ! deflate_finished ( deflate ) ) {
+ DBGC ( extracted, "ZLIB %p decompression incomplete\n",
+ extracted );
+ rc = -EINVAL;
+ goto err_unfinished;
+ }
+
+ /* Finish if output image size was correct */
+ if ( out.offset == extracted->len )
+ break;
+
+ /* Otherwise, resize output image and retry */
+ if ( ( rc = image_set_len ( extracted, out.offset ) ) != 0 ) {
+ DBGC ( extracted, "ZLIB %p could not resize: %s\n",
+ extracted, strerror ( rc ) );
+ goto err_set_size;
+ }
+ }
+
+ /* Success */
+ rc = 0;
+
+ err_set_size:
+ err_unfinished:
+ err_inflate:
+ free ( deflate );
+ err_alloc:
+ return rc;
+}
+
+/**
+ * Extract zlib image
+ *
+ * @v image Image
+ * @v extracted Extracted image
+ * @ret rc Return status code
+ */
+static int zlib_extract ( struct image *image, struct image *extracted ) {
+ struct deflate_chunk in;
+ int rc;
+
+ /* Initialise input chunk */
+ deflate_chunk_init ( &in, image->data, 0, image->len );
+
+ /* Decompress image */
+ if ( ( rc = zlib_deflate ( DEFLATE_ZLIB, &in, extracted ) ) != 0 )
+ return rc;
+
+ return 0;
+}
+
+/**
+ * Probe zlib image
+ *
+ * @v image zlib image
+ * @ret rc Return status code
+ */
+static int zlib_probe ( struct image *image ) {
+ union zlib_magic magic;
+
+ /* Sanity check */
+ if ( image->len < sizeof ( magic ) ) {
+ DBGC ( image, "ZLIB %p image too short\n", image );
+ return -ENOEXEC;
+ }
+
+ /* Check magic header */
+ copy_from_user ( &magic, image->data, 0, sizeof ( magic ) );
+ if ( ! zlib_magic_is_valid ( &magic ) ) {
+ DBGC ( image, "ZLIB %p invalid magic data\n", image );
+ return -ENOEXEC;
+ }
+
+ return 0;
+}
+
+/** zlib image type */
+struct image_type zlib_image_type __image_type ( PROBE_NORMAL ) = {
+ .name = "zlib",
+ .probe = zlib_probe,
+ .extract = zlib_extract,
+ .exec = image_extract_exec,
+};
diff --git a/src/include/endian.h b/src/include/endian.h
index 79c3163ee..bdae9de45 100644
--- a/src/include/endian.h
+++ b/src/include/endian.h
@@ -8,14 +8,18 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
* Little-endian systems should define BYTE_ORDER as LITTLE_ENDIAN.
* This constant is intended to be used only at compile time.
*/
+#ifndef __LITTLE_ENDIAN
#define __LITTLE_ENDIAN 0x44332211UL
+#endif
/** Constant representing big-endian byte order
*
* Big-endian systems should define BYTE_ORDER as BIG_ENDIAN.
* This constant is intended to be used only at compile time.
*/
+#ifndef __BIG_ENDIAN
#define __BIG_ENDIAN 0x11223344UL
+#endif
#include "bits/endian.h"
diff --git a/src/include/ipxe/cpio.h b/src/include/ipxe/cpio.h
index 0637c531d..9c5e22d5a 100644
--- a/src/include/ipxe/cpio.h
+++ b/src/include/ipxe/cpio.h
@@ -9,6 +9,8 @@
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+#include <ipxe/image.h>
+
/** A CPIO archive header
*
* All field are hexadecimal ASCII numbers padded with '0' on the
@@ -48,6 +50,25 @@ struct cpio_header {
/** CPIO magic */
#define CPIO_MAGIC "070701"
+/** CPIO header length alignment */
+#define CPIO_ALIGN 4
+
+/** Alignment for CPIO archives within an initrd */
+#define INITRD_ALIGN 4096
+
+/**
+ * Get CPIO image name
+ *
+ * @v image Image
+ * @ret name Image name (not NUL terminated)
+ */
+static inline __attribute__ (( always_inline )) const char *
+cpio_name ( struct image *image ) {
+ return image->cmdline;
+}
+
extern void cpio_set_field ( char *field, unsigned long value );
+extern size_t cpio_name_len ( struct image *image );
+extern size_t cpio_header ( struct image *image, struct cpio_header *cpio );
#endif /* _IPXE_CPIO_H */
diff --git a/src/include/ipxe/errfile.h b/src/include/ipxe/errfile.h
index e3bf9f565..cf5757874 100644
--- a/src/include/ipxe/errfile.h
+++ b/src/include/ipxe/errfile.h
@@ -213,6 +213,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#define ERRFILE_usbblk ( ERRFILE_DRIVER | 0x00ce0000 )
#define ERRFILE_iphone ( ERRFILE_DRIVER | 0x00cf0000 )
#define ERRFILE_slirp ( ERRFILE_DRIVER | 0x00d00000 )
+#define ERRFILE_rdc ( ERRFILE_DRIVER | 0x00d10000 )
#define ERRFILE_aoe ( ERRFILE_NET | 0x00000000 )
#define ERRFILE_arp ( ERRFILE_NET | 0x00010000 )
@@ -301,6 +302,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#define ERRFILE_png ( ERRFILE_IMAGE | 0x00070000 )
#define ERRFILE_der ( ERRFILE_IMAGE | 0x00080000 )
#define ERRFILE_pem ( ERRFILE_IMAGE | 0x00090000 )
+#define ERRFILE_archive ( ERRFILE_IMAGE | 0x000a0000 )
+#define ERRFILE_zlib ( ERRFILE_IMAGE | 0x000b0000 )
+#define ERRFILE_gzip ( ERRFILE_IMAGE | 0x000c0000 )
#define ERRFILE_asn1 ( ERRFILE_OTHER | 0x00000000 )
#define ERRFILE_chap ( ERRFILE_OTHER | 0x00010000 )
diff --git a/src/include/ipxe/gzip.h b/src/include/ipxe/gzip.h
new file mode 100644
index 000000000..c8cf64147
--- /dev/null
+++ b/src/include/ipxe/gzip.h
@@ -0,0 +1,71 @@
+#ifndef _IPXE_GZIP_H
+#define _IPXE_GZIP_H
+
+/** @file
+ *
+ * gzip compressed images
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <stdint.h>
+#include <ipxe/image.h>
+
+/** gzip header */
+struct gzip_header {
+ /** Magic ID */
+ uint16_t magic;
+ /** Compression method */
+ uint8_t method;
+ /** Flags */
+ uint8_t flags;
+ /** Modification time */
+ uint32_t mtime;
+ /** Extra flags */
+ uint8_t extra;
+ /** Operating system */
+ uint8_t os;
+} __attribute__ (( packed ));
+
+/** Magic ID */
+#define GZIP_MAGIC 0x1f8b
+
+/** Compression method */
+#define GZIP_METHOD_DEFLATE 0x08
+
+/** CRC header is present */
+#define GZIP_FL_HCRC 0x02
+
+/** Extra header is present */
+#define GZIP_FL_EXTRA 0x04
+
+/** File name is present */
+#define GZIP_FL_NAME 0x08
+
+/** File comment is present */
+#define GZIP_FL_COMMENT 0x10
+
+/** gzip extra header */
+struct gzip_extra_header {
+ /** Extra header length (excluding this field) */
+ uint16_t len;
+} __attribute__ (( packed ));
+
+/** gzip CRC header */
+struct gzip_crc_header {
+ /** CRC-16 */
+ uint16_t crc;
+} __attribute__ (( packed ));
+
+/** gzip footer */
+struct gzip_footer {
+ /** CRC-32 */
+ uint32_t crc;
+ /** Uncompressed size (modulo 2^32) */
+ uint32_t len;
+} __attribute__ (( packed ));
+
+extern struct image_type gzip_image_type __image_type ( PROBE_NORMAL );
+
+#endif /* _IPXE_GZIP_H */
diff --git a/src/include/ipxe/image.h b/src/include/ipxe/image.h
index 4fd270081..0a5a26034 100644
--- a/src/include/ipxe/image.h
+++ b/src/include/ipxe/image.h
@@ -113,6 +113,14 @@ struct image_type {
*/
int ( * asn1 ) ( struct image *image, size_t offset,
struct asn1_cursor **cursor );
+ /**
+ * Extract archive image
+ *
+ * @v image Image
+ * @v extracted Extracted image
+ * @ret rc Return status code
+ */
+ int ( * extract ) ( struct image *image, struct image *extracted );
};
/**
@@ -175,6 +183,7 @@ extern struct image * alloc_image ( struct uri *uri );
extern int image_set_uri ( struct image *image, struct uri *uri );
extern int image_set_name ( struct image *image, const char *name );
extern int image_set_cmdline ( struct image *image, const char *cmdline );
+extern int image_set_len ( struct image *image, size_t len );
extern int image_set_data ( struct image *image, userptr_t data, size_t len );
extern int register_image ( struct image *image );
extern void unregister_image ( struct image *image );
@@ -189,6 +198,9 @@ extern struct image * image_memory ( const char *name, userptr_t data,
extern int image_pixbuf ( struct image *image, struct pixel_buffer **pixbuf );
extern int image_asn1 ( struct image *image, size_t offset,
struct asn1_cursor **cursor );
+extern int image_extract ( struct image *image, const char *name,
+ struct image **extracted );
+extern int image_extract_exec ( struct image *image );
/**
* Increment reference count on an image
diff --git a/src/include/ipxe/rndis.h b/src/include/ipxe/rndis.h
index bcb6d8e6a..e8ece1e85 100644
--- a/src/include/ipxe/rndis.h
+++ b/src/include/ipxe/rndis.h
@@ -84,7 +84,7 @@ struct rndis_initialise_completion {
/** Packet alignment factor */
uint32_t align;
/** Reserved */
- uint32_t reserved;
+ uint32_t reserved[2];
} __attribute__ (( packed ));
/** RNDIS halt message */
@@ -237,7 +237,7 @@ struct rndis_packet_message {
/** Per-packet information record */
struct rndis_packet_field ppi;
/** Reserved */
- uint32_t reserved;
+ uint32_t reserved[2];
} __attribute__ (( packed ));
/** RNDIS packet record */
diff --git a/src/include/ipxe/zlib.h b/src/include/ipxe/zlib.h
new file mode 100644
index 000000000..29016c38e
--- /dev/null
+++ b/src/include/ipxe/zlib.h
@@ -0,0 +1,43 @@
+#ifndef _IPXE_ZLIB_H
+#define _IPXE_ZLIB_H
+
+/** @file
+ *
+ * zlib compressed images
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <stdint.h>
+#include <byteswap.h>
+#include <ipxe/image.h>
+#include <ipxe/deflate.h>
+
+/** zlib magic header */
+union zlib_magic {
+ /** Compression method and flags */
+ uint8_t cmf;
+ /** Check value */
+ uint16_t check;
+} __attribute__ (( packed ));
+
+/**
+ * Check that zlib magic header is valid
+ *
+ * @v magic Magic header
+ * @ret is_valid Magic header is valid
+ */
+static inline int zlib_magic_is_valid ( union zlib_magic *magic ) {
+
+ /* Check magic value as per RFC 6713 */
+ return ( ( ( magic->cmf & 0x8f ) == 0x08 ) &&
+ ( ( be16_to_cpu ( magic->check ) % 31 ) == 0 ) );
+}
+
+extern int zlib_deflate ( enum deflate_format format, struct deflate_chunk *in,
+ struct image *extracted );
+
+extern struct image_type zlib_image_type __image_type ( PROBE_NORMAL );
+
+#endif /* _IPXE_ZLIB_H */
diff --git a/src/include/mii.h b/src/include/mii.h
index e2afef854..515ba224d 100644
--- a/src/include/mii.h
+++ b/src/include/mii.h
@@ -23,6 +23,8 @@ FILE_LICENCE ( GPL2_ONLY );
#define MII_EXPANSION 0x06 /* Expansion register */
#define MII_CTRL1000 0x09 /* 1000BASE-T control */
#define MII_STAT1000 0x0a /* 1000BASE-T status */
+#define MII_MMD_CTRL 0x0d /* MMD Access Control Register */
+#define MII_MMD_DATA 0x0e /* MMD Access Data Register */
#define MII_ESTATUS 0x0f /* Extended Status */
#define MII_DCOUNTER 0x12 /* Disconnect counter */
#define MII_FCSCOUNTER 0x13 /* False carrier counter */
diff --git a/src/include/readline/readline.h b/src/include/readline/readline.h
index afafbbdf5..3caf28b47 100644
--- a/src/include/readline/readline.h
+++ b/src/include/readline/readline.h
@@ -51,7 +51,8 @@ struct readline_history {
extern void history_free ( struct readline_history *history );
extern int readline_history ( const char *prompt, const char *prefill,
- struct readline_history *history, char **line );
+ struct readline_history *history,
+ unsigned long timeout, char **line );
extern char * __malloc readline ( const char *prompt );
#endif /* _READLINE_H */
diff --git a/src/include/stdio.h b/src/include/stdio.h
index a618482ce..ac17da83d 100644
--- a/src/include/stdio.h
+++ b/src/include/stdio.h
@@ -6,7 +6,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <stdarg.h>
-extern void putchar ( int character );
+extern int putchar ( int character );
extern int getchar ( void );
diff --git a/src/include/strings.h b/src/include/strings.h
index fab26dc28..d7e9d6971 100644
--- a/src/include/strings.h
+++ b/src/include/strings.h
@@ -189,5 +189,7 @@ bzero ( void *dest, size_t len ) {
}
int __pure strcasecmp ( const char *first, const char *second ) __nonnull;
+int __pure strncasecmp ( const char *first, const char *second,
+ size_t max ) __nonnull;
#endif /* _STRINGS_H */
diff --git a/src/include/usr/imgarchive.h b/src/include/usr/imgarchive.h
new file mode 100644
index 000000000..bf0c18f55
--- /dev/null
+++ b/src/include/usr/imgarchive.h
@@ -0,0 +1,16 @@
+#ifndef _USR_IMGARCHIVE_H
+#define _USR_IMGARCHIVE_H
+
+/** @file
+ *
+ * Archive image management
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <ipxe/image.h>
+
+extern int imgextract ( struct image *image, const char *name );
+
+#endif /* _USR_IMGARCHIVE_H */
diff --git a/src/interface/efi/efi_file.c b/src/interface/efi/efi_file.c
index 52de0987c..fc64b369c 100644
--- a/src/interface/efi/efi_file.c
+++ b/src/interface/efi/efi_file.c
@@ -38,6 +38,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <errno.h>
#include <wchar.h>
#include <ipxe/image.h>
+#include <ipxe/cpio.h>
#include <ipxe/efi/efi.h>
#include <ipxe/efi/Protocol/SimpleFileSystem.h>
#include <ipxe/efi/Protocol/BlockIo.h>
@@ -50,17 +51,54 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** EFI media ID */
#define EFI_MEDIA_ID_MAGIC 0x69505845
-/** An image exposed as an EFI file */
+/** An EFI virtual file reader */
+struct efi_file_reader {
+ /** EFI file */
+ struct efi_file *file;
+ /** Position within virtual file */
+ size_t pos;
+ /** Output data buffer */
+ void *data;
+ /** Length of output data buffer */
+ size_t len;
+};
+
+/** An EFI file */
struct efi_file {
+ /** Reference count */
+ struct refcnt refcnt;
/** EFI file protocol */
EFI_FILE_PROTOCOL file;
- /** Image */
+ /** Image (if any) */
struct image *image;
+ /** Filename */
+ const char *name;
/** Current file position */
size_t pos;
+ /**
+ * Read from file
+ *
+ * @v reader File reader
+ * @ret len Length read
+ */
+ size_t ( * read ) ( struct efi_file_reader *reader );
};
static struct efi_file efi_file_root;
+static struct efi_file efi_file_initrd;
+
+/**
+ * Free EFI file
+ *
+ * @v refcnt Reference count
+ */
+static void efi_file_free ( struct refcnt *refcnt ) {
+ struct efi_file *file =
+ container_of ( refcnt, struct efi_file, refcnt );
+
+ image_put ( file->image );
+ free ( file );
+}
/**
* Get EFI file name (for debugging)
@@ -70,28 +108,201 @@ static struct efi_file efi_file_root;
*/
static const char * efi_file_name ( struct efi_file *file ) {
- return ( file->image ? file->image->name : "<root>" );
+ return ( file == &efi_file_root ? "<root>" : file->name );
}
/**
* Find EFI file image
*
- * @v wname Filename
+ * @v name Filename
* @ret image Image, or NULL
*/
-static struct image * efi_file_find ( const CHAR16 *wname ) {
- char name[ wcslen ( wname ) + 1 /* NUL */ ];
+static struct image * efi_file_find ( const char *name ) {
struct image *image;
/* Find image */
- snprintf ( name, sizeof ( name ), "%ls", wname );
list_for_each_entry ( image, &images, list ) {
if ( strcasecmp ( image->name, name ) == 0 )
return image;
}
return NULL;
+}
+
+/**
+ * Get length of EFI file
+ *
+ * @v file EFI file
+ * @ret len Length of file
+ */
+static size_t efi_file_len ( struct efi_file *file ) {
+ struct efi_file_reader reader;
+
+ /* If this is the root directory, then treat as length zero */
+ if ( ! file->read )
+ return 0;
+
+ /* Initialise reader */
+ reader.file = file;
+ reader.pos = 0;
+ reader.data = NULL;
+ reader.len = 0;
+
+ /* Perform dummy read to determine file length */
+ file->read ( &reader );
+
+ return reader.pos;
+}
+
+/**
+ * Read chunk of EFI file
+ *
+ * @v reader EFI file reader
+ * @v data Input data, or UNULL to zero-fill
+ * @v len Length of input data
+ * @ret len Length of output data
+ */
+static size_t efi_file_read_chunk ( struct efi_file_reader *reader,
+ userptr_t data, size_t len ) {
+ struct efi_file *file = reader->file;
+ size_t offset;
+
+ /* Calculate offset into input data */
+ offset = ( file->pos - reader->pos );
+
+ /* Consume input data range */
+ reader->pos += len;
+
+ /* Calculate output length */
+ if ( offset < len ) {
+ len -= offset;
+ } else {
+ len = 0;
+ }
+ if ( len > reader->len )
+ len = reader->len;
+
+ /* Copy or zero output data */
+ if ( data ) {
+ copy_from_user ( reader->data, data, offset, len );
+ } else {
+ memset ( reader->data, 0, len );
+ }
+
+ /* Consume output buffer */
+ file->pos += len;
+ reader->data += len;
+ reader->len -= len;
+
+ return len;
+}
+
+/**
+ * Read from image-backed file
+ *
+ * @v reader EFI file reader
+ * @ret len Length read
+ */
+static size_t efi_file_read_image ( struct efi_file_reader *reader ) {
+ struct efi_file *file = reader->file;
+ struct image *image = file->image;
+
+ /* Read from file */
+ return efi_file_read_chunk ( reader, image->data, image->len );
+}
+
+/**
+ * Read from magic initrd file
+ *
+ * @v reader EFI file reader
+ * @ret len Length read
+ */
+static size_t efi_file_read_initrd ( struct efi_file_reader *reader ) {
+ struct efi_file *file = reader->file;
+ struct cpio_header cpio;
+ struct image *image;
+ const char *name;
+ size_t pad_len;
+ size_t cpio_len;
+ size_t name_len;
+ size_t len;
+
+ /* Read from file */
+ len = 0;
+ for_each_image ( image ) {
+
+ /* Ignore currently executing image */
+ if ( image == current_image )
+ continue;
+
+ /* Pad to alignment boundary */
+ pad_len = ( ( -reader->pos ) & ( INITRD_ALIGN - 1 ) );
+ if ( pad_len ) {
+ DBGC ( file, "EFIFILE %s [%#08zx,%#08zx) pad\n",
+ efi_file_name ( file ), reader->pos,
+ ( reader->pos + pad_len ) );
+ }
+ len += efi_file_read_chunk ( reader, UNULL, pad_len );
+
+ /* Read CPIO header, if applicable */
+ cpio_len = cpio_header ( image, &cpio );
+ if ( cpio_len ) {
+ name = cpio_name ( image );
+ name_len = cpio_name_len ( image );
+ pad_len = ( cpio_len - sizeof ( cpio ) - name_len );
+ DBGC ( file, "EFIFILE %s [%#08zx,%#08zx) %s header\n",
+ efi_file_name ( file ), reader->pos,
+ ( reader->pos + cpio_len ), image->name );
+ len += efi_file_read_chunk ( reader,
+ virt_to_user ( &cpio ),
+ sizeof ( cpio ) );
+ len += efi_file_read_chunk ( reader,
+ virt_to_user ( name ),
+ name_len );
+ len += efi_file_read_chunk ( reader, UNULL, pad_len );
+ }
+
+ /* Read file data */
+ DBGC ( file, "EFIFILE %s [%#08zx,%#08zx) %s\n",
+ efi_file_name ( file ), reader->pos,
+ ( reader->pos + image->len ), image->name );
+ len += efi_file_read_chunk ( reader, image->data, image->len );
+ }
+
+ return len;
+}
+
+/**
+ * Open fixed file
+ *
+ * @v file EFI file
+ * @v new New EFI file
+ * @ret efirc EFI status code
+ */
+static EFI_STATUS efi_file_open_fixed ( struct efi_file *file,
+ EFI_FILE_PROTOCOL **new ) {
+
+ /* Increment reference count */
+ ref_get ( &file->refcnt );
+
+ /* Return opened file */
+ *new = &file->file;
+
+ DBGC ( file, "EFIFILE %s opened\n", efi_file_name ( file ) );
+ return 0;
+}
+
+/**
+ * Associate file with image
+ *
+ * @v file EFI file
+ * @v image Image
+ */
+static void efi_file_image ( struct efi_file *file, struct image *image ) {
+ file->image = image;
+ file->name = image->name;
+ file->read = efi_file_read_image;
}
/**
@@ -106,50 +317,60 @@ static struct image * efi_file_find ( const CHAR16 *wname ) {
*/
static EFI_STATUS EFIAPI
efi_file_open ( EFI_FILE_PROTOCOL *this, EFI_FILE_PROTOCOL **new,
- CHAR16 *wname, UINT64 mode __unused,
- UINT64 attributes __unused ) {
+ CHAR16 *wname, UINT64 mode, UINT64 attributes __unused ) {
struct efi_file *file = container_of ( this, struct efi_file, file );
+ char buf[ wcslen ( wname ) + 1 /* NUL */ ];
struct efi_file *new_file;
struct image *image;
+ char *name;
+
+ /* Convert name to ASCII */
+ snprintf ( buf, sizeof ( buf ), "%ls", wname );
+ name = buf;
/* Initial '\' indicates opening from the root directory */
- while ( *wname == L'\\' ) {
+ while ( *name == '\\' ) {
file = &efi_file_root;
- wname++;
+ name++;
}
/* Allow root directory itself to be opened */
- if ( ( wname[0] == L'\0' ) || ( wname[0] == L'.' ) ) {
- *new = &efi_file_root.file;
- return 0;
- }
+ if ( ( name[0] == '\0' ) || ( name[0] == '.' ) )
+ return efi_file_open_fixed ( &efi_file_root, new );
/* Fail unless opening from the root */
- if ( file->image ) {
+ if ( file != &efi_file_root ) {
DBGC ( file, "EFIFILE %s is not a directory\n",
efi_file_name ( file ) );
return EFI_NOT_FOUND;
}
- /* Identify image */
- image = efi_file_find ( wname );
- if ( ! image ) {
- DBGC ( file, "EFIFILE \"%ls\" does not exist\n", wname );
- return EFI_NOT_FOUND;
- }
-
/* Fail unless opening read-only */
if ( mode != EFI_FILE_MODE_READ ) {
DBGC ( file, "EFIFILE %s cannot be opened in mode %#08llx\n",
- image->name, mode );
+ name, mode );
return EFI_WRITE_PROTECTED;
}
+ /* Allow magic initrd to be opened */
+ if ( strcasecmp ( name, efi_file_initrd.name ) == 0 )
+ return efi_file_open_fixed ( &efi_file_initrd, new );
+
+ /* Identify image */
+ image = efi_file_find ( name );
+ if ( ! image ) {
+ DBGC ( file, "EFIFILE %s does not exist\n", name );
+ return EFI_NOT_FOUND;
+ }
+
/* Allocate and initialise file */
new_file = zalloc ( sizeof ( *new_file ) );
+ if ( ! new_file )
+ return EFI_OUT_OF_RESOURCES;
+ ref_init ( &file->refcnt, efi_file_free );
memcpy ( &new_file->file, &efi_file_root.file,
sizeof ( new_file->file ) );
- new_file->image = image_get ( image );
+ efi_file_image ( new_file, image_get ( image ) );
*new = &new_file->file;
DBGC ( new_file, "EFIFILE %s opened\n", efi_file_name ( new_file ) );
@@ -165,14 +386,9 @@ efi_file_open ( EFI_FILE_PROTOCOL *this, EFI_FILE_PROTOCOL **new,
static EFI_STATUS EFIAPI efi_file_close ( EFI_FILE_PROTOCOL *this ) {
struct efi_file *file = container_of ( this, struct efi_file, file );
- /* Do nothing if this is the root */
- if ( ! file->image )
- return 0;
-
/* Close file */
DBGC ( file, "EFIFILE %s closed\n", efi_file_name ( file ) );
- image_put ( file->image );
- free ( file );
+ ref_put ( &file->refcnt );
return 0;
}
@@ -229,30 +445,29 @@ static EFI_STATUS efi_file_varlen ( UINT64 *base, size_t base_len,
/**
* Return file information structure
*
- * @v image Image, or NULL for the root directory
+ * @v file EFI file
* @v len Length of data buffer
* @v data Data buffer
* @ret efirc EFI status code
*/
-static EFI_STATUS efi_file_info ( struct image *image, UINTN *len,
+static EFI_STATUS efi_file_info ( struct efi_file *file, UINTN *len,
VOID *data ) {
EFI_FILE_INFO info;
- const char *name;
+ size_t file_len;
+
+ /* Get file length */
+ file_len = efi_file_len ( file );
/* Populate file information */
memset ( &info, 0, sizeof ( info ) );
- if ( image ) {
- info.FileSize = image->len;
- info.PhysicalSize = image->len;
- info.Attribute = EFI_FILE_READ_ONLY;
- name = image->name;
- } else {
- info.Attribute = ( EFI_FILE_READ_ONLY | EFI_FILE_DIRECTORY );
- name = "";
- }
-
- return efi_file_varlen ( &info.Size, SIZE_OF_EFI_FILE_INFO, name,
- len, data );
+ info.FileSize = file_len;
+ info.PhysicalSize = file_len;
+ info.Attribute = EFI_FILE_READ_ONLY;
+ if ( file == &efi_file_root )
+ info.Attribute |= EFI_FILE_DIRECTORY;
+
+ return efi_file_varlen ( &info.Size, SIZE_OF_EFI_FILE_INFO,
+ file->name, len, data );
}
/**
@@ -266,14 +481,16 @@ static EFI_STATUS efi_file_info ( struct image *image, UINTN *len,
static EFI_STATUS efi_file_read_dir ( struct efi_file *file, UINTN *len,
VOID *data ) {
EFI_STATUS efirc;
+ struct efi_file entry;
struct image *image;
unsigned int index;
- /* Construct directory entry at current position */
+ /* Construct directory entries for image-backed files */
index = file->pos;
for_each_image ( image ) {
if ( index-- == 0 ) {
- efirc = efi_file_info ( image, len, data );
+ efi_file_image ( &entry, image );
+ efirc = efi_file_info ( &entry, len, data );
if ( efirc == 0 )
file->pos++;
return efirc;
@@ -296,21 +513,25 @@ static EFI_STATUS efi_file_read_dir ( struct efi_file *file, UINTN *len,
static EFI_STATUS EFIAPI efi_file_read ( EFI_FILE_PROTOCOL *this,
UINTN *len, VOID *data ) {
struct efi_file *file = container_of ( this, struct efi_file, file );
- size_t remaining;
+ struct efi_file_reader reader;
+ size_t pos = file->pos;
/* If this is the root directory, then construct a directory entry */
- if ( ! file->image )
+ if ( ! file->read )
return efi_file_read_dir ( file, len, data );
+ /* Initialise reader */
+ reader.file = file;
+ reader.pos = 0;
+ reader.data = data;
+ reader.len = *len;
+
/* Read from the file */
- remaining = ( file->image->len - file->pos );
- if ( *len > remaining )
- *len = remaining;
DBGC ( file, "EFIFILE %s read [%#08zx,%#08zx)\n",
- efi_file_name ( file ), file->pos,
- ( ( size_t ) ( file->pos + *len ) ) );
- copy_from_user ( data, file->image->data, file->pos, *len );
- file->pos += *len;
+ efi_file_name ( file ), pos, file->pos );
+ *len = file->read ( &reader );
+ assert ( ( pos + *len ) == file->pos );
+
return 0;
}
@@ -342,24 +563,21 @@ static EFI_STATUS EFIAPI efi_file_write ( EFI_FILE_PROTOCOL *this,
static EFI_STATUS EFIAPI efi_file_set_position ( EFI_FILE_PROTOCOL *this,
UINT64 position ) {
struct efi_file *file = container_of ( this, struct efi_file, file );
+ size_t len;
- /* If this is the root directory, reset to the start */
- if ( ! file->image ) {
- DBGC ( file, "EFIFILE root directory rewound\n" );
- file->pos = 0;
- return 0;
- }
+ /* Get file length */
+ len = efi_file_len ( file );
/* Check for the magic end-of-file value */
if ( position == 0xffffffffffffffffULL )
- position = file->image->len;
+ position = len;
/* Fail if we attempt to seek past the end of the file (since
* we do not support writes).
*/
- if ( position > file->image->len ) {
+ if ( position > len ) {
DBGC ( file, "EFIFILE %s cannot seek to %#08llx of %#08zx\n",
- efi_file_name ( file ), position, file->image->len );
+ efi_file_name ( file ), position, len );
return EFI_UNSUPPORTED;
}
@@ -408,7 +626,7 @@ static EFI_STATUS EFIAPI efi_file_get_info ( EFI_FILE_PROTOCOL *this,
/* Get file information */
DBGC ( file, "EFIFILE %s get file information\n",
efi_file_name ( file ) );
- return efi_file_info ( file->image, len, data );
+ return efi_file_info ( file, len, data );
} else if ( memcmp ( type, &efi_file_system_info_id,
sizeof ( *type ) ) == 0 ) {
@@ -468,6 +686,27 @@ static EFI_STATUS EFIAPI efi_file_flush ( EFI_FILE_PROTOCOL *this ) {
/** Root directory */
static struct efi_file efi_file_root = {
+ .refcnt = REF_INIT ( ref_no_free ),
+ .file = {
+ .Revision = EFI_FILE_PROTOCOL_REVISION,
+ .Open = efi_file_open,
+ .Close = efi_file_close,
+ .Delete = efi_file_delete,
+ .Read = efi_file_read,
+ .Write = efi_file_write,
+ .GetPosition = efi_file_get_position,
+ .SetPosition = efi_file_set_position,
+ .GetInfo = efi_file_get_info,
+ .SetInfo = efi_file_set_info,
+ .Flush = efi_file_flush,
+ },
+ .image = NULL,
+ .name = "",
+};
+
+/** Magic initrd file */
+static struct efi_file efi_file_initrd = {
+ .refcnt = REF_INIT ( ref_no_free ),
.file = {
.Revision = EFI_FILE_PROTOCOL_REVISION,
.Open = efi_file_open,
@@ -482,6 +721,8 @@ static struct efi_file efi_file_root = {
.Flush = efi_file_flush,
},
.image = NULL,
+ .name = "initrd.magic",
+ .read = efi_file_read_initrd,
};
/**
@@ -496,8 +737,7 @@ efi_file_open_volume ( EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *filesystem __unused,
EFI_FILE_PROTOCOL **file ) {
DBGC ( &efi_file_root, "EFIFILE open volume\n" );
- *file = &efi_file_root.file;
- return 0;
+ return efi_file_open_fixed ( &efi_file_root, file );
}
/** EFI simple file system protocol */
diff --git a/src/interface/efi/efi_pci.c b/src/interface/efi/efi_pci.c
index 4adee0fd8..fda4aba0e 100644
--- a/src/interface/efi/efi_pci.c
+++ b/src/interface/efi/efi_pci.c
@@ -337,6 +337,9 @@ void * efipci_ioremap ( struct pci_device *pci, unsigned long bus_addr,
offset = le64_to_cpu ( u.res->qword.offset );
start = ( offset + le64_to_cpu ( u.res->qword.min ) );
end = ( start + le64_to_cpu ( u.res->qword.len ) );
+ DBGC2 ( pci, "EFIPCI " PCI_FMT " found range [%08llx,%08llx) "
+ "-> [%08llx,%08llx)\n", PCI_ARGS ( pci ), start, end,
+ ( start - offset ), ( end - offset ) );
if ( ( bus_addr < start ) || ( ( bus_addr + len ) > end ) )
continue;
@@ -523,7 +526,8 @@ static void * efipci_dma_alloc ( struct dma_device *dma,
/* Map buffer */
if ( ( rc = efipci_dma_map ( dma, map, virt_to_phys ( addr ),
- len, DMA_BI ) ) != 0 )
+ ( pages * EFI_PAGE_SIZE ),
+ DMA_BI ) ) != 0 )
goto err_map;
/* Increment allocation count (for debugging) */
diff --git a/src/interface/efi/efi_veto.c b/src/interface/efi/efi_veto.c
index 6ff7898e9..b616539d3 100644
--- a/src/interface/efi/efi_veto.c
+++ b/src/interface/efi/efi_veto.c
@@ -362,7 +362,7 @@ static int efi_veto_driver ( EFI_HANDLE driver ) {
}
/**
- * Veto Dell Ip4ConfigDxe driver
+ * Veto Ip4ConfigDxe driver on some platforms
*
* @v binding Driver binding protocol
* @v loaded Loaded image protocol
@@ -372,19 +372,21 @@ static int efi_veto_driver ( EFI_HANDLE driver ) {
* @ret vetoed Driver is to be vetoed
*/
static int
-efi_veto_dell_ip4config ( EFI_DRIVER_BINDING_PROTOCOL *binding __unused,
- EFI_LOADED_IMAGE_PROTOCOL *loaded __unused,
- EFI_COMPONENT_NAME_PROTOCOL *wtf __unused,
- const char *manufacturer, const CHAR16 *name ) {
+efi_veto_ip4config ( EFI_DRIVER_BINDING_PROTOCOL *binding __unused,
+ EFI_LOADED_IMAGE_PROTOCOL *loaded __unused,
+ EFI_COMPONENT_NAME_PROTOCOL *wtf __unused,
+ const char *manufacturer, const CHAR16 *name ) {
static const CHAR16 ip4cfg[] = L"IP4 CONFIG Network Service Driver";
static const char *dell = "Dell Inc.";
+ static const char *itautec = "Itautec S.A.";
/* Check manufacturer and driver name */
if ( ! manufacturer )
return 0;
if ( ! name )
return 0;
- if ( strcmp ( manufacturer, dell ) != 0 )
+ if ( ( strcmp ( manufacturer, dell ) != 0 ) &&
+ ( strcmp ( manufacturer, itautec ) != 0 ) )
return 0;
if ( memcmp ( name, ip4cfg, sizeof ( ip4cfg ) ) != 0 )
return 0;
@@ -436,8 +438,8 @@ efi_veto_hp_xhci ( EFI_DRIVER_BINDING_PROTOCOL *binding __unused,
/** Driver vetoes */
static struct efi_veto efi_vetoes[] = {
{
- .name = "Dell Ip4Config",
- .veto = efi_veto_dell_ip4config,
+ .name = "Ip4Config",
+ .veto = efi_veto_ip4config,
},
{
.name = "HP Xhci",
diff --git a/src/interface/xen/xenstore.c b/src/interface/xen/xenstore.c
index a14881fcd..caeb4e934 100644
--- a/src/interface/xen/xenstore.c
+++ b/src/interface/xen/xenstore.c
@@ -68,14 +68,14 @@ static void xenstore_send ( struct xen_hypervisor *xen, const void *data,
XENSTORE_RING_IDX cons;
XENSTORE_RING_IDX idx;
const char *bytes = data;
- size_t offset = 0;
+ size_t offset;
size_t fill;
DBGCP ( intf, "XENSTORE raw request:\n" );
DBGCP_HDA ( intf, MASK_XENSTORE_IDX ( prod ), data, len );
/* Write one byte at a time */
- while ( offset < len ) {
+ for ( offset = 0 ; offset < len ; offset++ ) {
/* Wait for space to become available */
while ( 1 ) {
@@ -90,7 +90,7 @@ static void xenstore_send ( struct xen_hypervisor *xen, const void *data,
/* Write byte */
idx = MASK_XENSTORE_IDX ( prod++ );
- writeb ( bytes[offset++], &intf->req[idx] );
+ writeb ( bytes[offset], &intf->req[idx] );
}
/* Update producer counter */
@@ -125,13 +125,13 @@ static void xenstore_recv ( struct xen_hypervisor *xen, void *data,
XENSTORE_RING_IDX prod;
XENSTORE_RING_IDX idx;
char *bytes = data;
- size_t offset = 0;
+ size_t offset;
size_t fill;
DBGCP ( intf, "XENSTORE raw response:\n" );
/* Read one byte at a time */
- while ( offset < len ) {
+ for ( offset = 0 ; offset < len ; offset++ ) {
/* Wait for data to be ready */
while ( 1 ) {
@@ -147,7 +147,7 @@ static void xenstore_recv ( struct xen_hypervisor *xen, void *data,
/* Read byte */
idx = MASK_XENSTORE_IDX ( cons++ );
if ( data )
- bytes[offset++] = readb ( &intf->rsp[idx] );
+ bytes[offset] = readb ( &intf->rsp[idx] );
}
if ( data )
DBGCP_HDA ( intf, MASK_XENSTORE_IDX ( cons - len ), data, len );
diff --git a/src/net/peerdisc.c b/src/net/peerdisc.c
index 55e3f7fa7..d7e0d2989 100644
--- a/src/net/peerdisc.c
+++ b/src/net/peerdisc.c
@@ -73,6 +73,9 @@ static LIST_HEAD ( peerdisc_segments );
*/
unsigned int peerdisc_timeout_secs = PEERDISC_DEFAULT_TIMEOUT_SECS;
+/** Most recently discovered peer (for any block) */
+static char *peerdisc_recent;
+
/** Hosted cache server */
static char *peerhost;
@@ -383,6 +386,7 @@ static int peerdisc_discovered ( struct peerdisc_segment *segment,
struct peerdisc_peer *peer;
struct peerdisc_client *peerdisc;
struct peerdisc_client *tmp;
+ char *recent;
/* Ignore duplicate peers */
list_for_each_entry ( peer, &segment->peers, list ) {
@@ -403,6 +407,15 @@ static int peerdisc_discovered ( struct peerdisc_segment *segment,
/* Add to end of list of peers */
list_add_tail ( &peer->list, &segment->peers );
+ /* Record as most recently discovered peer */
+ if ( location != peerdisc_recent ) {
+ recent = strdup ( location );
+ if ( recent ) {
+ free ( peerdisc_recent );
+ peerdisc_recent = recent;
+ }
+ }
+
/* Notify all clients */
list_for_each_entry_safe ( peerdisc, tmp, &segment->clients, list )
peerdisc->op->discovered ( peerdisc );
@@ -484,6 +497,16 @@ static struct peerdisc_segment * peerdisc_create ( const char *id ) {
} else {
+ /* Add most recently discovered peer to list of peers
+ *
+ * This is a performance optimisation: we assume that
+ * the most recently discovered peer for any block has
+ * a high probability of also having a copy of the
+ * next block that we attempt to discover.
+ */
+ if ( peerdisc_recent )
+ peerdisc_discovered ( segment, peerdisc_recent );
+
/* Start discovery timer */
start_timer_nodelay ( &segment->timer );
DBGC2 ( segment, "PEERDISC %p discovering %s\n",
diff --git a/src/net/tcp/httpconn.c b/src/net/tcp/httpconn.c
index f9221b27e..538c4dcf6 100644
--- a/src/net/tcp/httpconn.c
+++ b/src/net/tcp/httpconn.c
@@ -32,6 +32,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdlib.h>
#include <string.h>
+#include <strings.h>
#include <errno.h>
#include <byteswap.h>
#include <ipxe/tcpip.h>
@@ -63,7 +64,7 @@ static struct http_scheme * http_scheme ( struct uri *uri ) {
/* Identify scheme */
for_each_table_entry ( scheme, HTTP_SCHEMES ) {
- if ( strcmp ( uri->scheme, scheme->name ) == 0 )
+ if ( strcasecmp ( uri->scheme, scheme->name ) == 0 )
return scheme;
}
diff --git a/src/tests/gzip_test.c b/src/tests/gzip_test.c
new file mode 100644
index 000000000..fa76edc53
--- /dev/null
+++ b/src/tests/gzip_test.c
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2021 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+/** @file
+ *
+ * gzip image tests
+ *
+ */
+
+/* Forcibly enable assertions */
+#undef NDEBUG
+
+#include <stdint.h>
+#include <ipxe/image.h>
+#include <ipxe/gzip.h>
+#include <ipxe/test.h>
+
+/** A gzip test */
+struct gzip_test {
+ /** Compressed filename */
+ const char *compressed_name;
+ /** Compressed data */
+ const void *compressed;
+ /** Length of compressed data */
+ size_t compressed_len;
+ /** Expected uncompressed name */
+ const char *expected_name;
+ /** Expected uncompressed data */
+ const void *expected;
+ /** Length of expected uncompressed data */
+ size_t expected_len;
+};
+
+/** Define inline data */
+#define DATA(...) { __VA_ARGS__ }
+
+/** Define a gzip test */
+#define GZIP( name, COMPRESSED, EXPECTED ) \
+ static const uint8_t name ## _compressed[] = COMPRESSED; \
+ static const uint8_t name ## _expected[] = EXPECTED; \
+ static struct gzip_test name = { \
+ .compressed_name = #name ".gz", \
+ .compressed = name ## _compressed, \
+ .compressed_len = sizeof ( name ## _compressed ), \
+ .expected_name = #name, \
+ .expected = name ## _expected, \
+ .expected_len = sizeof ( name ## _expected ), \
+ };
+
+/** "Hello world" */
+GZIP ( hello_world,
+ DATA ( 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
+ 0xf3, 0x48, 0xcd, 0xc9, 0xc9, 0x57, 0x28, 0xcf, 0x2f, 0xca,
+ 0x49, 0x01, 0x00, 0x52, 0x9e, 0xd6, 0x8b, 0x0b, 0x00, 0x00,
+ 0x00 ),
+ DATA ( 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c,
+ 0x64 ) );
+
+/** "Hello filename" */
+GZIP ( hello_filename,
+ DATA ( 0x1f, 0x8b, 0x08, 0x08, 0xeb, 0x5b, 0x96, 0x60, 0x00, 0x03,
+ 0x68, 0x77, 0x2e, 0x74, 0x78, 0x74, 0x00, 0xf3, 0x48, 0xcd,
+ 0xc9, 0xc9, 0x57, 0x48, 0xcb, 0xcc, 0x49, 0xcd, 0x4b, 0xcc,
+ 0x4d, 0x05, 0x00, 0x69, 0x37, 0x25, 0x3c, 0x0e, 0x00, 0x00,
+ 0x00 ),
+ DATA ( 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x66, 0x69, 0x6c, 0x65,
+ 0x6e, 0x61, 0x6d, 0x65 ) );
+
+/** "Hello assorted headers" */
+GZIP ( hello_headers,
+ DATA ( 0x1f, 0x8b, 0x08, 0x1c, 0x11, 0x5c, 0x96, 0x60, 0x00, 0x03,
+ 0x05, 0x00, 0x41, 0x70, 0x01, 0x00, 0x0d, 0x68, 0x77, 0x2e,
+ 0x74, 0x78, 0x74, 0x00, 0x2f, 0x2f, 0x77, 0x68, 0x79, 0x3f,
+ 0x00, 0xf3, 0x48, 0xcd, 0xc9, 0xc9, 0x57, 0x48, 0x2c, 0x2e,
+ 0xce, 0x2f, 0x2a, 0x49, 0x4d, 0x51, 0xc8, 0x48, 0x4d, 0x4c,
+ 0x49, 0x2d, 0x2a, 0x06, 0x00, 0x59, 0xa4, 0x19, 0x61, 0x16,
+ 0x00, 0x00, 0x00 ),
+ DATA ( 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x61, 0x73, 0x73, 0x6f,
+ 0x72, 0x74, 0x65, 0x64, 0x20, 0x68, 0x65, 0x61, 0x64, 0x65,
+ 0x72, 0x73 ) );
+
+/**
+ * Report gzip test result
+ *
+ * @v test gzip test
+ * @v file Test code file
+ * @v line Test code line
+ */
+static void gzip_okx ( struct gzip_test *test, const char *file,
+ unsigned int line ) {
+ struct image *image;
+ struct image *extracted;
+
+ /* Construct compressed image */
+ image = image_memory ( test->compressed_name,
+ virt_to_user ( test->compressed ),
+ test->compressed_len );
+ okx ( image != NULL, file, line );
+ okx ( image->len == test->compressed_len, file, line );
+
+ /* Check type detection */
+ okx ( image->type == &gzip_image_type, file, line );
+
+ /* Extract archive image */
+ okx ( image_extract ( image, NULL, &extracted ) == 0, file, line );
+
+ /* Verify extracted image content */
+ okx ( extracted->len == test->expected_len, file, line );
+ okx ( memcmp_user ( extracted->data, 0,
+ virt_to_user ( test->expected ), 0,
+ test->expected_len ) == 0, file, line );
+
+ /* Verify extracted image name */
+ okx ( strcmp ( extracted->name, test->expected_name ) == 0,
+ file, line );
+
+ /* Unregister images */
+ unregister_image ( extracted );
+ unregister_image ( image );
+}
+#define gzip_ok( test ) gzip_okx ( test, __FILE__, __LINE__ )
+
+/**
+ * Perform gzip self-test
+ *
+ */
+static void gzip_test_exec ( void ) {
+
+ gzip_ok ( &hello_world );
+ gzip_ok ( &hello_filename );
+ gzip_ok ( &hello_headers );
+}
+
+/** gzip self-test */
+struct self_test gzip_test __self_test = {
+ .name = "gzip",
+ .exec = gzip_test_exec,
+};
diff --git a/src/tests/string_test.c b/src/tests/string_test.c
index 88a730aec..3afb8deb2 100644
--- a/src/tests/string_test.c
+++ b/src/tests/string_test.c
@@ -105,6 +105,14 @@ static void string_test_exec ( void ) {
ok ( strcasecmp ( "Uncle", "Uncle Jack" ) != 0 );
ok ( strcasecmp ( "not", "equal" ) != 0 );
+ /* Test strncasecmp() */
+ ok ( strncasecmp ( "", "", 0 ) == 0 );
+ ok ( strncasecmp ( "", "", 73 ) == 0 );
+ ok ( strncasecmp ( "Uncle Jack", "Uncle jack", 47 ) == 0 );
+ ok ( strncasecmp ( "Uncle Jack", "Uncle jake", 47 ) != 0 );
+ ok ( strncasecmp ( "Uncle Jack", "Uncle jake", 9 ) != 0 );
+ ok ( strncasecmp ( "Uncle Jack", "Uncle jake", 8 ) == 0 );
+
/* Test memcmp() */
ok ( memcmp ( "", "", 0 ) == 0 );
ok ( memcmp ( "Foo", "Foo", 3 ) == 0 );
diff --git a/src/tests/tests.c b/src/tests/tests.c
index 2e812d6ff..1cc4c81e8 100644
--- a/src/tests/tests.c
+++ b/src/tests/tests.c
@@ -73,3 +73,5 @@ REQUIRE_OBJECT ( bitops_test );
REQUIRE_OBJECT ( der_test );
REQUIRE_OBJECT ( pem_test );
REQUIRE_OBJECT ( ntlm_test );
+REQUIRE_OBJECT ( zlib_test );
+REQUIRE_OBJECT ( gzip_test );
diff --git a/src/tests/x509_test.c b/src/tests/x509_test.c
index 256c3e85e..b6cba575c 100644
--- a/src/tests/x509_test.c
+++ b/src/tests/x509_test.c
@@ -1037,6 +1037,7 @@ static void x509_test_exec ( void ) {
/* Check certificate names */
x509_check_name_ok ( &server_crt, "boot.test.ipxe.org" );
x509_check_name_ok ( &server_crt, "demo.test.ipxe.org" );
+ x509_check_name_ok ( &server_crt, "demo.test.iPXE.org" );
x509_check_name_fail_ok ( &server_crt, "incorrect.test.ipxe.org" );
x509_check_name_ok ( &server_crt, "anything.alt.test.ipxe.org" );
x509_check_name_ok ( &server_crt, "wildcard.alt.test.ipxe.org" );
diff --git a/src/tests/zlib_test.c b/src/tests/zlib_test.c
new file mode 100644
index 000000000..df52d09ac
--- /dev/null
+++ b/src/tests/zlib_test.c
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2021 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+/** @file
+ *
+ * zlib image tests
+ *
+ */
+
+/* Forcibly enable assertions */
+#undef NDEBUG
+
+#include <stdint.h>
+#include <ipxe/image.h>
+#include <ipxe/zlib.h>
+#include <ipxe/test.h>
+
+/** A zlib test */
+struct zlib_test {
+ /** Compressed filename */
+ const char *compressed_name;
+ /** Compressed data */
+ const void *compressed;
+ /** Length of compressed data */
+ size_t compressed_len;
+ /** Expected uncompressed name */
+ const char *expected_name;
+ /** Expected uncompressed data */
+ const void *expected;
+ /** Length of expected uncompressed data */
+ size_t expected_len;
+};
+
+/** Define inline data */
+#define DATA(...) { __VA_ARGS__ }
+
+/** Define a zlib test */
+#define ZLIB( name, COMPRESSED, EXPECTED ) \
+ static const uint8_t name ## _compressed[] = COMPRESSED; \
+ static const uint8_t name ## _expected[] = EXPECTED; \
+ static struct zlib_test name = { \
+ .compressed_name = #name ".z", \
+ .compressed = name ## _compressed, \
+ .compressed_len = sizeof ( name ## _compressed ), \
+ .expected_name = #name, \
+ .expected = name ## _expected, \
+ .expected_len = sizeof ( name ## _expected ), \
+ };
+
+/** "Hello world" */
+ZLIB ( hello_world,
+ DATA ( 0x78, 0x9c, 0xf3, 0x48, 0xcd, 0xc9, 0xc9, 0x57, 0x28, 0xcf,
+ 0x2f, 0xca, 0x49, 0x01, 0x00, 0x18, 0xab, 0x04, 0x3d ),
+ DATA ( 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c,
+ 0x64 ) );
+
+/**
+ * Report zlib test result
+ *
+ * @v test zlib test
+ * @v file Test code file
+ * @v line Test code line
+ */
+static void zlib_okx ( struct zlib_test *test, const char *file,
+ unsigned int line ) {
+ struct image *image;
+ struct image *extracted;
+
+ /* Construct compressed image */
+ image = image_memory ( test->compressed_name,
+ virt_to_user ( test->compressed ),
+ test->compressed_len );
+ okx ( image != NULL, file, line );
+ okx ( image->len == test->compressed_len, file, line );
+
+ /* Check type detection */
+ okx ( image->type == &zlib_image_type, file, line );
+
+ /* Extract archive image */
+ okx ( image_extract ( image, NULL, &extracted ) == 0, file, line );
+
+ /* Verify extracted image content */
+ okx ( extracted->len == test->expected_len, file, line );
+ okx ( memcmp_user ( extracted->data, 0,
+ virt_to_user ( test->expected ), 0,
+ test->expected_len ) == 0, file, line );
+
+ /* Verify extracted image name */
+ okx ( strcmp ( extracted->name, test->expected_name ) == 0,
+ file, line );
+
+ /* Unregister images */
+ unregister_image ( extracted );
+ unregister_image ( image );
+}
+#define zlib_ok( test ) zlib_okx ( test, __FILE__, __LINE__ )
+
+/**
+ * Perform zlib self-test
+ *
+ */
+static void zlib_test_exec ( void ) {
+
+ zlib_ok ( &hello_world );
+}
+
+/** zlib self-test */
+struct self_test zlib_test __self_test = {
+ .name = "zlib",
+ .exec = zlib_test_exec,
+};
diff --git a/src/usr/imgarchive.c b/src/usr/imgarchive.c
new file mode 100644
index 000000000..6849dd510
--- /dev/null
+++ b/src/usr/imgarchive.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2021 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <stdio.h>
+#include <ipxe/image.h>
+#include <usr/imgarchive.h>
+
+/** @file
+ *
+ * Archive image management
+ *
+ */
+
+/**
+ * Extract archive image
+ *
+ * @v image Image
+ * @v name Extracted image name (or NULL to use default)
+ * @ret rc Return status code
+ */
+int imgextract ( struct image *image, const char *name ) {
+ struct image *extracted;
+ int rc;
+
+ /* Extract archive image */
+ if ( ( rc = image_extract ( image, name, &extracted ) ) != 0 ) {
+ printf ( "Could not extract image: %s\n", strerror ( rc ) );
+ return rc;
+ }
+
+ return 0;
+}
diff --git a/src/util/elf2efi.c b/src/util/elf2efi.c
index 5542b99f8..8af53aeb4 100644
--- a/src/util/elf2efi.c
+++ b/src/util/elf2efi.c
@@ -125,7 +125,21 @@
#define R_ARM_V4BX 40
#endif
-#define EFI_FILE_ALIGN 0x20
+/**
+ * Alignment of raw data of sections in the image file
+ *
+ * Some versions of signtool.exe will spuriously complain if this
+ * value is less than 512.
+ */
+#define EFI_FILE_ALIGN 0x200
+
+/**
+ * Alignment of sections when loaded into memory
+ *
+ * This must equal the architecture page size, in order to allow for
+ * the possibility of the firmware using page-level protection to
+ * enforce section attributes at runtime.
+ */
#define EFI_IMAGE_ALIGN 0x1000
struct elf_file {
diff --git a/src/util/genfsimg b/src/util/genfsimg
index c3123f3ed..1635a11ac 100755
--- a/src/util/genfsimg
+++ b/src/util/genfsimg
@@ -230,7 +230,7 @@ done
# since isohybrid will refuse to work without them.
#
if [ -n "${ISOIMG}" ] ; then
- ISOARGS="-J -R"
+ ISOARGS="-J -R -l"
copy_syslinux_file "isolinux.bin" "${ISODIR}"
copy_syslinux_file "ldlinux.c32" "${ISODIR}" 2>/dev/null || true
ISOARGS="${ISOARGS} -no-emul-boot -eltorito-boot isolinux.bin"
@@ -240,6 +240,16 @@ if [ -n "${ISOIMG}" ] ; then
else
FATIMG=
fi
+ if [ -n "${SOURCE_DATE_EPOCH:-}" ] ; then
+ DATE_FMT="+%Y%m%d%H%M%S00"
+ BUILD_DATE=$(date -u -d "@${SOURCE_DATE_EPOCH}" "${DATE_FMT}" \
+ 2>/dev/null || \
+ date -u -r "${SOURCE_DATE_EPOCH}" "${DATE_FMT}" \
+ 2>/dev/null || \
+ date -u "${DATE_FMT}")
+ ISOARGS="${ISOARGS} --set_all_file_dates ${BUILD_DATE}"
+ ISOARGS="${ISOARGS} --modification-date=${BUILD_DATE}"
+ fi
fi
# Create FAT filesystem image, if applicable
@@ -297,7 +307,11 @@ if [ -n "${ISOIMG}" ] ; then
-publisher "ipxe.org" -sysid "iPXE" -o "${ISOIMG}" \
${ISOARGS} "${ISODIR}"
if isohybrid --version >/dev/null 2>&1 ; then
- isohybrid "${ISOIMG}"
+ ISOHYBRIDARGS=
+ if [ -n "${SOURCE_DATE_EPOCH:-}" ] ; then
+ ISOHYBRIDARGS="${ISOHYBRIDARGS} --id ${SOURCE_DATE_EPOCH}"
+ fi
+ isohybrid ${ISOHYBRIDARGS} "${ISOIMG}"
fi
fi