Merge commit 'holger/strings'
authorMichael Brown <mcb30@etherboot.org>
Thu, 23 Aug 2007 20:51:57 +0000 (21:51 +0100)
committerMichael Brown <mcb30@etherboot.org>
Thu, 23 Aug 2007 20:51:57 +0000 (21:51 +0100)
52 files changed:
src/Makefile
src/Makefile.housekeeping
src/arch/i386/Config
src/arch/i386/image/bzimage.c
src/arch/i386/image/multiboot.c
src/arch/i386/image/nbi.c
src/arch/i386/image/pxe_image.c
src/arch/i386/include/bits/stdint.h [moved from src/arch/i386/include/stdint.h with 50% similarity]
src/arch/i386/interface/pcbios/int13.c
src/arch/i386/interface/pxe/pxe_call.c
src/core/cpio.c [new file with mode: 0644]
src/core/cwuri.c
src/core/ibft.c [new file with mode: 0644]
src/core/image.c
src/core/monojob.c
src/core/posix_io.c
src/drivers/net/via-velocity.c
src/hci/commands/image_cmd.c
src/hci/shell.c
src/hci/shell_banner.c
src/image/script.c
src/include/compiler.h
src/include/gpxe/cpio.h [new file with mode: 0644]
src/include/gpxe/dhcp.h
src/include/gpxe/errfile.h
src/include/gpxe/features.h [new file with mode: 0644]
src/include/gpxe/ibft.h
src/include/gpxe/image.h
src/include/gpxe/monojob.h
src/include/gpxe/posix_io.h
src/include/gpxe/retry.h
src/include/gpxe/uri.h
src/include/pxe.h
src/include/pxe_api.h
src/include/stdint.h [new file with mode: 0644]
src/include/usr/imgmgmt.h
src/interface/pxe/pxe_file.c [new file with mode: 0644]
src/interface/pxe/pxe_tftp.c
src/net/aoe.c
src/net/ipv6.c
src/net/retry.c
src/net/tcp.c
src/net/tcp/ftp.c
src/net/tcp/http.c
src/net/tcp/https.c
src/net/tcp/iscsi.c
src/net/udp/dhcp.c
src/net/udp/dns.c
src/net/udp/tftp.c
src/usr/autoboot.c
src/usr/dhcpmgmt.c
src/usr/imgmgmt.c

index 8e0c8be..0f8ddca 100644 (file)
@@ -29,6 +29,8 @@ endif
 ifeq ($(ARCH),x86_64)
 ARCH           := i386
 CFLAGS         += -m32
+ASFLAGS         += --32
+LDFLAGS         += -m elf_i386
 endif
 
 # Drag in architecture-specific Config
@@ -39,36 +41,28 @@ include arch/$(ARCH)/Config
 # If invoked with no build target, print out a helpfully suggestive
 # message.
 #
-noargs : blib $(BIN)/NIC
-       @echo '===================================================='
+noargs : blib $(BIN)/NIC $(BIN)/gpxe.dsk $(BIN)/gpxe.iso $(BIN)/gpxe.usb
+       @echo '==========================================================='
        @echo
-       @echo ' *** WARNING: THE INSTRUCTIONS BELOW DO NOT FULLY WORK YET !!!  ***'
-       @echo ' ***                    PLEASE STAY TUNED                       ***' 
+       @echo 'To create a bootable floppy, type'
+       @echo '    cat $(BIN)/gpxe.dsk > /dev/fd0'
+       @echo 'where /dev/fd0 is your floppy drive.  This will erase any'
+       @echo 'data already on the disk.'
        @echo
-       @echo 'No target specified. To specify a target, do: '
+       @echo 'To create a bootable USB key, type'
+       @echo '    cat $(BIN)/gpxe.usb > /dev/sdX'
+       @echo 'where /dev/sdX is your USB key, and is *not* a real hard'
+       @echo 'disk on your system.  This will erase any data already on'
+       @echo 'the USB key.'
        @echo
-       @echo '    make bin/<rom-name>.<output-format> '
+       @echo 'To create a bootable CD-ROM, burn the ISO image '
+       @echo '$(BIN)/gpxe.iso to a blank CD-ROM.'
        @echo
-       @echo 'where <output-format> is one of {$(MEDIA) }'
+       @echo 'These images contain drivers for all supported cards.  You'
+       @echo 'can build more customised images, and ROM images, using'
+       @echo '    make bin/<rom-name>.<output-format>'
        @echo
-       @echo 'or: '
-       @echo
-       @echo '    make all<output-format>s'
-       @echo
-       @echo 'to generate all possible images of format <output-format>'
-       @echo
-       @echo 'For example, '
-       @echo
-       @echo '    make allroms '
-       @echo
-       @echo 'will generate all possible .rom (rom burnable) images, and'
-       @echo
-       @echo '    make alldsks'
-       @echo
-       @echo 'will generate all possible .dsk (bootable floppy) images, or'
-       @echo
-       @echo '===================================================='
-       @exit 1
+       @echo '==========================================================='
 
 # Locations of utilities
 #
index 108cc3a..6126247 100644 (file)
@@ -39,6 +39,14 @@ version :
        @$(TOUCH) $@
 VERYCLEANUP    += .toolcheck
 
+# Check for correct syntax for echo -e
+#
+ifeq ($(shell echo '\0101'),A)
+ECHO_E = echo
+else
+ECHO_E = echo -e
+endif
+
 # Build verbosity
 #
 ifeq ($(V),1)
@@ -121,7 +129,7 @@ define obj_template
        @$(CPP) $(CFLAGS) $(CFLAGS_$(3)) $(CFLAGS_$(4)) -DOBJECT=$(4) \
                -Wno-error -M $(1) -MT "$(4)_DEPS" -MG -MP | \
                sed 's/_DEPS\s*:/_DEPS =/' >> $(2)
-       @echo -e '\n$$(BIN)/$(4).o : $(1) $$(MAKEDEPS) $$($(4)_DEPS)' \
+       @$(ECHO_E) '\n$$(BIN)/$(4).o : $(1) $$(MAKEDEPS) $$($(4)_DEPS)' \
                 '\n\t$$(QM)echo "  [BUILD] $$@"\n' \
                 '\n\t$$(RULE_$(3))\n' \
                 '\nBOBJS += $$(BIN)/$(4).o\n' \
@@ -180,7 +188,7 @@ CLEANUP             += $(BIN)/NIC
 # TGT_ROM_NAME : the ROM name (e.g. "dfe538")
 # TGT_MEDIA    : the media type (e.g. "rom")
 #
-DRIVERS_etherboot = $(DRIVERS)
+DRIVERS_gpxe   = $(DRIVERS)
 CARD_DRIVER    = $(firstword $(DRIVER_$(1)) $(1))
 TGT_ELEMENTS   = $(subst --, ,$(firstword $(subst ., ,$(notdir $@))))
 TGT_PREFIX     = $(word 2,$(subst ., ,$(notdir $@)))
@@ -368,7 +376,7 @@ define media_template
        @$(MKDIR) -p $(dir $(2))
        @$(RM) $(2)
        @$(TOUCH) $(2)
-       @echo -e '$$(BIN)/%$(1) : $$(BIN)/%$(1).zbin' \
+       @$(ECHO_E) '$$(BIN)/%$(1) : $$(BIN)/%$(1).zbin' \
                  '\n\t$$(QM)echo "  [FINISH] $$@"' \
                  '\n\t$$(Q)$$(CP) $$< $$@' \
                  '\n\t$$(Q)$$(FINALISE_$(1))' \
@@ -395,6 +403,11 @@ include $(MEDIA_DEPS)
 allroms allzroms : all%s : $(foreach ROM,$(ROMS),$(BIN)/$(ROM).%)
 all%s : $(foreach DRIVER,$(DRIVERS),$(BIN)/$(DRIVER).%)
 
+# Alias for gpxe.%
+#
+$(BIN)/etherboot.% : $(BIN)/gpxe.%
+       ln -sf $(notdir $<) $@
+
 # The compression utilities
 #
 $(NRV2B) : util/nrv2b.c $(MAKEDEPS)
index 16de411..1c086ec 100644 (file)
@@ -122,10 +122,6 @@ CFLAGS+=   -malign-jumps=1 -malign-loops=1 -malign-functions=1
 else
 CFLAGS+=       -falign-jumps=1 -falign-loops=1 -falign-functions=1
 endif
-GCC_MINORVERSION = $(word 2, $(GCC_VERSION))
-ifneq ($(GCC_MINORVERSION),4)
-CFLAGS+=       -march=i386
-endif
 
 # this is almost always a win. the kernel uses it, too.
 CFLAGS+= -mpreferred-stack-boundary=2
@@ -150,8 +146,3 @@ endif
 
 # An alternate location for isolinux.bin can be set here
 # ISOLINUX_BIN=/path/to/isolinux.bin
-
-# These seem to have some relevance to compiling on x86_64
-# EXTRA_CFLAGS=-m32
-# EXTRA_ASFLAGS=--32
-# EXTRA_LDFLAGS=-m elf_i386
index 0d01f6a..ad2a04c 100644 (file)
 #include <gpxe/segment.h>
 #include <gpxe/init.h>
 #include <gpxe/initrd.h>
+#include <gpxe/cpio.h>
+#include <gpxe/features.h>
+
+FEATURE ( FEATURE_IMAGE, "bzImage", DHCP_EB_FEATURE_BZIMAGE, 1 );
 
 struct image_type bzimage_image_type __image_type ( PROBE_NORMAL );
 
@@ -166,6 +170,63 @@ static int bzimage_set_cmdline ( struct image *image,
        return 0;
 }
 
+/**
+ * Load initrd
+ *
+ * @v image            bzImage image
+ * @v initrd           initrd image
+ * @v address          Address at which to load, or UNULL
+ * @ret len            Length of loaded image, rounded up to 4 bytes
+ */
+static size_t bzimage_load_initrd ( struct image *image,
+                                   struct image *initrd,
+                                   userptr_t address ) {
+       char *filename = initrd->cmdline;
+       struct cpio_header cpio;
+        size_t offset = 0;
+
+       /* Ignore images which aren't initrds */
+       if ( initrd->type != &initrd_image_type )
+               return 0;
+
+       /* Create cpio header before non-prebuilt images */
+       if ( filename && filename[0] ) {
+               size_t name_len = ( strlen ( filename ) + 1 );
+
+               DBGC ( image, "bzImage %p inserting initrd %p as %s\n",
+                      image, initrd, filename );
+               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 ( address ) {
+                       copy_to_user ( address, offset, &cpio,
+                                      sizeof ( cpio ) );
+               }
+               offset += sizeof ( cpio );
+               if ( address ) {
+                       copy_to_user ( address, offset, filename,
+                                      name_len );
+               }
+               offset += name_len;
+               offset = ( ( offset + 0x03 ) & ~0x03 );
+       }
+
+       /* Copy in initrd image body */
+       if ( address ) {
+               DBGC ( image, "bzImage %p has initrd %p at [%lx,%lx)\n",
+                      image, initrd, address, ( address + offset ) );
+               memcpy_user ( address, offset, initrd->data, 0,
+                             initrd->len );
+       }
+       offset += initrd->len;
+
+       offset = ( ( offset + 0x03 ) & ~0x03 );
+       return offset;
+}
+
 /**
  * Load initrds, if any
  *
@@ -173,21 +234,16 @@ static int bzimage_set_cmdline ( struct image *image,
  * @v exec_ctx         Execution context
  * @ret rc             Return status code
  */
-static int bzimage_load_initrd ( struct image *image,
-                                struct bzimage_exec_context *exec_ctx ) {
+static int bzimage_load_initrds ( struct image *image,
+                                 struct bzimage_exec_context *exec_ctx ) {
        struct image *initrd;
-       size_t initrd_len;
        size_t total_len = 0;
-       size_t offset = 0;
-       physaddr_t start;
+       physaddr_t address;
        int rc;
 
        /* Add up length of all initrd images */
        for_each_image ( initrd ) {
-               if ( initrd->type != &initrd_image_type )
-                       continue;
-               initrd_len = ( ( initrd->len + 0x0f ) & ~0x0f );
-               total_len += initrd_len;
+               total_len += bzimage_load_initrd ( image, initrd, UNULL );
        }
 
        /* Give up if no initrd images found */
@@ -198,47 +254,39 @@ static int bzimage_load_initrd ( struct image *image,
         * starting from the downloaded kernel image itself and
         * working downwards until we hit an available region.
         */
-       for ( start = ( user_to_phys ( image->data, 0 ) & ~0xfffff ) ; ;
-             start -= 0x100000 ) {
+       for ( address = ( user_to_phys ( image->data, 0 ) & ~0xfffff ) ; ;
+             address -= 0x100000 ) {
                /* Check that we're not going to overwrite the
                 * kernel itself.  This check isn't totally
                 * accurate, but errs on the side of caution.
                 */
-               if ( start <= ( BZI_LOAD_HIGH_ADDR + image->len ) ) {
+               if ( address <= ( BZI_LOAD_HIGH_ADDR + image->len ) ) {
                        DBGC ( image, "bzImage %p could not find a location "
                               "for initrd\n", image );
                        return -ENOBUFS;
                }
                /* Check that we are within the kernel's range */
-               if ( ( start + total_len ) > exec_ctx->mem_limit )
+               if ( ( address + total_len ) > exec_ctx->mem_limit )
                        continue;
                /* Prepare and verify segment */
-               if ( ( rc = prep_segment ( phys_to_user ( start ), 0,
+               if ( ( rc = prep_segment ( phys_to_user ( address ), 0,
                                           total_len ) ) != 0 )
                        continue;
                /* Use this address */
                break;
        }
 
+       /* Record initrd location */
+       exec_ctx->ramdisk_image = address;
+       exec_ctx->ramdisk_size = total_len;
+
        /* Construct initrd */
        DBGC ( image, "bzImage %p constructing initrd at [%lx,%lx)\n",
-              image, start, ( start + total_len ) );
+              image, address, ( address + total_len ) );
        for_each_image ( initrd ) {
-               if ( initrd->type != &initrd_image_type )
-                       continue;
-               initrd_len = ( ( initrd->len + 0x0f ) & ~0x0f );
-               DBGC ( image, "bzImage %p has initrd %p at [%lx,%lx)\n",
-                      image, initrd, ( start + offset ),
-                      ( start + offset + initrd->len ) );
-               memcpy_user ( phys_to_user ( start ), offset,
-                             initrd->data, 0, initrd->len );
-               offset += initrd_len;
+               address += bzimage_load_initrd ( image, initrd,
+                                                phys_to_user ( address ) );
        }
-       assert ( offset == total_len );
-
-       /* Record initrd location */
-       exec_ctx->ramdisk_image = start;
-       exec_ctx->ramdisk_size = total_len;
 
        return 0;
 }
@@ -281,7 +329,7 @@ static int bzimage_exec ( struct image *image ) {
                return rc;
 
        /* Load any initrds */
-       if ( ( rc = bzimage_load_initrd ( image, &exec_ctx ) ) != 0 )
+       if ( ( rc = bzimage_load_initrds ( image, &exec_ctx ) ) != 0 )
                return rc;
 
        /* Update and store kernel header */
index 546de36..fbaebd5 100644 (file)
@@ -23,6 +23,7 @@
  *
  */
 
+#include <stdio.h>
 #include <errno.h>
 #include <assert.h>
 #include <realmode.h>
@@ -33,6 +34,9 @@
 #include <gpxe/memmap.h>
 #include <gpxe/elf.h>
 #include <gpxe/init.h>
+#include <gpxe/features.h>
+
+FEATURE ( FEATURE_IMAGE, "Multiboot", DHCP_EB_FEATURE_MULTIBOOT, 1 );
 
 struct image_type multiboot_image_type __image_type ( PROBE_MULTIBOOT );
 
@@ -48,6 +52,16 @@ struct image_type multiboot_image_type __image_type ( PROBE_MULTIBOOT );
  */
 #define MAX_MODULES 8
 
+/**
+ * Maximum combined length of command lines
+ *
+ * Again; sorry.  Some broken OSes zero out any non-base memory that
+ * isn't part of the loaded module set, so we can't just use
+ * virt_to_phys(cmdline) to point to the command lines, even though
+ * this would comply with the Multiboot spec.
+ */
+#define MB_MAX_CMDLINE 512
+
 /** Multiboot flags that we support */
 #define MB_SUPPORTED_FLAGS ( MB_FLAG_PGALIGN | MB_FLAG_MEMMAP | \
                             MB_FLAG_VIDMODE | MB_FLAG_RAW )
@@ -74,6 +88,13 @@ struct multiboot_header_info {
        size_t offset;
 };
 
+/** Multiboot module command lines */
+static char __bss16_array ( mb_cmdlines, [MB_MAX_CMDLINE] );
+#define mb_cmdlines __use_data16 ( mb_cmdlines )
+
+/** Offset within module command lines */
+static unsigned int mb_cmdline_offset;
+
 /**
  * Build multiboot memory map
  *
@@ -115,6 +136,32 @@ static void multiboot_build_memmap ( struct image *image,
        }
 }
 
+/**
+ * Add command line in base memory
+ *
+ * @v cmdline          Command line
+ * @ret physaddr       Physical address of command line
+ */
+physaddr_t multiboot_add_cmdline ( const char *cmdline ) {
+       char *mb_cmdline;
+
+       if ( ! cmdline )
+               cmdline = "";
+
+       /* Copy command line to base memory buffer */
+       mb_cmdline = ( mb_cmdlines + mb_cmdline_offset );
+       mb_cmdline_offset +=
+               ( snprintf ( mb_cmdline,
+                            ( sizeof ( mb_cmdlines ) - mb_cmdline_offset ),
+                            "%s", cmdline ) + 1 );
+
+       /* Truncate to terminating NUL in buffer if necessary */
+       if ( mb_cmdline_offset > sizeof ( mb_cmdlines ) )
+               mb_cmdline_offset = ( sizeof ( mb_cmdlines ) - 1 );
+
+       return virt_to_phys ( mb_cmdline );
+}
+
 /**
  * Build multiboot module list
  *
@@ -147,42 +194,35 @@ multiboot_build_module_list ( struct image *image,
                if ( module_image == image )
                        continue;
 
-               /* If we don't have a data structure to populate, just count */
-               if ( modules ) {
-                       
-                       /* At least some OSes expect the multiboot
-                        * modules to be in ascending order, so we
-                        * have to support it.
-                        */
-                       start = user_to_phys ( module_image->data, 0 );
-                       end = user_to_phys ( module_image->data,
-                                            module_image->len );
-                       for ( insert = 0 ; insert < count ; insert++ ) {
-                               if ( start < modules[insert].mod_start )
-                                       break;
-                       }
-                       module = &modules[insert];
-                       memmove ( ( module + 1 ), module,
-                                 ( ( count - insert ) * sizeof ( *module ) ));
-                       module->mod_start = start;
-                       module->mod_end = end;
-                       module->string = virt_to_phys ( module_image->cmdline);
-                       module->reserved = 0;
-                       
-                       /* We promise to page-align modules */
-                       assert ( ( module->mod_start & 0xfff ) == 0 );
+               /* At least some OSes expect the multiboot modules to
+                * be in ascending order, so we have to support it.
+                */
+               start = user_to_phys ( module_image->data, 0 );
+               end = user_to_phys ( module_image->data, module_image->len );
+               for ( insert = 0 ; insert < count ; insert++ ) {
+                       if ( start < modules[insert].mod_start )
+                               break;
                }
+               module = &modules[insert];
+               memmove ( ( module + 1 ), module,
+                         ( ( count - insert ) * sizeof ( *module ) ) );
+               module->mod_start = start;
+               module->mod_end = end;
+               module->string =
+                       multiboot_add_cmdline ( module_image->cmdline );
+               module->reserved = 0;
+               
+               /* We promise to page-align modules */
+               assert ( ( module->mod_start & 0xfff ) == 0 );
 
                count++;
        }
 
        /* Dump module configuration */
-       if ( modules ) {
-               for ( i = 0 ; i < count ; i++ ) {
-                       DBGC ( image, "MULTIBOOT %p module %d is [%lx,%lx)\n",
-                              image, i, modules[i].mod_start,
-                              modules[i].mod_end );
-               }
+       for ( i = 0 ; i < count ; i++ ) {
+               DBGC ( image, "MULTIBOOT %p module %d is [%lx,%lx)\n",
+                      image, i, modules[i].mod_start,
+                      modules[i].mod_end );
        }
 
        return count;
@@ -226,7 +266,8 @@ static int multiboot_exec ( struct image *image ) {
                         MBI_FLAG_CMDLINE | MBI_FLAG_MODS );
        multiboot_build_memmap ( image, &mbinfo, mbmemmap,
                                 ( sizeof(mbmemmap) / sizeof(mbmemmap[0]) ) );
-       mbinfo.cmdline = virt_to_phys ( image->cmdline );
+       mb_cmdline_offset = 0;
+       mbinfo.cmdline = multiboot_add_cmdline ( image->cmdline );
        mbinfo.mods_count = multiboot_build_module_list ( image, mbmodules,
                                ( sizeof(mbmodules) / sizeof(mbmodules[0]) ) );
        mbinfo.mods_addr = virt_to_phys ( mbmodules );
index 2de381d..a1d7455 100644 (file)
@@ -10,6 +10,7 @@
 #include <gpxe/netdevice.h>
 #include <gpxe/dhcp.h>
 #include <gpxe/image.h>
+#include <gpxe/features.h>
 
 /** @file
  *
@@ -26,6 +27,8 @@
  *
  */
 
+FEATURE ( FEATURE_IMAGE, "NBI", DHCP_EB_FEATURE_NBI, 1 );
+
 struct image_type nbi_image_type __image_type ( PROBE_NORMAL );
 
 /**
index 3da38e0..9e634f1 100644 (file)
@@ -29,6 +29,9 @@
 #include <gpxe/image.h>
 #include <gpxe/segment.h>
 #include <gpxe/netdevice.h>
+#include <gpxe/features.h>
+
+FEATURE ( FEATURE_IMAGE, "PXE", DHCP_EB_FEATURE_PXE, 1 );
 
 struct image_type pxe_image_type __image_type ( PROBE_PXE );
 
similarity index 50%
rename from src/arch/i386/include/stdint.h
rename to src/arch/i386/include/bits/stdint.h
index 34bea8b..a2947cd 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef STDINT_H
-#define STDINT_H
+#ifndef _BITS_STDINT_H
+#define _BITS_STDINT_H
 
 typedef typeof(sizeof(int))    size_t;
 typedef signed long            ssize_t;
@@ -18,22 +18,4 @@ typedef signed long long     int64_t;
 typedef unsigned long          physaddr_t;
 typedef unsigned long          intptr_t;
 
-typedef int8_t s8;
-typedef uint8_t u8;
-typedef int16_t s16;
-typedef uint16_t u16;
-typedef int32_t s32;
-typedef uint32_t u32;
-typedef int64_t s64;
-typedef uint64_t u64;
-
-typedef int8_t int8;
-typedef uint8_t uint8;
-typedef int16_t int16;
-typedef uint16_t uint16;
-typedef int32_t int32;
-typedef uint32_t uint32;
-typedef int64_t int64;
-typedef uint64_t uint64;
-
-#endif /* STDINT_H */
+#endif /* _BITS_STDINT_H */
index 53817c7..a26dcff 100644 (file)
@@ -543,8 +543,9 @@ void register_int13_drive ( struct int13_drive *drive ) {
 
        /* Assign drive number if none specified, update BIOS drive count */
        get_real ( num_drives, BDA_SEG, BDA_NUM_DRIVES );
-       if ( ! drive->drive )
-               drive->drive = ( num_drives | 0x80 );
+       if ( ( drive->drive & 0xff ) == 0xff )
+               drive->drive = num_drives;
+       drive->drive |= 0x80;
        num_drives++;
        if ( num_drives <= ( drive->drive & 0x7f ) )
                num_drives = ( ( drive->drive & 0x7f ) + 1 );
index 1c1b506..8f1dd0a 100644 (file)
@@ -91,6 +91,11 @@ union pxenv_call {
                        ( struct s_PXENV_UNDI_GET_IFACE_INFO * );
        PXENV_EXIT_t ( * undi_get_state ) ( struct s_PXENV_UNDI_GET_STATE * );
        PXENV_EXIT_t ( * undi_isr ) ( struct s_PXENV_UNDI_ISR * );
+       PXENV_EXIT_t ( * file_open ) ( struct s_PXENV_FILE_OPEN * );
+       PXENV_EXIT_t ( * file_close ) ( struct s_PXENV_FILE_CLOSE * );
+       PXENV_EXIT_t ( * file_select ) ( struct s_PXENV_FILE_SELECT * );
+       PXENV_EXIT_t ( * file_read ) ( struct s_PXENV_FILE_READ * );
+       PXENV_EXIT_t ( * get_file_size ) ( struct s_PXENV_GET_FILE_SIZE * );
 };
 
 /**
@@ -269,6 +274,26 @@ __cdecl void pxe_api_call ( struct i386_all_regs *ix86 ) {
                pxenv_call.undi_isr = pxenv_undi_isr;
                param_len = sizeof ( pxenv_any.undi_isr );
                break;
+       case PXENV_FILE_OPEN:
+               pxenv_call.file_open = pxenv_file_open;
+               param_len = sizeof ( pxenv_any.file_open );
+               break;
+       case PXENV_FILE_CLOSE:
+               pxenv_call.file_close = pxenv_file_close;
+               param_len = sizeof ( pxenv_any.file_close );
+               break;
+       case PXENV_FILE_SELECT:
+               pxenv_call.file_select = pxenv_file_select;
+               param_len = sizeof ( pxenv_any.file_select );
+               break;
+       case PXENV_FILE_READ:
+               pxenv_call.file_read = pxenv_file_read;
+               param_len = sizeof ( pxenv_any.file_read );
+               break;
+       case PXENV_GET_FILE_SIZE:
+               pxenv_call.get_file_size = pxenv_get_file_size;
+               param_len = sizeof ( pxenv_any.get_file_size );
+               break;
        default:
                DBG ( "PXENV_UNKNOWN_%hx", opcode );
                pxenv_call.unknown = pxenv_unknown;
diff --git a/src/core/cpio.c b/src/core/cpio.c
new file mode 100644 (file)
index 0000000..7d2e882
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/** @file
+ *
+ * CPIO archives
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <gpxe/cpio.h>
+
+/**
+ * Set field within a CPIO header
+ *
+ * @v field            Field within CPIO header
+ * @v value            Value to set
+ */
+void cpio_set_field ( char *field, unsigned long value ) {
+       char buf[9];
+
+       snprintf ( buf, sizeof ( buf ), "%08lx", value );
+       memcpy ( field, buf, 8 );
+}
index cf5e90f..c7f0138 100644 (file)
@@ -33,10 +33,9 @@ struct uri *cwuri = NULL;
 /**
  * Change working URI
  *
- * @v uri              New working URI
+ * @v uri              New working URI, or NULL
  */
 void churi ( struct uri *uri ) {
-       if ( cwuri )
-               uri_put ( cwuri );
+       uri_put ( cwuri );
        cwuri = uri_get ( uri );
 }
diff --git a/src/core/ibft.c b/src/core/ibft.c
new file mode 100644 (file)
index 0000000..5f03367
--- /dev/null
@@ -0,0 +1,325 @@
+/*
+ * Copyright Fen Systems Ltd. 2007.  Portions of this code are derived
+ * from IBM Corporation Sample Programs.  Copyright IBM Corporation
+ * 2004, 2007.  All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <byteswap.h>
+#include <realmode.h>
+#include <gpxe/pci.h>
+#include <gpxe/acpi.h>
+#include <gpxe/in.h>
+#include <gpxe/netdevice.h>
+#include <gpxe/dhcp.h>
+#include <gpxe/iscsi.h>
+#include <gpxe/ibft.h>
+
+/** @file
+ *
+ * iSCSI boot firmware table
+ *
+ * The information in this file is derived from the document "iSCSI
+ * Boot Firmware Table (iBFT)" as published by IBM at
+ *
+ * ftp://ftp.software.ibm.com/systems/support/system_x_pdf/ibm_iscsi_boot_firmware_table_v1.02.pdf
+ *
+ */
+
+#define ibftab __use_data16 ( ibftab )
+/** The iBFT used by gPXE */
+struct gpxe_ibft __data16 ( ibftab ) = {
+       /* Table header */
+       .table = {
+               /* ACPI header */
+               .acpi = {
+                       .signature = IBFT_SIG,
+                       .length = sizeof ( ibftab ),
+                       .revision = 1,
+                       .oem_id = "FENSYS",
+                       .oem_table_id = "gPXE",
+               },
+               /* Control block */
+               .control = {
+                       .header = {
+                               .structure_id = IBFT_STRUCTURE_ID_CONTROL,
+                               .version = 1,
+                               .length = sizeof ( ibftab.table.control ),
+                               .flags = 0,
+                       },
+                       .initiator = offsetof ( typeof ( ibftab ), initiator ),
+                       .nic_0 = offsetof ( typeof ( ibftab ), nic ),
+                       .target_0 = offsetof ( typeof ( ibftab ), target ),
+               },
+       },
+       /* iSCSI initiator information */
+       .initiator = {
+               .header = {
+                       .structure_id = IBFT_STRUCTURE_ID_INITIATOR,
+                       .version = 1,
+                       .length = sizeof ( ibftab.initiator ),
+                       .flags = ( IBFT_FL_INITIATOR_BLOCK_VALID |
+                                  IBFT_FL_INITIATOR_FIRMWARE_BOOT_SELECTED ),
+               },
+       },
+       /* NIC information */
+       .nic = {
+               .header = {
+                       .structure_id = IBFT_STRUCTURE_ID_NIC,
+                       .version = 1,
+                       .length = sizeof ( ibftab.nic ),
+                       .flags = ( IBFT_FL_NIC_BLOCK_VALID |
+                                  IBFT_FL_NIC_FIRMWARE_BOOT_SELECTED ),
+               },
+       },
+       /* iSCSI target information */
+       .target = {
+               .header = {
+                       .structure_id = IBFT_STRUCTURE_ID_TARGET,
+                       .version = 1,
+                       .length = sizeof ( ibftab.target ),
+                       .flags = ( IBFT_FL_TARGET_BLOCK_VALID |
+                                  IBFT_FL_TARGET_FIRMWARE_BOOT_SELECTED ),
+               },
+       },
+};
+
+/**
+ * Fill in an IP address field within iBFT
+ *
+ * @v ipaddr           IP address field
+ * @v in               IPv4 address
+ */
+static void ibft_set_ipaddr ( struct ibft_ipaddr *ipaddr, struct in_addr in ) {
+       memset ( ipaddr, 0, sizeof ( ipaddr ) );
+       if ( in.s_addr ) {
+               ipaddr->in = in;
+               ipaddr->ones = 0xffff;
+       }
+}
+
+/**
+ * Fill in an IP address within iBFT from DHCP option
+ *
+ * @v ipaddr           IP address field
+ * @v tag              DHCP option tag
+ */
+static void ibft_set_ipaddr_option ( struct ibft_ipaddr *ipaddr,
+                                    unsigned int tag ) {
+       struct in_addr in;
+       find_global_dhcp_ipv4_option ( tag, &in );
+       ibft_set_ipaddr ( ipaddr, in );
+}
+
+/**
+ * Fill in a string field within iBFT
+ *
+ * @v strings          iBFT string block descriptor
+ * @v string           String field
+ * @v data             String to fill in
+ * @v len              Length of string to fill in
+ * @ret rc             Return status code
+ */
+static int ibft_set_string ( struct ibft_string_block *strings,
+                            struct ibft_string *string,
+                            const void *data, size_t len ) {
+       char *dest;
+       char *end;
+       unsigned int remaining;
+
+       dest = ( ( ( char * ) strings->table ) + strings->offset );
+       end = ( ( ( char * ) strings->table ) + strings->table->acpi.length );
+       remaining = ( end - dest );
+
+       if ( len >= remaining )
+               return -ENOMEM;
+
+       memcpy ( dest, data, len );
+       dest[len] = '\0';
+
+       string->offset = strings->offset;
+       string->length = len;
+       strings->offset += ( len + 1 );
+       return 0;
+}
+
+/**
+ * Fill in a string field within iBFT from DHCP option
+ *
+ * @v strings          iBFT string block descriptor
+ * @v string           String field
+ * @v tag              DHCP option tag
+ * @ret rc             Return status code
+ */
+static int ibft_set_string_option ( struct ibft_string_block *strings,
+                                   struct ibft_string *string,
+                                   unsigned int tag ) {
+       struct dhcp_option *option;
+
+       option = find_global_dhcp_option ( tag );
+       if ( ! option ) {
+               string->offset = 0;
+               string->length = 0;
+               return 0;
+       }
+
+       return ibft_set_string ( strings, string, option->data.string,
+                                option->len );
+}
+
+/**
+ * Fill in NIC portion of iBFT
+ *
+ * @v nic              NIC portion of iBFT
+ * @v strings          iBFT string block descriptor
+ * @v netdev           Network device
+ * @ret rc             Return status code
+ */
+static int ibft_fill_nic ( struct ibft_nic *nic,
+                          struct ibft_string_block *strings,
+                          struct net_device *netdev ) {
+       struct in_addr netmask_addr;
+       unsigned int netmask_count = 0;
+       int rc;
+
+       /* Extract values from DHCP configuration */
+       ibft_set_ipaddr_option ( &nic->ip_address, DHCP_EB_YIADDR );
+       ibft_set_ipaddr_option ( &nic->gateway, DHCP_ROUTERS );
+       ibft_set_ipaddr_option ( &nic->dns[0], DHCP_DNS_SERVERS );
+       if ( ( rc = ibft_set_string_option ( strings, &nic->hostname,
+                                            DHCP_HOST_NAME ) ) != 0 )
+               return rc;
+
+       /* Derive subnet mask prefix from subnet mask */
+       find_global_dhcp_ipv4_option ( DHCP_SUBNET_MASK, &netmask_addr );
+       while ( netmask_addr.s_addr ) {
+               if ( netmask_addr.s_addr & 0x1 )
+                       netmask_count++;
+               netmask_addr.s_addr >>= 1;
+       }
+       nic->subnet_mask_prefix = netmask_count;
+
+       /* Extract values from net-device configuration */
+       memcpy ( nic->mac_address, netdev->ll_addr,
+                sizeof ( nic->mac_address ) );
+       nic->pci_bus_dev_func = netdev->dev->desc.location;
+
+       return 0;
+}
+
+/**
+ * Fill in Initiator portion of iBFT
+ *
+ * @v initiator                Initiator portion of iBFT
+ * @v strings          iBFT string block descriptor
+ * @ret rc             Return status code
+ */
+static int ibft_fill_initiator ( struct ibft_initiator *initiator,
+                                struct ibft_string_block *strings ) {
+       const char *initiator_iqn = iscsi_initiator_iqn();
+       int rc;
+
+       if ( ( rc = ibft_set_string ( strings, &initiator->initiator_name,
+                                     initiator_iqn,
+                                     strlen ( initiator_iqn ) ) ) != 0)
+               return rc;
+
+       return 0;
+}
+
+/**
+ * Fill in Target portion of iBFT
+ *
+ * @v target           Target portion of iBFT
+ * @v strings          iBFT string block descriptor
+ * @v iscsi            iSCSI session
+ * @ret rc             Return status code
+ */
+static int ibft_fill_target ( struct ibft_target *target,
+                             struct ibft_string_block *strings,
+                             struct iscsi_session *iscsi ) {
+       struct sockaddr_in *sin_target =
+               ( struct sockaddr_in * ) &iscsi->target_sockaddr;
+       int rc;
+
+       /* Fill in Target values */
+       ibft_set_ipaddr ( &target->ip_address, sin_target->sin_addr );
+       target->socket = ntohs ( sin_target->sin_port );
+       if ( ( rc = ibft_set_string ( strings, &target->target_name,
+                                     iscsi->target_iqn,
+                                     strlen ( iscsi->target_iqn ) ) ) != 0 )
+               return rc;
+       if ( iscsi->username ) {
+               if ( ( rc = ibft_set_string ( strings, &target->chap_name,
+                                             iscsi->username,
+                                             strlen ( iscsi->username ) ))!=0)
+                       return rc;
+       }
+       if ( iscsi->password ) {
+               if ( ( rc = ibft_set_string ( strings, &target->chap_secret,
+                                             iscsi->password,
+                                             strlen ( iscsi->password ) ))!=0)
+                       return rc;
+               target->chap_type = IBFT_CHAP_ONE_WAY;
+       }
+
+       return 0;
+}
+
+/**
+ * Fill in all variable portions of iBFT
+ *
+ * @v netdev           Network device
+ * @v initiator_iqn    Initiator IQN
+ * @v st_target                Target socket address
+ * @v target_iqn       Target IQN
+ * @ret rc             Return status code
+ *
+ */
+int ibft_fill_data ( struct net_device *netdev,
+                    struct iscsi_session *iscsi ) {
+       struct ibft_string_block strings = {
+               .table = &ibftab.table,
+               .offset = offsetof ( typeof ( ibftab ), strings ),
+       };
+       int rc;
+
+       /* Fill in NIC, Initiator and Target portions */
+       if ( ( rc = ibft_fill_nic ( &ibftab.nic, &strings, netdev ) ) != 0 )
+               return rc;
+       if ( ( rc = ibft_fill_initiator ( &ibftab.initiator,
+                                         &strings ) ) != 0 )
+               return rc;
+       if ( ( rc = ibft_fill_target ( &ibftab.target, &strings,
+                                      iscsi ) ) != 0 )
+               return rc;
+
+       /* Update checksum */
+       acpi_fix_checksum ( &ibftab.table.acpi );
+
+       return 0;
+}
index 04bd083..440a68c 100644 (file)
 #include <stdio.h>
 #include <errno.h>
 #include <assert.h>
+#include <libgen.h>
 #include <gpxe/list.h>
 #include <gpxe/umalloc.h>
+#include <gpxe/uri.h>
 #include <gpxe/image.h>
 
 /** @file
@@ -49,6 +51,7 @@ static struct image_type image_types_end[0]
 static void free_image ( struct refcnt *refcnt ) {
        struct image *image = container_of ( refcnt, struct image, refcnt );
 
+       uri_put ( image->uri );
        ufree ( image->data );
        free ( image );
        DBGC ( image, "IMAGE %p freed\n", image );
@@ -69,6 +72,45 @@ struct image * alloc_image ( void ) {
        return image;
 }
 
+/**
+ * Set image URI
+ *
+ * @v image            Image
+ * @v URI              New image URI
+ * @ret rc             Return status code
+ *
+ * If no name is set, the name will be updated to the base name of the
+ * URI path (if any).
+ */
+int image_set_uri ( struct image *image, struct uri *uri ) {
+       const char *path = uri->path;
+
+       /* Replace URI reference */
+       uri_put ( image->uri );
+       image->uri = uri_get ( uri );
+
+       /* Set name if none already specified */
+       if ( path && ( ! image->name[0] ) )
+               image_set_name ( image, basename ( ( char * ) path ) );
+
+       return 0;
+}
+
+/**
+ * Set image command line
+ *
+ * @v image            Image
+ * @v cmdline          New image command line
+ * @ret rc             Return status code
+ */
+int image_set_cmdline ( struct image *image, const char *cmdline ) {
+       free ( image->cmdline );
+       image->cmdline = strdup ( cmdline );
+       if ( ! image->cmdline )
+               return -ENOMEM;
+       return 0;
+}
+
 /**
  * Register executable/loadable image
  *
@@ -195,6 +237,7 @@ int image_autoload ( struct image *image ) {
  * @ret rc             Return status code
  */
 int image_exec ( struct image *image ) {
+       struct uri *old_cwuri;
        int rc;
 
        /* Image must be loaded first */
@@ -210,13 +253,57 @@ int image_exec ( struct image *image ) {
        if ( ! image->type->exec )
                return -ENOEXEC;
 
+       /* Switch current working directory to be that of the image itself */
+       old_cwuri = uri_get ( cwuri );
+       churi ( image->uri );
+
        /* Try executing the image */
        if ( ( rc = image->type->exec ( image ) ) != 0 ) {
                DBGC ( image, "IMAGE %p could not execute: %s\n",
                       image, strerror ( rc ) );
-               return rc;
+               goto done;
        }
 
-       /* Well, some formats might return... */
+ done:
+       /* Reset current working directory */
+       churi ( old_cwuri );
+       uri_put ( old_cwuri );
+
+       return rc;
+}
+
+/**
+ * Register and autoload an image
+ *
+ * @v image            Image
+ * @ret rc             Return status code
+ */
+int register_and_autoload_image ( struct image *image ) {
+       int rc;
+
+       if ( ( rc = register_image ( image ) ) != 0 )
+               return rc;
+
+       if ( ( rc = image_autoload ( image ) ) != 0 )
+               return rc;
+
+       return 0;
+}
+
+/**
+ * Register and autoexec an image
+ *
+ * @v image            Image
+ * @ret rc             Return status code
+ */
+int register_and_autoexec_image ( struct image *image ) {
+       int rc;
+
+       if ( ( rc = register_and_autoload_image ( image ) ) != 0 )
+               return rc;
+
+       if ( ( rc = image_exec ( image ) ) != 0 )
+               return rc;
+
        return 0;
 }
index b4042a3..ea9bc83 100644 (file)
@@ -16,6 +16,8 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+#include <string.h>
+#include <stdio.h>
 #include <errno.h>
 #include <gpxe/process.h>
 #include <console.h>
@@ -54,11 +56,14 @@ struct job_interface monojob = {
 /**
  * Wait for single foreground job to complete
  *
+ * @v string           Job description to display
  * @ret rc             Job final status code
  */
-int monojob_wait ( void ) {
+int monojob_wait ( const char *string ) {
        int key;
+       int rc;
 
+       printf ( "%s... ", string );
        monojob_rc = -EINPROGRESS;
        while ( monojob_rc == -EINPROGRESS ) {
                step();
@@ -67,12 +72,20 @@ int monojob_wait ( void ) {
                        switch ( key ) {
                        case CTRL_C:
                                job_kill ( &monojob );
-                               return -ECANCELED;
-                               break;
+                               rc = -ECANCELED;
+                               goto done;
                        default:
                                break;
                        }
                }
        }
-       return monojob_rc;
+       rc = monojob_rc;
+
+done:
+       if ( rc ) {
+               printf ( "%s\n", strerror ( rc ) );
+       } else {
+               printf ( "ok\n" );
+       }
+       return rc;
 }
index 21f818b..530ce65 100644 (file)
@@ -60,12 +60,6 @@ struct posix_file {
 /** List of open files */
 static LIST_HEAD ( posix_files );
 
-/** Minimum file descriptor that will ever be allocated */
-#define POSIX_FD_MIN ( 1 )
-
-/** Maximum file descriptor that will ever be allocated */
-#define POSIX_FD_MAX ( 255 )
-
 /**
  * Free open file
  *
@@ -251,6 +245,38 @@ int open ( const char *uri_string ) {
        return rc;
 }
 
+/**
+ * Check file descriptors for readiness
+ *
+ * @v readfds          File descriptors to check
+ * @v wait             Wait until data is ready
+ * @ret nready         Number of ready file descriptors
+ */
+int select ( fd_set *readfds, int wait ) {
+       struct posix_file *file;
+       int fd;
+
+       do {
+               for ( fd = POSIX_FD_MIN ; fd <= POSIX_FD_MAX ; fd++ ) {
+                       if ( ! FD_ISSET ( fd, readfds ) )
+                               continue;
+                       file = posix_fd_to_file ( fd );
+                       if ( ! file )
+                               return -EBADF;
+                       if ( ( list_empty ( &file->data ) ) &&
+                            ( file->rc != -EINPROGRESS ) )
+                               continue;
+                       /* Data is available or status has changed */
+                       FD_ZERO ( readfds );
+                       FD_SET ( fd, readfds );
+                       return 1;
+               }
+               step();
+       } while ( wait );
+
+       return 0;
+}
+
 /**
  * Read data from file
  *
@@ -258,47 +284,45 @@ int open ( const char *uri_string ) {
  * @v offset           Starting offset within data buffer
  * @v len              Maximum length to read
  * @ret len            Actual length read, or negative error number
+ *
+ * This call is non-blocking; if no data is available to read then
+ * -EWOULDBLOCK will be returned.
  */
 ssize_t read_user ( int fd, userptr_t buffer, off_t offset, size_t max_len ) {
        struct posix_file *file;
        struct io_buffer *iobuf;
-       size_t frag_len;
-       ssize_t len = 0;
+       size_t len;
 
        /* Identify file */
        file = posix_fd_to_file ( fd );
        if ( ! file )
                return -EBADF;
 
-       while ( 1 ) {
-               /* Try to fetch more data if none available */
-               if ( list_empty ( &file->data ) )
-                       step();
-               /* Dequeue at most one received I/O buffer into user buffer */
-               list_for_each_entry ( iobuf, &file->data, list ) {
-                       frag_len = iob_len ( iobuf );
-                       if ( frag_len > max_len )
-                               frag_len = max_len;
-                       copy_to_user ( buffer, offset, iobuf->data,
-                                      frag_len );
-                       iob_pull ( iobuf, frag_len );
-                       if ( ! iob_len ( iobuf ) ) {
-                               list_del ( &iobuf-> list );
-                               free_iob ( iobuf );
-                       }
-                       file->pos += frag_len;
-                       len += frag_len;
-                       offset += frag_len;
-                       max_len -= frag_len;
-                       break;
+       /* Try to fetch more data if none available */
+       if ( list_empty ( &file->data ) )
+               step();
+
+       /* Dequeue at most one received I/O buffer into user buffer */
+       list_for_each_entry ( iobuf, &file->data, list ) {
+               len = iob_len ( iobuf );
+               if ( len > max_len )
+                       len = max_len;
+               copy_to_user ( buffer, offset, iobuf->data, len );
+               iob_pull ( iobuf, len );
+               if ( ! iob_len ( iobuf ) ) {
+                       list_del ( &iobuf->list );
+                       free_iob ( iobuf );
                }
-               /* If buffer is full, return */
-               if ( ! max_len )
-                       return len;
-               /* If file has completed, return */
-               if ( file->rc != -EINPROGRESS )
-                       return ( file->rc ? file->rc : len );
+               file->pos += len;
+               return len;
        }
+
+       /* If file has completed, return (after returning all data) */
+       if ( file->rc != -EINPROGRESS )
+               return file->rc;
+
+       /* No data ready and file still in progress; return -WOULDBLOCK */
+       return -EWOULDBLOCK;
 }
 
 /**
index bb934bb..428f609 100644 (file)
@@ -259,7 +259,7 @@ static struct velocity_info_tbl chip_info_table[] = {
  */
 
 static void velocity_set_int_opt(int *opt, int val, int min, int max,
-                                int def, char *name, char *devname)
+                                int def, char *name, const char *devname)
 {
        if (val == -1) {
                printf("%s: set value of parameter %s to %d\n",
@@ -292,7 +292,7 @@ static void velocity_set_int_opt(int *opt, int val, int min, int max,
  */
 
 static void velocity_set_bool_opt(u32 * opt, int val, int def, u32 flag,
-                                 char *name, char *devname)
+                                 char *name, const char *devname)
 {
        (*opt) &= (~flag);
        if (val == -1) {
@@ -322,7 +322,7 @@ static void velocity_set_bool_opt(u32 * opt, int val, int def, u32 flag,
  */
 
 static void velocity_get_options(struct velocity_opt *opts, int index,
-                                char *devname)
+                                const char *devname)
 {
 
        /* FIXME Do the options need to be configurable */
@@ -708,7 +708,7 @@ static int velocity_probe( struct nic *nic, struct pci_device *pci)
        DBG ( "%s: %s at ioaddr %#hX\n", pci->driver_name, eth_ntoa ( nic->node_addr ),
              (unsigned int) BASE );
 
-       velocity_get_options(&vptr->options, 0, (char *) pci->driver_name);
+       velocity_get_options(&vptr->options, 0, pci->driver_name);
 
        /* 
         *      Mask out the options cannot be set to the chip
index 97d41bd..44689dd 100644 (file)
  *
  */
 
-/**
- * Print image description
- *
- */
+enum image_action {
+       IMG_FETCH = 0,
+       IMG_LOAD,
+       IMG_EXEC,
+};
 
 /**
  * Fill in image command line
  * @v image            Image
  * @v nargs            Argument count
  * @v args             Argument list
+ * @ret rc             Return status code
  */
-static void imgfill_cmdline ( struct image *image, unsigned int nargs, 
-                              char **args ) {
+static int imgfill_cmdline ( struct image *image, unsigned int nargs, 
+                            char **args ) {
+       char buf[256];
        size_t used = 0;
 
-       image->cmdline[0] = '\0';
-       while ( ( used < sizeof ( image->cmdline ) ) && nargs-- ) {
-               used += snprintf ( &image->cmdline[used],
-                                  ( sizeof ( image->cmdline ) - used ),
-                                  "%s%s", ( used ? " " : "" ), *(args++) );
+       memset ( buf, 0, sizeof ( buf ) );
+       while ( ( used < sizeof ( buf ) ) && nargs-- ) {
+               used += snprintf ( &buf[used], ( sizeof ( buf ) - used ),
+                                  " %s", *(args++) );
        }
+
+       return image_set_cmdline ( image, &buf[1] );
 }
 
 /**
@@ -62,12 +66,18 @@ static void imgfill_cmdline ( struct image *image, unsigned int nargs,
  *
  * @v argv             Argument list
  */
-static void imgfetch_core_syntax ( char **argv, int load ) {
+static void imgfetch_core_syntax ( char **argv, enum image_action action ) {
+       static const char *actions[] = {
+               [IMG_FETCH]     = "Fetch",
+               [IMG_LOAD]      = "Fetch and load",
+               [IMG_EXEC]      = "Fetch and execute",
+       };
+
        printf ( "Usage:\n"
                 "  %s [-n|--name <name>] filename [arguments...]\n"
                 "\n"
                 "%s executable/loadable image\n",
-                argv[0], ( load ? "Fetch and load" : "Fetch" ) );
+                argv[0], actions[action] );
 }
 
 /**
@@ -79,7 +89,8 @@ static void imgfetch_core_syntax ( char **argv, int load ) {
  * @v argv             Argument list
  * @ret rc             Return status code
  */
-static int imgfetch_core_exec ( struct image_type *image_type, int load,
+static int imgfetch_core_exec ( struct image_type *image_type,
+                               enum image_action action,
                                int argc, char **argv ) {
        static struct option longopts[] = {
                { "help", 0, NULL, 'h' },
@@ -89,6 +100,7 @@ static int imgfetch_core_exec ( struct image_type *image_type, int load,
        struct image *image;
        const char *name = NULL;
        char *filename;
+       int ( * image_register ) ( struct image *image );
        int c;
        int rc;
 
@@ -104,14 +116,14 @@ static int imgfetch_core_exec ( struct image_type *image_type, int load,
                        /* Display help text */
                default:
                        /* Unrecognised/invalid option */
-                       imgfetch_core_syntax ( argv, load );
+                       imgfetch_core_syntax ( argv, action );
                        return -EINVAL;
                }
        }
 
        /* Need at least a filename remaining after the options */
        if ( optind == argc ) {
-               imgfetch_core_syntax ( argv, load );
+               imgfetch_core_syntax ( argv, action );
                return -EINVAL;
        }
        filename = argv[optind++];
@@ -126,18 +138,37 @@ static int imgfetch_core_exec ( struct image_type *image_type, int load,
        }
 
        /* Fill in image name */
-       if ( name )
-               strncpy ( image->name, name, ( sizeof ( image->name ) - 1 ) );
+       if ( name ) {
+               if ( ( rc = image_set_name ( image, name ) ) != 0 )
+                       return rc;
+       }
 
        /* Set image type (if specified) */
        image->type = image_type;
 
        /* Fill in command line */
-       imgfill_cmdline ( image, ( argc - optind ), &argv[optind] );
+       if ( ( rc = imgfill_cmdline ( image, ( argc - optind ),
+                                     &argv[optind] ) ) != 0 )
+               return rc;
 
        /* Fetch the image */
-       if ( ( rc = imgfetch ( image, filename, load ) ) != 0 ) {
-               printf ( "Could not fetch %s: %s\n", name, strerror ( rc ) );
+       switch ( action ) {
+       case IMG_FETCH:
+               image_register = register_image;
+               break;
+       case IMG_LOAD:
+               image_register = register_and_autoload_image;
+               break;
+       case IMG_EXEC:
+               image_register = register_and_autoexec_image;
+               break;
+       default:
+               assert ( 0 );
+               return -EINVAL;
+       }
+       if ( ( rc = imgfetch ( image, filename, image_register ) ) != 0 ) {
+               printf ( "Could not fetch %s: %s\n",
+                        filename, strerror ( rc ) );
                image_put ( image );
                return rc;
        }
@@ -156,7 +187,8 @@ static int imgfetch_core_exec ( struct image_type *image_type, int load,
 static int imgfetch_exec ( int argc, char **argv ) {
        int rc;
 
-       if ( ( rc = imgfetch_core_exec ( NULL, 0, argc, argv ) ) != 0 )
+       if ( ( rc = imgfetch_core_exec ( NULL, IMG_FETCH,
+                                        argc, argv ) ) != 0 )
                return rc;
 
        return 0;
@@ -172,7 +204,7 @@ static int imgfetch_exec ( int argc, char **argv ) {
 static int kernel_exec ( int argc, char **argv ) {
        int rc;
 
-       if ( ( rc = imgfetch_core_exec ( NULL, 1, argc, argv ) ) != 0 )
+       if ( ( rc = imgfetch_core_exec ( NULL, IMG_LOAD, argc, argv ) ) != 0 )
                return rc;
 
        return 0;
@@ -188,7 +220,7 @@ static int kernel_exec ( int argc, char **argv ) {
 static int initrd_exec ( int argc, char **argv ) {
        int rc;
 
-       if ( ( rc = imgfetch_core_exec ( &initrd_image_type, 0,
+       if ( ( rc = imgfetch_core_exec ( &initrd_image_type, IMG_FETCH,
                                         argc, argv ) ) != 0 )
                return rc;
 
@@ -286,6 +318,7 @@ static int imgargs_exec ( int argc, char **argv ) {
        struct image *image;
        const char *name;
        int c;
+       int rc;
 
        /* Parse options */
        while ( ( c = getopt_long ( argc, argv, "h", longopts, NULL ) ) >= 0 ){
@@ -312,7 +345,10 @@ static int imgargs_exec ( int argc, char **argv ) {
                printf ( "No such image: %s\n", name );
                return 1;
        }
-       imgfill_cmdline ( image, ( argc - optind ), &argv[optind] );
+       if ( ( rc = imgfill_cmdline ( image, ( argc - optind ),
+                                     &argv[optind] ) ) != 0 )
+               return rc;
+
 
        return 0;
 }
index b14af54..18b1068 100644 (file)
@@ -62,12 +62,22 @@ struct command exit_command __command = {
 /** "help" command body */
 static int help_exec ( int argc __unused, char **argv __unused ) {
        struct command *command;
+       unsigned int hpos = 0;
 
        printf ( "\nAvailable commands:\n\n" );
        for ( command = commands ; command < commands_end ; command++ ) {
-               printf ( "  %s\n", command->name );
+               hpos += printf ( "  %s", command->name );
+               if ( hpos > ( 16 * 4 ) ) {
+                       printf ( "\n" );
+                       hpos = 0;
+               } else {
+                       while ( hpos % 16 ) {
+                               printf ( " " );
+                               hpos++;
+                       }
+               }
        }
-       printf ( "\nType \"<command> --help\" for further information\n\n" );
+       printf ( "\n\nType \"<command> --help\" for further information\n\n" );
        return 0;
 }
 
index 1413fe1..d313d4d 100644 (file)
@@ -19,6 +19,7 @@
 #include <stdio.h>
 #include <console.h>
 #include <latch.h>
+#include <gpxe/features.h>
 #include <gpxe/shell_banner.h>
 
 /** @file
@@ -33,6 +34,9 @@
 #define BOLD   "\033[1m"
 #define CYAN   "\033[36m"
 
+static struct feature features[0] __table_start ( struct feature, features );
+static struct feature features_end[0] __table_end ( struct feature, features );
+
 /**
  * Print shell banner and prompt for shell entry
  *
@@ -40,6 +44,7 @@
  */
 int shell_banner ( void ) {
        unsigned long timeout = ( currticks() + BANNER_TIMEOUT );
+       struct feature *feature;
        int key;
        int enter_shell = 0;
 
@@ -47,7 +52,11 @@ int shell_banner ( void ) {
        printf ( NORMAL "\n\n\n" BOLD "gPXE " VERSION
                 NORMAL " -- Open Source Boot Firmware -- "
                 CYAN "http://etherboot.org" NORMAL "\n"
-                "Press Ctrl-B for the gPXE command line..." );
+                "Features:" );
+       for ( feature = features ; feature < features_end ; feature++ ) {
+               printf ( " %s", feature->name );
+       }
+       printf ( "\nPress Ctrl-B for the gPXE command line..." );
 
        /* Wait for key */
        while ( currticks() < timeout ) {
index 8e511d2..c882152 100644 (file)
@@ -58,6 +58,7 @@ static int script_exec ( struct image *image ) {
                len = sizeof ( cmdbuf );
                if ( len > remaining )
                        len = remaining;
+               memset ( cmdbuf, 0, sizeof ( cmdbuf ) );
                copy_from_user ( cmdbuf, image->data, offset, len );
 
                /* Find end of line */
@@ -75,8 +76,8 @@ static int script_exec ( struct image *image ) {
                *eol = '\0';
                DBG ( "$ %s\n", cmdbuf );
                if ( ( rc = system ( cmdbuf ) ) != 0 ) {
-                       DBG ( "Command \"%s\" exited with status %d\n",
-                             cmdbuf, rc );
+                       DBG ( "Command \"%s\" failed: %s\n",
+                             cmdbuf, strerror ( rc ) );
                        goto done;
                }
                
index 15efb70..a195e53 100644 (file)
@@ -336,6 +336,11 @@ extern void dbg_hex_dump_da ( unsigned long dispaddr,
  */
 #define __shared __asm__ ( "_shared_bss" )
 
+/**
+ * Optimisation barrier
+ */
+#define barrier() __asm__ __volatile__ ( "" : : : "memory" )
+
 #endif /* ASSEMBLY */
 
 #endif /* COMPILER_H */
diff --git a/src/include/gpxe/cpio.h b/src/include/gpxe/cpio.h
new file mode 100644 (file)
index 0000000..ba6f844
--- /dev/null
@@ -0,0 +1,51 @@
+#ifndef _GPXE_CPIO_H
+#define _GPXE_CPIO_H
+
+/** @file
+ *
+ * CPIO archives
+ *
+ */
+
+/** A CPIO archive header
+ *
+ * All field are hexadecimal ASCII numbers padded with '0' on the
+ * left to the full width of the field.
+ */
+struct cpio_header {
+       /** The string "070701" or "070702" */
+       char c_magic[6];
+       /** File inode number */
+       char c_ino[8];
+       /** File mode and permissions */
+       char c_mode[8];
+       /** File uid */
+       char c_uid[8];
+       /** File gid */
+       char c_gid[8];
+       /** Number of links */
+       char c_nlink[8];
+       /** Modification time */
+       char c_mtime[8];
+       /** Size of data field */
+       char c_filesize[8];
+       /** Major part of file device number */
+       char c_maj[8];
+       /** Minor part of file device number */
+       char c_min[8];
+       /** Major part of device node reference */
+       char c_rmaj[8];
+       /** Minor part of device node reference */
+       char c_rmin[8];
+       /** Length of filename, including final NUL */
+       char c_namesize[8];
+       /** Checksum of data field if c_magic is 070702, othersize zero */
+       char c_chksum[8];
+} __attribute__ (( packed ));
+
+/** CPIO magic */
+#define CPIO_MAGIC "070701"
+
+extern void cpio_set_field ( char *field, unsigned long value );
+
+#endif /* _GPXE_CPIO_H */
index 8f5651b..43bccf1 100644 (file)
@@ -168,6 +168,11 @@ struct job_interface;
  */
 #define DHCP_EB_SIADDR DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 3 )
 
+/*
+ * Tags in the range 0x10-0x7f are reserved for feature markers
+ *
+ */
+
 /** Network device descriptor
  *
  * Byte 0 is the bus type ID; remaining bytes depend on the bus type.
index 48db1dc..4f9e7bc 100644 (file)
 #define ERRFILE_rtl8139                     ( ERRFILE_DRIVER | 0x002a0000 )
 #define ERRFILE_smc9000                     ( ERRFILE_DRIVER | 0x002b0000 )
 #define ERRFILE_tg3                 ( ERRFILE_DRIVER | 0x002c0000 )
+#define ERRFILE_3c509_eisa          ( ERRFILE_DRIVER | 0x002d0000 )
+#define ERRFILE_3c515               ( ERRFILE_DRIVER | 0x002e0000 )
+#define ERRFILE_3c529               ( ERRFILE_DRIVER | 0x002f0000 )
+#define ERRFILE_3c595               ( ERRFILE_DRIVER | 0x00300000 )
+#define ERRFILE_3c5x9               ( ERRFILE_DRIVER | 0x00310000 )
+#define ERRFILE_3c90x               ( ERRFILE_DRIVER | 0x00320000 )
+#define ERRFILE_amd8111e            ( ERRFILE_DRIVER | 0x00330000 )
+#define ERRFILE_davicom                     ( ERRFILE_DRIVER | 0x00340000 )
+#define ERRFILE_depca               ( ERRFILE_DRIVER | 0x00350000 )
+#define ERRFILE_dmfe                ( ERRFILE_DRIVER | 0x00360000 )
+#define ERRFILE_e1000               ( ERRFILE_DRIVER | 0x00370000 )
+#define ERRFILE_eepro100            ( ERRFILE_DRIVER | 0x00380000 )
+#define ERRFILE_epic100                     ( ERRFILE_DRIVER | 0x00390000 )
+#define ERRFILE_forcedeth           ( ERRFILE_DRIVER | 0x003a0000 )
+#define ERRFILE_mtd80x              ( ERRFILE_DRIVER | 0x003b0000 )
+#define ERRFILE_ns83820                     ( ERRFILE_DRIVER | 0x003c0000 )
+#define ERRFILE_ns8390              ( ERRFILE_DRIVER | 0x003d0000 )
+#define ERRFILE_pcnet32                     ( ERRFILE_DRIVER | 0x003e0000 )
+#define ERRFILE_r8169               ( ERRFILE_DRIVER | 0x003f0000 )
+#define ERRFILE_sis900              ( ERRFILE_DRIVER | 0x00400000 )
+#define ERRFILE_sundance            ( ERRFILE_DRIVER | 0x00410000 )
+#define ERRFILE_tlan                ( ERRFILE_DRIVER | 0x00420000 )
+#define ERRFILE_tulip               ( ERRFILE_DRIVER | 0x00430000 )
+#define ERRFILE_via_rhine           ( ERRFILE_DRIVER | 0x00440000 )
+#define ERRFILE_via_velocity        ( ERRFILE_DRIVER | 0x00450000 )
+#define ERRFILE_w89c840                     ( ERRFILE_DRIVER | 0x00460000 )
 
 #define ERRFILE_scsi                ( ERRFILE_DRIVER | 0x00700000 )
 
diff --git a/src/include/gpxe/features.h b/src/include/gpxe/features.h
new file mode 100644 (file)
index 0000000..a520131
--- /dev/null
@@ -0,0 +1,88 @@
+#ifndef _GPXE_FEATURES_H
+#define _GPXE_FEATURES_H
+
+#include <stdint.h>
+#include <gpxe/tables.h>
+#include <gpxe/dhcp.h>
+
+/** @file
+ *
+ * Feature list
+ *
+ */
+
+/**
+ * @defgroup featurecat Feature categories
+ * @{
+ */
+
+#define FEATURE_PROTOCOL               01 /**< Network protocols */
+#define FEATURE_IMAGE                  02 /**< Image formats */
+#define FEATURE_MISC                   03 /**< Miscellaneous */
+
+/** @} */
+
+/**
+ * @defgroup dhcpfeatures DHCP feature option tags
+ *
+ * DHCP feature option tags are Etherboot encapsulated options in the
+ * range 0x10-0x7f.
+ *
+ * @{
+ */
+
+#define DHCP_EB_FEATURE_PXE_EXT                0x10 /**< PXE API extensions */
+#define DHCP_EB_FEATURE_ISCSI          0x11 /**< iSCSI protocol */
+#define DHCP_EB_FEATURE_AOE            0x12 /**< AoE protocol */
+#define DHCP_EB_FEATURE_HTTP           0x13 /**< HTTP protocol */
+#define DHCP_EB_FEATURE_HTTPS          0x14 /**< HTTPS protocol */
+#define DHCP_EB_FEATURE_TFTP           0x15 /**< TFTP protocol */
+#define DHCP_EB_FEATURE_FTP            0x16 /**< FTP protocol */
+#define DHCP_EB_FEATURE_DNS            0x17 /**< DNS protocol */
+#define DHCP_EB_FEATURE_BZIMAGE                0x18 /**< bzImage format */
+#define DHCP_EB_FEATURE_MULTIBOOT      0x19 /**< Multiboot format */
+#define DHCP_EB_FEATURE_NBI            0x20 /**< NBI format */
+#define DHCP_EB_FEATURE_PXE            0x21 /**< PXE format */
+
+/** @} */
+
+/** Declare a feature code for DHCP */
+#define __dhcp_feature( category )                                         \
+        __table ( uint8_t, dhcp_features, category )
+
+/** Construct a DHCP feature table entry */
+#define DHCP_FEATURE( category, feature_opt, version )                     \
+       _DHCP_FEATURE ( category, OBJECT, feature_opt, version )
+#define _DHCP_FEATURE( category, _name, feature_opt, version )             \
+       __DHCP_FEATURE ( category, _name, feature_opt, version )
+#define __DHCP_FEATURE( category, _name, feature_opt, version )                    \
+       uint8_t __dhcp_feature_ ## _name [] __dhcp_feature ( category ) = { \
+               feature_opt, DHCP_BYTE ( version )                          \
+       };
+
+/** A named feature */
+struct feature {
+       /** Feature name */
+       char *name;
+};
+
+/** Declare a named feature */
+#define __feature_name( category )                                         \
+       __table ( struct feature, features, category )
+
+/** Construct a named feature */
+#define FEATURE_NAME( category, text )                                     \
+       _FEATURE_NAME ( category, OBJECT, text )
+#define _FEATURE_NAME( category, _name, text )                             \
+       __FEATURE_NAME ( category, _name, text )
+#define __FEATURE_NAME( category, _name, text )                                    \
+       struct feature __feature_ ## _name __feature_name ( category ) = {  \
+               .name = text,                                               \
+       };
+
+/** Declare a feature */
+#define FEATURE( category, text, feature_opt, version )                            \
+       FEATURE_NAME ( category, text );                                    \
+       DHCP_FEATURE ( category, feature_opt, version );
+
+#endif /* _GPXE_FEATURES_H */
index 70d2848..5eef547 100644 (file)
 #ifndef _GPXE_IBFT_H
 #define _GPXE_IBFT_H
 
-/* Placeholder file */
+/*
+ * Copyright Fen Systems Ltd. 2007.  Portions of this code are derived
+ * from IBM Corporation Sample Programs.  Copyright IBM Corporation
+ * 2004, 2007.  All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+/** @file
+ *
+ * iSCSI boot firmware table
+ *
+ * The information in this file is derived from the document "iSCSI
+ * Boot Firmware Table (iBFT)" as published by IBM at
+ *
+ * ftp://ftp.software.ibm.com/systems/support/system_x_pdf/ibm_iscsi_boot_firmware_table_v1.02.pdf
+ *
+ */
+
+#include <stdint.h>
+#include <gpxe/acpi.h>
+#include <gpxe/in.h>
+
+/** iSCSI Boot Firmware Table signature */
+#define IBFT_SIG "iBFT"
+
+/** An offset from the start of the iBFT */
+typedef uint16_t ibft_off_t;
+
+/** Length of a string within the iBFT (excluding terminating NUL) */
+typedef uint16_t ibft_size_t;
+
+/** A string within the iBFT */
+struct ibft_string {
+       /** Length of string */
+       ibft_size_t length;
+       /** Offset to string */
+       ibft_off_t offset;
+} __attribute__ (( packed ));
+
+/** An IP address within the iBFT */
+struct ibft_ipaddr {
+       /** Reserved; must be zero */
+       uint16_t zeroes[5];
+       /** Must be 0xffff if IPv4 address is present, otherwise zero */
+       uint16_t ones;
+       /** The IPv4 address, or zero if not present */
+       struct in_addr in;
+} __attribute__ (( packed ));
+
+/**
+ * iBFT structure header
+ *
+ * This structure is common to several sections within the iBFT.
+ */
+struct ibft_header {
+       /** Structure ID
+        *
+        * This is an IBFT_STRUCTURE_ID_XXX constant
+        */
+       uint8_t structure_id;
+       /** Version (always 1) */
+       uint8_t version;
+       /** Length, including this header */
+       uint16_t length;
+       /** Index 
+        *
+        * This is the number of the NIC or Target, when applicable.
+        */
+       uint8_t index;
+       /** Flags */
+       uint8_t flags;
+} __attribute__ (( packed ));
+
+/**
+ * iBFT Control structure
+ *
+ */
+struct ibft_control {
+       /** Common header */
+       struct ibft_header header;
+       /** Extensions */
+       uint16_t extensions;
+       /** Offset to Initiator structure */
+       ibft_off_t initiator;
+       /** Offset to NIC structure for NIC 0 */
+       ibft_off_t nic_0;
+       /** Offset to Target structure for target 0 */
+       ibft_off_t target_0;
+       /** Offset to NIC structure for NIC 1 */
+       ibft_off_t nic_1;
+       /** Offset to Target structure for target 1 */
+       ibft_off_t target_1;
+} __attribute__ (( packed ));
+
+/** Structure ID for Control section */
+#define IBFT_STRUCTURE_ID_CONTROL 0x01
+
+/** Attempt login only to specified target
+ *
+ * If this flag is not set, all targets will be logged in to.
+ */
+#define IBFT_FL_CONTROL_SINGLE_LOGIN_ONLY 0x01
+
+/**
+ * iBFT Initiator structure
+ *
+ */
+struct ibft_initiator {
+       /** Common header */
+       struct ibft_header header;
+       /** iSNS server */
+       struct ibft_ipaddr isns_server;
+       /** SLP server */
+       struct ibft_ipaddr slp_server;
+       /** Primary and secondary Radius servers */
+       struct ibft_ipaddr radius[2];
+       /** Initiator name */
+       struct ibft_string initiator_name;
+} __attribute__ (( packed ));
+
+/** Structure ID for Initiator section */
+#define IBFT_STRUCTURE_ID_INITIATOR 0x02
+
+/** Initiator block valid */
+#define IBFT_FL_INITIATOR_BLOCK_VALID 0x01
+
+/** Initiator firmware boot selected */
+#define IBFT_FL_INITIATOR_FIRMWARE_BOOT_SELECTED 0x02
+
+/**
+ * iBFT NIC structure
+ *
+ */
+struct ibft_nic {
+       /** Common header */
+       struct ibft_header header;
+       /** IP address */
+       struct ibft_ipaddr ip_address;
+       /** Subnet mask
+        *
+        * This is the length of the subnet mask in bits (e.g. /24).
+        */
+       uint8_t subnet_mask_prefix;
+       /** Origin */
+       uint8_t origin;
+       /** Default gateway */
+       struct ibft_ipaddr gateway;
+       /** Primary and secondary DNS servers */
+       struct ibft_ipaddr dns[2];
+       /** DHCP server */
+       struct ibft_ipaddr dhcp;
+       /** VLAN tag */
+       uint16_t vlan;
+       /** MAC address */
+       uint8_t mac_address[6];
+       /** PCI bus:dev:fn */
+       uint16_t pci_bus_dev_func;
+       /** Hostname */
+       struct ibft_string hostname;
+} __attribute__ (( packed ));
+
+/** Structure ID for NIC section */
+#define IBFT_STRUCTURE_ID_NIC 0x03
+
+/** NIC block valid */
+#define IBFT_FL_NIC_BLOCK_VALID 0x01
+
+/** NIC firmware boot selected */
+#define IBFT_FL_NIC_FIRMWARE_BOOT_SELECTED 0x02
+
+/** NIC global / link local */
+#define IBFT_FL_NIC_GLOBAL 0x04
+
+/**
+ * iBFT Target structure
+ *
+ */
+struct ibft_target {
+       /** Common header */
+       struct ibft_header header;
+       /** IP address */
+       struct ibft_ipaddr ip_address;
+       /** TCP port */
+       uint16_t socket;
+       /** Boot LUN */
+       uint64_t boot_lun;
+       /** CHAP type
+        *
+        * This is an IBFT_CHAP_XXX constant.
+        */
+       uint8_t chap_type;
+       /** NIC association */
+       uint8_t nic_association;
+       /** Target name */
+       struct ibft_string target_name;
+       /** CHAP name */
+       struct ibft_string chap_name;
+       /** CHAP secret */
+       struct ibft_string chap_secret;
+       /** Reverse CHAP name */
+       struct ibft_string reverse_chap_name;
+       /** Reverse CHAP secret */
+       struct ibft_string reverse_chap_secret;
+} __attribute__ (( packed ));
+
+/** Structure ID for Target section */
+#define IBFT_STRUCTURE_ID_TARGET 0x04
+
+/** Target block valid */
+#define IBFT_FL_TARGET_BLOCK_VALID 0x01
+
+/** Target firmware boot selected */
+#define IBFT_FL_TARGET_FIRMWARE_BOOT_SELECTED 0x02
+
+/** Target use Radius CHAP */
+#define IBFT_FL_TARGET_USE_CHAP 0x04
+
+/** Target use Radius rCHAP */
+#define IBFT_FL_TARGET_USE_RCHAP 0x08
+
+/* Values for chap_type */
+#define IBFT_CHAP_NONE         0       /**< No CHAP authentication */
+#define IBFT_CHAP_ONE_WAY      1       /**< One-way CHAP */
+#define IBFT_CHAP_MUTUAL       2       /**< Mutual CHAP */
+
+/**
+ * iSCSI Boot Firmware Table (iBFT)
+ */
+struct ibft_table {
+       /** ACPI header */
+       struct acpi_description_header acpi;
+       /** Reserved */
+       uint8_t reserved[12];
+       /** Control structure */
+       struct ibft_control control;
+} __attribute__ (( packed ));
+
+/**
+ * iSCSI string block descriptor
+ *
+ * This is an internal structure that we use to keep track of the
+ * allocation of string data.
+ */
+struct ibft_string_block {
+       /** The iBFT containing these strings */
+       struct ibft_table *table;
+       /** Offset of first free byte within iBFT */
+       unsigned int offset;
+};
+
+/** Amount of space reserved for strings in a gPXE iBFT */
+#define IBFT_STRINGS_SIZE 384
+
+/**
+ * An iBFT created by gPXE
+ *
+ */
+struct gpxe_ibft {
+       /** The fixed section */
+       struct ibft_table table;
+       /** The Initiator section */
+       struct ibft_initiator initiator __attribute__ (( aligned ( 16 ) ));
+       /** The NIC section */
+       struct ibft_nic nic __attribute__ (( aligned ( 16 ) ));
+       /** The Target section */
+       struct ibft_target target __attribute__ (( aligned ( 16 ) ));
+       /** Strings block */
+       char strings[IBFT_STRINGS_SIZE];
+} __attribute__ (( packed, aligned ( 16 ) ));
+
+struct net_device;
+struct iscsi_session;
+
+extern int ibft_fill_data ( struct net_device *netdev,
+                           struct iscsi_session *iscsi );
 
-static inline int ibft_fill_data ( struct net_device *netdev __unused,
-                                  struct iscsi_session *iscsi __unused ) {
-       return 0;
-}
 #endif /* _GPXE_IBFT_H */
index 7f09d9c..76dc3b8 100644 (file)
 #include <gpxe/uaccess.h>
 #include <gpxe/refcnt.h>
 
+struct uri;
 struct image_type;
 
-/** Maximum length of a command line */
-#define CMDLINE_MAX 128
-
 /** An executable or loadable image */
 struct image {
        /** Reference count */
        struct refcnt refcnt;
 
-       /** Name */
-       char name[16];
        /** List of registered images */
        struct list_head list;
+
+       /** URI of image */
+       struct uri *uri;
+       /** Name */
+       char name[16];
        /** Flags */
        unsigned int flags;
 
        /** Command line to pass to image */
-       char cmdline[CMDLINE_MAX];
+       char *cmdline;
        /** Raw file image */
        userptr_t data;
        /** Length of raw file image */
@@ -114,6 +115,8 @@ extern struct list_head images;
        list_for_each_entry ( (image), &images, list )
 
 extern struct image * alloc_image ( void );
+extern int image_set_uri ( struct image *image, struct uri *uri );
+extern int image_set_cmdline ( struct image *image, const char *cmdline );
 extern int register_image ( struct image *image );
 extern void unregister_image ( struct image *image );
 extern void promote_image ( struct image *image );
@@ -121,6 +124,8 @@ struct image * find_image ( const char *name );
 extern int image_load ( struct image *image );
 extern int image_autoload ( struct image *image );
 extern int image_exec ( struct image *image );
+extern int register_and_autoload_image ( struct image *image );
+extern int register_and_autoexec_image ( struct image *image );
 
 /**
  * Increment reference count on an image
@@ -142,4 +147,16 @@ static inline void image_put ( struct image *image ) {
        ref_put ( &image->refcnt );
 }
 
+/**
+ * Set image name
+ *
+ * @v image            Image
+ * @v name             New image name
+ * @ret rc             Return status code
+ */
+static inline int image_set_name ( struct image *image, const char *name ) {
+       strncpy ( image->name, name, ( sizeof ( image->name ) - 1 ) );
+       return 0;
+}
+
 #endif /* _GPXE_IMAGE_H */
index f6cebb6..aaa38d0 100644 (file)
@@ -10,6 +10,6 @@
 struct job_interface;
 
 extern struct job_interface monojob;
-extern int monojob_wait ( void );
+extern int monojob_wait ( const char *string );
 
 #endif /* _GPXE_MONOJOB_H */
index a5cf0c7..9984db0 100644 (file)
 #include <stdint.h>
 #include <gpxe/uaccess.h>
 
+/** Minimum file descriptor that will ever be allocated */
+#define POSIX_FD_MIN ( 1 )
+
+/** Maximum file descriptor that will ever be allocated */
+#define POSIX_FD_MAX ( 31 )
+
+/** File descriptor set as used for select() */
+typedef uint32_t fd_set;
+
 extern int open ( const char *uri_string );
 extern ssize_t read_user ( int fd, userptr_t buffer,
                           off_t offset, size_t len );
+extern int select ( fd_set *readfds, int wait );
 extern ssize_t fsize ( int fd );
 extern int close ( int fd );
 
+/**
+ * Zero a file descriptor set
+ *
+ * @v set              File descriptor set
+ */
+static inline __attribute__ (( always_inline )) void
+FD_ZERO ( fd_set *set ) {
+       *set = 0;
+}
+
+/**
+ * Set a bit within a file descriptor set
+ *
+ * @v fd               File descriptor
+ * @v set              File descriptor set
+ */
+static inline __attribute__ (( always_inline )) void
+FD_SET ( int fd, fd_set *set ) {
+       *set |= ( 1 << fd );
+}
+
+/**
+ * Clear a bit within a file descriptor set
+ *
+ * @v fd               File descriptor
+ * @v set              File descriptor set
+ */
+static inline __attribute__ (( always_inline )) void
+FD_CLR ( int fd, fd_set *set ) {
+       *set &= ~( 1 << fd );
+}
+
+/**
+ * Test a bit within a file descriptor set
+ *
+ * @v fd               File descriptor
+ * @v set              File descriptor set
+ * @ret is_set         Corresponding bit is set
+ */
+static inline __attribute__ (( always_inline )) int
+FD_ISSET ( int fd, fd_set *set ) {
+       return ( *set & ( 1 << fd ) );
+}
+
 /**
  * Read data from file
  *
index e0c0248..e71e7b3 100644 (file)
@@ -35,6 +35,7 @@ struct retry_timer {
 };
 
 extern void start_timer ( struct retry_timer *timer );
+extern void start_timer_nodelay ( struct retry_timer *timer );
 extern void stop_timer ( struct retry_timer *timer );
 
 /**
index b138931..514bc47 100644 (file)
@@ -94,7 +94,7 @@ static inline int uri_has_absolute_path ( struct uri *uri ) {
  * @v uri                      URI
  * @ret has_relative_path      URI has a relative path
  *
- * An relative path begins with something other than a '/'.  Note that
+ * A relative path begins with something other than a '/'.  Note that
  * this is a separate concept from a relative URI.  Note also that a
  * URI may not have a path at all.
  */
@@ -105,8 +105,8 @@ static inline int uri_has_relative_path ( struct uri *uri ) {
 /**
  * Increment URI reference count
  *
- * @v uri              URI
- * @ret uri            URI
+ * @v uri              URI, or NULL
+ * @ret uri            URI as passed in
  */
 static inline __attribute__ (( always_inline )) struct uri *
 uri_get ( struct uri *uri ) {
@@ -117,7 +117,7 @@ uri_get ( struct uri *uri ) {
 /**
  * Decrement URI reference count
  *
- * @v uri              URI
+ * @v uri              URI, or NULL
  */
 static inline __attribute__ (( always_inline )) void
 uri_put ( struct uri *uri ) {
index 301bb10..ecb664d 100644 (file)
@@ -58,6 +58,11 @@ union u_PXENV_ANY {
        struct s_PXENV_UNDI_GET_IFACE_INFO      undi_get_iface_info;
        struct s_PXENV_UNDI_GET_STATE           undi_get_state;
        struct s_PXENV_UNDI_ISR                 undi_isr;
+       struct s_PXENV_FILE_OPEN                file_open;
+       struct s_PXENV_FILE_CLOSE               file_close;
+       struct s_PXENV_FILE_SELECT              file_select;
+       struct s_PXENV_FILE_READ                file_read;
+       struct s_PXENV_GET_FILE_SIZE            get_file_size;
 };
 
 typedef union u_PXENV_ANY PXENV_ANY_t;
index e644132..8dc1607 100644 (file)
@@ -1555,6 +1555,137 @@ extern PXENV_EXIT_t pxenv_undi_isr ( struct s_PXENV_UNDI_ISR *undi_isr );
 
 /** @} */ /* pxe_undi_api */
 
+/** @defgroup pxe_file_api PXE FILE API
+ *
+ * POSIX-like file operations
+ *
+ * @{
+ */
+
+/** @defgroup pxenv_file_open PXENV_FILE_OPEN
+ *
+ * FILE OPEN
+ *
+ * @{
+ */
+
+/** PXE API function code for pxenv_file_open() */
+#define PXENV_FILE_OPEN                        0x00e0
+
+/** Parameter block for pxenv_file_open() */
+struct s_PXENV_FILE_OPEN {
+       PXENV_STATUS_t Status;          /**< PXE status code */
+       UINT16_t FileHandle;            /**< File handle */
+       SEGOFF16_t FileName;            /**< File URL */
+       UINT32_t Reserved;              /**< Reserved */
+} PACKED;
+
+typedef struct s_PXENV_FILE_OPEN PXENV_FILE_OPEN_t;
+
+extern PXENV_EXIT_t pxenv_file_open ( struct s_PXENV_FILE_OPEN *file_open );
+
+/** @} */ /* pxenv_file_open */
+
+/** @defgroup pxenv_file_close PXENV_FILE_CLOSE
+ *
+ * FILE CLOSE
+ *
+ * @{
+ */
+
+/** PXE API function code for pxenv_file_close() */
+#define PXENV_FILE_CLOSE               0x00e1
+
+/** Parameter block for pxenv_file_close() */
+struct s_PXENV_FILE_CLOSE {
+       PXENV_STATUS_t Status;          /**< PXE status code */
+       UINT16_t FileHandle;            /**< File handle */
+} PACKED;
+
+typedef struct s_PXENV_FILE_CLOSE PXENV_FILE_CLOSE_t;
+
+extern PXENV_EXIT_t pxenv_file_close ( struct s_PXENV_FILE_CLOSE
+                                      *file_close );
+
+/** @} */ /* pxenv_file_close */
+
+/** @defgroup pxenv_file_select PXENV_FILE_SELECT
+ *
+ * FILE SELECT
+ *
+ * @{
+ */
+
+/** PXE API function code for pxenv_file_select() */
+#define PXENV_FILE_SELECT              0x00e2
+
+/** File is ready for reading */
+#define RDY_READ                       0x0001
+
+/** Parameter block for pxenv_file_select() */
+struct s_PXENV_FILE_SELECT {
+       PXENV_STATUS_t Status;          /**< PXE status code */
+       UINT16_t FileHandle;            /**< File handle */
+       UINT16_t Ready;                 /**< Indication of readiness */
+} PACKED;
+
+typedef struct s_PXENV_FILE_SELECT PXENV_FILE_SELECT_t;
+
+extern PXENV_EXIT_t pxenv_file_select ( struct s_PXENV_FILE_SELECT
+                                       *file_select );
+
+/** @} */ /* pxenv_file_select */
+
+/** @defgroup pxenv_file_read PXENV_FILE_READ
+ *
+ * FILE READ
+ *
+ * @{
+ */
+
+/** PXE API function code for pxenv_file_read() */
+#define PXENV_FILE_READ                0x00e3
+
+/** Parameter block for pxenv_file_read() */
+struct s_PXENV_FILE_READ {
+       PXENV_STATUS_t Status;          /**< PXE status code */
+       UINT16_t FileHandle;            /**< File handle */
+       UINT16_t BufferSize;            /**< Data buffer size */
+       SEGOFF16_t Buffer;              /**< Data buffer */
+} PACKED;
+
+typedef struct s_PXENV_FILE_READ PXENV_FILE_READ_t;
+
+extern PXENV_EXIT_t pxenv_file_read ( struct s_PXENV_FILE_READ *file_read );
+
+/** @} */ /* pxenv_file_read */
+
+/** @defgroup pxenv_get_file_size PXENV_GET_FILE_SIZE
+ *
+ * GET FILE SIZE
+ *
+ * @{
+ */
+
+/** PXE API function code for pxenv_get_file_size() */
+#define PXENV_GET_FILE_SIZE            0x00e4
+
+/** Parameter block for pxenv_get_file_size() */
+struct s_PXENV_GET_FILE_SIZE {
+       PXENV_STATUS_t Status;          /**< PXE status code */
+       UINT16_t FileHandle;            /**< File handle */
+       UINT32_t FileSize;              /**< File size */
+} PACKED;
+
+typedef struct s_PXENV_GET_FILE_SIZE PXENV_GET_FILE_SIZE_t;
+
+extern PXENV_EXIT_t pxenv_get_file_size ( struct s_PXENV_GET_FILE_SIZE
+                                         *get_file_size );
+
+/** @} */ /* pxenv_get_file_size */
+
+/** @} */ /* pxe_file_api */
+
 /** @defgroup pxe_loader_api PXE Loader API
  *
  * The UNDI ROM loader API
diff --git a/src/include/stdint.h b/src/include/stdint.h
new file mode 100644 (file)
index 0000000..4b0e44f
--- /dev/null
@@ -0,0 +1,24 @@
+#ifndef _STDINT_H
+#define _STDINT_H
+
+#include <bits/stdint.h>
+
+typedef int8_t s8;
+typedef uint8_t u8;
+typedef int16_t s16;
+typedef uint16_t u16;
+typedef int32_t s32;
+typedef uint32_t u32;
+typedef int64_t s64;
+typedef uint64_t u64;
+
+typedef int8_t int8;
+typedef uint8_t uint8;
+typedef int16_t int16;
+typedef uint16_t uint16;
+typedef int32_t int32;
+typedef uint32_t uint32;
+typedef int64_t int64;
+typedef uint64_t uint64;
+
+#endif /* _STDINT_H */
index b3cbffb..438af00 100644 (file)
@@ -9,7 +9,8 @@
 
 struct image;
 
-extern int imgfetch ( struct image *image, const char *filename, int load );
+extern int imgfetch ( struct image *image, const char *uri_string,
+                     int ( * image_register ) ( struct image *image ) );
 extern int imgload ( struct image *image );
 extern int imgexec ( struct image *image );
 extern struct image * imgautoselect ( void );
diff --git a/src/interface/pxe/pxe_file.c b/src/interface/pxe/pxe_file.c
new file mode 100644 (file)
index 0000000..01dac8f
--- /dev/null
@@ -0,0 +1,191 @@
+/** @file
+ *
+ * PXE FILE API
+ *
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <byteswap.h>
+#include <gpxe/uaccess.h>
+#include <gpxe/posix_io.h>
+#include <gpxe/features.h>
+#include <pxe.h>
+
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FEATURE ( FEATURE_MISC, "PXEXT", DHCP_EB_FEATURE_PXE_EXT, 1 );
+
+/**
+ * FILE OPEN
+ *
+ * @v file_open                                Pointer to a struct s_PXENV_FILE_OPEN
+ * @v s_PXENV_FILE_OPEN::FileName      URL of file to open
+ * @ret #PXENV_EXIT_SUCCESS            File was opened
+ * @ret #PXENV_EXIT_FAILURE            File was not opened
+ * @ret s_PXENV_FILE_OPEN::Status      PXE status code
+ * @ret s_PXENV_FILE_OPEN::FileHandle  Handle of opened file
+ *
+ */
+PXENV_EXIT_t pxenv_file_open ( struct s_PXENV_FILE_OPEN *file_open ) {
+       userptr_t filename;
+       size_t filename_len;
+       int fd;
+
+       DBG ( "PXENV_FILE_OPEN" );
+
+       /* Copy name from external program, and open it */
+       filename = real_to_user ( file_open->FileName.segment,
+                             file_open->FileName.offset );
+       filename_len = strlen_user ( filename, 0 );
+       {
+               char uri_string[ filename_len + 1 ];
+
+               copy_from_user ( uri_string, filename, 0,
+                                sizeof ( uri_string ) );
+               DBG ( " %s", uri_string );
+               fd = open ( uri_string );
+       }
+
+       if ( fd < 0 ) {
+               file_open->Status = PXENV_STATUS ( fd );
+               return PXENV_EXIT_FAILURE;
+       }
+
+       DBG ( " as file %d", fd );
+
+       file_open->FileHandle = fd;
+       file_open->Status = PXENV_STATUS_SUCCESS;
+       return PXENV_EXIT_SUCCESS;
+}
+
+/**
+ * FILE CLOSE
+ *
+ * @v file_close                       Pointer to a struct s_PXENV_FILE_CLOSE
+ * @v s_PXENV_FILE_CLOSE::FileHandle   File handle
+ * @ret #PXENV_EXIT_SUCCESS            File was closed
+ * @ret #PXENV_EXIT_FAILURE            File was not closed
+ * @ret s_PXENV_FILE_CLOSE::Status     PXE status code
+ *
+ */
+PXENV_EXIT_t pxenv_file_close ( struct s_PXENV_FILE_CLOSE *file_close ) {
+
+       DBG ( "PXENV_FILE_CLOSE %d", file_close->FileHandle );
+
+       close ( file_close->FileHandle );
+       file_close->Status = PXENV_STATUS_SUCCESS;
+       return PXENV_EXIT_SUCCESS;
+}
+
+/**
+ * FILE SELECT
+ *
+ * @v file_select                      Pointer to a struct s_PXENV_FILE_SELECT
+ * @v s_PXENV_FILE_SELECT::FileHandle  File handle
+ * @ret #PXENV_EXIT_SUCCESS            File has been checked for readiness
+ * @ret #PXENV_EXIT_FAILURE            File has not been checked for readiness
+ * @ret s_PXENV_FILE_SELECT::Status    PXE status code
+ * @ret s_PXENV_FILE_SELECT::Ready     Indication of readiness
+ *
+ */
+PXENV_EXIT_t pxenv_file_select ( struct s_PXENV_FILE_SELECT *file_select ) {
+       fd_set fdset;
+       int ready;
+
+       DBG ( "PXENV_FILE_SELECT %d", file_select->FileHandle );
+
+       FD_ZERO ( &fdset );
+       FD_SET ( file_select->FileHandle, &fdset );
+       if ( ( ready = select ( &fdset, 0 ) ) < 0 ) {
+               file_select->Status = PXENV_STATUS ( ready );
+               return PXENV_EXIT_FAILURE;
+       }
+
+       file_select->Ready = ( ready ? RDY_READ : 0 );
+       file_select->Status = PXENV_STATUS_SUCCESS;
+       return PXENV_EXIT_SUCCESS;
+}
+
+/**
+ * FILE READ
+ *
+ * @v file_read                                Pointer to a struct s_PXENV_FILE_READ
+ * @v s_PXENV_FILE_READ::FileHandle    File handle
+ * @v s_PXENV_FILE_READ::BufferSize    Size of data buffer
+ * @v s_PXENV_FILE_READ::Buffer                Data buffer
+ * @ret #PXENV_EXIT_SUCCESS            Data has been read from file
+ * @ret #PXENV_EXIT_FAILURE            Data has not been read from file
+ * @ret s_PXENV_FILE_READ::Status      PXE status code
+ * @ret s_PXENV_FILE_READ::Ready       Indication of readiness
+ * @ret s_PXENV_FILE_READ::BufferSize  Length of data read
+ *
+ */
+PXENV_EXIT_t pxenv_file_read ( struct s_PXENV_FILE_READ *file_read ) {
+       userptr_t buffer;
+       ssize_t len;
+
+       DBG ( "PXENV_FILE_READ %d to %04x:%04x+%04x", file_read->FileHandle,
+             file_read->Buffer.segment, file_read->Buffer.offset,
+             file_read->BufferSize );
+
+       buffer = real_to_user ( file_read->Buffer.segment,
+                               file_read->Buffer.offset );
+       if ( ( len = read_user ( file_read->FileHandle, buffer, 0,
+                               file_read->BufferSize ) ) < 0 ) {
+               file_read->Status = PXENV_STATUS ( len );
+               return PXENV_EXIT_FAILURE;
+       }
+
+       DBG ( " read %04zx", ( ( size_t ) len ) );
+
+       file_read->BufferSize = len;
+       file_read->Status = PXENV_STATUS_SUCCESS;
+       return PXENV_EXIT_SUCCESS;
+}
+
+/**
+ * GET FILE SIZE
+ *
+ * @v get_file_size                    Pointer to a struct s_PXENV_GET_FILE_SIZE
+ * @v s_PXENV_GET_FILE_SIZE::FileHandle        File handle
+ * @ret #PXENV_EXIT_SUCCESS            File size has been determined
+ * @ret #PXENV_EXIT_FAILURE            File size has not been determined
+ * @ret s_PXENV_GET_FILE_SIZE::Status  PXE status code
+ * @ret s_PXENV_GET_FILE_SIZE::FileSize        Size of file
+ */
+PXENV_EXIT_t pxenv_get_file_size ( struct s_PXENV_GET_FILE_SIZE
+                                  *get_file_size ) {
+       ssize_t filesize;
+
+       DBG ( "PXENV_GET_FILE_SIZE %d", get_file_size->FileHandle );
+
+       filesize = fsize ( get_file_size->FileHandle );
+       if ( filesize < 0 ) {
+               get_file_size->Status = PXENV_STATUS ( filesize );
+               return PXENV_EXIT_FAILURE;
+       }
+
+       DBG ( " is %zd", ( ( size_t ) filesize ) );
+
+       get_file_size->FileSize = filesize;
+       get_file_size->Status = PXENV_STATUS_SUCCESS;
+       return PXENV_EXIT_SUCCESS;
+}
index 5197a63..64f7ffd 100644 (file)
@@ -78,6 +78,37 @@ static void pxe_tftp_build_uri ( char *uri_string,
                   ( ( filename[0] == '/' ) ? "" : "/" ), filename );
 }
 
+/**
+ * Read as much as possible from file
+ *
+ * @v fd                               File descriptor
+ * @v buffer                           Data buffer
+ * @v max_len                          Maximum length to read
+ * @ret len                            Actual length read, or negative error
+ */
+static ssize_t pxe_tftp_read_all ( int fd, userptr_t buffer,
+                                  size_t max_len ) {
+       fd_set fdset;
+       off_t offset = 0;
+       int ready;
+       ssize_t len;
+
+       do {
+               FD_ZERO ( &fdset );
+               FD_SET ( fd, &fdset );
+               ready = select ( &fdset, 1 );
+               if ( ready < 0 )
+                       return ready;
+               len = read_user ( fd, buffer, offset, max_len );
+               if ( len < 0 )
+                       return len;
+               offset += len;
+               max_len -= len;
+       } while ( max_len && len );
+
+       return offset;
+}
+
 /**
  * TFTP OPEN
  *
@@ -251,11 +282,12 @@ PXENV_EXIT_t pxenv_tftp_read ( struct s_PXENV_TFTP_READ *tftp_read ) {
 
        buffer = real_to_user ( tftp_read->Buffer.segment,
                                tftp_read->Buffer.offset );
-       len = read_user ( pxe_single_fd, buffer, 0, pxe_single_blksize );
+       len = pxe_tftp_read_all ( pxe_single_fd, buffer, pxe_single_blksize );
        if ( len < 0 ) {
                tftp_read->Status = PXENV_STATUS ( len );
                return PXENV_EXIT_FAILURE;
        }
+
        tftp_read->BufferSize = len;
        tftp_read->PacketNumber = ++pxe_single_blkidx;
 
@@ -359,10 +391,8 @@ PXENV_EXIT_t pxenv_tftp_read_file ( struct s_PXENV_TFTP_READ_FILE
        char uri_string[PXE_URI_LEN];
        int fd;
        userptr_t buffer;
-       size_t max_len;
-       ssize_t frag_len;
-       size_t len = 0;
-       int rc = -ENOBUFS;
+       ssize_t len;
+       int rc = 0;
 
        DBG ( "PXENV_TFTP_READ_FILE" );
 
@@ -384,16 +414,9 @@ PXENV_EXIT_t pxenv_tftp_read_file ( struct s_PXENV_TFTP_READ_FILE
 
        /* Read file */
        buffer = phys_to_user ( tftp_read_file->Buffer );
-       max_len = tftp_read_file->BufferSize;
-       while ( max_len ) {
-               frag_len = read_user ( fd, buffer, len, max_len );
-               if ( frag_len <= 0 ) {
-                       rc = frag_len;
-                       break;
-               }
-               len += frag_len;
-               max_len -= frag_len;
-       }
+       len = pxe_tftp_read_all ( fd, buffer, tftp_read_file->BufferSize );
+       if ( len < 0 )
+               rc = len;
 
        close ( fd );
        tftp_read_file->BufferSize = len;
index fd82665..e3f84e5 100644 (file)
@@ -31,6 +31,7 @@
 #include <gpxe/ata.h>
 #include <gpxe/netdevice.h>
 #include <gpxe/process.h>
+#include <gpxe/features.h>
 #include <gpxe/aoe.h>
 
 /** @file
@@ -39,6 +40,8 @@
  *
  */
 
+FEATURE ( FEATURE_PROTOCOL, "AoE", DHCP_EB_FEATURE_AOE, 1 );
+
 struct net_protocol aoe_protocol;
 
 /** List of all AoE sessions */
index c228f09..c07ff94 100644 (file)
@@ -19,10 +19,7 @@ struct net_protocol ipv6_protocol;
 
 /* Unspecified IP6 address */
 static struct in6_addr ip6_none = {
-        .in6_u.u6_addr32[0] = 0,
-        .in6_u.u6_addr32[1] = 0,
-        .in6_u.u6_addr32[2] = 0,
-        .in6_u.u6_addr32[3] = 0,
+        .in6_u.u6_addr32 = { 0,0,0,0 }
 };
 
 /** An IPv6 routing table entry */
index 6734968..0f711e6 100644 (file)
@@ -73,6 +73,18 @@ void start_timer ( struct retry_timer *timer ) {
               timer, timer->start, ( timer->start + timer->timeout ) );
 }
 
+/**
+ * Start timer with no delay
+ *
+ * @v timer            Retry timer
+ *
+ * This starts the timer running with a zero timeout value.
+ */
+void start_timer_nodelay ( struct retry_timer *timer ) {
+       start_timer ( timer );
+       timer->timeout = 0;
+}
+
 /**
  * Stop timer
  *
index 01daf75..28cf95f 100644 (file)
@@ -232,7 +232,7 @@ static int tcp_open ( struct xfer_interface *xfer, struct sockaddr *peer,
                goto err;
 
        /* Start timer to initiate SYN */
-       start_timer ( &tcp->timer );
+       start_timer_nodelay ( &tcp->timer );
 
        /* Attach parent interface, transfer reference to connection
         * list and return
index 646638a..0e4d969 100644 (file)
@@ -11,6 +11,7 @@
 #include <gpxe/xfer.h>
 #include <gpxe/open.h>
 #include <gpxe/uri.h>
+#include <gpxe/features.h>
 #include <gpxe/ftp.h>
 
 /** @file
@@ -19,6 +20,8 @@
  *
  */
 
+FEATURE ( FEATURE_PROTOCOL, "FTP", DHCP_EB_FEATURE_FTP, 1 );
+
 /**
  * FTP states
  *
index 727c033..2a5450e 100644 (file)
 #include <gpxe/tcpip.h>
 #include <gpxe/process.h>
 #include <gpxe/linebuf.h>
+#include <gpxe/features.h>
 #include <gpxe/http.h>
 
+FEATURE ( FEATURE_PROTOCOL, "HTTP", DHCP_EB_FEATURE_HTTP, 1 );
+
 /** HTTP receive state */
 enum http_rx_state {
        HTTP_RX_RESPONSE = 0,
index 148e4bf..15ab32e 100644 (file)
@@ -27,6 +27,9 @@
 #include <gpxe/open.h>
 #include <gpxe/tls.h>
 #include <gpxe/http.h>
+#include <gpxe/features.h>
+
+FEATURE ( FEATURE_PROTOCOL, "HTTPS", DHCP_EB_FEATURE_HTTPS, 1 );
 
 /**
  * Initiate an HTTPS connection
index e645917..ccb6cff 100644 (file)
@@ -32,6 +32,7 @@
 #include <gpxe/uaccess.h>
 #include <gpxe/tcpip.h>
 #include <gpxe/dhcp.h>
+#include <gpxe/features.h>
 #include <gpxe/iscsi.h>
 
 /** @file
@@ -40,6 +41,8 @@
  *
  */
 
+FEATURE ( FEATURE_PROTOCOL, "iSCSI", DHCP_EB_FEATURE_ISCSI, 1 );
+
 /** iSCSI initiator name (explicitly specified) */
 static char *iscsi_explicit_initiator_iqn;
 
index f8f59e2..86695f1 100644 (file)
@@ -70,6 +70,10 @@ static uint8_t dhcp_request_options_data[] = {
        DHCP_END
 };
 
+/** DHCP feature codes */
+static uint8_t dhcp_features[0] __table_start ( uint8_t, dhcp_features );
+static uint8_t dhcp_features_end[0] __table_end ( uint8_t, dhcp_features );
+
 /**
  * Name a DHCP packet type
  *
@@ -508,6 +512,7 @@ int create_dhcp_request ( struct net_device *netdev, int msgtype,
                          struct dhcp_packet *dhcppkt ) {
        struct device_description *desc = &netdev->dev->desc;
        struct dhcp_netdev_desc dhcp_desc;
+       size_t dhcp_features_len;
        int rc;
 
        /* Create DHCP packet */
@@ -544,6 +549,16 @@ int create_dhcp_request ( struct net_device *netdev, int msgtype,
                }
        }
 
+       /* Add options to identify the feature list */
+       dhcp_features_len = ( dhcp_features_end - dhcp_features );
+       if ( ( rc = set_dhcp_packet_option ( dhcppkt, DHCP_EB_ENCAP,
+                                            dhcp_features,
+                                            dhcp_features_len ) ) != 0 ) {
+               DBG ( "DHCP could not set features list option: %s\n",
+                     strerror ( rc ) );
+               return rc;
+       }
+
        /* Add options to identify the network device */
        dhcp_desc.type = desc->bus_type;
        dhcp_desc.vendor = htons ( desc->vendor );
@@ -897,7 +912,7 @@ int start_dhcp ( struct job_interface *job, struct net_device *netdev,
                goto err;
 
        /* Start timer to initiate initial DHCPREQUEST */
-       start_timer ( &dhcp->timer );
+       start_timer_nodelay ( &dhcp->timer );
 
        /* Attach parent interface, mortalise self, and return */
        job_plug_plug ( &dhcp->job, job );
index b141eea..f32b2e0 100644 (file)
@@ -31,6 +31,7 @@
 #include <gpxe/retry.h>
 #include <gpxe/tcpip.h>
 #include <gpxe/dhcp.h>
+#include <gpxe/features.h>
 #include <gpxe/dns.h>
 
 /** @file
@@ -39,6 +40,8 @@
  *
  */
 
+FEATURE ( FEATURE_PROTOCOL, "DNS", DHCP_EB_FEATURE_DNS, 1 );
+
 /** The DNS server */
 static struct sockaddr_tcpip nameserver = {
        .st_port = htons ( DNS_PORT ),
index 106c704..7f1c4ce 100644 (file)
@@ -30,6 +30,7 @@
 #include <gpxe/uri.h>
 #include <gpxe/tcpip.h>
 #include <gpxe/retry.h>
+#include <gpxe/features.h>
 #include <gpxe/tftp.h>
 
 /** @file
@@ -38,6 +39,8 @@
  *
  */
 
+FEATURE ( FEATURE_PROTOCOL, "TFTP", DHCP_EB_FEATURE_TFTP, 1 );
+
 /**
  * A TFTP request
  *
@@ -654,7 +657,7 @@ int tftp_open ( struct xfer_interface *xfer, struct uri *uri ) {
                goto err;
 
        /* Start timer to initiate RRQ */
-       start_timer ( &tftp->timer );
+       start_timer_nodelay ( &tftp->timer );
 
        /* Attach to parent interface, mortalise self, and return */
        xfer_plug_plug ( &tftp->xfer, xfer );
index 53283d1..9183697 100644 (file)
@@ -60,26 +60,21 @@ static int boot_filename ( const char *filename ) {
                printf ( "Out of memory\n" );
                return -ENOMEM;
        }
-       if ( ( rc = imgfetch ( image, filename, 0 ) ) != 0 ) {
-               printf ( "Could not retrieve %s: %s\n",
+       if ( ( rc = imgfetch ( image, filename,
+                              register_and_autoload_image ) ) != 0 ) {
+               printf ( "Could not load %s: %s\n",
                         filename, strerror ( rc ) );
-               image_put ( image );
-               return rc;
-       }
-       if ( ( rc = imgload ( image ) ) != 0 ) {
-               printf ( "Could not load %s: %s\n", image->name,
-                        strerror ( rc ) );
-               image_put ( image );
-               return rc;
+               goto done;
        }
        if ( ( rc = imgexec ( image ) ) != 0 ) {
-               printf ( "Could not execute %s: %s\n", image->name,
-                        strerror ( rc ) );
-               image_put ( image );
-               return rc;
+               printf ( "Could not boot %s: %s\n",
+                        filename, strerror ( rc ) );
+               goto done;
        }
 
-       return 0;
+ done:
+       image_put ( image );
+       return rc;
 }
 
 /**
index f1eb2d6..bd05c5e 100644 (file)
@@ -56,15 +56,9 @@ int dhcp ( struct net_device *netdev ) {
        }
 
        /* Perform DHCP */
-       printf ( "DHCP (%s %s)...", netdev->name, netdev_hwaddr ( netdev ) );
+       printf ( "DHCP (%s %s)", netdev->name, netdev_hwaddr ( netdev ) );
        if ( ( rc = start_dhcp ( &monojob, netdev, dhcp_success ) ) == 0 )
-               rc = monojob_wait();
-
-       if ( rc == 0 ) {
-               printf ( "done\n" );
-       } else {
-               printf ( "failed (%s)\n", strerror ( rc ) );
-       }
+               rc = monojob_wait ( "" );
 
        return rc;
 }
index ab4897b..bead486 100644 (file)
@@ -24,6 +24,7 @@
 #include <gpxe/downloader.h>
 #include <gpxe/monojob.h>
 #include <gpxe/open.h>
+#include <gpxe/uri.h>
 #include <usr/imgmgmt.h>
 
 /** @file
  *
  */
 
-static int imgfetch_autoload ( struct image *image ) {
-       int rc;
-
-       if ( ( rc = register_image ( image ) ) != 0 )
-               return rc;
-
-       if ( ( rc = image_autoload ( image ) ) != 0 )
-               return rc;
-
-       return 0;
-}
-
 /**
  * Fetch an image
  *
  * @v uri_string       URI as a string (e.g. "http://www.nowhere.com/vmlinuz")
  * @v name             Name for image, or NULL
- * @ret new_image      Newly created image
+ * @v register_image   Image registration routine
  * @ret rc             Return status code
  */
-int imgfetch ( struct image *image, const char *uri_string, int load ) {
+int imgfetch ( struct image *image, const char *uri_string,
+              int ( * image_register ) ( struct image *image ) ) {
+       struct uri *uri;
        int rc;
 
-       if ( ( rc = create_downloader ( &monojob, image, 
-                                       ( load ? imgfetch_autoload :
-                                         register_image ),
-                                       LOCATION_URI_STRING,
-                                       uri_string ) ) == 0 )
-               rc = monojob_wait();
+       if ( ! ( uri = parse_uri ( uri_string ) ) )
+               return -ENOMEM;
+
+       image_set_uri ( image, uri );
+
+       if ( ( rc = create_downloader ( &monojob, image, image_register,
+                                       LOCATION_URI, uri ) ) == 0 )
+               rc = monojob_wait ( uri_string );
 
+       uri_put ( uri );
        return rc;
 }
 
@@ -118,7 +112,7 @@ void imgstat ( struct image *image ) {
                printf ( " [%s]", image->type->name );
        if ( image->flags & IMAGE_LOADED )
                printf ( " [LOADED]" );
-       if ( image->cmdline[0] )
+       if ( image->cmdline )
                printf ( " \"%s\"", image->cmdline );
        printf ( "\n" );
 }