Home | History | Annotate | Download | only in image
      1 /*
      2  * Copyright (C) 2007 Michael Brown <mbrown (at) 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 FILE_LICENCE ( GPL2_OR_LATER );
     20 
     21 /**
     22  * @file
     23  *
     24  * Multiboot image format
     25  *
     26  */
     27 
     28 #include <stdio.h>
     29 #include <errno.h>
     30 #include <assert.h>
     31 #include <realmode.h>
     32 #include <multiboot.h>
     33 #include <gpxe/uaccess.h>
     34 #include <gpxe/image.h>
     35 #include <gpxe/segment.h>
     36 #include <gpxe/memmap.h>
     37 #include <gpxe/elf.h>
     38 #include <gpxe/init.h>
     39 #include <gpxe/features.h>
     40 
     41 FEATURE ( FEATURE_IMAGE, "Multiboot", DHCP_EB_FEATURE_MULTIBOOT, 1 );
     42 
     43 struct image_type multiboot_image_type __image_type ( PROBE_MULTIBOOT );
     44 
     45 /**
     46  * Maximum number of modules we will allow for
     47  *
     48  * If this has bitten you: sorry.  I did have a perfect scheme with a
     49  * dynamically allocated list of modules on the protected-mode stack,
     50  * but it was incompatible with some broken OSes that can only access
     51  * low memory at boot time (even though we kindly set up 4GB flat
     52  * physical addressing as per the multiboot specification.
     53  *
     54  */
     55 #define MAX_MODULES 8
     56 
     57 /**
     58  * Maximum combined length of command lines
     59  *
     60  * Again; sorry.  Some broken OSes zero out any non-base memory that
     61  * isn't part of the loaded module set, so we can't just use
     62  * virt_to_phys(cmdline) to point to the command lines, even though
     63  * this would comply with the Multiboot spec.
     64  */
     65 #define MB_MAX_CMDLINE 512
     66 
     67 /** Multiboot flags that we support */
     68 #define MB_SUPPORTED_FLAGS ( MB_FLAG_PGALIGN | MB_FLAG_MEMMAP | \
     69 			     MB_FLAG_VIDMODE | MB_FLAG_RAW )
     70 
     71 /** Compulsory feature multiboot flags */
     72 #define MB_COMPULSORY_FLAGS 0x0000ffff
     73 
     74 /** Optional feature multiboot flags */
     75 #define MB_OPTIONAL_FLAGS 0xffff0000
     76 
     77 /**
     78  * Multiboot flags that we don't support
     79  *
     80  * We only care about the compulsory feature flags (bits 0-15); we are
     81  * allowed to ignore the optional feature flags.
     82  */
     83 #define MB_UNSUPPORTED_FLAGS ( MB_COMPULSORY_FLAGS & ~MB_SUPPORTED_FLAGS )
     84 
     85 /** A multiboot header descriptor */
     86 struct multiboot_header_info {
     87 	/** The actual multiboot header */
     88 	struct multiboot_header mb;
     89 	/** Offset of header within the multiboot image */
     90 	size_t offset;
     91 };
     92 
     93 /** Multiboot module command lines */
     94 static char __bss16_array ( mb_cmdlines, [MB_MAX_CMDLINE] );
     95 #define mb_cmdlines __use_data16 ( mb_cmdlines )
     96 
     97 /** Offset within module command lines */
     98 static 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  */
    108 static void multiboot_build_memmap ( struct image *image,
    109 				     struct multiboot_info *mbinfo,
    110 				     struct multiboot_memory_map *mbmemmap,
    111 				     unsigned int limit ) {
    112 	struct memory_map memmap;
    113 	unsigned int i;
    114 
    115 	/* Get memory map */
    116 	get_memmap ( &memmap );
    117 
    118 	/* Translate into multiboot format */
    119 	memset ( mbmemmap, 0, sizeof ( *mbmemmap ) );
    120 	for ( i = 0 ; i < memmap.count ; i++ ) {
    121 		if ( i >= limit ) {
    122 			DBGC ( image, "MULTIBOOT %p limit of %d memmap "
    123 			       "entries reached\n", image, limit );
    124 			break;
    125 		}
    126 		mbmemmap[i].size = ( sizeof ( mbmemmap[i] ) -
    127 				     sizeof ( mbmemmap[i].size ) );
    128 		mbmemmap[i].base_addr = memmap.regions[i].start;
    129 		mbmemmap[i].length = ( memmap.regions[i].end -
    130 				       memmap.regions[i].start );
    131 		mbmemmap[i].type = MBMEM_RAM;
    132 		mbinfo->mmap_length += sizeof ( mbmemmap[i] );
    133 		if ( memmap.regions[i].start == 0 )
    134 			mbinfo->mem_lower = ( memmap.regions[i].end / 1024 );
    135 		if ( memmap.regions[i].start == 0x100000 )
    136 			mbinfo->mem_upper = ( ( memmap.regions[i].end -
    137 						0x100000 ) / 1024 );
    138 	}
    139 }
    140 
    141 /**
    142  * Add command line in base memory
    143  *
    144  * @v imgname		Image name
    145  * @v cmdline		Command line
    146  * @ret physaddr	Physical address of command line
    147  */
    148 physaddr_t multiboot_add_cmdline ( const char *imgname, const char *cmdline ) {
    149 	char *mb_cmdline;
    150 
    151 	if ( ! cmdline )
    152 		cmdline = "";
    153 
    154 	/* Copy command line to base memory buffer */
    155 	mb_cmdline = ( mb_cmdlines + mb_cmdline_offset );
    156 	mb_cmdline_offset +=
    157 		( snprintf ( mb_cmdline,
    158 			     ( sizeof ( mb_cmdlines ) - mb_cmdline_offset ),
    159 			     "%s %s", imgname, cmdline ) + 1 );
    160 
    161 	/* Truncate to terminating NUL in buffer if necessary */
    162 	if ( mb_cmdline_offset > sizeof ( mb_cmdlines ) )
    163 		mb_cmdline_offset = ( sizeof ( mb_cmdlines ) - 1 );
    164 
    165 	return virt_to_phys ( mb_cmdline );
    166 }
    167 
    168 /**
    169  * Build multiboot module list
    170  *
    171  * @v image		Multiboot image
    172  * @v modules		Module list to fill, or NULL
    173  * @ret count		Number of modules
    174  */
    175 static unsigned int
    176 multiboot_build_module_list ( struct image *image,
    177 			      struct multiboot_module *modules,
    178 			      unsigned int limit ) {
    179 	struct image *module_image;
    180 	struct multiboot_module *module;
    181 	unsigned int count = 0;
    182 	unsigned int insert;
    183 	physaddr_t start;
    184 	physaddr_t end;
    185 	unsigned int i;
    186 
    187 	/* Add each image as a multiboot module */
    188 	for_each_image ( module_image ) {
    189 
    190 		if ( count >= limit ) {
    191 			DBGC ( image, "MULTIBOOT %p limit of %d modules "
    192 			       "reached\n", image, limit );
    193 			break;
    194 		}
    195 
    196 		/* Do not include kernel image itself as a module */
    197 		if ( module_image == image )
    198 			continue;
    199 
    200 		/* At least some OSes expect the multiboot modules to
    201 		 * be in ascending order, so we have to support it.
    202 		 */
    203 		start = user_to_phys ( module_image->data, 0 );
    204 		end = user_to_phys ( module_image->data, module_image->len );
    205 		for ( insert = 0 ; insert < count ; insert++ ) {
    206 			if ( start < modules[insert].mod_start )
    207 				break;
    208 		}
    209 		module = &modules[insert];
    210 		memmove ( ( module + 1 ), module,
    211 			  ( ( count - insert ) * sizeof ( *module ) ) );
    212 		module->mod_start = start;
    213 		module->mod_end = end;
    214 		module->string = multiboot_add_cmdline ( module_image->name,
    215 						       module_image->cmdline );
    216 		module->reserved = 0;
    217 
    218 		/* We promise to page-align modules */
    219 		assert ( ( module->mod_start & 0xfff ) == 0 );
    220 
    221 		count++;
    222 	}
    223 
    224 	/* Dump module configuration */
    225 	for ( i = 0 ; i < count ; i++ ) {
    226 		DBGC ( image, "MULTIBOOT %p module %d is [%x,%x)\n",
    227 		       image, i, modules[i].mod_start,
    228 		       modules[i].mod_end );
    229 	}
    230 
    231 	return count;
    232 }
    233 
    234 /**
    235  * The multiboot information structure
    236  *
    237  * Kept in base memory because some OSes won't find it elsewhere,
    238  * along with the other structures belonging to the Multiboot
    239  * information table.
    240  */
    241 static struct multiboot_info __bss16 ( mbinfo );
    242 #define mbinfo __use_data16 ( mbinfo )
    243 
    244 /** The multiboot bootloader name */
    245 static char __data16_array ( mb_bootloader_name, [] ) = "gPXE " VERSION;
    246 #define mb_bootloader_name __use_data16 ( mb_bootloader_name )
    247 
    248 /** The multiboot memory map */
    249 static struct multiboot_memory_map
    250 	__bss16_array ( mbmemmap, [MAX_MEMORY_REGIONS] );
    251 #define mbmemmap __use_data16 ( mbmemmap )
    252 
    253 /** The multiboot module list */
    254 static struct multiboot_module __bss16_array ( mbmodules, [MAX_MODULES] );
    255 #define mbmodules __use_data16 ( mbmodules )
    256 
    257 /**
    258  * Execute multiboot image
    259  *
    260  * @v image		Multiboot image
    261  * @ret rc		Return status code
    262  */
    263 static int multiboot_exec ( struct image *image ) {
    264 	physaddr_t entry = image->priv.phys;
    265 
    266 	/* Populate multiboot information structure */
    267 	memset ( &mbinfo, 0, sizeof ( mbinfo ) );
    268 	mbinfo.flags = ( MBI_FLAG_LOADER | MBI_FLAG_MEM | MBI_FLAG_MMAP |
    269 			 MBI_FLAG_CMDLINE | MBI_FLAG_MODS );
    270 	mb_cmdline_offset = 0;
    271 	mbinfo.cmdline = multiboot_add_cmdline ( image->name, image->cmdline );
    272 	mbinfo.mods_count = multiboot_build_module_list ( image, mbmodules,
    273 				( sizeof(mbmodules) / sizeof(mbmodules[0]) ) );
    274 	mbinfo.mods_addr = virt_to_phys ( mbmodules );
    275 	mbinfo.mmap_addr = virt_to_phys ( mbmemmap );
    276 	mbinfo.boot_loader_name = virt_to_phys ( mb_bootloader_name );
    277 
    278 	/* Multiboot images may not return and have no callback
    279 	 * interface, so shut everything down prior to booting the OS.
    280 	 */
    281 	shutdown ( SHUTDOWN_BOOT );
    282 
    283 	/* Build memory map after unhiding bootloader memory regions as part of
    284 	 * shutting everything down.
    285 	 */
    286 	multiboot_build_memmap ( image, &mbinfo, mbmemmap,
    287 				 ( sizeof(mbmemmap) / sizeof(mbmemmap[0]) ) );
    288 
    289 	/* Jump to OS with flat physical addressing */
    290 	DBGC ( image, "MULTIBOOT %p starting execution at %lx\n",
    291 	       image, entry );
    292 	__asm__ __volatile__ ( PHYS_CODE ( "pushl %%ebp\n\t"
    293 					   "call *%%edi\n\t"
    294 					   "popl %%ebp\n\t" )
    295 			       : : "a" ( MULTIBOOT_BOOTLOADER_MAGIC ),
    296 			           "b" ( virt_to_phys ( &mbinfo ) ),
    297 			           "D" ( entry )
    298 			       : "ecx", "edx", "esi", "memory" );
    299 
    300 	DBGC ( image, "MULTIBOOT %p returned\n", image );
    301 
    302 	/* It isn't safe to continue after calling shutdown() */
    303 	while ( 1 ) {}
    304 
    305 	return -ECANCELED;  /* -EIMPOSSIBLE, anyone? */
    306 }
    307 
    308 /**
    309  * Find multiboot header
    310  *
    311  * @v image		Multiboot file
    312  * @v hdr		Multiboot header descriptor to fill in
    313  * @ret rc		Return status code
    314  */
    315 static int multiboot_find_header ( struct image *image,
    316 				   struct multiboot_header_info *hdr ) {
    317 	uint32_t buf[64];
    318 	size_t offset;
    319 	unsigned int buf_idx;
    320 	uint32_t checksum;
    321 
    322 	/* Scan through first 8kB of image file 256 bytes at a time.
    323 	 * (Use the buffering to avoid the overhead of a
    324 	 * copy_from_user() for every dword.)
    325 	 */
    326 	for ( offset = 0 ; offset < 8192 ; offset += sizeof ( buf[0] ) ) {
    327 		/* Check for end of image */
    328 		if ( offset > image->len )
    329 			break;
    330 		/* Refill buffer if applicable */
    331 		buf_idx = ( ( offset % sizeof ( buf ) ) / sizeof ( buf[0] ) );
    332 		if ( buf_idx == 0 ) {
    333 			copy_from_user ( buf, image->data, offset,
    334 					 sizeof ( buf ) );
    335 		}
    336 		/* Check signature */
    337 		if ( buf[buf_idx] != MULTIBOOT_HEADER_MAGIC )
    338 			continue;
    339 		/* Copy header and verify checksum */
    340 		copy_from_user ( &hdr->mb, image->data, offset,
    341 				 sizeof ( hdr->mb ) );
    342 		checksum = ( hdr->mb.magic + hdr->mb.flags +
    343 			     hdr->mb.checksum );
    344 		if ( checksum != 0 )
    345 			continue;
    346 		/* Record offset of multiboot header and return */
    347 		hdr->offset = offset;
    348 		return 0;
    349 	}
    350 
    351 	/* No multiboot header found */
    352 	return -ENOEXEC;
    353 }
    354 
    355 /**
    356  * Load raw multiboot image into memory
    357  *
    358  * @v image		Multiboot file
    359  * @v hdr		Multiboot header descriptor
    360  * @ret rc		Return status code
    361  */
    362 static int multiboot_load_raw ( struct image *image,
    363 				struct multiboot_header_info *hdr ) {
    364 	size_t offset;
    365 	size_t filesz;
    366 	size_t memsz;
    367 	userptr_t buffer;
    368 	int rc;
    369 
    370 	/* Sanity check */
    371 	if ( ! ( hdr->mb.flags & MB_FLAG_RAW ) ) {
    372 		DBGC ( image, "MULTIBOOT %p is not flagged as a raw image\n",
    373 		       image );
    374 		return -EINVAL;
    375 	}
    376 
    377 	/* Verify and prepare segment */
    378 	offset = ( hdr->offset - hdr->mb.header_addr + hdr->mb.load_addr );
    379 	filesz = ( hdr->mb.load_end_addr ?
    380 		   ( hdr->mb.load_end_addr - hdr->mb.load_addr ) :
    381 		   ( image->len - offset ) );
    382 	memsz = ( hdr->mb.bss_end_addr ?
    383 		  ( hdr->mb.bss_end_addr - hdr->mb.load_addr ) : filesz );
    384 	buffer = phys_to_user ( hdr->mb.load_addr );
    385 	if ( ( rc = prep_segment ( buffer, filesz, memsz ) ) != 0 ) {
    386 		DBGC ( image, "MULTIBOOT %p could not prepare segment: %s\n",
    387 		       image, strerror ( rc ) );
    388 		return rc;
    389 	}
    390 
    391 	/* Copy image to segment */
    392 	memcpy_user ( buffer, 0, image->data, offset, filesz );
    393 
    394 	/* Record execution entry point in image private data field */
    395 	image->priv.phys = hdr->mb.entry_addr;
    396 
    397 	return 0;
    398 }
    399 
    400 /**
    401  * Load ELF multiboot image into memory
    402  *
    403  * @v image		Multiboot file
    404  * @ret rc		Return status code
    405  */
    406 static int multiboot_load_elf ( struct image *image ) {
    407 	int rc;
    408 
    409 	/* Load ELF image*/
    410 	if ( ( rc = elf_load ( image ) ) != 0 ) {
    411 		DBGC ( image, "MULTIBOOT %p ELF image failed to load: %s\n",
    412 		       image, strerror ( rc ) );
    413 		return rc;
    414 	}
    415 
    416 	return 0;
    417 }
    418 
    419 /**
    420  * Load multiboot image into memory
    421  *
    422  * @v image		Multiboot file
    423  * @ret rc		Return status code
    424  */
    425 static int multiboot_load ( struct image *image ) {
    426 	struct multiboot_header_info hdr;
    427 	int rc;
    428 
    429 	/* Locate multiboot header, if present */
    430 	if ( ( rc = multiboot_find_header ( image, &hdr ) ) != 0 ) {
    431 		DBGC ( image, "MULTIBOOT %p has no multiboot header\n",
    432 		       image );
    433 		return rc;
    434 	}
    435 	DBGC ( image, "MULTIBOOT %p found header with flags %08x\n",
    436 	       image, hdr.mb.flags );
    437 
    438 	/* This is a multiboot image, valid or otherwise */
    439 	if ( ! image->type )
    440 		image->type = &multiboot_image_type;
    441 
    442 	/* Abort if we detect flags that we cannot support */
    443 	if ( hdr.mb.flags & MB_UNSUPPORTED_FLAGS ) {
    444 		DBGC ( image, "MULTIBOOT %p flags %08x not supported\n",
    445 		       image, ( hdr.mb.flags & MB_UNSUPPORTED_FLAGS ) );
    446 		return -ENOTSUP;
    447 	}
    448 
    449 	/* There is technically a bit MB_FLAG_RAW to indicate whether
    450 	 * this is an ELF or a raw image.  In practice, grub will use
    451 	 * the ELF header if present, and Solaris relies on this
    452 	 * behaviour.
    453 	 */
    454 	if ( ( ( rc = multiboot_load_elf ( image ) ) != 0 ) &&
    455 	     ( ( rc = multiboot_load_raw ( image, &hdr ) ) != 0 ) )
    456 		return rc;
    457 
    458 	return 0;
    459 }
    460 
    461 /** Multiboot image type */
    462 struct image_type multiboot_image_type __image_type ( PROBE_MULTIBOOT ) = {
    463 	.name = "Multiboot",
    464 	.load = multiboot_load,
    465 	.exec = multiboot_exec,
    466 };
    467