source: bootcd/isolinux/syslinux-6.03/gpxe/src/core/image.c

Last change on this file was e16e8f2, checked in by Edwin Eefting <edwin@datux.nl>, 3 years ago

bootstuff

  • Property mode set to 100644
File size: 7.3 KB
Line 
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
19FILE_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 */
40struct list_head images = LIST_HEAD_INIT ( images );
41
42/**
43 * Free executable/loadable image
44 *
45 * @v refcnt            Reference counter
46 */
47static 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 */
62struct 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 */
82int 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 */
103int 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 */
117int 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 */
141void 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 */
153struct 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 */
171static 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 */
196int 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 */
209int 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 */
236int 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 */
300int 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 */
318int 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}
Note: See TracBrowser for help on using the repository browser.