• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2006 Michael Brown <mbrown@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  */
free_image(struct refcnt * refcnt)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  */
alloc_image(void)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  */
image_set_uri(struct image * image,struct uri * uri)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  */
image_set_cmdline(struct image * image,const char * cmdline)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  */
register_image(struct image * image)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  */
unregister_image(struct image * image)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  */
find_image(const char * name)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  */
image_load_type(struct image * image,struct image_type * type)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  */
image_load(struct image * image)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  */
image_autoload(struct image * image)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  */
image_exec(struct image * image)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  */
register_and_autoload_image(struct image * image)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  */
register_and_autoexec_image(struct image * image)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