| /** @file |
| * |
| * Embedded image support |
| * |
| * Embedded images are images built into the gPXE binary and do not require |
| * fetching over the network. |
| */ |
| |
| FILE_LICENCE ( GPL2_OR_LATER ); |
| |
| #include <string.h> |
| #include <gpxe/image.h> |
| #include <gpxe/uaccess.h> |
| #include <gpxe/init.h> |
| |
| /** |
| * Free embedded image |
| * |
| * @v refcnt Reference counter |
| */ |
| static void __attribute__ (( unused )) |
| 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 ) { |
| int i; |
| struct image *image; |
| void *data; |
| int rc; |
| |
| /* Skip if we have no embedded images */ |
| if ( ! sizeof ( embedded_images ) ) |
| return; |
| |
| /* Fix up data pointers and register images */ |
| for ( i = 0 ; i < ( int ) ( 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, |
| }; |