multiboot.c File Reference

Multiboot image format. More...

#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.


Detailed Description

Multiboot image format.

Definition in file multiboot.c.


Define Documentation

#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:

Multiboot flags that we support.

Definition at line 68 of file multiboot.c.

#define MB_COMPULSORY_FLAGS   0x0000ffff

Compulsory feature multiboot flags.

Definition at line 72 of file multiboot.c.

#define MB_OPTIONAL_FLAGS   0xffff0000

Optional feature multiboot flags.

Definition at line 75 of file multiboot.c.

#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 )

Definition at line 95 of file multiboot.c.

Referenced by multiboot_add_cmdline().

#define mbinfo   __use_data16 ( mbinfo )

Definition at line 242 of file multiboot.c.

Referenced by multiboot_exec().

#define mb_bootloader_name   __use_data16 ( mb_bootloader_name )

Definition at line 246 of file multiboot.c.

Referenced by multiboot_exec().

#define mbmemmap   __use_data16 ( mbmemmap )

Definition at line 251 of file multiboot.c.

Referenced by multiboot_exec().

#define mbmodules   __use_data16 ( mbmodules )

Definition at line 255 of file multiboot.c.

Referenced by multiboot_exec().


Function Documentation

FILE_LICENCE ( GPL2_OR_LATER   ) 

FEATURE ( FEATURE_IMAGE  ,
"Multiboot"  ,
DHCP_EB_FEATURE_MULTIBOOT  ,
 
)

struct image_type multiboot_image_type __image_type ( PROBE_MULTIBOOT   )  [read]

Initial value:

 {
        .name = "Multiboot",
        .load = multiboot_load,
        .exec = multiboot_exec,
}
Multiboot image type.

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.

Parameters:
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.

Parameters:
imgname Image name
cmdline Command line
Return values:
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.

Parameters:
image Multiboot image
modules Module list to fill, or NULL
Return values:
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.

Parameters:
image Multiboot image
Return values:
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.

Parameters:
image Multiboot file
hdr Multiboot header descriptor to fill in
Return values:
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.

Parameters:
image Multiboot file
hdr Multiboot header descriptor
Return values:
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.

Parameters:
image Multiboot file
Return values:
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.

Parameters:
image Multiboot file
Return values:
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 }


Variable Documentation

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().


Generated on Tue Apr 6 20:01:12 2010 for gPXE by  doxygen 1.5.7.1