diff --git a/contrib/scripts/gpxelinux.gpxe b/contrib/scripts/gpxelinux.gpxe new file mode 100644 index 00000000..dcfc80e6 --- /dev/null +++ b/contrib/scripts/gpxelinux.gpxe @@ -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 index 00000000..e3539fc0 --- /dev/null +++ b/contrib/scripts/static.gpxe @@ -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 diff --git a/src/Makefile.housekeeping b/src/Makefile.housekeeping index ab6f29c2..d8413447 100644 --- a/src/Makefile.housekeeping +++ b/src/Makefile.housekeeping @@ -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 -$(BIN)/embed.o: $(BIN)/embedimg.bin -CFLAGS_embed = -DEMBEDIMG=\"$(BIN)/embedimg.bin\" +$(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)/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)) diff --git a/src/core/config.c b/src/core/config.c index b14d25a8..741579fe 100644 --- a/src/core/config.c +++ b/src/core/config.c @@ -218,3 +218,4 @@ REQUIRE_OBJECT ( gdbstub_cmd ); * */ REQUIRE_OBJECT ( device ); +REQUIRE_OBJECT ( embedded ); diff --git a/src/core/main.c b/src/core/main.c index e72b8c90..8d360c42 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -19,6 +19,7 @@ Literature dealing with the network protocols: #include #include #include +#include #include #include @@ -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 index 00000000..0b080b58 --- /dev/null +++ b/src/image/default.gpxe @@ -0,0 +1,2 @@ +#!gpxe +autoboot diff --git a/src/image/embed.S b/src/image/embed.S deleted file mode 100644 index ef7d693b..00000000 --- a/src/image/embed.S +++ /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: diff --git a/src/image/embedded.c b/src/image/embedded.c index 0ce09783..f76ca11b 100644 --- a/src/image/embedded.c +++ b/src/image/embedded.c @@ -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 #include -#include #include -#include -#include +#include -extern char _embedded_image_start[], _embedded_image_end[]; - -struct image *embedded_image(void) -{ - static int reclaimed = 0; - struct image *image; - size_t eisize = _embedded_image_end - _embedded_image_start; - - if ( !eisize ) - return NULL; /* No embedded image */ - - if ( reclaimed ) - return NULL; /* Already reclaimed */ - - DBG ( "Embedded image: %zd bytes at %p\n", - eisize, _embedded_image_start ); - - image = alloc_image(); - if (!image) - return NULL; - - 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); - - /* Reclaim embedded image memory */ - reclaimed = 1; - mpopulate(_embedded_image_start, eisize); - - return image; +/** + * Free embedded image + * + * @v refcnt Reference counter + */ +static void embedded_image_free ( struct refcnt *refcnt __unused ) { + /* Do nothing */ } +/* 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 + +/* 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 +}; + +/** + * Register all embedded images + */ +static void embedded_init ( void ) { + unsigned int i; + struct image *image; + void *data; + int rc; + + /* Fix up data pointers and register images */ + for ( i = 0 ; i < ( sizeof ( embedded_images ) / + sizeof ( embedded_images[0] ) ) ; i++ ) { + image = &embedded_images[i]; + + /* 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 ); + + DBG ( "Embedded image \"%s\": %zd bytes at %p\n", + image->name, image->len, data ); + + if ( ( rc = register_image ( image ) ) != 0 ) { + DBG ( "Could not register embedded image \"%s\": " + "%s\n", image->name, strerror ( rc ) ); + return; + } + } + + /* 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 index ec457055..00000000 --- a/src/include/gpxe/embedded.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef _GPXE_EMBEDDED_H -#define _GPXE_EMBEDDED_H - -#include - -struct image *embedded_image(void); - -#endif - diff --git a/src/include/gpxe/errfile.h b/src/include/gpxe/errfile.h index 4809e50c..90c21a7e 100644 --- a/src/include/gpxe/errfile.h +++ b/src/include/gpxe/errfile.h @@ -145,6 +145,7 @@ #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 ) diff --git a/src/include/gpxe/uri.h b/src/include/gpxe/uri.h index 37f3aac9..3803868d 100644 --- a/src/include/gpxe/uri.h +++ b/src/include/gpxe/uri.h @@ -7,6 +7,7 @@ * */ +#include #include #include diff --git a/src/usr/autoboot.c b/src/usr/autoboot.c index cad625e4..98e79a7f 100644 --- a/src/usr/autoboot.c +++ b/src/usr/autoboot.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include @@ -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 ) );