summaryrefslogtreecommitdiffstats
path: root/contrib/syslinux-4.02/gpxe/src/core/image.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/syslinux-4.02/gpxe/src/core/image.c')
-rw-r--r--contrib/syslinux-4.02/gpxe/src/core/image.c328
1 files changed, 328 insertions, 0 deletions
diff --git a/contrib/syslinux-4.02/gpxe/src/core/image.c b/contrib/syslinux-4.02/gpxe/src/core/image.c
new file mode 100644
index 0000000..24fe51a
--- /dev/null
+++ b/contrib/syslinux-4.02/gpxe/src/core/image.c
@@ -0,0 +1,328 @@
+/*
+ * 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.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#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 );
+
+/**
+ * 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 );
+ image_put ( image->replacement );
+ 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 ) {
+ DBGC ( image, "IMAGE %p unregistered\n", image );
+ list_del ( &image->list );
+ image_put ( 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_each_table_entry ( type, IMAGE_TYPES ) {
+ 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 image *replacement;
+ 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 );
+
+ /* Take out a temporary reference to the image. This allows
+ * the image to unregister itself if necessary, without
+ * automatically freeing itself.
+ */
+ image_get ( image );
+
+ /* Try executing the image */
+ if ( ( rc = image->type->exec ( image ) ) != 0 ) {
+ DBGC ( image, "IMAGE %p could not execute: %s\n",
+ image, strerror ( rc ) );
+ /* Do not return yet; we still have clean-up to do */
+ }
+
+ /* Pick up replacement image before we drop the original
+ * image's temporary reference.
+ */
+ replacement = image->replacement;
+
+ /* Drop temporary reference to the original image */
+ image_put ( image );
+
+ /* Reset current working directory */
+ churi ( old_cwuri );
+ uri_put ( old_cwuri );
+
+ /* Tail-recurse into replacement image, if one exists */
+ if ( replacement ) {
+ DBGC ( image, "IMAGE %p replacing self with IMAGE %p\n",
+ image, replacement );
+ if ( ( rc = image_exec ( replacement ) ) != 0 )
+ return rc;
+ }
+
+ 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;
+}