e270540aab02fc6ce2372b3ab423ab23aef2d97b
[people/pcmattman/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 <gpxe/list.h>
26 #include <gpxe/umalloc.h>
27 #include <gpxe/image.h>
28
29 /** @file
30  *
31  * Executable/loadable images
32  *
33  */
34
35 /** List of registered images */
36 struct list_head images = LIST_HEAD_INIT ( images );
37
38 /** List of image types */
39 static struct image_type image_types[0]
40         __table_start ( struct image_type, image_types );
41 static struct image_type image_types_end[0]
42         __table_end ( struct image_type, image_types );
43
44 /**
45  * Free executable/loadable image
46  *
47  * @v refcnt            Reference counter
48  */
49 static void free_image ( struct refcnt *refcnt ) {
50         struct image *image = container_of ( refcnt, struct image, refcnt );
51
52         ufree ( image->data );
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  */
62 struct image * alloc_image ( void ) {
63         struct image *image;
64
65         image = malloc ( sizeof ( *image ) );
66         if ( image ) {
67                 memset ( image, 0, sizeof ( *image ) );
68                 image->refcnt.free = free_image;
69         }
70         return image;
71 }
72
73 /**
74  * Register executable/loadable image
75  *
76  * @v image             Executable/loadable image
77  * @ret rc              Return status code
78  */
79 int register_image ( struct image *image ) {
80         static unsigned int imgindex = 0;
81
82         /* Create image name if it doesn't already have one */
83         if ( ! image->name[0] ) {
84                 snprintf ( image->name, sizeof ( image->name ), "img%d",
85                            imgindex++ );
86         }
87
88         /* Add to image list */
89         image_get ( image );
90         list_add_tail ( &image->list, &images );
91         DBGC ( image, "IMAGE %p at [%lx,%lx) registered as %s\n",
92                image, user_to_phys ( image->data, 0 ),
93                user_to_phys ( image->data, image->len ), image->name );
94
95         return 0;
96 }
97
98 /**
99  * Unregister executable/loadable image
100  *
101  * @v image             Executable/loadable image
102  */
103 void unregister_image ( struct image *image ) {
104         list_del ( &image->list );
105         image_put ( image );
106         DBGC ( image, "IMAGE %p unregistered\n", image );
107 }
108
109 /**
110  * Move image to start of list of registered images
111  *
112  * @v image             Executable/loadable image
113  *
114  * Move the image to the start of the image list.  This makes it
115  * easier to keep track of which of the images marked as loaded is
116  * likely to still be valid.
117  */
118 void promote_image ( struct image *image ) {
119         list_del ( &image->list );
120         list_add ( &image->list, &images );
121 }
122
123 /**
124  * Find image by name
125  *
126  * @v name              Image name
127  * @ret image           Executable/loadable image, or NULL
128  */
129 struct image * find_image ( const char *name ) {
130         struct image *image;
131
132         list_for_each_entry ( image, &images, list ) {
133                 if ( strcmp ( image->name, name ) == 0 )
134                         return image;
135         }
136
137         return NULL;
138 }
139
140 /**
141  * Load executable/loadable image into memory
142  *
143  * @v image             Executable/loadable image
144  * @v type              Executable/loadable image type
145  * @ret rc              Return status code
146  */
147 static int image_load_type ( struct image *image, struct image_type *type ) {
148         int rc;
149
150         /* Check image is actually loadable */
151         if ( ! type->load )
152                 return -ENOEXEC;
153
154         /* Try the image loader */
155         if ( ( rc = type->load ( image ) ) != 0 ) {
156                 DBGC ( image, "IMAGE %p could not load as %s: %s\n",
157                        image, type->name, strerror ( rc ) );
158                 return rc;
159         }
160
161         /* Flag as loaded */
162         image->flags |= IMAGE_LOADED;
163         return 0;
164 }
165
166 /**
167  * Load executable/loadable image into memory
168  *
169  * @v image             Executable/loadable image
170  * @ret rc              Return status code
171  */
172 int image_load ( struct image *image ) {
173
174         assert ( image->type != NULL );
175
176         return image_load_type ( image, image->type );
177 }
178
179 /**
180  * Autodetect image type and load executable/loadable image into memory
181  *
182  * @v image             Executable/loadable image
183  * @ret rc              Return status code
184  */
185 int image_autoload ( struct image *image ) {
186         struct image_type *type;
187         int rc;
188
189         /* If image already has a type, use it */
190         if ( image->type )
191                 return image_load ( image );
192
193         /* Otherwise probe for a suitable type */
194         for ( type = image_types ; type < image_types_end ; type++ ) {
195                 DBGC ( image, "IMAGE %p trying type %s\n", image, type->name );
196                 rc = image_load_type ( image, type );
197                 if ( image->type == NULL )
198                         continue;
199                 return rc;
200         }
201
202         DBGC ( image, "IMAGE %p format not recognised\n", image );
203         return -ENOEXEC;
204 }
205
206 /**
207  * Execute loaded image
208  *
209  * @v image             Loaded image
210  * @ret rc              Return status code
211  */
212 int image_exec ( struct image *image ) {
213         int rc;
214
215         /* Image must be loaded first */
216         if ( ! ( image->flags & IMAGE_LOADED ) ) {
217                 DBGC ( image, "IMAGE %p could not execute: not loaded\n",
218                        image );
219                 return -ENOTTY;
220         }
221
222         assert ( image->type != NULL );
223
224         /* Check that image is actually executable */
225         if ( ! image->type->exec )
226                 return -ENOEXEC;
227
228         /* Try executing the image */
229         if ( ( rc = image->type->exec ( image ) ) != 0 ) {
230                 DBGC ( image, "IMAGE %p could not execute: %s\n",
231                        image, strerror ( rc ) );
232                 return rc;
233         }
234
235         /* Well, some formats might return... */
236         return 0;
237 }