Bläddra i källkod

Provide registration mechanism for loaded images, so that we can e.g.

refer to them by name from the command line, or build them into a
multiboot module list.

Use setting image->type to disambiguate between "not my image" and "bad
image"; this avoids relying on specific values of the error code.
tags/v0.9.3
Michael Brown 18 år sedan
förälder
incheckning
f59ad50504
4 ändrade filer med 262 tillägg och 122 borttagningar
  1. 92
    38
      src/arch/i386/image/multiboot.c
  2. 115
    62
      src/core/image.c
  3. 11
    5
      src/image/elf.c
  4. 44
    17
      src/include/gpxe/image.h

+ 92
- 38
src/arch/i386/image/multiboot.c Visa fil

@@ -24,6 +24,7 @@
24 24
  */
25 25
 
26 26
 #include <errno.h>
27
+#include <alloca.h>
27 28
 #include <multiboot.h>
28 29
 #include <gpxe/uaccess.h>
29 30
 #include <gpxe/image.h>
@@ -31,6 +32,8 @@
31 32
 #include <gpxe/memmap.h>
32 33
 #include <gpxe/elf.h>
33 34
 
35
+struct image_type multiboot_image_type __image_type;
36
+
34 37
 /** Multiboot flags that we support */
35 38
 #define MB_SUPPORTED_FLAGS ( MB_FLAG_PGALIGN | MB_FLAG_MEMMAP | \
36 39
 			     MB_FLAG_VIDMODE | MB_FLAG_RAW )
@@ -58,57 +61,116 @@ struct multiboot_header_info {
58 61
 };
59 62
 
60 63
 /**
61
- * Execute multiboot image
64
+ * Build multiboot memory map
62 65
  *
63
- * @v image		ELF file
64
- * @ret rc		Return status code
66
+ * @v mbinfo		Multiboot information structure
67
+ * @v mbmemmap		Multiboot memory map
65 68
  */
66
-static int multiboot_execute ( struct image *image ) {
67
-	static const char *bootloader_name = "gPXE " VERSION;
68
-	struct multiboot_info mbinfo;
69
+static void multiboot_build_memmap ( struct multiboot_info *mbinfo,
70
+				     struct multiboot_memory_map *mbmemmap ) {
69 71
 	struct memory_map memmap;
70
-	struct multiboot_memory_map mbmemmap[ sizeof ( memmap.regions ) /
71
-					      sizeof ( memmap.regions[0] ) ];
72 72
 	unsigned int i;
73 73
 
74
-	/* Populate multiboot information structure */
75
-	memset ( &mbinfo, 0, sizeof ( mbinfo ) );
76
-
77
-	/* Set boot loader name */
78
-	mbinfo.flags |= MBI_FLAG_LOADER;
79
-	mbinfo.boot_loader_name = virt_to_phys ( bootloader_name );
80
-	
81 74
 	/* Get memory map */
82 75
 	get_memmap ( &memmap );
83
-	memset ( mbmemmap, 0, sizeof ( mbmemmap ) );
76
+
77
+	/* Translate into multiboot format */
78
+	memset ( mbmemmap, 0, sizeof ( *mbmemmap ) );
84 79
 	for ( i = 0 ; i < memmap.count ; i++ ) {
85 80
 		mbmemmap[i].size = sizeof ( mbmemmap[i] );
86 81
 		mbmemmap[i].base_addr = memmap.regions[i].start;
87 82
 		mbmemmap[i].length = ( memmap.regions[i].end -
88 83
 				       memmap.regions[i].start );
89 84
 		mbmemmap[i].type = MBMEM_RAM;
90
-		mbinfo.mmap_length += sizeof ( mbmemmap[i] );
85
+		mbinfo->mmap_length += sizeof ( mbmemmap[i] );
91 86
 		if ( memmap.regions[i].start == 0 )
92
-			mbinfo.mem_lower = memmap.regions[i].end;
87
+			mbinfo->mem_lower = memmap.regions[i].end;
93 88
 		if ( memmap.regions[i].start == 0x100000 )
94
-			mbinfo.mem_upper = ( memmap.regions[i].end - 0x100000);
89
+			mbinfo->mem_upper = ( memmap.regions[i].end -
90
+					      0x100000 );
95 91
 	}
96
-	mbinfo.flags |= ( MBI_FLAG_MEM | MBI_FLAG_MMAP );
92
+}
93
+
94
+/**
95
+ * Build multiboot module list
96
+ *
97
+ * @v image		Multiboot image
98
+ * @v modules		Module list to fill, or NULL
99
+ * @ret count		Number of modules
100
+ */
101
+static unsigned int
102
+multiboot_build_module_list ( struct image *image,
103
+			      struct multiboot_module *modules ) {
104
+	struct image *module_image;
105
+	struct multiboot_module *module;
106
+	unsigned int count = 0;
107
+
108
+	for_each_image ( module_image ) {
109
+		/* Do not include kernel image as a module */
110
+		if ( module_image == image )
111
+			continue;
112
+		module = &modules[count++];
113
+		/* Populate module data structure, if applicable */
114
+		if ( ! modules )
115
+			continue;
116
+		module->mod_start = user_to_phys ( module_image->data, 0 );
117
+		module->mod_end = user_to_phys ( module_image->data,
118
+						 module_image->len );
119
+		if ( image->cmdline )
120
+			module->string = virt_to_phys ( image->cmdline );
121
+	}
122
+
123
+	return count;
124
+}
125
+
126
+/**
127
+ * Execute multiboot image
128
+ *
129
+ * @v image		Multiboot image
130
+ * @ret rc		Return status code
131
+ */
132
+static int multiboot_exec ( struct image *image ) {
133
+	static const char *bootloader_name = "gPXE " VERSION;
134
+	struct multiboot_info mbinfo;
135
+	struct multiboot_memory_map mbmemmap[MAX_MEMORY_REGIONS];
136
+	struct multiboot_module *modules;
137
+	unsigned int num_modules;
138
+
139
+	/* Populate multiboot information structure */
140
+	memset ( &mbinfo, 0, sizeof ( mbinfo ) );
141
+
142
+	/* Set boot loader name */
143
+	mbinfo.boot_loader_name = virt_to_phys ( bootloader_name );
144
+	mbinfo.flags |= MBI_FLAG_LOADER;
145
+	
146
+	/* Build memory map */
147
+	multiboot_build_memmap ( &mbinfo, mbmemmap );
97 148
 	mbinfo.mmap_addr = virt_to_phys ( &mbmemmap[0].base_addr );
149
+	mbinfo.flags |= ( MBI_FLAG_MEM | MBI_FLAG_MMAP );
98 150
 
99 151
 	/* Set command line, if present */
100 152
 	if ( image->cmdline ) {
101
-		mbinfo.flags |= MBI_FLAG_CMDLINE;
102 153
 		mbinfo.cmdline = virt_to_phys ( image->cmdline );
154
+		mbinfo.flags |= MBI_FLAG_CMDLINE;
103 155
 	}
104 156
 
157
+	/* Construct module list */
158
+	num_modules = multiboot_build_module_list ( image, NULL );
159
+	modules = alloca ( num_modules * sizeof ( *modules ) );
160
+	multiboot_build_module_list ( image, modules );
161
+	mbinfo.mods_count = num_modules;
162
+	mbinfo.mods_addr = virt_to_phys ( modules );
163
+	mbinfo.flags |= MBI_FLAG_MODS;
164
+
105 165
 	/* Jump to OS with flat physical addressing */
106
-	__asm__ __volatile__ ( PHYS_CODE ( "xchgw %%bx,%%bx\n\t"
107
-					   "call *%%edi\n\t" )
166
+	__asm__ __volatile__ ( PHYS_CODE ( /* Preserve %ebp for alloca() */
167
+					   "pushl %%ebp\n\t"
168
+					   "call *%%edi\n\t"
169
+					   "popl %%ebp\n\t" )
108 170
 			       : : "a" ( MULTIBOOT_BOOTLOADER_MAGIC ),
109 171
 			           "b" ( virt_to_phys ( &mbinfo ) ),
110 172
 			           "D" ( image->entry )
111
-			       : "ecx", "edx", "esi", "ebp" );
173
+			       : "ecx", "edx", "esi", "memory" );
112 174
 
113 175
 	return -ECANCELED;
114 176
 }
@@ -191,7 +253,6 @@ static int multiboot_load_raw ( struct image *image,
191 253
 
192 254
 	/* Record execution entry point */
193 255
 	image->entry = hdr->mb.entry_addr;
194
-	image->execute = multiboot_execute;
195 256
 
196 257
 	return 0;
197 258
 }
@@ -209,21 +270,9 @@ static int multiboot_load_elf ( struct image *image ) {
209 270
 	if ( ( rc = elf_load ( image ) ) != 0 ) {
210 271
 		DBG ( "Multiboot ELF image failed to load: %s\n",
211 272
 		      strerror ( rc ) );
212
-		/* We must translate "not an ELF image" (i.e. ENOEXEC)
213
-		 * into "invalid multiboot image", to avoid screwing
214
-		 * up the image probing logic.
215
-		 */
216
-		if ( rc == -ENOEXEC ) {
217
-			return -ENOTSUP;
218
-		} else {
219
-			return rc;
220
-		}
273
+		return rc;
221 274
 	}
222 275
 
223
-	/* Capture execution method */
224
-	if ( image->execute )
225
-		image->execute = multiboot_execute;
226
-
227 276
 	return 0;
228 277
 }
229 278
 
@@ -244,6 +293,10 @@ int multiboot_load ( struct image *image ) {
244 293
 	}
245 294
 	DBG ( "Found multiboot header with flags %08lx\n", hdr.mb.flags );
246 295
 
296
+	/* This is a multiboot image, valid or otherwise */
297
+	if ( ! image->type )
298
+		image->type = &multiboot_image_type;
299
+
247 300
 	/* Abort if we detect flags that we cannot support */
248 301
 	if ( hdr.mb.flags & MB_UNSUPPORTED_FLAGS ) {
249 302
 		DBG ( "Multiboot flags %08lx not supported\n",
@@ -267,4 +320,5 @@ int multiboot_load ( struct image *image ) {
267 320
 struct image_type multiboot_image_type __image_type = {
268 321
 	.name = "Multiboot",
269 322
 	.load = multiboot_load,
323
+	.exec = multiboot_exec,
270 324
 };

+ 115
- 62
src/core/image.c Visa fil

@@ -1,85 +1,138 @@
1
-#include "dev.h"
2
-#include <gpxe/buffer.h>
3
-#include <console.h>
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/image.h>
27
+
28
+/** @file
29
+ *
30
+ * Executable/loadable images
31
+ *
32
+ */
4 33
 
5
-#if 0
34
+/** List of registered images */
35
+struct list_head images = LIST_HEAD_INIT ( images );
6 36
 
7
-static struct image images[0] __image_start;
8
-static struct image images_end[0] __image_end;
37
+/** List of image types */
38
+static struct image_type image_types[0]
39
+	__table_start ( struct image_type, image_types );
40
+static struct image_type image_types_end[0]
41
+	__table_end ( struct image_type, image_types );
9 42
 
10
-/*
11
- * Print all images
43
+/**
44
+ * Register executable/loadable image
12 45
  *
46
+ * @v image		Executable/loadable image
47
+ * @ret rc		Return status code
13 48
  */
14
-void print_images ( void ) {
15
-	struct image *image;
49
+int register_image ( struct image *image ) {
50
+	static unsigned int imgindex = 0;
16 51
 
17
-	for ( image = images ; image < images_end ; image++ ) {
18
-		printf ( "%s ", image->name );
19
-	}
52
+	/* Create image name */
53
+	snprintf ( image->name, sizeof ( image->name ), "img%d",
54
+		   imgindex++ );
55
+
56
+	/* Add to image list */
57
+	list_add_tail ( &image->list, &images );
58
+	DBGC ( image, "IMAGE %p registered as %s\n", image, image->name );
59
+
60
+	return 0;
20 61
 }
21 62
 
22
-/*
23
- * Identify the image format
63
+/**
64
+ * Unregister executable/loadable image
24 65
  *
66
+ * @v image		Executable/loadable image
25 67
  */
26
-static struct image * identify_image ( physaddr_t start, physaddr_t len,
27
-				       void **context ) {
28
-	struct image *image;
29
-	
30
-	for ( image = images ; image < images_end ; image++ ) {
31
-		if ( image->probe ( start, len, context ) )
32
-			return image;
33
-	}
34
-	
35
-	return NULL;
68
+void unregister_image ( struct image *image ) {
69
+	list_del ( &image->list );
70
+	DBGC ( image, "IMAGE %p unregistered\n", image );
36 71
 }
37 72
 
38
-/*
39
- * Load an image into memory at a location determined by the image
40
- * format
73
+/**
74
+ * Load executable/loadable image into memory
41 75
  *
76
+ * @v image		Executable/loadable image
77
+ * @ret rc		Return status code
42 78
  */
43
-int autoload ( struct dev *dev, struct image **image, void **context ) {
44
-	struct buffer buffer;
45
-	int rc = 0;
46
-
47
-	/* Prepare the load buffer */
48
-	if ( ! init_load_buffer ( &buffer ) ) {
49
-		DBG ( "IMAGE could not initialise load buffer\n" );
50
-		goto out;
51
-	}
79
+int image_load ( struct image *image ) {
80
+	int rc;
52 81
 
53
-	/* Load the image into the load buffer */
54
-	if ( ! load ( dev, &buffer ) ) {
55
-		DBG ( "IMAGE could not load image\n" );
56
-		goto out_free;
82
+	assert ( image->type != NULL );
83
+
84
+	if ( ( rc = image->type->load ( image ) ) != 0 ) {
85
+		DBGC ( image, "IMAGE %p could not load: %s\n",
86
+		       image, strerror ( rc ) );
87
+		return rc;
57 88
 	}
58 89
 
59
-	/* Shrink the load buffer */
60
-	trim_load_buffer ( &buffer );
90
+	return 0;
91
+}
61 92
 
62
-	/* Identify the image type */
63
-	*image = identify_image ( buffer.start, buffer.fill, context );
64
-	if ( ! *image ) {
65
-		DBG ( "IMAGE could not identify image type\n" );
66
-		goto out_free;
67
-	}
93
+/**
94
+ * Autodetect image type and load executable/loadable image into memory
95
+ *
96
+ * @v image		Executable/loadable image
97
+ * @ret rc		Return status code
98
+ */
99
+int image_autoload ( struct image *image ) {
100
+	struct image_type *type;
101
+	int rc;
68 102
 
69
-	/* Move the image into the target location */
70
-	if ( ! (*image)->load ( buffer.start, buffer.fill, *context ) ) {
71
-		DBG ( "IMAGE could not move to target location\n" );
72
-		goto out_free;
103
+	for ( type = image_types ; type < image_types_end ; type++ ) {
104
+		rc = type->load ( image );
105
+		if ( image->type == NULL )
106
+			continue;
107
+		if ( rc != 0 ) {
108
+			DBGC ( image, "IMAGE %p (%s) could not load: %s\n",
109
+			       image, image->type->name, strerror ( rc ) );
110
+			return rc;
111
+		}
112
+		return 0;
73 113
 	}
74 114
 
75
-	/* Return success */
76
-	rc = 1;
77
-
78
- out_free:
79
-	/* Free the load buffer */
80
-	done_load_buffer ( &buffer );
81
- out:
82
-	return rc;
115
+	DBGC ( image, "IMAGE %p format not recognised\n", image );
116
+	return -ENOEXEC;
83 117
 }
84 118
 
85
-#endif
119
+/**
120
+ * Execute loaded image
121
+ *
122
+ * @v image		Loaded image
123
+ * @ret rc		Return status code
124
+ */
125
+int image_exec ( struct image *image ) {
126
+	int rc;
127
+
128
+	assert ( image->type != NULL );
129
+
130
+	if ( ( rc = image->type->exec ( image ) ) != 0 ) {
131
+		DBGC ( image, "IMAGE %p could not execute: %s\n",
132
+		       image, strerror ( rc ) );
133
+		return rc;
134
+	}
135
+
136
+	/* Well, some formats might return... */
137
+	return 0;
138
+}

+ 11
- 5
src/image/elf.c Visa fil

@@ -30,6 +30,8 @@
30 30
 #include <gpxe/image.h>
31 31
 #include <gpxe/elf.h>
32 32
 
33
+struct image_type elf_image_type __image_type;
34
+
33 35
 typedef Elf32_Ehdr	Elf_Ehdr;
34 36
 typedef Elf32_Phdr	Elf_Phdr;
35 37
 typedef Elf32_Off	Elf_Off;
@@ -40,7 +42,7 @@ typedef Elf32_Off	Elf_Off;
40 42
  * @v image		ELF file
41 43
  * @ret rc		Return status code
42 44
  */
43
-static int elf_execute ( struct image *image __unused ) {
45
+static int elf_exec ( struct image *image __unused ) {
44 46
 	return -ENOTSUP;
45 47
 }
46 48
 
@@ -63,7 +65,7 @@ static int elf_load_segment ( struct image *image, Elf_Phdr *phdr ) {
63 65
 	/* Check segment lies within image */
64 66
 	if ( ( phdr->p_offset + phdr->p_filesz ) > image->len ) {
65 67
 		DBG ( "ELF segment outside ELF file\n" );
66
-		return -ERANGE;
68
+		return -ENOEXEC;
67 69
 	}
68 70
 
69 71
 	/* Find start address: use physical address for preference,
@@ -75,7 +77,7 @@ static int elf_load_segment ( struct image *image, Elf_Phdr *phdr ) {
75 77
 		dest = phdr->p_vaddr;
76 78
 	if ( ! dest ) {
77 79
 		DBG ( "ELF segment loads to physical address 0\n" );
78
-		return -ERANGE;
80
+		return -ENOEXEC;
79 81
 	}
80 82
 	buffer = phys_to_user ( dest );
81 83
 
@@ -117,13 +119,17 @@ int elf_load ( struct image *image ) {
117 119
 		return -ENOEXEC;
118 120
 	}
119 121
 
122
+	/* This is an ELF image, valid or otherwise */
123
+	if ( ! image->type )
124
+		image->type = &elf_image_type;
125
+
120 126
 	/* Read ELF program headers */
121 127
 	for ( phoff = ehdr.e_phoff , phnum = ehdr.e_phnum ; phnum ;
122 128
 	      phoff += ehdr.e_phentsize, phnum-- ) {
123 129
 		if ( phoff > image->len ) {
124 130
 			DBG ( "ELF program header %d outside ELF image\n",
125 131
 			      phnum );
126
-			return -ERANGE;
132
+			return -ENOEXEC;
127 133
 		}
128 134
 		copy_from_user ( &phdr, image->data, phoff, sizeof ( phdr ) );
129 135
 		if ( ( rc = elf_load_segment ( image, &phdr ) ) != 0 )
@@ -132,7 +138,6 @@ int elf_load ( struct image *image ) {
132 138
 
133 139
 	/* Fill in entry point address */
134 140
 	image->entry = ehdr.e_entry;
135
-	image->execute = elf_execute;
136 141
 
137 142
 	return 0;
138 143
 }
@@ -141,4 +146,5 @@ int elf_load ( struct image *image ) {
141 146
 struct image_type elf_image_type __image_type = {
142 147
 	.name = "ELF",
143 148
 	.load = elf_load,
149
+	.exec = elf_exec,
144 150
 };

+ 44
- 17
src/include/gpxe/image.h Visa fil

@@ -4,37 +4,44 @@
4 4
 /**
5 5
  * @file
6 6
  *
7
- * Executable/loadable image formats
7
+ * Executable/loadable images
8 8
  *
9 9
  */
10 10
 
11 11
 #include <gpxe/tables.h>
12
+#include <gpxe/list.h>
13
+#include <gpxe/uaccess.h>
14
+
15
+struct image_type;
12 16
 
13 17
 /** An executable or loadable image */
14 18
 struct image {
19
+	/** Name */
20
+	char name[16];
21
+	/** List of registered images */
22
+	struct list_head list;
23
+
24
+	/** Command line to pass to image */
25
+	const char *cmdline;
26
+
15 27
 	/** Raw file image */
16 28
 	userptr_t data;
17 29
 	/** Length of raw file image */
18 30
 	size_t len;
19 31
 
20
-	/** Execute method
21
-	 *
22
-	 * Filled in by the image loader.  If NULL, then the image
23
-	 * cannot be executed.
24
-	 */
25
-	int ( * execute ) ( struct image *image );
26 32
 	/** Entry point */
27 33
 	physaddr_t entry;
28 34
 
29
-	/** Command line to pass to image */
30
-	const char *cmdline;
35
+	/** Image type, if known */
36
+	struct image_type *type;
31 37
 };
32 38
 
33 39
 /** An executable or loadable image type */
34 40
 struct image_type {
35 41
 	/** Name of this image type */
36 42
 	char *name;
37
-	/** Load image into memory
43
+	/**
44
+	 * Load image into memory
38 45
 	 *
39 46
 	 * @v image		Executable/loadable image
40 47
 	 * @ret rc		Return status code
@@ -44,15 +51,23 @@ struct image_type {
44 51
 	 * information it may require later (e.g. the execution
45 52
 	 * address) within the @c image structure.
46 53
 	 *
47
-	 * The method should return -ENOEXEC if and only if the image
48
-	 * is not in the correct format.  Other errors will be
49
-	 * interpreted as "I claim this image format, but there's
50
-	 * something wrong with it that makes it unloadable".  In
51
-	 * particular, returning -ENOEXEC will cause the image probing
52
-	 * code to try the next available image type, while returning
53
-	 * any other error will terminate image probing.
54
+	 * If the file image is in the correct format, the method must
55
+	 * update @c image->type to point to its own type (unless @c
56
+	 * image->type is already set).  This allows the autoloading
57
+	 * code to disambiguate between "this is not my image format"
58
+	 * and "there is something wrong with this image".  In
59
+	 * particular, setting @c image->type and then returning an
60
+	 * error will cause image_autoload() to abort and return an
61
+	 * error, rather than continuing to the next image type.
54 62
 	 */
55 63
 	int ( * load ) ( struct image *image );
64
+	/**
65
+	 * Execute loaded image
66
+	 *
67
+	 * @v image		Loaded image
68
+	 * @ret rc		Return status code
69
+	 */
70
+	int ( * exec ) ( struct image *image );
56 71
 };
57 72
 
58 73
 /** An executable or loadable image type */
@@ -68,4 +83,16 @@ struct image_type {
68 83
  */
69 84
 #define __default_image_type __table ( struct image_type, image_types, 02 )
70 85
 
86
+extern struct list_head images;
87
+
88
+/** Iterate over all registered images */
89
+#define for_each_image( image ) \
90
+	list_for_each_entry ( (image), &images, list )
91
+
92
+extern int register_image ( struct image *image );
93
+extern void unregister_image ( struct image *image );
94
+extern int image_load ( struct image *image );
95
+extern int image_autoload ( struct image *image );
96
+extern int image_exec ( struct image *image );
97
+
71 98
 #endif /* _GPXE_IMAGE_H */

Laddar…
Avbryt
Spara