Browse Source

Capable of loading a multiboot image into memory

tags/v0.9.3
Michael Brown 17 years ago
parent
commit
d488a172eb
1 changed files with 235 additions and 0 deletions
  1. 235
    0
      src/arch/i386/image/multiboot.c

+ 235
- 0
src/arch/i386/image/multiboot.c View File

@@ -0,0 +1,235 @@
1
+/*
2
+ * Copyright (C) 2007 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
+/**
20
+ * @file
21
+ *
22
+ * Multiboot image format
23
+ *
24
+ */
25
+
26
+#include <errno.h>
27
+#include <multiboot.h>
28
+#include <gpxe/uaccess.h>
29
+#include <gpxe/image.h>
30
+#include <gpxe/segment.h>
31
+#include <gpxe/elf.h>
32
+
33
+/** Boot modules must be page aligned */
34
+#define MB_FLAG_PGALIGN 0x00000001
35
+
36
+/** Memory map must be provided */
37
+#define MB_FLAG_MEMMAP 0x00000002
38
+
39
+/** Video mode information must be provided */
40
+#define MB_FLAG_VIDMODE 0x00000004
41
+
42
+/** Image is a raw multiboot image (not ELF) */
43
+#define MB_FLAG_RAW 0x00010000
44
+
45
+/** Multiboot flags that we support */
46
+#define MB_SUPPORTED_FLAGS ( MB_FLAG_PGALIGN | MB_FLAG_MEMMAP | \
47
+			     MB_FLAG_VIDMODE | MB_FLAG_RAW )
48
+
49
+/** Compulsory feature multiboot flags */
50
+#define MB_COMPULSORY_FLAGS 0x0000ffff
51
+
52
+/** Optional feature multiboot flags */
53
+#define MB_OPTIONAL_FLAGS 0xffff0000
54
+
55
+/**
56
+ * Multiboot flags that we don't support
57
+ *
58
+ * We only care about the compulsory feature flags (bits 0-15); we are
59
+ * allowed to ignore the optional feature flags.
60
+ */
61
+#define MB_UNSUPPORTED_FLAGS ( MB_COMPULSORY_FLAGS & ~MB_SUPPORTED_FLAGS )
62
+
63
+/** A multiboot header descriptor */
64
+struct multiboot_header_info {
65
+	/** The actual multiboot header */
66
+	struct multiboot_header mb;
67
+	/** Offset of header within the multiboot image */
68
+	size_t offset;
69
+};
70
+
71
+/**
72
+ * Execute multiboot image
73
+ *
74
+ * @v image		ELF file
75
+ * @ret rc		Return status code
76
+ */
77
+static int multiboot_execute ( struct image *image __unused ) {
78
+	return -ENOTSUP;
79
+}
80
+
81
+/**
82
+ * Find multiboot header
83
+ *
84
+ * @v image		Multiboot file
85
+ * @v hdr		Multiboot header descriptor to fill in
86
+ * @ret rc		Return status code
87
+ */
88
+static int multiboot_find_header ( struct image *image,
89
+				   struct multiboot_header_info *hdr ) {
90
+	uint32_t buf[64];
91
+	size_t offset;
92
+	unsigned int buf_idx;
93
+	uint32_t checksum;
94
+
95
+	/* Scan through first 8kB of image file 256 bytes at a time.
96
+	 * (Use the buffering to avoid the overhead of a
97
+	 * copy_from_user() for every dword.)
98
+	 */
99
+	for ( offset = 0 ; offset < 8192 ; offset += sizeof ( buf[0] ) ) {
100
+		/* Check for end of image */
101
+		if ( offset > image->len )
102
+			break;
103
+		/* Refill buffer if applicable */
104
+		buf_idx = ( ( offset % sizeof ( buf ) ) / sizeof ( buf[0] ) );
105
+		if ( buf_idx == 0 ) {
106
+			copy_from_user ( buf, image->data, offset,
107
+					 sizeof ( buf ) );
108
+		}
109
+		/* Check signature */
110
+		if ( buf[buf_idx] != MULTIBOOT_HEADER_MAGIC )
111
+			continue;
112
+		/* Copy header and verify checksum */
113
+		copy_from_user ( &hdr->mb, image->data, offset,
114
+				 sizeof ( hdr->mb ) );
115
+		checksum = ( hdr->mb.magic + hdr->mb.flags +
116
+			     hdr->mb.checksum );
117
+		if ( checksum != 0 )
118
+			continue;
119
+		/* Record offset of multiboot header and return */
120
+		hdr->offset = offset;
121
+		return 0;
122
+	}
123
+
124
+	/* No multiboot header found */
125
+	return -ENOEXEC;
126
+}
127
+
128
+/**
129
+ * Load raw multiboot image into memory
130
+ *
131
+ * @v image		Multiboot file
132
+ * @v hdr		Multiboot header descriptor
133
+ * @ret rc		Return status code
134
+ */
135
+static int multiboot_load_raw ( struct image *image,
136
+				struct multiboot_header_info *hdr ) {
137
+	size_t offset;
138
+	size_t filesz;
139
+	size_t memsz;
140
+	userptr_t buffer;
141
+	int rc;
142
+
143
+	/* Verify and prepare segment */
144
+	offset = ( hdr->offset - hdr->mb.header_addr + hdr->mb.load_addr );
145
+	filesz = ( hdr->mb.load_end_addr - hdr->mb.load_addr );
146
+	memsz = ( hdr->mb.bss_end_addr - hdr->mb.load_addr );
147
+	buffer = phys_to_user ( hdr->mb.load_addr );
148
+	if ( ( rc = prep_segment ( buffer, filesz, memsz ) ) != 0 ) {
149
+		DBG ( "Multiboot could not prepare segment: %s\n",
150
+		      strerror ( rc ) );
151
+		return rc;
152
+	}
153
+
154
+	/* Copy image to segment */
155
+	copy_user ( buffer, 0, image->data, offset, filesz );
156
+
157
+	/* Record execution entry point */
158
+	image->entry = hdr->mb.entry_addr;
159
+	image->execute = multiboot_execute;
160
+
161
+	return 0;
162
+}
163
+
164
+/**
165
+ * Load ELF multiboot image into memory
166
+ *
167
+ * @v image		Multiboot file
168
+ * @ret rc		Return status code
169
+ */
170
+static int multiboot_load_elf ( struct image *image ) {
171
+	int rc;
172
+
173
+	/* Load ELF image*/
174
+	if ( ( rc = elf_load ( image ) ) != 0 ) {
175
+		DBG ( "Multiboot ELF image failed to load: %s\n",
176
+		      strerror ( rc ) );
177
+		/* We must translate "not an ELF image" (i.e. ENOEXEC)
178
+		 * into "invalid multiboot image", to avoid screwing
179
+		 * up the image probing logic.
180
+		 */
181
+		if ( rc == -ENOEXEC ) {
182
+			return -ENOTSUP;
183
+		} else {
184
+			return rc;
185
+		}
186
+	}
187
+
188
+	/* Capture execution method */
189
+	if ( image->execute )
190
+		image->execute = multiboot_execute;
191
+
192
+	return 0;
193
+}
194
+
195
+/**
196
+ * Load multiboot image into memory
197
+ *
198
+ * @v image		Multiboot file
199
+ * @ret rc		Return status code
200
+ */
201
+int multiboot_load ( struct image *image ) {
202
+	struct multiboot_header_info hdr;
203
+	int rc;
204
+
205
+	/* Locate multiboot header, if present */
206
+	if ( ( rc = multiboot_find_header ( image, &hdr ) ) != 0 ) {
207
+		DBG ( "No multiboot header\n" );
208
+		return rc;
209
+	}
210
+	DBG ( "Found multiboot header with flags %08lx\n", hdr.mb.flags );
211
+
212
+	/* Abort if we detect flags that we cannot support */
213
+	if ( hdr.mb.flags & MB_UNSUPPORTED_FLAGS ) {
214
+		DBG ( "Multiboot flags %08lx not supported\n",
215
+		      ( hdr.mb.flags & MB_UNSUPPORTED_FLAGS ) );
216
+		return -ENOTSUP;
217
+	}
218
+
219
+	/* Load the actual image */
220
+	if ( hdr.mb.flags & MB_FLAG_RAW ) {
221
+		if ( ( rc = multiboot_load_raw ( image, &hdr ) ) != 0 )
222
+			return rc;
223
+	} else {
224
+		if ( ( rc = multiboot_load_elf ( image ) ) != 0 )
225
+			return rc;
226
+	}
227
+
228
+	return 0;
229
+}
230
+
231
+/** Multiboot image type */
232
+struct image_type multiboot_image_type __image_type = {
233
+	.name = "Multiboot",
234
+	.load = multiboot_load,
235
+};

Loading…
Cancel
Save