Browse Source

[multiboot] Place multiboot modules low in memory

Solaris assumes that there is enough space above the Multiboot modules
to use as a decompression and scratch area.  This assumption is
invalid when using iPXE, which places the Multiboot modules near the
top of (32-bit) memory.

Fix by copying the modules to an area of memory immediately following
the loaded kernel.

Debugged-by: Michael Brown <mcb30@ipxe.org>
Debugged-by: Scott McWhirter <scottm@joyent.com>
Tested-by: Robin Smidsrød <robin@smidsrod.no>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 12 years ago
parent
commit
62eb2294f0
4 changed files with 69 additions and 52 deletions
  1. 2
    1
      src/arch/i386/image/elfboot.c
  2. 51
    47
      src/arch/i386/image/multiboot.c
  3. 15
    3
      src/image/elf.c
  4. 1
    1
      src/include/ipxe/elf.h

+ 2
- 1
src/arch/i386/image/elfboot.c View File

42
  */
42
  */
43
 static int elfboot_exec ( struct image *image ) {
43
 static int elfboot_exec ( struct image *image ) {
44
 	physaddr_t entry;
44
 	physaddr_t entry;
45
+	physaddr_t max;
45
 	int rc;
46
 	int rc;
46
 
47
 
47
 	/* Load the image using core ELF support */
48
 	/* Load the image using core ELF support */
48
-	if ( ( rc = elf_load ( image, &entry ) ) != 0 ) {
49
+	if ( ( rc = elf_load ( image, &entry, &max ) ) != 0 ) {
49
 		DBGC ( image, "ELF %p could not load: %s\n",
50
 		DBGC ( image, "ELF %p could not load: %s\n",
50
 		       image, strerror ( rc ) );
51
 		       image, strerror ( rc ) );
51
 		return rc;
52
 		return rc;

+ 51
- 47
src/arch/i386/image/multiboot.c View File

143
  * @v image		Image
143
  * @v image		Image
144
  * @ret physaddr	Physical address of command line
144
  * @ret physaddr	Physical address of command line
145
  */
145
  */
146
-physaddr_t multiboot_add_cmdline ( struct image *image ) {
146
+static physaddr_t multiboot_add_cmdline ( struct image *image ) {
147
 	char *mb_cmdline = ( mb_cmdlines + mb_cmdline_offset );
147
 	char *mb_cmdline = ( mb_cmdlines + mb_cmdline_offset );
148
 	size_t remaining = ( sizeof ( mb_cmdlines ) - mb_cmdline_offset );
148
 	size_t remaining = ( sizeof ( mb_cmdlines ) - mb_cmdline_offset );
149
 	char *buf = mb_cmdline;
149
 	char *buf = mb_cmdline;
174
 }
174
 }
175
 
175
 
176
 /**
176
 /**
177
- * Build multiboot module list
177
+ * Add multiboot modules
178
  *
178
  *
179
  * @v image		Multiboot image
179
  * @v image		Multiboot image
180
- * @v modules		Module list to fill, or NULL
181
- * @ret count		Number of modules
180
+ * @v start		Start address for modules
181
+ * @v mbinfo		Multiboot information structure
182
+ * @v modules		Multiboot module list
183
+ * @ret rc		Return status code
182
  */
184
  */
183
-static unsigned int
184
-multiboot_build_module_list ( struct image *image,
185
-			      struct multiboot_module *modules,
186
-			      unsigned int limit ) {
185
+static int multiboot_add_modules ( struct image *image, physaddr_t start,
186
+				   struct multiboot_info *mbinfo,
187
+				   struct multiboot_module *modules,
188
+				   unsigned int limit ) {
187
 	struct image *module_image;
189
 	struct image *module_image;
188
 	struct multiboot_module *module;
190
 	struct multiboot_module *module;
189
-	unsigned int count = 0;
190
-	unsigned int insert;
191
-	physaddr_t start;
192
-	physaddr_t end;
193
-	unsigned int i;
191
+	int rc;
194
 
192
 
195
 	/* Add each image as a multiboot module */
193
 	/* Add each image as a multiboot module */
196
 	for_each_image ( module_image ) {
194
 	for_each_image ( module_image ) {
197
 
195
 
198
-		if ( count >= limit ) {
196
+		if ( mbinfo->mods_count >= limit ) {
199
 			DBGC ( image, "MULTIBOOT %p limit of %d modules "
197
 			DBGC ( image, "MULTIBOOT %p limit of %d modules "
200
 			       "reached\n", image, limit );
198
 			       "reached\n", image, limit );
201
 			break;
199
 			break;
205
 		if ( module_image == image )
203
 		if ( module_image == image )
206
 			continue;
204
 			continue;
207
 
205
 
208
-		/* At least some OSes expect the multiboot modules to
209
-		 * be in ascending order, so we have to support it.
210
-		 */
211
-		start = user_to_phys ( module_image->data, 0 );
212
-		end = user_to_phys ( module_image->data, module_image->len );
213
-		for ( insert = 0 ; insert < count ; insert++ ) {
214
-			if ( start < modules[insert].mod_start )
215
-				break;
206
+		/* Page-align the module */
207
+		start = ( ( start + 0xfff ) & ~0xfff );
208
+
209
+		/* Prepare segment */
210
+		if ( ( rc = prep_segment ( phys_to_user ( start ),
211
+					   module_image->len,
212
+					   module_image->len ) ) != 0 ) {
213
+			DBGC ( image, "MULTIBOOT %p could not prepare module "
214
+			       "%s: %s\n", image, module_image->name,
215
+			       strerror ( rc ) );
216
+			return rc;
216
 		}
217
 		}
217
-		module = &modules[insert];
218
-		memmove ( ( module + 1 ), module,
219
-			  ( ( count - insert ) * sizeof ( *module ) ) );
218
+
219
+		/* Copy module */
220
+		memcpy_user ( phys_to_user ( start ), 0,
221
+			      module_image->data, 0, module_image->len );
222
+
223
+		/* Add module to list */
224
+		module = &modules[mbinfo->mods_count++];
220
 		module->mod_start = start;
225
 		module->mod_start = start;
221
-		module->mod_end = end;
226
+		module->mod_end = ( start + module_image->len );
222
 		module->string = multiboot_add_cmdline ( module_image );
227
 		module->string = multiboot_add_cmdline ( module_image );
223
 		module->reserved = 0;
228
 		module->reserved = 0;
224
-		
225
-		/* We promise to page-align modules */
226
-		assert ( ( module->mod_start & 0xfff ) == 0 );
227
-
228
-		count++;
229
-	}
230
-
231
-	/* Dump module configuration */
232
-	for ( i = 0 ; i < count ; i++ ) {
233
-		DBGC ( image, "MULTIBOOT %p module %d is [%x,%x)\n",
234
-		       image, i, modules[i].mod_start,
235
-		       modules[i].mod_end );
229
+		DBGC ( image, "MULTIBOOT %p module %s is [%x,%x)\n",
230
+		       image, module_image->name, module->mod_start,
231
+		       module->mod_end );
232
+		start += module_image->len;
236
 	}
233
 	}
237
 
234
 
238
-	return count;
235
+	return 0;
239
 }
236
 }
240
 
237
 
241
 /**
238
 /**
314
  * @v image		Multiboot file
311
  * @v image		Multiboot file
315
  * @v hdr		Multiboot header descriptor
312
  * @v hdr		Multiboot header descriptor
316
  * @ret entry		Entry point
313
  * @ret entry		Entry point
314
+ * @ret max		Maximum used address
317
  * @ret rc		Return status code
315
  * @ret rc		Return status code
318
  */
316
  */
319
 static int multiboot_load_raw ( struct image *image,
317
 static int multiboot_load_raw ( struct image *image,
320
 				struct multiboot_header_info *hdr,
318
 				struct multiboot_header_info *hdr,
321
-				physaddr_t *entry ) {
319
+				physaddr_t *entry, physaddr_t *max ) {
322
 	size_t offset;
320
 	size_t offset;
323
 	size_t filesz;
321
 	size_t filesz;
324
 	size_t memsz;
322
 	size_t memsz;
349
 	/* Copy image to segment */
347
 	/* Copy image to segment */
350
 	memcpy_user ( buffer, 0, image->data, offset, filesz );
348
 	memcpy_user ( buffer, 0, image->data, offset, filesz );
351
 
349
 
352
-	/* Record execution entry point */
350
+	/* Record execution entry point and maximum used address */
353
 	*entry = hdr->mb.entry_addr;
351
 	*entry = hdr->mb.entry_addr;
352
+	*max = ( hdr->mb.load_addr + memsz );
354
 
353
 
355
 	return 0;
354
 	return 0;
356
 }
355
 }
360
  *
359
  *
361
  * @v image		Multiboot file
360
  * @v image		Multiboot file
362
  * @ret entry		Entry point
361
  * @ret entry		Entry point
362
+ * @ret max		Maximum used address
363
  * @ret rc		Return status code
363
  * @ret rc		Return status code
364
  */
364
  */
365
-static int multiboot_load_elf ( struct image *image, physaddr_t *entry ) {
365
+static int multiboot_load_elf ( struct image *image, physaddr_t *entry,
366
+				physaddr_t *max ) {
366
 	int rc;
367
 	int rc;
367
 
368
 
368
 	/* Load ELF image*/
369
 	/* Load ELF image*/
369
-	if ( ( rc = elf_load ( image, entry ) ) != 0 ) {
370
+	if ( ( rc = elf_load ( image, entry, max ) ) != 0 ) {
370
 		DBGC ( image, "MULTIBOOT %p ELF image failed to load: %s\n",
371
 		DBGC ( image, "MULTIBOOT %p ELF image failed to load: %s\n",
371
 		       image, strerror ( rc ) );
372
 		       image, strerror ( rc ) );
372
 		return rc;
373
 		return rc;
384
 static int multiboot_exec ( struct image *image ) {
385
 static int multiboot_exec ( struct image *image ) {
385
 	struct multiboot_header_info hdr;
386
 	struct multiboot_header_info hdr;
386
 	physaddr_t entry;
387
 	physaddr_t entry;
388
+	physaddr_t max;
387
 	int rc;
389
 	int rc;
388
 
390
 
389
 	/* Locate multiboot header, if present */
391
 	/* Locate multiboot header, if present */
405
 	 * the ELF header if present, and Solaris relies on this
407
 	 * the ELF header if present, and Solaris relies on this
406
 	 * behaviour.
408
 	 * behaviour.
407
 	 */
409
 	 */
408
-	if ( ( ( rc = multiboot_load_elf ( image, &entry ) ) != 0 ) &&
409
-	     ( ( rc = multiboot_load_raw ( image, &hdr, &entry ) ) != 0 ) )
410
+	if ( ( ( rc = multiboot_load_elf ( image, &entry, &max ) ) != 0 ) &&
411
+	     ( ( rc = multiboot_load_raw ( image, &hdr, &entry, &max ) ) != 0 ))
410
 		return rc;
412
 		return rc;
411
 
413
 
412
 	/* Populate multiboot information structure */
414
 	/* Populate multiboot information structure */
415
 			 MBI_FLAG_CMDLINE | MBI_FLAG_MODS );
417
 			 MBI_FLAG_CMDLINE | MBI_FLAG_MODS );
416
 	mb_cmdline_offset = 0;
418
 	mb_cmdline_offset = 0;
417
 	mbinfo.cmdline = multiboot_add_cmdline ( image );
419
 	mbinfo.cmdline = multiboot_add_cmdline ( image );
418
-	mbinfo.mods_count = multiboot_build_module_list ( image, mbmodules,
419
-				( sizeof(mbmodules) / sizeof(mbmodules[0]) ) );
420
 	mbinfo.mods_addr = virt_to_phys ( mbmodules );
420
 	mbinfo.mods_addr = virt_to_phys ( mbmodules );
421
 	mbinfo.mmap_addr = virt_to_phys ( mbmemmap );
421
 	mbinfo.mmap_addr = virt_to_phys ( mbmemmap );
422
 	mbinfo.boot_loader_name = virt_to_phys ( mb_bootloader_name );
422
 	mbinfo.boot_loader_name = virt_to_phys ( mb_bootloader_name );
423
+	if ( ( rc = multiboot_add_modules ( image, max, &mbinfo, mbmodules,
424
+					    ( sizeof ( mbmodules ) /
425
+					      sizeof ( mbmodules[0] ) ) ) ) !=0)
426
+		return rc;
423
 
427
 
424
 	/* Multiboot images may not return and have no callback
428
 	/* Multiboot images may not return and have no callback
425
 	 * interface, so shut everything down prior to booting the OS.
429
 	 * interface, so shut everything down prior to booting the OS.

+ 15
- 3
src/image/elf.c View File

47
  * @v phdr		ELF program header
47
  * @v phdr		ELF program header
48
  * @v ehdr		ELF executable header
48
  * @v ehdr		ELF executable header
49
  * @ret entry		Entry point, if found
49
  * @ret entry		Entry point, if found
50
+ * @ret max		Maximum used address
50
  * @ret rc		Return status code
51
  * @ret rc		Return status code
51
  */
52
  */
52
 static int elf_load_segment ( struct image *image, Elf_Phdr *phdr,
53
 static int elf_load_segment ( struct image *image, Elf_Phdr *phdr,
53
-			      Elf_Ehdr *ehdr, physaddr_t *entry ) {
54
+			      Elf_Ehdr *ehdr, physaddr_t *entry,
55
+			      physaddr_t *max ) {
54
 	physaddr_t dest;
56
 	physaddr_t dest;
57
+	physaddr_t end;
55
 	userptr_t buffer;
58
 	userptr_t buffer;
56
 	unsigned long e_offset;
59
 	unsigned long e_offset;
57
 	int rc;
60
 	int rc;
79
 		return -ENOEXEC;
82
 		return -ENOEXEC;
80
 	}
83
 	}
81
 	buffer = phys_to_user ( dest );
84
 	buffer = phys_to_user ( dest );
85
+	end = ( dest + phdr->p_memsz );
82
 
86
 
83
 	DBGC ( image, "ELF %p loading segment [%x,%x) to [%x,%x,%x)\n", image,
87
 	DBGC ( image, "ELF %p loading segment [%x,%x) to [%x,%x,%x)\n", image,
84
 	       phdr->p_offset, ( phdr->p_offset + phdr->p_filesz ),
88
 	       phdr->p_offset, ( phdr->p_offset + phdr->p_filesz ),
93
 		return rc;
97
 		return rc;
94
 	}
98
 	}
95
 
99
 
100
+	/* Update maximum used address, if applicable */
101
+	if ( end > *max )
102
+		*max = end;
103
+
96
 	/* Copy image to segment */
104
 	/* Copy image to segment */
97
 	memcpy_user ( buffer, 0, image->data, phdr->p_offset, phdr->p_filesz );
105
 	memcpy_user ( buffer, 0, image->data, phdr->p_offset, phdr->p_filesz );
98
 
106
 
119
  *
127
  *
120
  * @v image		ELF file
128
  * @v image		ELF file
121
  * @ret entry		Entry point
129
  * @ret entry		Entry point
130
+ * @ret max		Maximum used address
122
  * @ret rc		Return status code
131
  * @ret rc		Return status code
123
  */
132
  */
124
-int elf_load ( struct image *image, physaddr_t *entry ) {
133
+int elf_load ( struct image *image, physaddr_t *entry, physaddr_t *max ) {
125
 	static const uint8_t e_ident[] = {
134
 	static const uint8_t e_ident[] = {
126
 		[EI_MAG0]	= ELFMAG0,
135
 		[EI_MAG0]	= ELFMAG0,
127
 		[EI_MAG1]	= ELFMAG1,
136
 		[EI_MAG1]	= ELFMAG1,
143
 		return -ENOEXEC;
152
 		return -ENOEXEC;
144
 	}
153
 	}
145
 
154
 
155
+	/* Initialise maximum used address */
156
+	*max = 0;
157
+
146
 	/* Invalidate entry point */
158
 	/* Invalidate entry point */
147
 	*entry = 0;
159
 	*entry = 0;
148
 
160
 
156
 		}
168
 		}
157
 		copy_from_user ( &phdr, image->data, phoff, sizeof ( phdr ) );
169
 		copy_from_user ( &phdr, image->data, phoff, sizeof ( phdr ) );
158
 		if ( ( rc = elf_load_segment ( image, &phdr, &ehdr,
170
 		if ( ( rc = elf_load_segment ( image, &phdr, &ehdr,
159
-					       entry ) ) != 0 ) {
171
+					       entry, max ) ) != 0 ) {
160
 			return rc;
172
 			return rc;
161
 		}
173
 		}
162
 	}
174
 	}

+ 1
- 1
src/include/ipxe/elf.h View File

12
 
12
 
13
 #include <elf.h>
13
 #include <elf.h>
14
 
14
 
15
-extern int elf_load ( struct image *image, physaddr_t *entry );
15
+extern int elf_load ( struct image *image, physaddr_t *entry, physaddr_t *max );
16
 
16
 
17
 #endif /* _IPXE_ELF_H */
17
 #endif /* _IPXE_ELF_H */

Loading…
Cancel
Save