d896be0e99994170f6debf104b2554c9c2d5ea78
[people/mdeck/gpxe.git] / src / core / image.c
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 #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>
30
31 /** @file
32  *
33  * Executable/loadable images
34  *
35  */
36
37 /** List of registered images */
38 struct list_head images = LIST_HEAD_INIT ( images );
39
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 );
45
46 /**
47  * Free executable/loadable image
48  *
49  * @v refcnt            Reference counter
50  */
51 static void free_image ( struct refcnt *refcnt ) {
52         struct image *image = container_of ( refcnt, struct image, refcnt );
53
54         uri_put ( image->uri );
55         ufree ( image->data );
56         free ( image );
57         DBGC ( image, "IMAGE %p freed\n", image );
58 }
59
60 /**
61  * Allocate executable/loadable image
62  *
63  * @ret image           Executable/loadable image
64  */
65 struct image * alloc_image ( void ) {
66         struct image *image;
67
68         image = zalloc ( sizeof ( *image ) );
69         if ( image ) {
70                 image->refcnt.free = free_image;
71         }
72         return image;
73 }
74
75 /**
76  * Set image URI
77  *
78  * @v image             Image
79  * @v URI               New image URI
80  * @ret rc              Return status code
81  *
82  * If no name is set, the name will be updated to the base name of the
83  * URI path (if any).
84  */
85 int image_set_uri ( struct image *image, struct uri *uri ) {
86         const char *path = uri->path;
87
88         /* Replace URI reference */
89         uri_put ( image->uri );
90         image->uri = uri_get ( uri );
91
92         /* Set name if none already specified */
93         if ( path && ( ! image->name[0] ) )
94                 image_set_name ( image, basename ( ( char * ) path ) );
95
96         return 0;
97 }
98
99 /**
100  * Set image command line
101  *
102  * @v image             Image
103  * @v cmdline           New image command line
104  * @ret rc              Return status code
105  */
106 int image_set_cmdline ( struct image *image, const char *cmdline ) {
107         free ( image->cmdline );
108         image->cmdline = strdup ( cmdline );
109         if ( ! image->cmdline )
110                 return -ENOMEM;
111         return 0;
112 }
113
114 /**
115  * Register executable/loadable image
116  *
117  * @v image             Executable/loadable image
118  * @ret rc              Return status code
119  */
120 int register_image ( struct image *image ) {
121         static unsigned int imgindex = 0;
122
123         /* Create image name if it doesn't already have one */
124         if ( ! image->name[0] ) {
125                 snprintf ( image->name, sizeof ( image->name ), "img%d",
126                            imgindex++ );
127         }
128
129         /* Add to image list */
130         image_get ( image );
131         list_add_tail ( &image->list, &images );
132         DBGC ( image, "IMAGE %p at [%lx,%lx) registered as %s\n",
133                image, user_to_phys ( image->data, 0 ),
134                user_to_phys ( image->data, image->len ), image->name );
135
136         return 0;
137 }
138
139 /**
140  * Unregister executable/loadable image
141  *
142  * @v image             Executable/loadable image
143  */
144 void unregister_image ( struct image *image ) {
145         list_del ( &image->list );
146         image_put ( image );
147         DBGC ( image, "IMAGE %p unregistered\n", image );
148 }
149
150 /**
151  * Find image by name
152  *
153  * @v name              Image name
154  * @ret image           Executable/loadable image, or NULL
155  */
156 struct image * find_image ( const char *name ) {
157         struct image *image;
158
159         for_each_image ( image ) {
160                 if ( strcmp ( image->name, name ) == 0 )
161                         return image;
162         }
163
164         return NULL;
165 }
166
167 /**
168  * Load executable/loadable image into memory
169  *
170  * @v image             Executable/loadable image
171  * @v type              Executable/loadable image type
172  * @ret rc              Return status code
173  */
174 static int image_load_type ( struct image *image, struct image_type *type ) {
175         struct image *tmp_image;
176         int rc;
177
178         /* Check image is actually loadable */
179         if ( ! type->load )
180                 return -ENOEXEC;
181
182         /* Clear the loaded flag on all images; loading this image
183          * will invalidate any previous loads.  (Even if loading
184          * fails, the previously loaded image may still have been
185          * partially overwritten.)
186          */
187         for_each_image ( tmp_image )
188                 tmp_image->flags &= ~IMAGE_LOADED;
189
190         /* Try the image loader */
191         if ( ( rc = type->load ( image ) ) != 0 ) {
192                 DBGC ( image, "IMAGE %p could not load as %s: %s\n",
193                        image, type->name, strerror ( rc ) );
194                 return rc;
195         }
196
197         /* Flag as loaded */
198         image->flags |= IMAGE_LOADED;
199         return 0;
200 }
201
202 /**
203  * Load executable/loadable image into memory
204  *
205  * @v image             Executable/loadable image
206  * @ret rc              Return status code
207  */
208 int image_load ( struct image *image ) {
209
210         assert ( image->type != NULL );
211
212         return image_load_type ( image, image->type );
213 }
214
215 /**
216  * Autodetect image type and load executable/loadable image into memory
217  *
218  * @v image             Executable/loadable image
219  * @ret rc              Return status code
220  */
221 int image_autoload ( struct image *image ) {
222         struct image_type *type;
223         int rc;
224
225         /* If image already has a type, use it */
226         if ( image->type )
227                 return image_load ( image );
228
229         /* Otherwise probe for a suitable type */
230         for ( type = image_types ; type < image_types_end ; type++ ) {
231                 DBGC ( image, "IMAGE %p trying type %s\n", image, type->name );
232                 rc = image_load_type ( image, type );
233                 if ( image->type == NULL )
234                         continue;
235                 return rc;
236         }
237
238         DBGC ( image, "IMAGE %p format not recognised\n", image );
239         return -ENOEXEC;
240 }
241
242 /**
243  * Execute loaded image
244  *
245  * @v image             Loaded image
246  * @ret rc              Return status code
247  */
248 int image_exec ( struct image *image ) {
249         struct uri *old_cwuri;
250         int rc;
251
252         /* Image must be loaded first */
253         if ( ! ( image->flags & IMAGE_LOADED ) ) {
254                 DBGC ( image, "IMAGE %p could not execute: not loaded\n",
255                        image );
256                 return -ENOTTY;
257         }
258
259         assert ( image->type != NULL );
260
261         /* Check that image is actually executable */
262         if ( ! image->type->exec )
263                 return -ENOEXEC;
264
265         /* Switch current working directory to be that of the image itself */
266         old_cwuri = uri_get ( cwuri );
267         churi ( image->uri );
268
269         /* Try executing the image */
270         if ( ( rc = image->type->exec ( image ) ) != 0 ) {
271                 DBGC ( image, "IMAGE %p could not execute: %s\n",
272                        image, strerror ( rc ) );
273                 goto done;
274         }
275
276  done:
277         /* Reset current working directory */
278         churi ( old_cwuri );
279         uri_put ( old_cwuri );
280
281         return rc;
282 }
283
284 /**
285  * Register and autoload an image
286  *
287  * @v image             Image
288  * @ret rc              Return status code
289  */
290 int register_and_autoload_image ( struct image *image ) {
291         int rc;
292
293         if ( ( rc = register_image ( image ) ) != 0 )
294                 return rc;
295
296         if ( ( rc = image_autoload ( image ) ) != 0 )
297                 return rc;
298
299         return 0;
300 }
301
302 /**
303  * Register and autoexec an image
304  *
305  * @v image             Image
306  * @ret rc              Return status code
307  */
308 int register_and_autoexec_image ( struct image *image ) {
309         int rc;
310
311         if ( ( rc = register_and_autoload_image ( image ) ) != 0 )
312                 return rc;
313
314         if ( ( rc = image_exec ( image ) ) != 0 )
315                 return rc;
316
317         return 0;
318 }