]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[image] Allow multiple embedded images
authorMichael Brown <mcb30@etherboot.org>
Mon, 16 Feb 2009 00:28:30 +0000 (00:28 +0000)
committerMichael Brown <mcb30@etherboot.org>
Mon, 16 Feb 2009 00:30:36 +0000 (00:30 +0000)
This patch extends the embedded image feature to allow multiple
embedded images instead of just one.

gPXE now always boots the first embedded image on startup instead of
doing the hardcoded DHCP boot (aka autoboot).

Based heavily upon a patch by Stefan Hajnoczi <stefanha@gmail.com>.

12 files changed:
contrib/scripts/gpxelinux.gpxe [new file with mode: 0644]
contrib/scripts/static.gpxe [new file with mode: 0644]
src/Makefile.housekeeping
src/core/config.c
src/core/main.c
src/image/default.gpxe [new file with mode: 0644]
src/image/embed.S [deleted file]
src/image/embedded.c
src/include/gpxe/embedded.h [deleted file]
src/include/gpxe/errfile.h
src/include/gpxe/uri.h
src/usr/autoboot.c

diff --git a/contrib/scripts/gpxelinux.gpxe b/contrib/scripts/gpxelinux.gpxe
new file mode 100644 (file)
index 0000000..dcfc80e
--- /dev/null
@@ -0,0 +1,4 @@
+#!gpxe
+dhcp net0
+imgload img1
+boot img1
diff --git a/contrib/scripts/static.gpxe b/contrib/scripts/static.gpxe
new file mode 100644 (file)
index 0000000..e3539fc
--- /dev/null
@@ -0,0 +1,8 @@
+#!gpxe
+ifopen net0
+set net0/ip 10.0.2.15
+set net0/netmask 255.255.255.0
+set net0/gateway 10.0.2.2
+set net0/dns 10.0.2.3
+kernel http://etherboot.org/gtest/gtest.gpxe
+boot gtest.gpxe
index ab6f29c2331ba7e6633db856798193dd18e0031b..d8413447cfe93f090a9a92d322f184b473256111 100644 (file)
@@ -85,6 +85,13 @@ VERYCLEANUP  += .toolcheck
 # Check for various tool workarounds
 #
 
+# Make syntax does not allow use of comma or space in certain places.
+# This ugly workaround is suggested in the manual.
+#
+COMMA  := ,
+EMPTY  :=
+SPACE  := $(EMPTY) $(EMPTY)
+
 # Check for an old version of gas (binutils 2.9.1)
 #
 OLDGAS := $(shell $(AS) --version | grep -q '2\.9\.1' && $(ECHO) -DGAS291)
@@ -280,9 +287,9 @@ ASFLAGS             += --fatal-warnings
 ASFLAGS                += $(EXTRA_ASFLAGS)
 LDFLAGS                += $(EXTRA_LDFLAGS)
 
-# Embedded image, if present
+# Embedded image(s), or default if not set
 #
-EMBEDDED_IMAGE = /dev/null
+EMBEDDED_IMAGE = image/default.gpxe
 
 # Inhibit -Werror if NO_WERROR is specified on make command line
 #
@@ -406,13 +413,31 @@ drivers :
 roms :
        @$(ECHO) $(ROMS)
 
-# Embedded binary
-$(BIN)/embedimg.bin: $(EMBEDDED_IMAGE)
-       $(QM)$(ECHO) "  [COPY] $@"
-       $(Q)$(CP) -f $(EMBEDDED_IMAGE) $@
+# List of embedded images included in the last build of embedded.o.
+# This is needed in order to correctly rebuild embedded.o whenever the
+# list of objects changes.
+#
+EMBEDDED_LIST  := $(BIN)/.embedded.list
+ifeq ($(wildcard $(EMBEDDED_LIST)),)
+EMBEDDED_LIST_IMAGE :=
+else
+EMBEDDED_LIST_IMAGE := $(shell cat $(EMBEDDED_LIST))
+endif
+ifneq ($(EMBEDDED_LIST_IMAGE),$(EMBEDDED_IMAGE))
+$(shell $(ECHO) "$(EMBEDDED_IMAGE)" > $(EMBEDDED_LIST))
+endif
+
+$(EMBEDDED_LIST) :
+
+VERYCLEANUP    += $(EMBEDDED_LIST)
+
+EMBEDDED_FILES := $(subst $(COMMA), ,$(EMBEDDED_IMAGE))
+EMBED_ALL      := $(foreach i,$(shell seq 1 $(words $(EMBEDDED_FILES))),\
+                    EMBED ( $(i), \"$(word $(i), $(EMBEDDED_FILES))\",\
+                            \"$(notdir $(word $(i),$(EMBEDDED_FILES)))\" ))
 
-$(BIN)/embed.o: $(BIN)/embedimg.bin
-CFLAGS_embed = -DEMBEDIMG=\"$(BIN)/embedimg.bin\"
+$(BIN)/embedded.o : $(EMBEDDED_FILES) $(EMBEDDED_LIST)
+CFLAGS_embedded = -DEMBED_ALL="$(EMBED_ALL)"
 
 # Generate the NIC file from the parsed source files.  The NIC file is
 # only for rom-o-matic.
@@ -491,7 +516,6 @@ TGT_MAKEROM_FLAGS = $(strip $(MAKEROM_FLAGS_$(TGT_ROM_NAME)) \
 # Calculate list of debugging versions of objects to be included in
 # the target.
 #
-COMMA          := ,
 DEBUG_LIST     = $(subst $(COMMA), ,$(DEBUG))
 DEBUG_OBJ_LEVEL        = $(firstword $(word 2,$(subst :, ,$(1))) 1)
 DEBUG_OBJ_BASE = $(word 1,$(subst :, ,$(1))).dbg$(call DEBUG_OBJ_LEVEL,$(1))
index b14d25a8df30aeaf75af8bee47c5e801d37e82b9..741579feb467aea216964a536d09a679ca8eb016 100644 (file)
@@ -218,3 +218,4 @@ REQUIRE_OBJECT ( gdbstub_cmd );
  *
  */
 REQUIRE_OBJECT ( device );
+REQUIRE_OBJECT ( embedded );
index e72b8c9025dc867bab5dd9fdb86292a5bd438103..8d360c4236008dab0105b285d951a4c5eb76eb28 100644 (file)
@@ -19,6 +19,7 @@ Literature dealing with the network protocols:
 #include <gpxe/features.h>
 #include <gpxe/shell.h>
 #include <gpxe/shell_banner.h>
+#include <gpxe/image.h>
 #include <usr/autoboot.h>
 #include <config/general.h>
 
@@ -36,6 +37,7 @@ static struct feature features_end[0] __table_end ( struct feature, features );
  */
 __asmcall int main ( void ) {
        struct feature *feature;
+       struct image *image;
 
        /* Some devices take an unreasonably long time to initialise */
        printf ( PRODUCT_SHORT_NAME " initialising devices...\n" );
@@ -68,11 +70,16 @@ __asmcall int main ( void ) {
                /* User wants shell; just give them a shell */
                shell();
        } else {
-               /* User doesn't want shell; try booting.  If booting
-                * fails, offer a second chance to enter the shell for
-                * diagnostics.
+               /* User doesn't want shell; load and execute the first
+                * image.  If booting fails (i.e. if the image
+                * returns, or fails to execute), offer a second
+                * chance to enter the shell for diagnostics.
                 */
-               autoboot();
+               for_each_image ( image ) {
+                       image_exec ( image );
+                       break;
+               }
+
                if ( shell_banner() )
                        shell();
        }
diff --git a/src/image/default.gpxe b/src/image/default.gpxe
new file mode 100644 (file)
index 0000000..0b080b5
--- /dev/null
@@ -0,0 +1,2 @@
+#!gpxe
+autoboot
diff --git a/src/image/embed.S b/src/image/embed.S
deleted file mode 100644 (file)
index ef7d693..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-       .section ".data", "aw", @progbits
-       .balign 4
-       .globl _embedded_image_start
-_embedded_image_start:
-       .incbin EMBEDIMG
-       .globl _embedded_image_end
-_embedded_image_end:
index 0ce097833f10087933827f1412dfa98c0cd32717..f76ca11b6c1c4d49cea54beb4f43b49c7c05b857 100644 (file)
@@ -1,49 +1,94 @@
 /** @file
  *
- * Take a possible embedded image and put it in a struct image
- * data structure.
+ * Embedded image support
+ *
+ * Embedded images are images built into the gPXE binary and do not require
+ * fetching over the network.
  */
 
+#include <string.h>
 #include <gpxe/image.h>
-#include <gpxe/malloc.h>
 #include <gpxe/uaccess.h>
-#include <gpxe/umalloc.h>
-#include <gpxe/embedded.h>
+#include <gpxe/init.h>
 
-extern char _embedded_image_start[], _embedded_image_end[];
+/**
+ * Free embedded image
+ *
+ * @v refcnt           Reference counter
+ */
+static void embedded_image_free ( struct refcnt *refcnt __unused ) {
+       /* Do nothing */
+}
 
-struct image *embedded_image(void)
-{
-       static int reclaimed = 0;
-       struct image *image;
-       size_t eisize = _embedded_image_end - _embedded_image_start;
+/* Raw image data for all embedded images */
+#undef EMBED
+#define EMBED( _index, _path, _name )                                  \
+       extern char embedded_image_ ## _index ## _data[];               \
+       extern char embedded_image_ ## _index ## _len[];                \
+       __asm__ ( ".section \".rodata\", \"a\", @progbits\n\t"          \
+                 "\nembedded_image_" #_index "_data:\n\t"              \
+                 ".incbin \"" _path "\"\n\t"                           \
+                 "\nembedded_image_" #_index "_end:\n\t"               \
+                 ".equ embedded_image_" #_index "_len, "               \
+                       "( embedded_image_" #_index "_end - "           \
+                       "  embedded_image_" #_index "_data )\n\t"       \
+                 ".previous\n\t" );
+EMBED_ALL
 
-       if ( !eisize )
-               return NULL;    /* No embedded image */
+/* Image structures for all embedded images */
+#undef EMBED
+#define EMBED( _index, _path, _name ) {                                        \
+       .refcnt = { .free = embedded_image_free, },                     \
+       .name = _name,                                                  \
+       .data = ( userptr_t ) ( embedded_image_ ## _index ## _data ),   \
+       .len = ( size_t ) embedded_image_ ## _index ## _len,            \
+},
+static struct image embedded_images[] = {
+       EMBED_ALL
+};
 
-       if ( reclaimed )
-               return NULL;    /* Already reclaimed */
+/**
+ * Register all embedded images
+ */
+static void embedded_init ( void ) {
+       unsigned int i;
+       struct image *image;
+       void *data;
+       int rc;
 
-       DBG ( "Embedded image: %zd bytes at %p\n",
-             eisize, _embedded_image_start );
+       /* Fix up data pointers and register images */
+       for ( i = 0 ; i < ( sizeof ( embedded_images ) /
+                           sizeof ( embedded_images[0] ) ) ; i++ ) {
+               image = &embedded_images[i];
 
-       image = alloc_image();
-       if (!image)
-               return NULL;
+               /* virt_to_user() cannot be used in a static
+                * initialiser, so we cast the pointer to a userptr_t
+                * in the initialiser and fix it up here.  (This will
+                * actually be a no-op on most platforms.)
+                */
+               data = ( ( void * ) image->data );
+               image->data = virt_to_user ( data );
 
-       image->len     = eisize;
-       image->data    = umalloc(eisize);
-       if (image->data == UNULL) {
-               image_put(image);
-               return image = NULL;
-       }
-       copy_to_user(image->data, 0, _embedded_image_start, eisize);
-       register_image(image);
+               DBG ( "Embedded image \"%s\": %zd bytes at %p\n",
+                     image->name, image->len, data );
 
-       /* Reclaim embedded image memory */
-       reclaimed = 1;
-       mpopulate(_embedded_image_start, eisize);
+               if ( ( rc = register_image ( image ) ) != 0 ) {
+                       DBG ( "Could not register embedded image \"%s\": "
+                             "%s\n", image->name, strerror ( rc ) );
+                       return;
+               }
+       }
 
-       return image;
+       /* Load the first image */
+       image = &embedded_images[0];
+       if ( ( rc = image_autoload ( image ) ) != 0 ) {
+               DBG ( "Could not load embedded image \"%s\": %s\n",
+                     image->name, strerror ( rc ) );
+               return;
+       }
 }
 
+/** Embedded image initialisation function */
+struct init_fn embedded_init_fn __init_fn ( INIT_NORMAL ) = {
+       .initialise = embedded_init,
+};
diff --git a/src/include/gpxe/embedded.h b/src/include/gpxe/embedded.h
deleted file mode 100644 (file)
index ec45705..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-#ifndef _GPXE_EMBEDDED_H
-#define _GPXE_EMBEDDED_H
-
-#include <gpxe/image.h>
-
-struct image *embedded_image(void);
-
-#endif
-
index 4809e50c9e59e308b99d15f757474ed508ae2177..90c21a7e3e153afd23bf1dc3e43d7febe65e14cd 100644 (file)
 #define ERRFILE_script               ( ERRFILE_IMAGE | 0x00020000 )
 #define ERRFILE_segment                      ( ERRFILE_IMAGE | 0x00030000 )
 #define ERRFILE_efi_image            ( ERRFILE_IMAGE | 0x00040000 )
+#define ERRFILE_embedded             ( ERRFILE_IMAGE | 0x00050000 )
 
 #define ERRFILE_asn1                 ( ERRFILE_OTHER | 0x00000000 )
 #define ERRFILE_chap                 ( ERRFILE_OTHER | 0x00010000 )
index 37f3aac9572a54334b8819104a1afde787fef12f..3803868d2bd36e70e019a63f46b8a0493903233c 100644 (file)
@@ -7,6 +7,7 @@
  *
  */
 
+#include <stddef.h>
 #include <stdlib.h>
 #include <gpxe/refcnt.h>
 
index cad625e4cecc1e75bbded573458d9ba140b42fd6..98e79a7fdbee0911587799763aaf28620c70e606 100644 (file)
@@ -23,7 +23,6 @@
 #include <gpxe/dhcp.h>
 #include <gpxe/settings.h>
 #include <gpxe/image.h>
-#include <gpxe/embedded.h>
 #include <gpxe/sanboot.h>
 #include <gpxe/uri.h>
 #include <usr/ifmgmt.h>
@@ -59,30 +58,6 @@ static struct net_device * find_boot_netdev ( void ) {
        return NULL;
 }
 
-/**
- * Boot embedded image
- *
- * @ret rc             Return status code
- */
-static int boot_embedded_image ( void ) {
-       struct image *image;
-       int rc;
-
-       image = embedded_image();
-       if ( !image )
-               return ENOENT;
-
-       if ( ( rc = imgload ( image ) ) != 0 ) {
-               printf ( "Could not load embedded image: %s\n",
-                        strerror ( rc ) );
-       } else if ( ( rc = imgexec ( image ) ) != 0 ) {
-               printf ( "Could not boot embedded image: %s\n",
-                        strerror ( rc ) );
-       }
-       image_put ( image );
-       return rc;
-}
-
 /**
  * Boot using next-server and filename
  *
@@ -196,11 +171,6 @@ static int netboot ( struct net_device *netdev ) {
                return rc;
        route();
 
-       /* Try to boot an embedded image if we have one */
-       rc = boot_embedded_image ();
-       if ( rc != ENOENT )
-               return rc;
-
        /* Try PXE menu boot, if applicable */
        fetch_string_setting ( NULL, &vendor_class_id_setting,
                               buf, sizeof ( buf ) );