176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** @file
276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Embedded image support
476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Embedded images are images built into the gPXE binary and do not require
676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * fetching over the network.
776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
976d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanFILE_LICENCE ( GPL2_OR_LATER );
1076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
1176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <string.h>
1276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <gpxe/image.h>
1376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <gpxe/uaccess.h>
1476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <gpxe/init.h>
1576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
1676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/**
1776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Free embedded image
1876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
1976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v refcnt		Reference counter
2076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
2176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void __attribute__ (( unused ))
2276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanembedded_image_free ( struct refcnt *refcnt __unused ) {
2376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* Do nothing */
2476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
2576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
2676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Raw image data for all embedded images */
2776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#undef EMBED
2876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define EMBED( _index, _path, _name )					\
2976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	extern char embedded_image_ ## _index ## _data[];		\
3076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	extern char embedded_image_ ## _index ## _len[];		\
3176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	__asm__ ( ".section \".rodata\", \"a\", @progbits\n\t"		\
3276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		  "\nembedded_image_" #_index "_data:\n\t"		\
3376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		  ".incbin \"" _path "\"\n\t"				\
3476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		  "\nembedded_image_" #_index "_end:\n\t"		\
3576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		  ".equ embedded_image_" #_index "_len, "		\
3676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			"( embedded_image_" #_index "_end - "		\
3776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			"  embedded_image_" #_index "_data )\n\t"	\
3876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		  ".previous\n\t" );
3976d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanEMBED_ALL
4076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
4176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Image structures for all embedded images */
4276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#undef EMBED
4376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define EMBED( _index, _path, _name ) {					\
4476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	.refcnt = { .free = embedded_image_free, },			\
4576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	.name = _name,							\
4676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	.data = ( userptr_t ) ( embedded_image_ ## _index ## _data ),	\
4776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	.len = ( size_t ) embedded_image_ ## _index ## _len,		\
4876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman},
4976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic struct image embedded_images[] = {
5076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	EMBED_ALL
5176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman};
5276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
5376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/**
5476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Register all embedded images
5576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
5676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void embedded_init ( void ) {
5776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	int i;
5876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct image *image;
5976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	void *data;
6076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	int rc;
6176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
6276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* Skip if we have no embedded images */
6376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if ( ! sizeof ( embedded_images ) )
6476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		return;
6576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
6676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* Fix up data pointers and register images */
6776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	for ( i = 0 ; i < ( int ) ( sizeof ( embedded_images ) /
6876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman				    sizeof ( embedded_images[0] ) ) ; i++ ) {
6976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		image = &embedded_images[i];
7076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
7176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		/* virt_to_user() cannot be used in a static
7276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		 * initialiser, so we cast the pointer to a userptr_t
7376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		 * in the initialiser and fix it up here.  (This will
7476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		 * actually be a no-op on most platforms.)
7576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		 */
7676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		data = ( ( void * ) image->data );
7776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		image->data = virt_to_user ( data );
7876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
7976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		DBG ( "Embedded image \"%s\": %zd bytes at %p\n",
8076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		      image->name, image->len, data );
8176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
8276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		if ( ( rc = register_image ( image ) ) != 0 ) {
8376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			DBG ( "Could not register embedded image \"%s\": "
8476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			      "%s\n", image->name, strerror ( rc ) );
8576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			return;
8676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		}
8776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
8876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
8976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* Load the first image */
9076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	image = &embedded_images[0];
9176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if ( ( rc = image_autoload ( image ) ) != 0 ) {
9276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		DBG ( "Could not load embedded image \"%s\": %s\n",
9376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		      image->name, strerror ( rc ) );
9476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		return;
9576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
9676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
9776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
9876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** Embedded image initialisation function */
9976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstruct init_fn embedded_init_fn __init_fn ( INIT_NORMAL ) = {
10076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	.initialise = embedded_init,
10176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman};
102