741b054783f3d837cdfa53a63f38d37e3c27d985
[people/lynusvaz/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         image_put ( image->replacement );
57         free ( image );
58         DBGC ( image, "IMAGE %p freed\n", image );
59 }
60
61 /**
62  * Allocate executable/loadable image
63  *
64  * @ret image           Executable/loadable image
65  */
66 struct image * alloc_image ( void ) {
67         struct image *image;
68
69         image = zalloc ( sizeof ( *image ) );
70         if ( image ) {
71                 image->refcnt.free = free_image;
72         }
73         return image;
74 }
75
76 /**
77  * Set image URI
78  *
79  * @v image             Image
80  * @v URI               New image URI
81  * @ret rc              Return status code
82  *
83  * If no name is set, the name will be updated to the base name of the
84  * URI path (if any).
85  */
86 int image_set_uri ( struct image *image, struct uri *uri ) {
87         const char *path = uri->path;
88
89         /* Replace URI reference */
90         uri_put ( image->uri );
91         image->uri = uri_get ( uri );
92
93         /* Set name if none already specified */
94         if ( path && ( ! image->name[0] ) )
95                 image_set_name ( image, basename ( ( char * ) path ) );
96
97         return 0;
98 }
99
100 /**
101  * Set image command line
102  *
103  * @v image             Image
104  * @v cmdline           New image command line
105  * @ret rc              Return status code
106  */
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;
113 }
114
115 /**
116  * Register executable/loadable image
117  *
118  * @v image             Executable/loadable image
119  * @ret rc              Return status code
120  */
121 int register_image ( struct image *image ) {
122         static unsigned int imgindex = 0;
123
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++ );
128         }
129
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 );
136
137         return 0;
138 }
139
140 /**
141  * Unregister executable/loadable image
142  *
143  * @v image             Executable/loadable image
144  */
145 void unregister_image ( struct image *image ) {
146         DBGC ( image, "IMAGE %p unregistered\n", image );
147         list_del ( &image->list );
148         image_put ( image );
149 }
150
151 /**
152  * Find image by name
153  *
154  * @v name              Image name
155  * @ret image           Executable/loadable image, or NULL
156  */
157 struct image * find_image ( const char *name ) {
158         struct image *image;
159
160         list_for_each_entry ( image, &images, list ) {
161                 if ( strcmp ( image->name, name ) == 0 )
162                         return image;
163         }
164
165         return NULL;
166 }
167
168 /**
169  * Load executable/loadable image into memory
170  *
171  * @v image             Executable/loadable image
172  * @v type              Executable/loadable image type
173  * @ret rc              Return status code
174  */
175 static int image_load_type ( struct image *image, struct image_type *type ) {
176         int rc;
177
178         /* Check image is actually loadable */
179         if ( ! type->load )
180                 return -ENOEXEC;
181
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;
187         }
188
189         /* Flag as loaded */
190         image->flags |= IMAGE_LOADED;
191         return 0;
192 }
193
194 /**
195  * Load executable/loadable image into memory
196  *
197  * @v image             Executable/loadable image
198  * @ret rc              Return status code
199  */
200 int image_load ( struct image *image ) {
201
202         assert ( image->type != NULL );
203
204         return image_load_type ( image, image->type );
205 }
206
207 /**
208  * Autodetect image type and load executable/loadable image into memory
209  *
210  * @v image             Executable/loadable image
211  * @ret rc              Return status code
212  */
213 int image_autoload ( struct image *image ) {
214         struct image_type *type;
215         int rc;
216
217         /* If image already has a type, use it */
218         if ( image->type )
219                 return image_load ( image );
220
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;
228         }
229
230         DBGC ( image, "IMAGE %p format not recognised\n", image );
231         return -ENOEXEC;
232 }
233
234 /**
235  * Execute loaded image
236  *
237  * @v image             Loaded image
238  * @ret rc              Return status code
239  */
240 int image_exec ( struct image *image ) {
241         struct image *replacement;
242         struct uri *old_cwuri;
243         int rc;
244
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;
250         }
251
252         assert ( image->type != NULL );
253
254         /* Check that image is actually executable */
255         if ( ! image->type->exec )
256                 return -ENOEXEC;
257
258         /* Switch current working directory to be that of the image itself */
259         old_cwuri = uri_get ( cwuri );
260         churi ( image->uri );
261
262         /* Take out a temporary reference to the image.  This allows
263          * the image to unregister itself if necessary, without
264          * automatically freeing itself.
265          */
266         image_get ( image );
267
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 */
273         }
274
275         /* Pick up replacement image before we drop the original
276          * image's temporary reference.
277          */
278         if ( ( replacement = image->replacement ) != NULL )
279                 image_get ( replacement );
280
281         /* Drop temporary reference to the original image */
282         image_put ( image );
283
284         /* Reset current working directory */
285         churi ( old_cwuri );
286         uri_put ( old_cwuri );
287
288         /* Tail-recurse into replacement image, if one exists */
289         if ( replacement ) {
290                 DBGC ( image, "IMAGE %p replacing self with IMAGE %p\n",
291                        image, replacement );
292                 if ( ( rc = image_exec ( replacement ) ) != 0 )
293                         return rc;
294         }
295
296         return rc;
297 }
298
299 /**
300  * Register and autoload an image
301  *
302  * @v image             Image
303  * @ret rc              Return status code
304  */
305 int register_and_autoload_image ( struct image *image ) {
306         int rc;
307
308         if ( ( rc = register_image ( image ) ) != 0 )
309                 return rc;
310
311         if ( ( rc = image_autoload ( image ) ) != 0 )
312                 return rc;
313
314         return 0;
315 }
316
317 /**
318  * Register and autoexec an image
319  *
320  * @v image             Image
321  * @ret rc              Return status code
322  */
323 int register_and_autoexec_image ( struct image *image ) {
324         int rc;
325
326         if ( ( rc = register_and_autoload_image ( image ) ) != 0 )
327                 return rc;
328
329         if ( ( rc = image_exec ( image ) ) != 0 )
330                 return rc;
331
332         return 0;
333 }