2 * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
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.
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.
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.
22 * Multiboot image format
27 #include <multiboot.h>
28 #include <gpxe/uaccess.h>
29 #include <gpxe/image.h>
30 #include <gpxe/segment.h>
33 /** Boot modules must be page aligned */
34 #define MB_FLAG_PGALIGN 0x00000001
36 /** Memory map must be provided */
37 #define MB_FLAG_MEMMAP 0x00000002
39 /** Video mode information must be provided */
40 #define MB_FLAG_VIDMODE 0x00000004
42 /** Image is a raw multiboot image (not ELF) */
43 #define MB_FLAG_RAW 0x00010000
45 /** Multiboot flags that we support */
46 #define MB_SUPPORTED_FLAGS ( MB_FLAG_PGALIGN | MB_FLAG_MEMMAP | \
47 MB_FLAG_VIDMODE | MB_FLAG_RAW )
49 /** Compulsory feature multiboot flags */
50 #define MB_COMPULSORY_FLAGS 0x0000ffff
52 /** Optional feature multiboot flags */
53 #define MB_OPTIONAL_FLAGS 0xffff0000
56 * Multiboot flags that we don't support
58 * We only care about the compulsory feature flags (bits 0-15); we are
59 * allowed to ignore the optional feature flags.
61 #define MB_UNSUPPORTED_FLAGS ( MB_COMPULSORY_FLAGS & ~MB_SUPPORTED_FLAGS )
63 /** A multiboot header descriptor */
64 struct multiboot_header_info {
65 /** The actual multiboot header */
66 struct multiboot_header mb;
67 /** Offset of header within the multiboot image */
72 * Execute multiboot image
75 * @ret rc Return status code
77 static int multiboot_execute ( struct image *image ) {
78 struct multiboot_info mbinfo;
80 /* Populate multiboot information structure */
81 memset ( &mbinfo, 0, sizeof ( mbinfo ) );
84 /* Jump to OS with flat physical addressing */
85 __asm__ ( PHYS_CODE ( "call *%%edi\n\t" )
86 : : "a" ( MULTIBOOT_BOOTLOADER_MAGIC ),
87 "b" ( virt_to_phys ( &mbinfo ) ),
89 : "ecx", "edx", "esi", "ebp" );
95 * Find multiboot header
97 * @v image Multiboot file
98 * @v hdr Multiboot header descriptor to fill in
99 * @ret rc Return status code
101 static int multiboot_find_header ( struct image *image,
102 struct multiboot_header_info *hdr ) {
105 unsigned int buf_idx;
108 /* Scan through first 8kB of image file 256 bytes at a time.
109 * (Use the buffering to avoid the overhead of a
110 * copy_from_user() for every dword.)
112 for ( offset = 0 ; offset < 8192 ; offset += sizeof ( buf[0] ) ) {
113 /* Check for end of image */
114 if ( offset > image->len )
116 /* Refill buffer if applicable */
117 buf_idx = ( ( offset % sizeof ( buf ) ) / sizeof ( buf[0] ) );
118 if ( buf_idx == 0 ) {
119 copy_from_user ( buf, image->data, offset,
122 /* Check signature */
123 if ( buf[buf_idx] != MULTIBOOT_HEADER_MAGIC )
125 /* Copy header and verify checksum */
126 copy_from_user ( &hdr->mb, image->data, offset,
127 sizeof ( hdr->mb ) );
128 checksum = ( hdr->mb.magic + hdr->mb.flags +
132 /* Record offset of multiboot header and return */
133 hdr->offset = offset;
137 /* No multiboot header found */
142 * Load raw multiboot image into memory
144 * @v image Multiboot file
145 * @v hdr Multiboot header descriptor
146 * @ret rc Return status code
148 static int multiboot_load_raw ( struct image *image,
149 struct multiboot_header_info *hdr ) {
156 /* Verify and prepare segment */
157 offset = ( hdr->offset - hdr->mb.header_addr + hdr->mb.load_addr );
158 filesz = ( hdr->mb.load_end_addr - hdr->mb.load_addr );
159 memsz = ( hdr->mb.bss_end_addr - hdr->mb.load_addr );
160 buffer = phys_to_user ( hdr->mb.load_addr );
161 if ( ( rc = prep_segment ( buffer, filesz, memsz ) ) != 0 ) {
162 DBG ( "Multiboot could not prepare segment: %s\n",
167 /* Copy image to segment */
168 copy_user ( buffer, 0, image->data, offset, filesz );
170 /* Record execution entry point */
171 image->entry = hdr->mb.entry_addr;
172 image->execute = multiboot_execute;
178 * Load ELF multiboot image into memory
180 * @v image Multiboot file
181 * @ret rc Return status code
183 static int multiboot_load_elf ( struct image *image ) {
187 if ( ( rc = elf_load ( image ) ) != 0 ) {
188 DBG ( "Multiboot ELF image failed to load: %s\n",
190 /* We must translate "not an ELF image" (i.e. ENOEXEC)
191 * into "invalid multiboot image", to avoid screwing
192 * up the image probing logic.
194 if ( rc == -ENOEXEC ) {
201 /* Capture execution method */
202 if ( image->execute )
203 image->execute = multiboot_execute;
209 * Load multiboot image into memory
211 * @v image Multiboot file
212 * @ret rc Return status code
214 int multiboot_load ( struct image *image ) {
215 struct multiboot_header_info hdr;
218 /* Locate multiboot header, if present */
219 if ( ( rc = multiboot_find_header ( image, &hdr ) ) != 0 ) {
220 DBG ( "No multiboot header\n" );
223 DBG ( "Found multiboot header with flags %08lx\n", hdr.mb.flags );
225 /* Abort if we detect flags that we cannot support */
226 if ( hdr.mb.flags & MB_UNSUPPORTED_FLAGS ) {
227 DBG ( "Multiboot flags %08lx not supported\n",
228 ( hdr.mb.flags & MB_UNSUPPORTED_FLAGS ) );
232 /* Load the actual image */
233 if ( hdr.mb.flags & MB_FLAG_RAW ) {
234 if ( ( rc = multiboot_load_raw ( image, &hdr ) ) != 0 )
237 if ( ( rc = multiboot_load_elf ( image ) ) != 0 )
244 /** Multiboot image type */
245 struct image_type multiboot_image_type __image_type = {
247 .load = multiboot_load,