Home | History | Annotate | Download | only in core
      1 /*
      2  * Copyright (C) 2006 Michael Brown <mbrown (at) fensystems.co.uk>.
      3  *
      4  * This program is free software; you can redistribute it and/or
      5  * modify it under the terms of the GNU General Public License as
      6  * published by the Free Software Foundation; either version 2 of the
      7  * License, or any later version.
      8  *
      9  * This program is distributed in the hope that it will be useful, but
     10  * WITHOUT ANY WARRANTY; without even the implied warranty of
     11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     12  * General Public License for more details.
     13  *
     14  * You should have received a copy of the GNU General Public License
     15  * along with this program; if not, write to the Free Software
     16  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
     17  */
     18 
     19 FILE_LICENCE ( GPL2_OR_LATER );
     20 
     21 #include <stddef.h>
     22 #include <string.h>
     23 #include <stdlib.h>
     24 #include <stdio.h>
     25 #include <errno.h>
     26 #include <assert.h>
     27 #include <libgen.h>
     28 #include <gpxe/list.h>
     29 #include <gpxe/umalloc.h>
     30 #include <gpxe/uri.h>
     31 #include <gpxe/image.h>
     32 
     33 /** @file
     34  *
     35  * Executable/loadable images
     36  *
     37  */
     38 
     39 /** List of registered images */
     40 struct list_head images = LIST_HEAD_INIT ( images );
     41 
     42 /**
     43  * Free executable/loadable image
     44  *
     45  * @v refcnt		Reference counter
     46  */
     47 static void free_image ( struct refcnt *refcnt ) {
     48 	struct image *image = container_of ( refcnt, struct image, refcnt );
     49 
     50 	uri_put ( image->uri );
     51 	ufree ( image->data );
     52 	image_put ( image->replacement );
     53 	free ( image );
     54 	DBGC ( image, "IMAGE %p freed\n", image );
     55 }
     56 
     57 /**
     58  * Allocate executable/loadable image
     59  *
     60  * @ret image		Executable/loadable image
     61  */
     62 struct image * alloc_image ( void ) {
     63 	struct image *image;
     64 
     65 	image = zalloc ( sizeof ( *image ) );
     66 	if ( image ) {
     67 		image->refcnt.free = free_image;
     68 	}
     69 	return image;
     70 }
     71 
     72 /**
     73  * Set image URI
     74  *
     75  * @v image		Image
     76  * @v URI		New image URI
     77  * @ret rc		Return status code
     78  *
     79  * If no name is set, the name will be updated to the base name of the
     80  * URI path (if any).
     81  */
     82 int image_set_uri ( struct image *image, struct uri *uri ) {
     83 	const char *path = uri->path;
     84 
     85 	/* Replace URI reference */
     86 	uri_put ( image->uri );
     87 	image->uri = uri_get ( uri );
     88 
     89 	/* Set name if none already specified */
     90 	if ( path && ( ! image->name[0] ) )
     91 		image_set_name ( image, basename ( ( char * ) path ) );
     92 
     93 	return 0;
     94 }
     95 
     96 /**
     97  * Set image command line
     98  *
     99  * @v image		Image
    100  * @v cmdline		New image command line
    101  * @ret rc		Return status code
    102  */
    103 int image_set_cmdline ( struct image *image, const char *cmdline ) {
    104 	free ( image->cmdline );
    105 	image->cmdline = strdup ( cmdline );
    106 	if ( ! image->cmdline )
    107 		return -ENOMEM;
    108 	return 0;
    109 }
    110 
    111 /**
    112  * Register executable/loadable image
    113  *
    114  * @v image		Executable/loadable image
    115  * @ret rc		Return status code
    116  */
    117 int register_image ( struct image *image ) {
    118 	static unsigned int imgindex = 0;
    119 
    120 	/* Create image name if it doesn't already have one */
    121 	if ( ! image->name[0] ) {
    122 		snprintf ( image->name, sizeof ( image->name ), "img%d",
    123 			   imgindex++ );
    124 	}
    125 
    126 	/* Add to image list */
    127 	image_get ( image );
    128 	list_add_tail ( &image->list, &images );
    129 	DBGC ( image, "IMAGE %p at [%lx,%lx) registered as %s\n",
    130 	       image, user_to_phys ( image->data, 0 ),
    131 	       user_to_phys ( image->data, image->len ), image->name );
    132 
    133 	return 0;
    134 }
    135 
    136 /**
    137  * Unregister executable/loadable image
    138  *
    139  * @v image		Executable/loadable image
    140  */
    141 void unregister_image ( struct image *image ) {
    142 	DBGC ( image, "IMAGE %p unregistered\n", image );
    143 	list_del ( &image->list );
    144 	image_put ( image );
    145 }
    146 
    147 /**
    148  * Find image by name
    149  *
    150  * @v name		Image name
    151  * @ret image		Executable/loadable image, or NULL
    152  */
    153 struct image * find_image ( const char *name ) {
    154 	struct image *image;
    155 
    156 	list_for_each_entry ( image, &images, list ) {
    157 		if ( strcmp ( image->name, name ) == 0 )
    158 			return image;
    159 	}
    160 
    161 	return NULL;
    162 }
    163 
    164 /**
    165  * Load executable/loadable image into memory
    166  *
    167  * @v image		Executable/loadable image
    168  * @v type		Executable/loadable image type
    169  * @ret rc		Return status code
    170  */
    171 static int image_load_type ( struct image *image, struct image_type *type ) {
    172 	int rc;
    173 
    174 	/* Check image is actually loadable */
    175 	if ( ! type->load )
    176 		return -ENOEXEC;
    177 
    178 	/* Try the image loader */
    179 	if ( ( rc = type->load ( image ) ) != 0 ) {
    180 		DBGC ( image, "IMAGE %p could not load as %s: %s\n",
    181 		       image, type->name, strerror ( rc ) );
    182 		return rc;
    183 	}
    184 
    185 	/* Flag as loaded */
    186 	image->flags |= IMAGE_LOADED;
    187 	return 0;
    188 }
    189 
    190 /**
    191  * Load executable/loadable image into memory
    192  *
    193  * @v image		Executable/loadable image
    194  * @ret rc		Return status code
    195  */
    196 int image_load ( struct image *image ) {
    197 
    198 	assert ( image->type != NULL );
    199 
    200 	return image_load_type ( image, image->type );
    201 }
    202 
    203 /**
    204  * Autodetect image type and load executable/loadable image into memory
    205  *
    206  * @v image		Executable/loadable image
    207  * @ret rc		Return status code
    208  */
    209 int image_autoload ( struct image *image ) {
    210 	struct image_type *type;
    211 	int rc;
    212 
    213 	/* If image already has a type, use it */
    214 	if ( image->type )
    215 		return image_load ( image );
    216 
    217 	/* Otherwise probe for a suitable type */
    218 	for_each_table_entry ( type, IMAGE_TYPES ) {
    219 		DBGC ( image, "IMAGE %p trying type %s\n", image, type->name );
    220 		rc = image_load_type ( image, type );
    221 		if ( image->type == NULL )
    222 			continue;
    223 		return rc;
    224 	}
    225 
    226 	DBGC ( image, "IMAGE %p format not recognised\n", image );
    227 	return -ENOEXEC;
    228 }
    229 
    230 /**
    231  * Execute loaded image
    232  *
    233  * @v image		Loaded image
    234  * @ret rc		Return status code
    235  */
    236 int image_exec ( struct image *image ) {
    237 	struct image *replacement;
    238 	struct uri *old_cwuri;
    239 	int rc;
    240 
    241 	/* Image must be loaded first */
    242 	if ( ! ( image->flags & IMAGE_LOADED ) ) {
    243 		DBGC ( image, "IMAGE %p could not execute: not loaded\n",
    244 		       image );
    245 		return -ENOTTY;
    246 	}
    247 
    248 	assert ( image->type != NULL );
    249 
    250 	/* Check that image is actually executable */
    251 	if ( ! image->type->exec )
    252 		return -ENOEXEC;
    253 
    254 	/* Switch current working directory to be that of the image itself */
    255 	old_cwuri = uri_get ( cwuri );
    256 	churi ( image->uri );
    257 
    258 	/* Take out a temporary reference to the image.  This allows
    259 	 * the image to unregister itself if necessary, without
    260 	 * automatically freeing itself.
    261 	 */
    262 	image_get ( image );
    263 
    264 	/* Try executing the image */
    265 	if ( ( rc = image->type->exec ( image ) ) != 0 ) {
    266 		DBGC ( image, "IMAGE %p could not execute: %s\n",
    267 		       image, strerror ( rc ) );
    268 		/* Do not return yet; we still have clean-up to do */
    269 	}
    270 
    271 	/* Pick up replacement image before we drop the original
    272 	 * image's temporary reference.
    273 	 */
    274 	replacement = image->replacement;
    275 
    276 	/* Drop temporary reference to the original image */
    277 	image_put ( image );
    278 
    279 	/* Reset current working directory */
    280 	churi ( old_cwuri );
    281 	uri_put ( old_cwuri );
    282 
    283 	/* Tail-recurse into replacement image, if one exists */
    284 	if ( replacement ) {
    285 		DBGC ( image, "IMAGE %p replacing self with IMAGE %p\n",
    286 		       image, replacement );
    287 		if ( ( rc = image_exec ( replacement ) ) != 0 )
    288 			return rc;
    289 	}
    290 
    291 	return rc;
    292 }
    293 
    294 /**
    295  * Register and autoload an image
    296  *
    297  * @v image		Image
    298  * @ret rc		Return status code
    299  */
    300 int register_and_autoload_image ( struct image *image ) {
    301 	int rc;
    302 
    303 	if ( ( rc = register_image ( image ) ) != 0 )
    304 		return rc;
    305 
    306 	if ( ( rc = image_autoload ( image ) ) != 0 )
    307 		return rc;
    308 
    309 	return 0;
    310 }
    311 
    312 /**
    313  * Register and autoexec an image
    314  *
    315  * @v image		Image
    316  * @ret rc		Return status code
    317  */
    318 int register_and_autoexec_image ( struct image *image ) {
    319 	int rc;
    320 
    321 	if ( ( rc = register_and_autoload_image ( image ) ) != 0 )
    322 		return rc;
    323 
    324 	if ( ( rc = image_exec ( image ) ) != 0 )
    325 		return rc;
    326 
    327 	return 0;
    328 }
    329