| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309 | 
							- /*
 -  * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
 -  *
 -  * This program is free software; you can redistribute it and/or
 -  * modify it under the terms of the GNU General Public License as
 -  * published by the Free Software Foundation; either version 2 of the
 -  * License, or any later version.
 -  *
 -  * This program is distributed in the hope that it will be useful, but
 -  * WITHOUT ANY WARRANTY; without even the implied warranty of
 -  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 -  * General Public License for more details.
 -  *
 -  * You should have received a copy of the GNU General Public License
 -  * along with this program; if not, write to the Free Software
 -  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 -  */
 - 
 - #include <stddef.h>
 - #include <string.h>
 - #include <stdlib.h>
 - #include <stdio.h>
 - #include <errno.h>
 - #include <assert.h>
 - #include <libgen.h>
 - #include <gpxe/list.h>
 - #include <gpxe/umalloc.h>
 - #include <gpxe/uri.h>
 - #include <gpxe/image.h>
 - 
 - /** @file
 -  *
 -  * Executable/loadable images
 -  *
 -  */
 - 
 - /** List of registered images */
 - struct list_head images = LIST_HEAD_INIT ( images );
 - 
 - /** List of image types */
 - static struct image_type image_types[0]
 - 	__table_start ( struct image_type, image_types );
 - static struct image_type image_types_end[0]
 - 	__table_end ( struct image_type, image_types );
 - 
 - /**
 -  * Free executable/loadable image
 -  *
 -  * @v refcnt		Reference counter
 -  */
 - static void free_image ( struct refcnt *refcnt ) {
 - 	struct image *image = container_of ( refcnt, struct image, refcnt );
 - 
 - 	uri_put ( image->uri );
 - 	ufree ( image->data );
 - 	free ( image );
 - 	DBGC ( image, "IMAGE %p freed\n", image );
 - }
 - 
 - /**
 -  * Allocate executable/loadable image
 -  *
 -  * @ret image		Executable/loadable image
 -  */
 - struct image * alloc_image ( void ) {
 - 	struct image *image;
 - 
 - 	image = zalloc ( sizeof ( *image ) );
 - 	if ( image ) {
 - 		image->refcnt.free = free_image;
 - 	}
 - 	return image;
 - }
 - 
 - /**
 -  * Set image URI
 -  *
 -  * @v image		Image
 -  * @v URI		New image URI
 -  * @ret rc		Return status code
 -  *
 -  * If no name is set, the name will be updated to the base name of the
 -  * URI path (if any).
 -  */
 - int image_set_uri ( struct image *image, struct uri *uri ) {
 - 	const char *path = uri->path;
 - 
 - 	/* Replace URI reference */
 - 	uri_put ( image->uri );
 - 	image->uri = uri_get ( uri );
 - 
 - 	/* Set name if none already specified */
 - 	if ( path && ( ! image->name[0] ) )
 - 		image_set_name ( image, basename ( ( char * ) path ) );
 - 
 - 	return 0;
 - }
 - 
 - /**
 -  * Set image command line
 -  *
 -  * @v image		Image
 -  * @v cmdline		New image command line
 -  * @ret rc		Return status code
 -  */
 - int image_set_cmdline ( struct image *image, const char *cmdline ) {
 - 	free ( image->cmdline );
 - 	image->cmdline = strdup ( cmdline );
 - 	if ( ! image->cmdline )
 - 		return -ENOMEM;
 - 	return 0;
 - }
 - 
 - /**
 -  * Register executable/loadable image
 -  *
 -  * @v image		Executable/loadable image
 -  * @ret rc		Return status code
 -  */
 - int register_image ( struct image *image ) {
 - 	static unsigned int imgindex = 0;
 - 
 - 	/* Create image name if it doesn't already have one */
 - 	if ( ! image->name[0] ) {
 - 		snprintf ( image->name, sizeof ( image->name ), "img%d",
 - 			   imgindex++ );
 - 	}
 - 
 - 	/* Add to image list */
 - 	image_get ( image );
 - 	list_add_tail ( &image->list, &images );
 - 	DBGC ( image, "IMAGE %p at [%lx,%lx) registered as %s\n",
 - 	       image, user_to_phys ( image->data, 0 ),
 - 	       user_to_phys ( image->data, image->len ), image->name );
 - 
 - 	return 0;
 - }
 - 
 - /**
 -  * Unregister executable/loadable image
 -  *
 -  * @v image		Executable/loadable image
 -  */
 - void unregister_image ( struct image *image ) {
 - 	list_del ( &image->list );
 - 	image_put ( image );
 - 	DBGC ( image, "IMAGE %p unregistered\n", image );
 - }
 - 
 - /**
 -  * Find image by name
 -  *
 -  * @v name		Image name
 -  * @ret image		Executable/loadable image, or NULL
 -  */
 - struct image * find_image ( const char *name ) {
 - 	struct image *image;
 - 
 - 	list_for_each_entry ( image, &images, list ) {
 - 		if ( strcmp ( image->name, name ) == 0 )
 - 			return image;
 - 	}
 - 
 - 	return NULL;
 - }
 - 
 - /**
 -  * Load executable/loadable image into memory
 -  *
 -  * @v image		Executable/loadable image
 -  * @v type		Executable/loadable image type
 -  * @ret rc		Return status code
 -  */
 - static int image_load_type ( struct image *image, struct image_type *type ) {
 - 	int rc;
 - 
 - 	/* Check image is actually loadable */
 - 	if ( ! type->load )
 - 		return -ENOEXEC;
 - 
 - 	/* Try the image loader */
 - 	if ( ( rc = type->load ( image ) ) != 0 ) {
 - 		DBGC ( image, "IMAGE %p could not load as %s: %s\n",
 - 		       image, type->name, strerror ( rc ) );
 - 		return rc;
 - 	}
 - 
 - 	/* Flag as loaded */
 - 	image->flags |= IMAGE_LOADED;
 - 	return 0;
 - }
 - 
 - /**
 -  * Load executable/loadable image into memory
 -  *
 -  * @v image		Executable/loadable image
 -  * @ret rc		Return status code
 -  */
 - int image_load ( struct image *image ) {
 - 
 - 	assert ( image->type != NULL );
 - 
 - 	return image_load_type ( image, image->type );
 - }
 - 
 - /**
 -  * Autodetect image type and load executable/loadable image into memory
 -  *
 -  * @v image		Executable/loadable image
 -  * @ret rc		Return status code
 -  */
 - int image_autoload ( struct image *image ) {
 - 	struct image_type *type;
 - 	int rc;
 - 
 - 	/* If image already has a type, use it */
 - 	if ( image->type )
 - 		return image_load ( image );
 - 
 - 	/* Otherwise probe for a suitable type */
 - 	for ( type = image_types ; type < image_types_end ; type++ ) {
 - 		DBGC ( image, "IMAGE %p trying type %s\n", image, type->name );
 - 		rc = image_load_type ( image, type );
 - 		if ( image->type == NULL )
 - 			continue;
 - 		return rc;
 - 	}
 - 
 - 	DBGC ( image, "IMAGE %p format not recognised\n", image );
 - 	return -ENOEXEC;
 - }
 - 
 - /**
 -  * Execute loaded image
 -  *
 -  * @v image		Loaded image
 -  * @ret rc		Return status code
 -  */
 - int image_exec ( struct image *image ) {
 - 	struct uri *old_cwuri;
 - 	int rc;
 - 
 - 	/* Image must be loaded first */
 - 	if ( ! ( image->flags & IMAGE_LOADED ) ) {
 - 		DBGC ( image, "IMAGE %p could not execute: not loaded\n",
 - 		       image );
 - 		return -ENOTTY;
 - 	}
 - 
 - 	assert ( image->type != NULL );
 - 
 - 	/* Check that image is actually executable */
 - 	if ( ! image->type->exec )
 - 		return -ENOEXEC;
 - 
 - 	/* Switch current working directory to be that of the image itself */
 - 	old_cwuri = uri_get ( cwuri );
 - 	churi ( image->uri );
 - 
 - 	/* Try executing the image */
 - 	if ( ( rc = image->type->exec ( image ) ) != 0 ) {
 - 		DBGC ( image, "IMAGE %p could not execute: %s\n",
 - 		       image, strerror ( rc ) );
 - 		goto done;
 - 	}
 - 
 -  done:
 - 	/* Reset current working directory */
 - 	churi ( old_cwuri );
 - 	uri_put ( old_cwuri );
 - 
 - 	return rc;
 - }
 - 
 - /**
 -  * Register and autoload an image
 -  *
 -  * @v image		Image
 -  * @ret rc		Return status code
 -  */
 - int register_and_autoload_image ( struct image *image ) {
 - 	int rc;
 - 
 - 	if ( ( rc = register_image ( image ) ) != 0 )
 - 		return rc;
 - 
 - 	if ( ( rc = image_autoload ( image ) ) != 0 )
 - 		return rc;
 - 
 - 	return 0;
 - }
 - 
 - /**
 -  * Register and autoexec an image
 -  *
 -  * @v image		Image
 -  * @ret rc		Return status code
 -  */
 - int register_and_autoexec_image ( struct image *image ) {
 - 	int rc;
 - 
 - 	if ( ( rc = register_and_autoload_image ( image ) ) != 0 )
 - 		return rc;
 - 
 - 	if ( ( rc = image_exec ( image ) ) != 0 )
 - 		return rc;
 - 
 - 	return 0;
 - }
 
 
  |