[sundance] Add reset completion check
[gpxe.git] / src / core / image.c
blob277d09a92553728726015cc1ef4356a8cfd9ec3a
1 /*
2 * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
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.
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.
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.
19 #include <stddef.h>
20 #include <string.h>
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <errno.h>
24 #include <assert.h>
25 #include <libgen.h>
26 #include <gpxe/list.h>
27 #include <gpxe/umalloc.h>
28 #include <gpxe/uri.h>
29 #include <gpxe/image.h>
31 /** @file
33 * Executable/loadable images
37 /** List of registered images */
38 struct list_head images = LIST_HEAD_INIT ( images );
40 /** List of image types */
41 static struct image_type image_types[0]
42 __table_start ( struct image_type, image_types );
43 static struct image_type image_types_end[0]
44 __table_end ( struct image_type, image_types );
46 /**
47 * Free executable/loadable image
49 * @v refcnt Reference counter
51 static void free_image ( struct refcnt *refcnt ) {
52 struct image *image = container_of ( refcnt, struct image, refcnt );
54 uri_put ( image->uri );
55 ufree ( image->data );
56 image_put ( image->replacement );
57 free ( image );
58 DBGC ( image, "IMAGE %p freed\n", image );
61 /**
62 * Allocate executable/loadable image
64 * @ret image Executable/loadable image
66 struct image * alloc_image ( void ) {
67 struct image *image;
69 image = zalloc ( sizeof ( *image ) );
70 if ( image ) {
71 image->refcnt.free = free_image;
73 return image;
76 /**
77 * Set image URI
79 * @v image Image
80 * @v URI New image URI
81 * @ret rc Return status code
83 * If no name is set, the name will be updated to the base name of the
84 * URI path (if any).
86 int image_set_uri ( struct image *image, struct uri *uri ) {
87 const char *path = uri->path;
89 /* Replace URI reference */
90 uri_put ( image->uri );
91 image->uri = uri_get ( uri );
93 /* Set name if none already specified */
94 if ( path && ( ! image->name[0] ) )
95 image_set_name ( image, basename ( ( char * ) path ) );
97 return 0;
101 * Set image command line
103 * @v image Image
104 * @v cmdline New image command line
105 * @ret rc Return status code
107 int image_set_cmdline ( struct image *image, const char *cmdline ) {
108 free ( image->cmdline );
109 image->cmdline = strdup ( cmdline );
110 if ( ! image->cmdline )
111 return -ENOMEM;
112 return 0;
116 * Register executable/loadable image
118 * @v image Executable/loadable image
119 * @ret rc Return status code
121 int register_image ( struct image *image ) {
122 static unsigned int imgindex = 0;
124 /* Create image name if it doesn't already have one */
125 if ( ! image->name[0] ) {
126 snprintf ( image->name, sizeof ( image->name ), "img%d",
127 imgindex++ );
130 /* Add to image list */
131 image_get ( image );
132 list_add_tail ( &image->list, &images );
133 DBGC ( image, "IMAGE %p at [%lx,%lx) registered as %s\n",
134 image, user_to_phys ( image->data, 0 ),
135 user_to_phys ( image->data, image->len ), image->name );
137 return 0;
141 * Unregister executable/loadable image
143 * @v image Executable/loadable image
145 void unregister_image ( struct image *image ) {
146 DBGC ( image, "IMAGE %p unregistered\n", image );
147 list_del ( &image->list );
148 image_put ( image );
152 * Find image by name
154 * @v name Image name
155 * @ret image Executable/loadable image, or NULL
157 struct image * find_image ( const char *name ) {
158 struct image *image;
160 list_for_each_entry ( image, &images, list ) {
161 if ( strcmp ( image->name, name ) == 0 )
162 return image;
165 return NULL;
169 * Load executable/loadable image into memory
171 * @v image Executable/loadable image
172 * @v type Executable/loadable image type
173 * @ret rc Return status code
175 static int image_load_type ( struct image *image, struct image_type *type ) {
176 int rc;
178 /* Check image is actually loadable */
179 if ( ! type->load )
180 return -ENOEXEC;
182 /* Try the image loader */
183 if ( ( rc = type->load ( image ) ) != 0 ) {
184 DBGC ( image, "IMAGE %p could not load as %s: %s\n",
185 image, type->name, strerror ( rc ) );
186 return rc;
189 /* Flag as loaded */
190 image->flags |= IMAGE_LOADED;
191 return 0;
195 * Load executable/loadable image into memory
197 * @v image Executable/loadable image
198 * @ret rc Return status code
200 int image_load ( struct image *image ) {
202 assert ( image->type != NULL );
204 return image_load_type ( image, image->type );
208 * Autodetect image type and load executable/loadable image into memory
210 * @v image Executable/loadable image
211 * @ret rc Return status code
213 int image_autoload ( struct image *image ) {
214 struct image_type *type;
215 int rc;
217 /* If image already has a type, use it */
218 if ( image->type )
219 return image_load ( image );
221 /* Otherwise probe for a suitable type */
222 for ( type = image_types ; type < image_types_end ; type++ ) {
223 DBGC ( image, "IMAGE %p trying type %s\n", image, type->name );
224 rc = image_load_type ( image, type );
225 if ( image->type == NULL )
226 continue;
227 return rc;
230 DBGC ( image, "IMAGE %p format not recognised\n", image );
231 return -ENOEXEC;
235 * Execute loaded image
237 * @v image Loaded image
238 * @ret rc Return status code
240 int image_exec ( struct image *image ) {
241 struct image *replacement;
242 struct uri *old_cwuri;
243 int rc;
245 /* Image must be loaded first */
246 if ( ! ( image->flags & IMAGE_LOADED ) ) {
247 DBGC ( image, "IMAGE %p could not execute: not loaded\n",
248 image );
249 return -ENOTTY;
252 assert ( image->type != NULL );
254 /* Check that image is actually executable */
255 if ( ! image->type->exec )
256 return -ENOEXEC;
258 /* Switch current working directory to be that of the image itself */
259 old_cwuri = uri_get ( cwuri );
260 churi ( image->uri );
262 /* Take out a temporary reference to the image. This allows
263 * the image to unregister itself if necessary, without
264 * automatically freeing itself.
266 image_get ( image );
268 /* Try executing the image */
269 if ( ( rc = image->type->exec ( image ) ) != 0 ) {
270 DBGC ( image, "IMAGE %p could not execute: %s\n",
271 image, strerror ( rc ) );
272 /* Do not return yet; we still have clean-up to do */
275 /* Pick up replacement image before we drop the original
276 * image's temporary reference.
278 replacement = image->replacement;
280 /* Drop temporary reference to the original image */
281 image_put ( image );
283 /* Reset current working directory */
284 churi ( old_cwuri );
285 uri_put ( old_cwuri );
287 /* Tail-recurse into replacement image, if one exists */
288 if ( replacement ) {
289 DBGC ( image, "IMAGE %p replacing self with IMAGE %p\n",
290 image, replacement );
291 if ( ( rc = image_exec ( replacement ) ) != 0 )
292 return rc;
295 return rc;
299 * Register and autoload an image
301 * @v image Image
302 * @ret rc Return status code
304 int register_and_autoload_image ( struct image *image ) {
305 int rc;
307 if ( ( rc = register_image ( image ) ) != 0 )
308 return rc;
310 if ( ( rc = image_autoload ( image ) ) != 0 )
311 return rc;
313 return 0;
317 * Register and autoexec an image
319 * @v image Image
320 * @ret rc Return status code
322 int register_and_autoexec_image ( struct image *image ) {
323 int rc;
325 if ( ( rc = register_and_autoload_image ( image ) ) != 0 )
326 return rc;
328 if ( ( rc = image_exec ( image ) ) != 0 )
329 return rc;
331 return 0;