mirror of
https://github.com/ipxe/ipxe
synced 2026-02-11 05:38:16 +03:00
[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>.
This commit is contained in:
@@ -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[];
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user