iPXE
multiboot.c
Go to the documentation of this file.
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., 51 Franklin Street, Fifth Floor, Boston, MA
17 * 02110-1301, USA.
18 *
19 * You can also choose to distribute this program under the terms of
20 * the Unmodified Binary Distribution Licence (as given in the file
21 * COPYING.UBDL), provided that you have satisfied its requirements.
22 */
23
24FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25
26/**
27 * @file
28 *
29 * Multiboot image format
30 *
31 */
32
33#include <stdio.h>
34#include <string.h>
35#include <errno.h>
36#include <assert.h>
37#include <realmode.h>
38#include <multiboot.h>
39#include <ipxe/image.h>
40#include <ipxe/segment.h>
41#include <ipxe/memmap.h>
42#include <ipxe/elf.h>
43#include <ipxe/init.h>
44#include <ipxe/features.h>
45#include <ipxe/uri.h>
46#include <ipxe/version.h>
47
49
50/**
51 * Maximum number of modules we will allow for
52 *
53 * If this has bitten you: sorry. I did have a perfect scheme with a
54 * dynamically allocated list of modules on the protected-mode stack,
55 * but it was incompatible with some broken OSes that can only access
56 * low memory at boot time (even though we kindly set up 4GB flat
57 * physical addressing as per the multiboot specification.
58 *
59 */
60#define MAX_MODULES 8
61
62/** Maximum number of memory map entries */
63#define MAX_MEMMAP 8
64
65/**
66 * Maximum combined length of command lines
67 *
68 * Again; sorry. Some broken OSes zero out any non-base memory that
69 * isn't part of the loaded module set, so we can't just use
70 * virt_to_phys(cmdline) to point to the command lines, even though
71 * this would comply with the Multiboot spec.
72 */
73#define MB_MAX_CMDLINE 512
74
75/** Multiboot flags that we support */
76#define MB_SUPPORTED_FLAGS ( MB_FLAG_PGALIGN | MB_FLAG_MEMMAP | \
77 MB_FLAG_VIDMODE | MB_FLAG_RAW )
78
79/** Compulsory feature multiboot flags */
80#define MB_COMPULSORY_FLAGS 0x0000ffff
81
82/** Optional feature multiboot flags */
83#define MB_OPTIONAL_FLAGS 0xffff0000
84
85/**
86 * Multiboot flags that we don't support
87 *
88 * We only care about the compulsory feature flags (bits 0-15); we are
89 * allowed to ignore the optional feature flags.
90 */
91#define MB_UNSUPPORTED_FLAGS ( MB_COMPULSORY_FLAGS & ~MB_SUPPORTED_FLAGS )
92
93/** Multiboot module command lines */
95#define mb_cmdlines __use_data16 ( mb_cmdlines )
96
97/** Offset within module command lines */
98static unsigned int mb_cmdline_offset;
99
100/**
101 * Build multiboot memory map
102 *
103 * @v image Multiboot image
104 * @v mbinfo Multiboot information structure
105 * @v mbmemmap Multiboot memory map
106 * @v limit Maxmimum number of memory map entries
107 */
108static void multiboot_build_memmap ( struct image *image,
109 struct multiboot_info *mbinfo,
111 unsigned int limit ) {
112 struct memmap_region region;
113 unsigned int remaining;
114
115 /* Translate into multiboot format */
116 memset ( mbmemmap, 0, sizeof ( *mbmemmap ) );
117 remaining = limit;
118 for_each_memmap ( &region, 0 ) {
119
120 /* Ignore any non-memory regions */
121 if ( ! ( region.flags & MEMMAP_FL_MEMORY ) )
122 continue;
123 DBGC_MEMMAP ( image, &region );
124
125 /* Check Multiboot memory map limit */
126 if ( ! remaining ) {
127 DBGC ( image, "MULTIBOOT %s limit of %d memmap "
128 "entries reached\n", image->name, limit );
129 break;
130 }
131
132 /* Populate Multiboot memory map entry */
133 mbmemmap->size = ( sizeof ( *mbmemmap ) -
134 sizeof ( mbmemmap->size ) );
135 mbmemmap->base_addr = region.min;
136 mbmemmap->length = memmap_size ( &region );
137 mbmemmap->type = MBMEM_RAM;
138
139 /* Update Multiboot information */
140 mbinfo->mmap_length += sizeof ( *mbmemmap );
141 if ( mbmemmap->base_addr == 0 )
142 mbinfo->mem_lower = ( mbmemmap->length / 1024 );
143 if ( mbmemmap->base_addr == 0x100000 )
144 mbinfo->mem_upper = ( mbmemmap->length / 1024 );
145
146 /* Move to next Multiboot memory map entry */
147 mbmemmap++;
148 remaining--;
149 }
150}
151
152/**
153 * Add command line in base memory
154 *
155 * @v image Image
156 * @ret physaddr Physical address of command line
157 */
159 char *mb_cmdline = ( mb_cmdlines + mb_cmdline_offset );
160 size_t remaining = ( sizeof ( mb_cmdlines ) - mb_cmdline_offset );
161 char *buf = mb_cmdline;
162 size_t len;
163
164 /* Copy image URI to base memory buffer as start of command line */
165 len = ( format_uri ( image->uri, buf, remaining ) + 1 /* NUL */ );
166 if ( len > remaining )
167 len = remaining;
169 buf += len;
170 remaining -= len;
171
172 /* Copy command line to base memory buffer, if present */
173 if ( image->cmdline ) {
174 mb_cmdline_offset--; /* Strip NUL */
175 buf--;
176 remaining++;
177 len = ( snprintf ( buf, remaining, " %s",
178 image->cmdline ) + 1 /* NUL */ );
179 if ( len > remaining )
180 len = remaining;
182 }
183
184 return virt_to_phys ( mb_cmdline );
185}
186
187/**
188 * Add multiboot modules
189 *
190 * @v image Multiboot image
191 * @v start Start address for modules
192 * @v mbinfo Multiboot information structure
193 * @v modules Multiboot module list
194 * @ret rc Return status code
195 */
197 struct multiboot_info *mbinfo,
198 struct multiboot_module *modules,
199 unsigned int limit ) {
200 struct image *module_image;
201 struct multiboot_module *module;
202 int rc;
203
204 /* Add each image as a multiboot module */
205 for_each_image ( module_image ) {
206
207 if ( mbinfo->mods_count >= limit ) {
208 DBGC ( image, "MULTIBOOT %s limit of %d modules "
209 "reached\n", image->name, limit );
210 break;
211 }
212
213 /* Skip hidden images */
214 if ( module_image->flags & IMAGE_HIDDEN )
215 continue;
216
217 /* Page-align the module */
218 start = ( ( start + 0xfff ) & ~0xfff );
219
220 /* Prepare segment */
221 if ( ( rc = prep_segment ( phys_to_virt ( start ),
222 module_image->len,
223 module_image->len ) ) != 0 ) {
224 DBGC ( image, "MULTIBOOT %s could not prepare module "
225 "%s: %s\n", image->name, module_image->name,
226 strerror ( rc ) );
227 return rc;
228 }
229
230 /* Copy module */
231 memcpy ( phys_to_virt ( start ), module_image->data,
232 module_image->len );
233
234 /* Add module to list */
235 module = &modules[mbinfo->mods_count++];
236 module->mod_start = start;
237 module->mod_end = ( start + module_image->len );
238 module->string = multiboot_add_cmdline ( module_image );
239 module->reserved = 0;
240 DBGC ( image, "MULTIBOOT %s module %s is [%x,%x)\n",
241 image->name, module_image->name, module->mod_start,
242 module->mod_end );
243 start += module_image->len;
244 }
245
246 return 0;
247}
248
249/**
250 * The multiboot information structure
251 *
252 * Kept in base memory because some OSes won't find it elsewhere,
253 * along with the other structures belonging to the Multiboot
254 * information table.
255 */
256static struct multiboot_info __bss16 ( mbinfo );
257#define mbinfo __use_data16 ( mbinfo )
258
259/** The multiboot bootloader name */
260static char __bss16_array ( mb_bootloader_name, [32] );
261#define mb_bootloader_name __use_data16 ( mb_bootloader_name )
262
263/** The multiboot memory map */
265#define mbmemmap __use_data16 ( mbmemmap )
266
267/** The multiboot module list */
269#define mbmodules __use_data16 ( mbmodules )
270
271/**
272 * Find multiboot header
273 *
274 * @v image Multiboot file
275 * @ret offset Offset to Multiboot header, or negative error
276 */
277static int multiboot_find_header ( struct image *image ) {
278 const struct multiboot_header *mb;
279 size_t offset;
281
282 /* Scan through first 8kB of image file */
283 for ( offset = 0 ; offset < 8192 ; offset += 4 ) {
284 /* Check for end of image */
285 if ( ( offset + sizeof ( *mb ) ) > image->len )
286 break;
287 mb = ( image->data + offset );
288 /* Check signature */
289 if ( mb->magic != MULTIBOOT_HEADER_MAGIC )
290 continue;
291 /* Copy header and verify checksum */
292 checksum = ( mb->magic + mb->flags + mb->checksum );
293 if ( checksum != 0 )
294 continue;
295 /* Return header */
296 return offset;
297 }
298
299 /* No multiboot header found */
300 DBGC ( image, "MULTIBOOT %s has no multiboot header\n",
301 image->name );
302 return -ENOEXEC;
303}
304
305/**
306 * Load raw multiboot image into memory
307 *
308 * @v image Multiboot image
309 * @v offset Offset to Multiboot header
310 * @ret entry Entry point
311 * @ret max Maximum used address
312 * @ret rc Return status code
313 */
314static int multiboot_load_raw ( struct image *image, size_t offset,
315 physaddr_t *entry, physaddr_t *max ) {
316 const struct multiboot_header *mb = ( image->data + offset );
317 size_t filesz;
318 size_t memsz;
319 void *buffer;
320 int rc;
321
322 /* Sanity check */
323 if ( ! ( mb->flags & MB_FLAG_RAW ) ) {
324 DBGC ( image, "MULTIBOOT %s is not flagged as a raw image\n",
325 image->name );
326 return -EINVAL;
327 }
328
329 /* Calculate starting offset within file */
330 if ( ( mb->load_addr > mb->header_addr ) ||
331 ( ( mb->header_addr - mb->load_addr ) > offset ) ) {
332 DBGC ( image, "MULTIBOOT %s has misplaced header\n",
333 image->name );
334 return -EINVAL;
335 }
336 offset -= ( mb->header_addr - mb->load_addr );
338
339 /* Calculate length of initialized data */
340 filesz = ( mb->load_end_addr ?
341 ( mb->load_end_addr - mb->load_addr ) :
342 ( image->len - offset ) );
343 if ( filesz > image->len ) {
344 DBGC ( image, "MULTIBOOT %s has overlength data\n",
345 image->name );
346 return -EINVAL;
347 }
348
349 /* Calculate length of uninitialised data */
350 memsz = ( mb->bss_end_addr ?
351 ( mb->bss_end_addr - mb->load_addr ) : filesz );
352 DBGC ( image, "MULTIBOOT %s loading [%zx,%zx) to [%x,%zx,%zx)\n",
353 image->name, offset, ( offset + filesz ), mb->load_addr,
354 ( mb->load_addr + filesz ), ( mb->load_addr + memsz ) );
355
356 /* Verify and prepare segment */
357 buffer = phys_to_virt ( mb->load_addr );
358 if ( ( rc = prep_segment ( buffer, filesz, memsz ) ) != 0 ) {
359 DBGC ( image, "MULTIBOOT %s could not prepare segment: %s\n",
360 image->name, strerror ( rc ) );
361 return rc;
362 }
363
364 /* Copy image to segment */
365 memcpy ( buffer, ( image->data + offset ), filesz );
366
367 /* Record execution entry point and maximum used address */
368 *entry = mb->entry_addr;
369 *max = ( mb->load_addr + memsz );
370
371 return 0;
372}
373
374/**
375 * Load ELF multiboot image into memory
376 *
377 * @v image Multiboot file
378 * @ret entry Entry point
379 * @ret max Maximum used address
380 * @ret rc Return status code
381 */
382static int multiboot_load_elf ( struct image *image, physaddr_t *entry,
383 physaddr_t *max ) {
384 int rc;
385
386 /* Load ELF image*/
387 if ( ( rc = elf_load ( image, entry, max ) ) != 0 ) {
388 DBGC ( image, "MULTIBOOT %s ELF image failed to load: %s\n",
389 image->name, strerror ( rc ) );
390 return rc;
391 }
392
393 return 0;
394}
395
396/**
397 * Execute multiboot image
398 *
399 * @v image Multiboot image
400 * @ret rc Return status code
401 */
402static int multiboot_exec ( struct image *image ) {
403 const struct multiboot_header *mb;
404 physaddr_t entry;
406 int offset;
407 int rc;
408
409 /* Locate multiboot header, if present */
411 if ( offset < 0 ) {
412 rc = offset;
413 return rc;
414 }
415 mb = ( image->data + offset );
416
417 /* Abort if we detect flags that we cannot support */
418 if ( mb->flags & MB_UNSUPPORTED_FLAGS ) {
419 DBGC ( image, "MULTIBOOT %s flags %#08x not supported\n",
420 image->name, ( mb->flags & MB_UNSUPPORTED_FLAGS ) );
421 return -ENOTSUP;
422 }
423
424 /* There is technically a bit MB_FLAG_RAW to indicate whether
425 * this is an ELF or a raw image. In practice, grub will use
426 * the ELF header if present, and Solaris relies on this
427 * behaviour.
428 */
429 if ( ( ( rc = multiboot_load_elf ( image, &entry, &max ) ) != 0 ) &&
430 ( ( rc = multiboot_load_raw ( image, offset, &entry,
431 &max ) ) != 0 ) ) {
432 return rc;
433 }
434
435 /* Populate multiboot information structure */
436 memset ( &mbinfo, 0, sizeof ( mbinfo ) );
440 mbinfo.cmdline = multiboot_add_cmdline ( image );
441 mbinfo.mods_addr = virt_to_phys ( mbmodules );
442 mbinfo.mmap_addr = virt_to_phys ( mbmemmap );
444 "iPXE %s", product_version );
445 mbinfo.boot_loader_name = virt_to_phys ( mb_bootloader_name );
447 ( sizeof ( mbmodules ) /
448 sizeof ( mbmodules[0] ) ) ) ) !=0)
449 return rc;
450
451 /* Multiboot images may not return and have no callback
452 * interface, so shut everything down prior to booting the OS.
453 */
455
456 /* Build memory map after unhiding bootloader memory regions as part of
457 * shutting everything down.
458 */
460 ( sizeof(mbmemmap) / sizeof(mbmemmap[0]) ) );
461
462 /* Jump to OS with flat physical addressing */
463 DBGC ( image, "MULTIBOOT %s starting execution at %lx\n",
464 image->name, entry );
465 __asm__ __volatile__ ( PHYS_CODE ( "pushl %%ebp\n\t"
466 "call *%%edi\n\t"
467 "popl %%ebp\n\t" )
468 : : "a" ( MULTIBOOT_BOOTLOADER_MAGIC ),
469 "b" ( virt_to_phys ( &mbinfo ) ),
470 "D" ( entry )
471 : "ecx", "edx", "esi", "memory" );
472
473 DBGC ( image, "MULTIBOOT %s returned\n", image->name );
474
475 /* It isn't safe to continue after calling shutdown() */
476 while ( 1 ) {}
477
478 return -ECANCELED; /* -EIMPOSSIBLE, anyone? */
479}
480
481/**
482 * Probe multiboot image
483 *
484 * @v image Multiboot file
485 * @ret rc Return status code
486 */
487static int multiboot_probe ( struct image *image ) {
488 const struct multiboot_header *mb;
489 int offset;
490 int rc;
491
492 /* Locate multiboot header, if present */
494 if ( offset < 0 ) {
495 rc = offset;
496 return rc;
497 }
498 mb = ( image->data + offset );
499 DBGC ( image, "MULTIBOOT %s found header at +%#x with flags %#08x\n",
500 image->name, offset, mb->flags );
501
502 return 0;
503}
504
505/** Multiboot image type */
506struct image_type multiboot_image_type __image_type ( PROBE_MULTIBOOT ) = {
507 .name = "Multiboot",
508 .probe = multiboot_probe,
509 .exec = multiboot_exec,
510};
struct arbelprm_rc_send_wqe rc
Definition arbel.h:3
__asm__ __volatile__("call *%9" :"=a"(result), "=c"(discard_ecx), "=d"(discard_edx) :"d"(0), "a"(code), "b"(0), "c"(in_phys), "D"(0), "S"(out_phys), "m"(hypercall))
unsigned int uint32_t
Definition stdint.h:12
unsigned long physaddr_t
Definition stdint.h:20
Assertions.
#define assert(condition)
Assert a condition at run-time.
Definition assert.h:50
#define max(x, y)
Definition ath.h:41
uint16_t offset
Offset to command line.
Definition bzimage.h:3
ring len
Length.
Definition dwmac.h:226
int elf_load(struct image *image, physaddr_t *entry, physaddr_t *max)
Load ELF image into memory.
Definition elf.c:206
Error codes.
static size_t memsz
Definition fdtmem.c:51
#define DBGC(...)
Definition compiler.h:505
#define DHCP_EB_FEATURE_MULTIBOOT
Multiboot format.
Definition features.h:46
#define FEATURE_IMAGE
Image formats.
Definition features.h:23
uint32_t start
Starting offset.
Definition netvsc.h:1
uint32_t buffer
Buffer index (or NETVSC_RNDIS_NO_BUFFER)
Definition netvsc.h:5
#define FILE_LICENCE(_licence)
Declare a particular licence as applying to a file.
Definition compiler.h:896
#define EINVAL
Invalid argument.
Definition errno.h:429
#define ENOEXEC
Exec format error.
Definition errno.h:520
#define ENOTSUP
Operation not supported.
Definition errno.h:590
#define ECANCELED
Operation canceled.
Definition errno.h:344
Executable images.
#define PROBE_MULTIBOOT
Multiboot image probe priority.
Definition image.h:151
#define for_each_image(image)
Iterate over all registered images.
Definition image.h:191
#define IMAGE_HIDDEN
Image will be hidden from enumeration.
Definition image.h:86
#define __image_type(probe_order)
An executable image type.
Definition image.h:170
void mb(void)
Memory barrier.
System memory map.
#define MEMMAP_FL_MEMORY
Contains memory.
Definition memmap.h:60
static uint64_t memmap_size(const struct memmap_region *region)
Get remaining size of memory region (from the described address upwards)
Definition memmap.h:99
#define for_each_memmap(region, hide)
Iterate over memory regions.
Definition memmap.h:184
#define DBGC_MEMMAP(...)
Definition memmap.h:207
String functions.
void * memcpy(void *dest, const void *src, size_t len) __nonnull
void * memset(void *dest, int character, size_t len) __nonnull
static void shutdown_boot(void)
Shut down system for OS boot.
Definition init.h:78
ELF image format.
Feature list.
#define FEATURE(category, text, feature_opt, version)
Declare a feature.
Definition features.h:101
Version number.
#define __bss16(variable)
Definition libkir.h:16
#define __bss16_array(variable, array)
Definition libkir.h:17
#define PHYS_CODE(asm_code_str)
Definition librm.h:167
uint16_t limit
Limit.
Definition librm.h:1
static int multiboot_load_raw(struct image *image, size_t offset, physaddr_t *entry, physaddr_t *max)
Load raw multiboot image into memory.
Definition multiboot.c:314
static unsigned int mb_cmdline_offset
Offset within module command lines.
Definition multiboot.c:98
#define MB_MAX_CMDLINE
Maximum combined length of command lines.
Definition multiboot.c:73
static physaddr_t multiboot_add_cmdline(struct image *image)
Add command line in base memory.
Definition multiboot.c:158
#define mbmodules
Definition multiboot.c:269
#define MAX_MEMMAP
Maximum number of memory map entries.
Definition multiboot.c:63
#define mbinfo
Definition multiboot.c:257
#define mb_cmdlines
Definition multiboot.c:95
static int multiboot_load_elf(struct image *image, physaddr_t *entry, physaddr_t *max)
Load ELF multiboot image into memory.
Definition multiboot.c:382
#define mbmemmap
Definition multiboot.c:265
#define MB_UNSUPPORTED_FLAGS
Multiboot flags that we don't support.
Definition multiboot.c:91
static int multiboot_exec(struct image *image)
Execute multiboot image.
Definition multiboot.c:402
#define MAX_MODULES
Maximum number of modules we will allow for.
Definition multiboot.c:60
static int multiboot_probe(struct image *image)
Probe multiboot image.
Definition multiboot.c:487
#define mb_bootloader_name
Definition multiboot.c:261
static int multiboot_add_modules(struct image *image, physaddr_t start, struct multiboot_info *mbinfo, struct multiboot_module *modules, unsigned int limit)
Add multiboot modules.
Definition multiboot.c:196
static void multiboot_build_memmap(struct image *image, struct multiboot_info *mbinfo, struct multiboot_memory_map *mbmemmap, unsigned int limit)
Build multiboot memory map.
Definition multiboot.c:108
static int multiboot_find_header(struct image *image)
Find multiboot header.
Definition multiboot.c:277
Multiboot operating systems.
#define MBI_FLAG_MODS
Multiboot information structure module fields are valid.
Definition multiboot.h:48
#define MB_FLAG_RAW
Image is a raw multiboot image (not ELF)
Definition multiboot.h:28
#define MBI_FLAG_CMDLINE
Multiboot information structure cmdline field is valid.
Definition multiboot.h:45
#define MULTIBOOT_BOOTLOADER_MAGIC
The magic number passed by a Multiboot-compliant boot loader.
Definition multiboot.h:36
#define MULTIBOOT_HEADER_MAGIC
The magic number for the Multiboot header.
Definition multiboot.h:16
#define MBI_FLAG_LOADER
Multiboot information structure boot loader name field is valid.
Definition multiboot.h:66
#define MBI_FLAG_MEM
Multiboot information structure mem_* fields are valid.
Definition multiboot.h:39
#define MBI_FLAG_MMAP
Multiboot information structure memory map is valid.
Definition multiboot.h:57
#define MBMEM_RAM
Usable RAM.
Definition multiboot.h:147
uint8_t checksum
Checksum.
Definition pnpbios.c:12
__asm__(".section \".rodata\", \"a\", " PROGBITS "\n\t" "\nprivate_key_data:\n\t" ".size private_key_data, ( . - private_key_data )\n\t" ".equ private_key_len, ( . - private_key_data )\n\t" ".previous\n\t")
int prep_segment(void *segment, size_t filesz, size_t memsz)
Prepare segment for loading.
Definition segment.c:61
Executable image segments.
char * strerror(int errno)
Retrieve string representation of error number.
Definition strerror.c:79
An executable image type.
Definition image.h:95
An executable image.
Definition image.h:24
unsigned int flags
Flags.
Definition image.h:40
const void * data
Read-only data.
Definition image.h:51
char * name
Name.
Definition image.h:38
size_t len
Length of raw file image.
Definition image.h:56
struct uri * uri
URI of image.
Definition image.h:32
char * cmdline
Command line to pass to image.
Definition image.h:43
A memory region descriptor.
Definition memmap.h:49
uint64_t min
Minimum address in region.
Definition memmap.h:51
unsigned int flags
Region flags.
Definition memmap.h:55
A multiboot header.
Definition multiboot.h:75
A multiboot information structure.
Definition multiboot.h:103
A multiboot memory map entry.
Definition multiboot.h:139
A multiboot module structure.
Definition multiboot.h:131
uint32_t mod_end
Definition multiboot.h:133
uint32_t mod_start
Definition multiboot.h:132
size_t format_uri(const struct uri *uri, char *buf, size_t len)
Format URI.
Definition uri.c:473
Uniform Resource Identifiers.
const char product_version[]
Product version string.
Definition version.c:71
int snprintf(char *buf, size_t size, const char *fmt,...)
Write a formatted string to a buffer.
Definition vsprintf.c:383