iPXE - Open Source Boot Firmware

[build] Rename gPXE to iPXE
[ipxe.git] / src / arch / i386 / image / multiboot.c
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., 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 <ipxe/uaccess.h>
34 #include <ipxe/image.h>
35 #include <ipxe/segment.h>
36 #include <ipxe/memmap.h>
37 #include <ipxe/elf.h>
38 #include <ipxe/init.h>
39 #include <ipxe/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, [] ) = "iPXE " 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 };