b5ef7c5926645adff2f17d368b5daa72f276af16
[people/xl0/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 <errno.h>
23 #include <assert.h>
24 #include <vsprintf.h>
25 #include <gpxe/list.h>
26 #include <gpxe/emalloc.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  * Register executable/loadable image
46  *
47  * @v image             Executable/loadable image
48  * @ret rc              Return status code
49  */
50 int register_image ( struct image *image ) {
51         static unsigned int imgindex = 0;
52
53         /* Create image name if it doesn't already have one */
54         if ( ! image->name[0] ) {
55                 snprintf ( image->name, sizeof ( image->name ), "img%d",
56                            imgindex++ );
57         }
58
59         /* Add to image list */
60         list_add_tail ( &image->list, &images );
61         DBGC ( image, "IMAGE %p at [%lx,%lx) registered as %s\n",
62                image, user_to_phys ( image->data, 0 ),
63                user_to_phys ( image->data, image->len ), image->name );
64
65         return 0;
66 }
67
68 /**
69  * Unregister executable/loadable image
70  *
71  * @v image             Executable/loadable image
72  */
73 void unregister_image ( struct image *image ) {
74         list_del ( &image->list );
75         DBGC ( image, "IMAGE %p unregistered\n", image );
76 }
77
78 /**
79  * Move image to start of list of registered images
80  *
81  * @v image             Executable/loadable image
82  *
83  * Move the image to the start of the image list.  This makes it
84  * easier to keep track of which of the images marked as loaded is
85  * likely to still be valid.
86  */
87 void promote_image ( struct image *image ) {
88         list_del ( &image->list );
89         list_add ( &image->list, &images );
90 }
91
92 /**
93  * Find image by name
94  *
95  * @v name              Image name
96  * @ret image           Executable/loadable image, or NULL
97  */
98 struct image * find_image ( const char *name ) {
99         struct image *image;
100
101         list_for_each_entry ( image, &images, list ) {
102                 if ( strcmp ( image->name, name ) == 0 )
103                         return image;
104         }
105
106         return NULL;
107 }
108
109 /**
110  * Load executable/loadable image into memory
111  *
112  * @v image             Executable/loadable image
113  * @v type              Executable/loadable image type
114  * @ret rc              Return status code
115  */
116 static int image_load_type ( struct image *image, struct image_type *type ) {
117         int rc;
118
119         if ( ( rc = type->load ( image ) ) != 0 ) {
120                 DBGC ( image, "IMAGE %p could not load as %s: %s\n",
121                        image, type->name, strerror ( rc ) );
122                 return rc;
123         }
124
125         /* Flag as loaded */
126         image->flags |= IMAGE_LOADED;
127         return 0;
128 }
129
130 /**
131  * Load executable/loadable image into memory
132  *
133  * @v image             Executable/loadable image
134  * @ret rc              Return status code
135  */
136 int image_load ( struct image *image ) {
137
138         assert ( image->type != NULL );
139
140         return image_load_type ( image, image->type );
141 }
142
143 /**
144  * Autodetect image type and load executable/loadable image into memory
145  *
146  * @v image             Executable/loadable image
147  * @ret rc              Return status code
148  */
149 int image_autoload ( struct image *image ) {
150         struct image_type *type;
151         int rc;
152
153         for ( type = image_types ; type < image_types_end ; type++ ) {
154                 DBGC ( image, "IMAGE %p trying type %s\n", image, type->name );
155                 rc = image_load_type ( image, type );
156                 if ( image->type == NULL )
157                         continue;
158                 return rc;
159         }
160
161         DBGC ( image, "IMAGE %p format not recognised\n", image );
162         return -ENOEXEC;
163 }
164
165 /**
166  * Execute loaded image
167  *
168  * @v image             Loaded image
169  * @ret rc              Return status code
170  */
171 int image_exec ( struct image *image ) {
172         int rc;
173
174         /* Image must be loaded first */
175         if ( ! ( image->flags & IMAGE_LOADED ) ) {
176                 DBGC ( image, "IMAGE %p could not execute: not loaded\n",
177                        image );
178                 return -ENOTTY;
179         }
180
181         assert ( image->type != NULL );
182
183         /* Try executing the image */
184         if ( ( rc = image->type->exec ( image ) ) != 0 ) {
185                 DBGC ( image, "IMAGE %p could not execute: %s\n",
186                        image, strerror ( rc ) );
187                 return rc;
188         }
189
190         /* Well, some formats might return... */
191         return 0;
192 }