1 /* grub-mkimage.c - make a bootable image */
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009 Free Software Foundation, Inc.
6 * GRUB is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * GRUB is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
21 #include <grub/types.h>
22 #include <grub/machine/boot.h>
23 #include <grub/machine/kernel.h>
24 #include <grub/machine/memory.h>
25 #include <grub/kernel.h>
26 #include <grub/disk.h>
27 #include <grub/util/misc.h>
28 #include <grub/util/resolve.h>
29 #include <grub/misc.h>
40 #include <grub/lib/LzmaEnc.h>
42 static void *SzAlloc(void *p
, size_t size
) { p
= p
; return xmalloc(size
); }
43 static void SzFree(void *p
, void *address
) { p
= p
; free(address
); }
44 static ISzAlloc g_Alloc
= { SzAlloc
, SzFree
};
47 compress_kernel (char *kernel_img
, size_t kernel_size
,
48 char **core_img
, size_t *core_size
)
51 unsigned char out_props
[5];
52 size_t out_props_size
= 5;
54 LzmaEncProps_Init(&props
);
55 props
.dictSize
= 1 << 16;
61 if (kernel_size
< GRUB_KERNEL_MACHINE_RAW_SIZE
)
62 grub_util_error ("the core image is too small");
64 *core_img
= xmalloc (kernel_size
);
65 memcpy (*core_img
, kernel_img
, GRUB_KERNEL_MACHINE_RAW_SIZE
);
67 *core_size
= kernel_size
- GRUB_KERNEL_MACHINE_RAW_SIZE
;
68 if (LzmaEncode((unsigned char *) *core_img
+ GRUB_KERNEL_MACHINE_RAW_SIZE
,
70 (unsigned char *) kernel_img
+ GRUB_KERNEL_MACHINE_RAW_SIZE
,
71 kernel_size
- GRUB_KERNEL_MACHINE_RAW_SIZE
,
72 &props
, out_props
, &out_props_size
,
73 0, NULL
, &g_Alloc
, &g_Alloc
) != SZ_OK
)
74 grub_util_error ("cannot compress the kernel image");
76 *core_size
+= GRUB_KERNEL_MACHINE_RAW_SIZE
;
79 #else /* No lzma compression */
82 compress_kernel (char *kernel_img
, size_t kernel_size
,
83 char **core_img
, size_t *core_size
)
85 *core_img
= xmalloc (kernel_size
);
86 memcpy (*core_img
, kernel_img
, kernel_size
);
87 *core_size
= kernel_size
;
90 #endif /* No lzma compression */
93 generate_image (const char *dir
, char *prefix
, FILE *out
, char *mods
[],
94 char *memdisk_path
, char *config_path
)
96 char *kernel_img
, *boot_img
, *core_img
;
97 size_t kernel_size
, boot_size
, total_module_size
, core_size
;
98 size_t memdisk_size
= 0, config_size
= 0;
99 char *kernel_path
, *boot_path
;
101 struct grub_util_path_list
*path_list
, *p
, *next
;
102 struct grub_module_info
*modinfo
;
104 path_list
= grub_util_resolve_dependencies (dir
, "moddep.lst", mods
);
106 kernel_path
= grub_util_get_path (dir
, "kernel.img");
107 kernel_size
= grub_util_get_image_size (kernel_path
);
109 total_module_size
= sizeof (struct grub_module_info
);
113 memdisk_size
= ALIGN_UP(grub_util_get_image_size (memdisk_path
), 512);
114 grub_util_info ("the size of memory disk is 0x%x", memdisk_size
);
115 total_module_size
+= memdisk_size
+ sizeof (struct grub_module_header
);
120 config_size
= grub_util_get_image_size (config_path
) + 1;
121 grub_util_info ("the size of config file is 0x%x", config_size
);
122 total_module_size
+= config_size
+ sizeof (struct grub_module_header
);
125 for (p
= path_list
; p
; p
= p
->next
)
126 total_module_size
+= (grub_util_get_image_size (p
->name
)
127 + sizeof (struct grub_module_header
));
129 grub_util_info ("the total module size is 0x%x", total_module_size
);
131 kernel_img
= xmalloc (kernel_size
+ total_module_size
);
132 grub_util_load_image (kernel_path
, kernel_img
);
134 if (GRUB_KERNEL_MACHINE_PREFIX
+ strlen (prefix
) + 1 > GRUB_KERNEL_MACHINE_DATA_END
)
135 grub_util_error ("prefix too long");
136 strcpy (kernel_img
+ GRUB_KERNEL_MACHINE_PREFIX
, prefix
);
138 /* Fill in the grub_module_info structure. */
139 modinfo
= (struct grub_module_info
*) (kernel_img
+ kernel_size
);
140 memset (modinfo
, 0, sizeof (struct grub_module_info
));
141 modinfo
->magic
= GRUB_MODULE_MAGIC
;
142 modinfo
->offset
= sizeof (struct grub_module_info
);
143 modinfo
->size
= total_module_size
;
145 offset
= kernel_size
+ sizeof (struct grub_module_info
);
146 for (p
= path_list
; p
; p
= p
->next
)
148 struct grub_module_header
*header
;
151 mod_size
= grub_util_get_image_size (p
->name
);
153 header
= (struct grub_module_header
*) (kernel_img
+ offset
);
154 memset (header
, 0, sizeof (struct grub_module_header
));
155 header
->type
= OBJ_TYPE_ELF
;
156 header
->size
= grub_host_to_target32 (mod_size
+ sizeof (*header
));
157 offset
+= sizeof (*header
);
159 grub_util_load_image (p
->name
, kernel_img
+ offset
);
165 struct grub_module_header
*header
;
167 header
= (struct grub_module_header
*) (kernel_img
+ offset
);
168 memset (header
, 0, sizeof (struct grub_module_header
));
169 header
->type
= OBJ_TYPE_MEMDISK
;
170 header
->size
= grub_host_to_target32 (memdisk_size
+ sizeof (*header
));
171 offset
+= sizeof (*header
);
173 grub_util_load_image (memdisk_path
, kernel_img
+ offset
);
174 offset
+= memdisk_size
;
179 struct grub_module_header
*header
;
181 header
= (struct grub_module_header
*) (kernel_img
+ offset
);
182 memset (header
, 0, sizeof (struct grub_module_header
));
183 header
->type
= OBJ_TYPE_CONFIG
;
184 header
->size
= grub_host_to_target32 (config_size
+ sizeof (*header
));
185 offset
+= sizeof (*header
);
187 grub_util_load_image (config_path
, kernel_img
+ offset
);
188 offset
+= config_size
;
189 *(kernel_img
+ offset
- 1) = 0;
192 grub_util_info ("kernel_img=%p, kernel_size=0x%x", kernel_img
, kernel_size
);
193 compress_kernel (kernel_img
, kernel_size
+ total_module_size
,
194 &core_img
, &core_size
);
196 grub_util_info ("the core size is 0x%x", core_size
);
198 #if defined(GRUB_MACHINE_PCBIOS)
201 num
= ((core_size
+ GRUB_DISK_SECTOR_SIZE
- 1) >> GRUB_DISK_SECTOR_BITS
);
203 grub_util_error ("the core image is too big");
205 boot_path
= grub_util_get_path (dir
, "diskboot.img");
206 boot_size
= grub_util_get_image_size (boot_path
);
207 if (boot_size
!= GRUB_DISK_SECTOR_SIZE
)
208 grub_util_error ("diskboot.img is not one sector size");
210 boot_img
= grub_util_read_image (boot_path
);
212 /* i386 is a little endian architecture. */
213 *((grub_uint16_t
*) (boot_img
+ GRUB_DISK_SECTOR_SIZE
214 - GRUB_BOOT_MACHINE_LIST_SIZE
+ 8))
215 = grub_cpu_to_le16 (num
);
217 grub_util_write_image (boot_img
, boot_size
, out
);
221 #elif defined(GRUB_MACHINE_QEMU)
226 boot_path
= grub_util_get_path (dir
, "boot.img");
227 boot_size
= grub_util_get_image_size (boot_path
);
228 boot_img
= grub_util_read_image (boot_path
);
230 /* Rom sizes must be 64k-aligned. */
231 rom_size
= ALIGN_UP (core_size
+ boot_size
, 64 * 1024);
233 rom_img
= xmalloc (rom_size
);
234 memset (rom_img
, 0, rom_size
);
236 *((grub_int32_t
*) (core_img
+ GRUB_KERNEL_MACHINE_CORE_ENTRY_ADDR
))
237 = grub_cpu_to_le32 ((grub_uint32_t
) -rom_size
);
239 memcpy (rom_img
, core_img
, core_size
);
241 *((grub_int32_t
*) (boot_img
+ GRUB_BOOT_MACHINE_CORE_ENTRY_ADDR
))
242 = grub_cpu_to_le32 ((grub_uint32_t
) -rom_size
);
244 memcpy (rom_img
+ rom_size
- boot_size
, boot_img
, boot_size
);
248 core_size
= rom_size
;
256 #ifdef GRUB_KERNEL_MACHINE_TOTAL_MODULE_SIZE
257 *((grub_uint32_t
*) (core_img
+ GRUB_KERNEL_MACHINE_TOTAL_MODULE_SIZE
))
258 = grub_cpu_to_le32 (total_module_size
);
260 *((grub_uint32_t
*) (core_img
+ GRUB_KERNEL_MACHINE_KERNEL_IMAGE_SIZE
))
261 = grub_cpu_to_le32 (kernel_size
);
262 #ifdef GRUB_KERNEL_MACHINE_COMPRESSED_SIZE
263 *((grub_uint32_t
*) (core_img
+ GRUB_KERNEL_MACHINE_COMPRESSED_SIZE
))
264 = grub_cpu_to_le32 (core_size
- GRUB_KERNEL_MACHINE_RAW_SIZE
);
267 #if defined(GRUB_KERNEL_MACHINE_INSTALL_DOS_PART) && defined(GRUB_KERNEL_MACHINE_INSTALL_BSD_PART)
268 /* If we included a drive in our prefix, let GRUB know it doesn't have to
269 prepend the drive told by BIOS. */
270 if (prefix
[0] == '(')
272 *((grub_int32_t
*) (core_img
+ GRUB_KERNEL_MACHINE_INSTALL_DOS_PART
))
273 = grub_cpu_to_le32 (-2);
274 *((grub_int32_t
*) (core_img
+ GRUB_KERNEL_MACHINE_INSTALL_BSD_PART
))
275 = grub_cpu_to_le32 (-2);
279 #ifdef GRUB_MACHINE_PCBIOS
280 if (GRUB_KERNEL_MACHINE_LINK_ADDR
+ core_size
> GRUB_MEMORY_MACHINE_UPPER
)
281 grub_util_error ("Core image is too big (%p > %p)\n",
282 GRUB_KERNEL_MACHINE_LINK_ADDR
+ core_size
, GRUB_MEMORY_MACHINE_UPPER
);
285 grub_util_write_image (core_img
, core_size
, out
);
292 next
= path_list
->next
;
293 free ((void *) path_list
->name
);
301 static struct option options
[] =
303 {"directory", required_argument
, 0, 'd'},
304 {"prefix", required_argument
, 0, 'p'},
305 {"memdisk", required_argument
, 0, 'm'},
306 {"config", required_argument
, 0, 'c'},
307 {"output", required_argument
, 0, 'o'},
308 {"help", no_argument
, 0, 'h'},
309 {"version", no_argument
, 0, 'V'},
310 {"verbose", no_argument
, 0, 'v'},
318 fprintf (stderr
, "Try ``grub-mkimage --help'' for more information.\n");
321 Usage: grub-mkimage [OPTION]... [MODULES]\n\
323 Make a bootable image of GRUB.\n\
325 -d, --directory=DIR use images and modules under DIR [default=%s]\n\
326 -p, --prefix=DIR set grub_prefix directory [default=%s]\n\
327 -m, --memdisk=FILE embed FILE as a memdisk image\n\
328 -c, --config=FILE embed FILE as boot config\n\
329 -o, --output=FILE output a generated image to FILE [default=stdout]\n\
330 -h, --help display this message and exit\n\
331 -V, --version print version information and exit\n\
332 -v, --verbose print verbose messages\n\
334 Report bugs to <%s>.\n\
335 ", GRUB_LIBDIR
, DEFAULT_DIRECTORY
, PACKAGE_BUGREPORT
);
341 main (int argc
, char *argv
[])
346 char *memdisk
= NULL
;
350 progname
= "grub-mkimage";
354 int c
= getopt_long (argc
, argv
, "d:p:m:c:o:hVv", options
, 0);
365 output
= xstrdup (optarg
);
372 dir
= xstrdup (optarg
);
379 memdisk
= xstrdup (optarg
);
384 prefix
= xstrdup ("(memdisk)/boot/grub");
391 config
= xstrdup (optarg
);
402 prefix
= xstrdup (optarg
);
406 printf ("grub-mkimage (%s) %s\n", PACKAGE_NAME
, PACKAGE_VERSION
);
421 fp
= fopen (output
, "wb");
423 grub_util_error ("cannot open %s", output
);
427 generate_image (dir
? : GRUB_LIBDIR
, prefix
? : DEFAULT_DIRECTORY
, fp
,
428 argv
+ optind
, memdisk
, config
);