Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[image] Allow multiple embedded images
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>.
  • Loading branch information
Michael Brown committed Feb 16, 2009
1 parent f16668d commit 076154a
Show file tree
Hide file tree
Showing 12 changed files with 138 additions and 91 deletions.
4 changes: 4 additions & 0 deletions contrib/scripts/gpxelinux.gpxe
@@ -0,0 +1,4 @@
#!gpxe
dhcp net0
imgload img1
boot img1
8 changes: 8 additions & 0 deletions 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
42 changes: 33 additions & 9 deletions src/Makefile.housekeeping
Expand Up @@ -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)
Expand Down Expand Up @@ -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
#
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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))
Expand Down
1 change: 1 addition & 0 deletions src/core/config.c
Expand Up @@ -218,3 +218,4 @@ REQUIRE_OBJECT ( gdbstub_cmd );
*
*/
REQUIRE_OBJECT ( device );
REQUIRE_OBJECT ( embedded );
15 changes: 11 additions & 4 deletions src/core/main.c
Expand Up @@ -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>

Expand All @@ -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" );
Expand Down Expand Up @@ -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();
}
Expand Down
2 changes: 2 additions & 0 deletions src/image/default.gpxe
@@ -0,0 +1,2 @@
#!gpxe
autoboot
7 changes: 0 additions & 7 deletions src/image/embed.S

This file was deleted.

109 changes: 77 additions & 32 deletions 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 <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,
};
9 changes: 0 additions & 9 deletions src/include/gpxe/embedded.h

This file was deleted.

1 change: 1 addition & 0 deletions src/include/gpxe/errfile.h
Expand Up @@ -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 )
Expand Down
1 change: 1 addition & 0 deletions src/include/gpxe/uri.h
Expand Up @@ -7,6 +7,7 @@
*
*/

#include <stddef.h>
#include <stdlib.h>
#include <gpxe/refcnt.h>

Expand Down
30 changes: 0 additions & 30 deletions src/usr/autoboot.c
Expand Up @@ -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>
Expand Down Expand Up @@ -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
*
Expand Down Expand Up @@ -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 ) );
Expand Down

0 comments on commit 076154a

Please sign in to comment.