#include <stdio.h>
#include <errno.h>
#include <assert.h>
#include <realmode.h>
#include <multiboot.h>
#include <gpxe/uaccess.h>
#include <gpxe/image.h>
#include <gpxe/segment.h>
#include <gpxe/memmap.h>
#include <gpxe/elf.h>
#include <gpxe/init.h>
#include <gpxe/features.h>
Go to the source code of this file.
Data Structures | |
| struct | multiboot_header_info |
| A multiboot header descriptor. More... | |
Defines | |
| #define | MAX_MODULES 8 |
| Maximum number of modules we will allow for. | |
| #define | MB_MAX_CMDLINE 512 |
| Maximum combined length of command lines. | |
| #define | MB_SUPPORTED_FLAGS |
| Multiboot flags that we support. | |
| #define | MB_COMPULSORY_FLAGS 0x0000ffff |
| Compulsory feature multiboot flags. | |
| #define | MB_OPTIONAL_FLAGS 0xffff0000 |
| Optional feature multiboot flags. | |
| #define | MB_UNSUPPORTED_FLAGS ( MB_COMPULSORY_FLAGS & ~MB_SUPPORTED_FLAGS ) |
| Multiboot flags that we don't support. | |
| #define | mb_cmdlines __use_data16 ( mb_cmdlines ) |
| #define | mbinfo __use_data16 ( mbinfo ) |
| #define | mb_bootloader_name __use_data16 ( mb_bootloader_name ) |
| #define | mbmemmap __use_data16 ( mbmemmap ) |
| #define | mbmodules __use_data16 ( mbmodules ) |
Functions | |
| FILE_LICENCE (GPL2_OR_LATER) | |
| FEATURE (FEATURE_IMAGE,"Multiboot", DHCP_EB_FEATURE_MULTIBOOT, 1) | |
| struct image_type multiboot_image_type | __image_type (PROBE_MULTIBOOT) |
| Multiboot image type. | |
| static char | __bss16_array (mb_cmdlines,[MB_MAX_CMDLINE]) |
| Multiboot module command lines. | |
| static void | multiboot_build_memmap (struct image *image, struct multiboot_info *mbinfo, struct multiboot_memory_map *mbmemmap, unsigned int limit) |
| Build multiboot memory map. | |
| physaddr_t | multiboot_add_cmdline (const char *imgname, const char *cmdline) |
| Add command line in base memory. | |
| static unsigned int | multiboot_build_module_list (struct image *image, struct multiboot_module *modules, unsigned int limit) |
| Build multiboot module list. | |
| static struct multiboot_info | __bss16 (mbinfo) |
| The multiboot information structure. | |
| static char | __data16_array (mb_bootloader_name,[]) |
| The multiboot bootloader name. | |
| static struct multiboot_memory_map | __bss16_array (mbmemmap,[MAX_MEMORY_REGIONS]) |
| The multiboot memory map. | |
| static struct multiboot_module | __bss16_array (mbmodules,[MAX_MODULES]) |
| The multiboot module list. | |
| static int | multiboot_exec (struct image *image) |
| Execute multiboot image. | |
| static int | multiboot_find_header (struct image *image, struct multiboot_header_info *hdr) |
| Find multiboot header. | |
| static int | multiboot_load_raw (struct image *image, struct multiboot_header_info *hdr) |
| Load raw multiboot image into memory. | |
| static int | multiboot_load_elf (struct image *image) |
| Load ELF multiboot image into memory. | |
| static int | multiboot_load (struct image *image) |
| Load multiboot image into memory. | |
Variables | |
| static unsigned int | mb_cmdline_offset |
| Offset within module command lines. | |
Definition in file multiboot.c.
| #define MAX_MODULES 8 |
Maximum number of modules we will allow for.
If this has bitten you: sorry. I did have a perfect scheme with a dynamically allocated list of modules on the protected-mode stack, but it was incompatible with some broken OSes that can only access low memory at boot time (even though we kindly set up 4GB flat physical addressing as per the multiboot specification.
Definition at line 55 of file multiboot.c.
| #define MB_MAX_CMDLINE 512 |
Maximum combined length of command lines.
Again; sorry. Some broken OSes zero out any non-base memory that isn't part of the loaded module set, so we can't just use virt_to_phys(cmdline) to point to the command lines, even though this would comply with the Multiboot spec.
Definition at line 65 of file multiboot.c.
| #define MB_SUPPORTED_FLAGS |
Value:
( MB_FLAG_PGALIGN | MB_FLAG_MEMMAP | \ MB_FLAG_VIDMODE | MB_FLAG_RAW )
Definition at line 68 of file multiboot.c.
| #define MB_COMPULSORY_FLAGS 0x0000ffff |
| #define MB_OPTIONAL_FLAGS 0xffff0000 |
| #define MB_UNSUPPORTED_FLAGS ( MB_COMPULSORY_FLAGS & ~MB_SUPPORTED_FLAGS ) |
Multiboot flags that we don't support.
We only care about the compulsory feature flags (bits 0-15); we are allowed to ignore the optional feature flags.
Definition at line 83 of file multiboot.c.
Referenced by multiboot_load().
| #define mb_cmdlines __use_data16 ( mb_cmdlines ) |
| #define mbinfo __use_data16 ( mbinfo ) |
| #define mb_bootloader_name __use_data16 ( mb_bootloader_name ) |
| #define mbmemmap __use_data16 ( mbmemmap ) |
| #define mbmodules __use_data16 ( mbmodules ) |
| FILE_LICENCE | ( | GPL2_OR_LATER | ) |
| FEATURE | ( | FEATURE_IMAGE | , | |
| "Multiboot" | , | |||
| DHCP_EB_FEATURE_MULTIBOOT | , | |||
| 1 | ||||
| ) |
| struct image_type multiboot_image_type __image_type | ( | PROBE_MULTIBOOT | ) | [read] |
Initial value:
{
.name = "Multiboot",
.load = multiboot_load,
.exec = multiboot_exec,
}
| static char __bss16_array | ( | mb_cmdlines | ) | [static] |
Multiboot module command lines.
| static void multiboot_build_memmap | ( | struct image * | image, | |
| struct multiboot_info * | mbinfo, | |||
| struct multiboot_memory_map * | mbmemmap, | |||
| unsigned int | limit | |||
| ) | [static] |
Build multiboot memory map.
| image | Multiboot image | |
| mbinfo | Multiboot information structure | |
| mbmemmap | Multiboot memory map | |
| limit | Maxmimum number of memory map entries |
Definition at line 108 of file multiboot.c.
References multiboot_memory_map::base_addr, memory_map::count, DBGC, memory_region::end, get_memmap(), multiboot_memory_map::length, MBMEM_RAM, multiboot_info::mem_lower, multiboot_info::mem_upper, memset(), multiboot_info::mmap_length, memory_map::regions, size, multiboot_memory_map::size, memory_region::start, and multiboot_memory_map::type.
Referenced by multiboot_exec().
00111 { 00112 struct memory_map memmap; 00113 unsigned int i; 00114 00115 /* Get memory map */ 00116 get_memmap ( &memmap ); 00117 00118 /* Translate into multiboot format */ 00119 memset ( mbmemmap, 0, sizeof ( *mbmemmap ) ); 00120 for ( i = 0 ; i < memmap.count ; i++ ) { 00121 if ( i >= limit ) { 00122 DBGC ( image, "MULTIBOOT %p limit of %d memmap " 00123 "entries reached\n", image, limit ); 00124 break; 00125 } 00126 mbmemmap[i].size = ( sizeof ( mbmemmap[i] ) - 00127 sizeof ( mbmemmap[i].size ) ); 00128 mbmemmap[i].base_addr = memmap.regions[i].start; 00129 mbmemmap[i].length = ( memmap.regions[i].end - 00130 memmap.regions[i].start ); 00131 mbmemmap[i].type = MBMEM_RAM; 00132 mbinfo->mmap_length += sizeof ( mbmemmap[i] ); 00133 if ( memmap.regions[i].start == 0 ) 00134 mbinfo->mem_lower = ( memmap.regions[i].end / 1024 ); 00135 if ( memmap.regions[i].start == 0x100000 ) 00136 mbinfo->mem_upper = ( ( memmap.regions[i].end - 00137 0x100000 ) / 1024 ); 00138 } 00139 }
| physaddr_t multiboot_add_cmdline | ( | const char * | imgname, | |
| const char * | cmdline | |||
| ) |
Add command line in base memory.
| imgname | Image name | |
| cmdline | Command line |
| physaddr | Physical address of command line |
Definition at line 148 of file multiboot.c.
References mb_cmdline_offset, mb_cmdlines, snprintf(), and virt_to_phys().
Referenced by multiboot_build_module_list(), and multiboot_exec().
00148 { 00149 char *mb_cmdline; 00150 00151 if ( ! cmdline ) 00152 cmdline = ""; 00153 00154 /* Copy command line to base memory buffer */ 00155 mb_cmdline = ( mb_cmdlines + mb_cmdline_offset ); 00156 mb_cmdline_offset += 00157 ( snprintf ( mb_cmdline, 00158 ( sizeof ( mb_cmdlines ) - mb_cmdline_offset ), 00159 "%s %s", imgname, cmdline ) + 1 ); 00160 00161 /* Truncate to terminating NUL in buffer if necessary */ 00162 if ( mb_cmdline_offset > sizeof ( mb_cmdlines ) ) 00163 mb_cmdline_offset = ( sizeof ( mb_cmdlines ) - 1 ); 00164 00165 return virt_to_phys ( mb_cmdline ); 00166 }
| static unsigned int multiboot_build_module_list | ( | struct image * | image, | |
| struct multiboot_module * | modules, | |||
| unsigned int | limit | |||
| ) | [static] |
Build multiboot module list.
| count | Number of modules |
Definition at line 176 of file multiboot.c.
References assert, image::cmdline, image::data, DBGC, for_each_image, image::len, memmove(), multiboot_module::mod_end, multiboot_module::mod_start, multiboot_add_cmdline(), image::name, multiboot_module::reserved, multiboot_module::string, and user_to_phys().
Referenced by multiboot_exec().
00178 { 00179 struct image *module_image; 00180 struct multiboot_module *module; 00181 unsigned int count = 0; 00182 unsigned int insert; 00183 physaddr_t start; 00184 physaddr_t end; 00185 unsigned int i; 00186 00187 /* Add each image as a multiboot module */ 00188 for_each_image ( module_image ) { 00189 00190 if ( count >= limit ) { 00191 DBGC ( image, "MULTIBOOT %p limit of %d modules " 00192 "reached\n", image, limit ); 00193 break; 00194 } 00195 00196 /* Do not include kernel image itself as a module */ 00197 if ( module_image == image ) 00198 continue; 00199 00200 /* At least some OSes expect the multiboot modules to 00201 * be in ascending order, so we have to support it. 00202 */ 00203 start = user_to_phys ( module_image->data, 0 ); 00204 end = user_to_phys ( module_image->data, module_image->len ); 00205 for ( insert = 0 ; insert < count ; insert++ ) { 00206 if ( start < modules[insert].mod_start ) 00207 break; 00208 } 00209 module = &modules[insert]; 00210 memmove ( ( module + 1 ), module, 00211 ( ( count - insert ) * sizeof ( *module ) ) ); 00212 module->mod_start = start; 00213 module->mod_end = end; 00214 module->string = multiboot_add_cmdline ( module_image->name, 00215 module_image->cmdline ); 00216 module->reserved = 0; 00217 00218 /* We promise to page-align modules */ 00219 assert ( ( module->mod_start & 0xfff ) == 0 ); 00220 00221 count++; 00222 } 00223 00224 /* Dump module configuration */ 00225 for ( i = 0 ; i < count ; i++ ) { 00226 DBGC ( image, "MULTIBOOT %p module %d is [%x,%x)\n", 00227 image, i, modules[i].mod_start, 00228 modules[i].mod_end ); 00229 } 00230 00231 return count; 00232 }
| static struct multiboot_info __bss16 | ( | mbinfo | ) | [static, read] |
The multiboot information structure.
Kept in base memory because some OSes won't find it elsewhere, along with the other structures belonging to the Multiboot information table.
| static char __data16_array | ( | mb_bootloader_name | ) | [static] |
The multiboot bootloader name.
| static struct multiboot_memory_map __bss16_array | ( | mbmemmap | ) | [static, read] |
The multiboot memory map.
| static struct multiboot_module __bss16_array | ( | mbmodules | ) | [static, read] |
The multiboot module list.
| static int multiboot_exec | ( | struct image * | image | ) | [static] |
Execute multiboot image.
| rc | Return status code |
Definition at line 263 of file multiboot.c.
References __asm__(), image::cmdline, DBGC, ECANCELED, entry, mb_bootloader_name, mb_cmdline_offset, MBI_FLAG_CMDLINE, MBI_FLAG_LOADER, MBI_FLAG_MEM, MBI_FLAG_MMAP, MBI_FLAG_MODS, mbinfo, mbmemmap, mbmodules, memset(), multiboot_add_cmdline(), MULTIBOOT_BOOTLOADER_MAGIC, multiboot_build_memmap(), multiboot_build_module_list(), image::name, image::phys, PHYS_CODE, image::priv, shutdown(), SHUTDOWN_BOOT, and virt_to_phys().
00263 { 00264 physaddr_t entry = image->priv.phys; 00265 00266 /* Populate multiboot information structure */ 00267 memset ( &mbinfo, 0, sizeof ( mbinfo ) ); 00268 mbinfo.flags = ( MBI_FLAG_LOADER | MBI_FLAG_MEM | MBI_FLAG_MMAP | 00269 MBI_FLAG_CMDLINE | MBI_FLAG_MODS ); 00270 mb_cmdline_offset = 0; 00271 mbinfo.cmdline = multiboot_add_cmdline ( image->name, image->cmdline ); 00272 mbinfo.mods_count = multiboot_build_module_list ( image, mbmodules, 00273 ( sizeof(mbmodules) / sizeof(mbmodules[0]) ) ); 00274 mbinfo.mods_addr = virt_to_phys ( mbmodules ); 00275 mbinfo.mmap_addr = virt_to_phys ( mbmemmap ); 00276 mbinfo.boot_loader_name = virt_to_phys ( mb_bootloader_name ); 00277 00278 /* Multiboot images may not return and have no callback 00279 * interface, so shut everything down prior to booting the OS. 00280 */ 00281 shutdown ( SHUTDOWN_BOOT ); 00282 00283 /* Build memory map after unhiding bootloader memory regions as part of 00284 * shutting everything down. 00285 */ 00286 multiboot_build_memmap ( image, &mbinfo, mbmemmap, 00287 ( sizeof(mbmemmap) / sizeof(mbmemmap[0]) ) ); 00288 00289 /* Jump to OS with flat physical addressing */ 00290 DBGC ( image, "MULTIBOOT %p starting execution at %lx\n", 00291 image, entry ); 00292 __asm__ __volatile__ ( PHYS_CODE ( "pushl %%ebp\n\t" 00293 "call *%%edi\n\t" 00294 "popl %%ebp\n\t" ) 00295 : : "a" ( MULTIBOOT_BOOTLOADER_MAGIC ), 00296 "b" ( virt_to_phys ( &mbinfo ) ), 00297 "D" ( entry ) 00298 : "ecx", "edx", "esi", "memory" ); 00299 00300 DBGC ( image, "MULTIBOOT %p returned\n", image ); 00301 00302 /* It isn't safe to continue after calling shutdown() */ 00303 while ( 1 ) {} 00304 00305 return -ECANCELED; /* -EIMPOSSIBLE, anyone? */ 00306 }
| static int multiboot_find_header | ( | struct image * | image, | |
| struct multiboot_header_info * | hdr | |||
| ) | [static] |
Find multiboot header.
| image | Multiboot file | |
| hdr | Multiboot header descriptor to fill in |
| rc | Return status code |
Definition at line 315 of file multiboot.c.
References multiboot_header::checksum, copy_from_user(), image::data, ENOEXEC, multiboot_header::flags, image::len, multiboot_header::magic, multiboot_header_info::mb, MULTIBOOT_HEADER_MAGIC, multiboot_header_info::offset, and offset.
Referenced by multiboot_load().
00316 { 00317 uint32_t buf[64]; 00318 size_t offset; 00319 unsigned int buf_idx; 00320 uint32_t checksum; 00321 00322 /* Scan through first 8kB of image file 256 bytes at a time. 00323 * (Use the buffering to avoid the overhead of a 00324 * copy_from_user() for every dword.) 00325 */ 00326 for ( offset = 0 ; offset < 8192 ; offset += sizeof ( buf[0] ) ) { 00327 /* Check for end of image */ 00328 if ( offset > image->len ) 00329 break; 00330 /* Refill buffer if applicable */ 00331 buf_idx = ( ( offset % sizeof ( buf ) ) / sizeof ( buf[0] ) ); 00332 if ( buf_idx == 0 ) { 00333 copy_from_user ( buf, image->data, offset, 00334 sizeof ( buf ) ); 00335 } 00336 /* Check signature */ 00337 if ( buf[buf_idx] != MULTIBOOT_HEADER_MAGIC ) 00338 continue; 00339 /* Copy header and verify checksum */ 00340 copy_from_user ( &hdr->mb, image->data, offset, 00341 sizeof ( hdr->mb ) ); 00342 checksum = ( hdr->mb.magic + hdr->mb.flags + 00343 hdr->mb.checksum ); 00344 if ( checksum != 0 ) 00345 continue; 00346 /* Record offset of multiboot header and return */ 00347 hdr->offset = offset; 00348 return 0; 00349 } 00350 00351 /* No multiboot header found */ 00352 return -ENOEXEC; 00353 }
| static int multiboot_load_raw | ( | struct image * | image, | |
| struct multiboot_header_info * | hdr | |||
| ) | [static] |
Load raw multiboot image into memory.
| image | Multiboot file | |
| hdr | Multiboot header descriptor |
| rc | Return status code |
Definition at line 362 of file multiboot.c.
References multiboot_header::bss_end_addr, image::data, DBGC, EINVAL, multiboot_header::entry_addr, multiboot_header::flags, multiboot_header::header_addr, image::len, multiboot_header::load_addr, multiboot_header::load_end_addr, multiboot_header_info::mb, MB_FLAG_RAW, memcpy_user(), multiboot_header_info::offset, offset, image::phys, phys_to_user(), prep_segment(), image::priv, and strerror().
Referenced by multiboot_load().
00363 { 00364 size_t offset; 00365 size_t filesz; 00366 size_t memsz; 00367 userptr_t buffer; 00368 int rc; 00369 00370 /* Sanity check */ 00371 if ( ! ( hdr->mb.flags & MB_FLAG_RAW ) ) { 00372 DBGC ( image, "MULTIBOOT %p is not flagged as a raw image\n", 00373 image ); 00374 return -EINVAL; 00375 } 00376 00377 /* Verify and prepare segment */ 00378 offset = ( hdr->offset - hdr->mb.header_addr + hdr->mb.load_addr ); 00379 filesz = ( hdr->mb.load_end_addr ? 00380 ( hdr->mb.load_end_addr - hdr->mb.load_addr ) : 00381 ( image->len - offset ) ); 00382 memsz = ( hdr->mb.bss_end_addr ? 00383 ( hdr->mb.bss_end_addr - hdr->mb.load_addr ) : filesz ); 00384 buffer = phys_to_user ( hdr->mb.load_addr ); 00385 if ( ( rc = prep_segment ( buffer, filesz, memsz ) ) != 0 ) { 00386 DBGC ( image, "MULTIBOOT %p could not prepare segment: %s\n", 00387 image, strerror ( rc ) ); 00388 return rc; 00389 } 00390 00391 /* Copy image to segment */ 00392 memcpy_user ( buffer, 0, image->data, offset, filesz ); 00393 00394 /* Record execution entry point in image private data field */ 00395 image->priv.phys = hdr->mb.entry_addr; 00396 00397 return 0; 00398 }
| static int multiboot_load_elf | ( | struct image * | image | ) | [static] |
Load ELF multiboot image into memory.
| image | Multiboot file |
| rc | Return status code |
Definition at line 406 of file multiboot.c.
References DBGC, elf_load(), and strerror().
Referenced by multiboot_load().
00406 { 00407 int rc; 00408 00409 /* Load ELF image*/ 00410 if ( ( rc = elf_load ( image ) ) != 0 ) { 00411 DBGC ( image, "MULTIBOOT %p ELF image failed to load: %s\n", 00412 image, strerror ( rc ) ); 00413 return rc; 00414 } 00415 00416 return 0; 00417 }
| static int multiboot_load | ( | struct image * | image | ) | [static] |
Load multiboot image into memory.
| image | Multiboot file |
| rc | Return status code |
Definition at line 425 of file multiboot.c.
References DBGC, ENOTSUP, multiboot_header::flags, multiboot_header_info::mb, MB_UNSUPPORTED_FLAGS, multiboot_find_header(), multiboot_load_elf(), multiboot_load_raw(), and image::type.
00425 { 00426 struct multiboot_header_info hdr; 00427 int rc; 00428 00429 /* Locate multiboot header, if present */ 00430 if ( ( rc = multiboot_find_header ( image, &hdr ) ) != 0 ) { 00431 DBGC ( image, "MULTIBOOT %p has no multiboot header\n", 00432 image ); 00433 return rc; 00434 } 00435 DBGC ( image, "MULTIBOOT %p found header with flags %08x\n", 00436 image, hdr.mb.flags ); 00437 00438 /* This is a multiboot image, valid or otherwise */ 00439 if ( ! image->type ) 00440 image->type = &multiboot_image_type; 00441 00442 /* Abort if we detect flags that we cannot support */ 00443 if ( hdr.mb.flags & MB_UNSUPPORTED_FLAGS ) { 00444 DBGC ( image, "MULTIBOOT %p flags %08x not supported\n", 00445 image, ( hdr.mb.flags & MB_UNSUPPORTED_FLAGS ) ); 00446 return -ENOTSUP; 00447 } 00448 00449 /* There is technically a bit MB_FLAG_RAW to indicate whether 00450 * this is an ELF or a raw image. In practice, grub will use 00451 * the ELF header if present, and Solaris relies on this 00452 * behaviour. 00453 */ 00454 if ( ( ( rc = multiboot_load_elf ( image ) ) != 0 ) && 00455 ( ( rc = multiboot_load_raw ( image, &hdr ) ) != 0 ) ) 00456 return rc; 00457 00458 return 0; 00459 }
unsigned int mb_cmdline_offset [static] |
Offset within module command lines.
Definition at line 98 of file multiboot.c.
Referenced by multiboot_add_cmdline(), and multiboot_exec().
1.5.7.1