1
/* grub-mkimage.c - make a bootable image */
3
* GRUB -- GRand Unified Bootloader
4
* Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 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>
26
#include <grub/i18n.h>
27
#include <grub/kernel.h>
28
#include <grub/disk.h>
29
#include <grub/util/misc.h>
30
#include <grub/util/resolve.h>
31
#include <grub/misc.h>
45
#include <grub/lib/LzmaEnc.h>
47
static void *SzAlloc(void *p, size_t size) { p = p; return xmalloc(size); }
48
static void SzFree(void *p, void *address) { p = p; free(address); }
49
static ISzAlloc g_Alloc = { SzAlloc, SzFree };
52
compress_kernel (char *kernel_img, size_t kernel_size,
53
char **core_img, size_t *core_size)
56
unsigned char out_props[5];
57
size_t out_props_size = 5;
59
LzmaEncProps_Init(&props);
60
props.dictSize = 1 << 16;
66
if (kernel_size < GRUB_KERNEL_MACHINE_RAW_SIZE)
67
grub_util_error (_("the core image is too small"));
69
*core_img = xmalloc (kernel_size);
70
memcpy (*core_img, kernel_img, GRUB_KERNEL_MACHINE_RAW_SIZE);
72
*core_size = kernel_size - GRUB_KERNEL_MACHINE_RAW_SIZE;
73
if (LzmaEncode((unsigned char *) *core_img + GRUB_KERNEL_MACHINE_RAW_SIZE,
75
(unsigned char *) kernel_img + GRUB_KERNEL_MACHINE_RAW_SIZE,
76
kernel_size - GRUB_KERNEL_MACHINE_RAW_SIZE,
77
&props, out_props, &out_props_size,
78
0, NULL, &g_Alloc, &g_Alloc) != SZ_OK)
79
grub_util_error (_("cannot compress the kernel image"));
81
*core_size += GRUB_KERNEL_MACHINE_RAW_SIZE;
84
#else /* No lzma compression */
87
compress_kernel (char *kernel_img, size_t kernel_size,
88
char **core_img, size_t *core_size)
90
*core_img = xmalloc (kernel_size);
91
memcpy (*core_img, kernel_img, kernel_size);
92
*core_size = kernel_size;
95
#endif /* No lzma compression */
98
generate_image (const char *dir, char *prefix, FILE *out, char *mods[],
99
char *memdisk_path, char *font_path, char *config_path,
100
#ifdef GRUB_PLATFORM_IMAGE_DEFAULT
101
grub_platform_image_format_t format
103
int dummy __attribute__ ((unused))
108
char *kernel_img, *core_img;
109
size_t kernel_size, total_module_size, core_size;
110
size_t memdisk_size = 0, font_size = 0, config_size = 0, config_size_pure = 0;
113
struct grub_util_path_list *path_list, *p, *next;
114
struct grub_module_info *modinfo;
116
path_list = grub_util_resolve_dependencies (dir, "moddep.lst", mods);
118
kernel_path = grub_util_get_path (dir, "kernel.img");
119
kernel_size = grub_util_get_image_size (kernel_path);
121
total_module_size = sizeof (struct grub_module_info);
125
memdisk_size = ALIGN_UP(grub_util_get_image_size (memdisk_path), 512);
126
grub_util_info ("the size of memory disk is 0x%x", memdisk_size);
127
total_module_size += memdisk_size + sizeof (struct grub_module_header);
132
font_size = ALIGN_UP(grub_util_get_image_size (font_path), 4);
133
total_module_size += font_size + sizeof (struct grub_module_header);
138
config_size_pure = grub_util_get_image_size (config_path) + 1;
139
config_size = ALIGN_UP(config_size_pure, 4);
140
grub_util_info ("the size of config file is 0x%x", config_size);
141
total_module_size += config_size + sizeof (struct grub_module_header);
144
for (p = path_list; p; p = p->next)
145
total_module_size += (grub_util_get_image_size (p->name)
146
+ sizeof (struct grub_module_header));
148
grub_util_info ("the total module size is 0x%x", total_module_size);
150
kernel_img = xmalloc (kernel_size + total_module_size);
151
grub_util_load_image (kernel_path, kernel_img);
153
if (GRUB_KERNEL_MACHINE_PREFIX + strlen (prefix) + 1 > GRUB_KERNEL_MACHINE_DATA_END)
154
grub_util_error (_("prefix is too long"));
155
strcpy (kernel_img + GRUB_KERNEL_MACHINE_PREFIX, prefix);
157
/* Fill in the grub_module_info structure. */
158
modinfo = (struct grub_module_info *) (kernel_img + kernel_size);
159
memset (modinfo, 0, sizeof (struct grub_module_info));
160
modinfo->magic = GRUB_MODULE_MAGIC;
161
modinfo->offset = sizeof (struct grub_module_info);
162
modinfo->size = total_module_size;
164
offset = kernel_size + sizeof (struct grub_module_info);
165
for (p = path_list; p; p = p->next)
167
struct grub_module_header *header;
168
size_t mod_size, orig_size;
170
orig_size = grub_util_get_image_size (p->name);
171
mod_size = ALIGN_UP(orig_size, 4);
173
header = (struct grub_module_header *) (kernel_img + offset);
174
memset (header, 0, sizeof (struct grub_module_header));
175
header->type = OBJ_TYPE_ELF;
176
header->size = grub_host_to_target32 (mod_size + sizeof (*header));
177
offset += sizeof (*header);
178
memset (kernel_img + offset + orig_size, 0, mod_size - orig_size);
180
grub_util_load_image (p->name, kernel_img + offset);
186
struct grub_module_header *header;
188
header = (struct grub_module_header *) (kernel_img + offset);
189
memset (header, 0, sizeof (struct grub_module_header));
190
header->type = OBJ_TYPE_MEMDISK;
191
header->size = grub_host_to_target32 (memdisk_size + sizeof (*header));
192
offset += sizeof (*header);
194
grub_util_load_image (memdisk_path, kernel_img + offset);
195
offset += memdisk_size;
200
struct grub_module_header *header;
202
header = (struct grub_module_header *) (kernel_img + offset);
203
memset (header, 0, sizeof (struct grub_module_header));
204
header->type = OBJ_TYPE_FONT;
205
header->size = grub_host_to_target32 (font_size + sizeof (*header));
206
offset += sizeof (*header);
208
grub_util_load_image (font_path, kernel_img + offset);
214
struct grub_module_header *header;
216
header = (struct grub_module_header *) (kernel_img + offset);
217
memset (header, 0, sizeof (struct grub_module_header));
218
header->type = OBJ_TYPE_CONFIG;
219
header->size = grub_host_to_target32 (config_size + sizeof (*header));
220
offset += sizeof (*header);
222
grub_util_load_image (config_path, kernel_img + offset);
223
*(kernel_img + offset + config_size_pure - 1) = 0;
224
offset += config_size;
227
grub_util_info ("kernel_img=%p, kernel_size=0x%x", kernel_img, kernel_size);
228
compress_kernel (kernel_img, kernel_size + total_module_size,
229
&core_img, &core_size);
231
grub_util_info ("the core size is 0x%x", core_size);
233
#if defined(GRUB_MACHINE_PCBIOS)
236
char *boot_path, *boot_img;
238
num = ((core_size + GRUB_DISK_SECTOR_SIZE - 1) >> GRUB_DISK_SECTOR_BITS);
240
grub_util_error (_("the core image is too big"));
242
boot_path = grub_util_get_path (dir, "diskboot.img");
243
boot_size = grub_util_get_image_size (boot_path);
244
if (boot_size != GRUB_DISK_SECTOR_SIZE)
245
grub_util_error (_("diskboot.img size must be %u bytes"),
246
GRUB_DISK_SECTOR_SIZE);
248
boot_img = grub_util_read_image (boot_path);
251
struct grub_boot_blocklist *block;
252
block = (struct grub_boot_blocklist *) (boot_img
253
+ GRUB_DISK_SECTOR_SIZE
255
block->len = grub_host_to_target16 (num);
257
/* This is filled elsewhere. Verify it just in case. */
258
assert (block->segment
259
== grub_host_to_target16 (GRUB_BOOT_MACHINE_KERNEL_SEG
260
+ (GRUB_DISK_SECTOR_SIZE >> 4)));
263
grub_util_write_image (boot_img, boot_size, out);
267
#elif defined(GRUB_MACHINE_QEMU)
271
char *boot_path, *boot_img;
274
boot_path = grub_util_get_path (dir, "boot.img");
275
boot_size = grub_util_get_image_size (boot_path);
276
boot_img = grub_util_read_image (boot_path);
278
/* Rom sizes must be 64k-aligned. */
279
rom_size = ALIGN_UP (core_size + boot_size, 64 * 1024);
281
rom_img = xmalloc (rom_size);
282
memset (rom_img, 0, rom_size);
284
*((grub_int32_t *) (core_img + GRUB_KERNEL_MACHINE_CORE_ENTRY_ADDR))
285
= grub_host_to_target32 ((grub_uint32_t) -rom_size);
287
memcpy (rom_img, core_img, core_size);
289
*((grub_int32_t *) (boot_img + GRUB_BOOT_MACHINE_CORE_ENTRY_ADDR))
290
= grub_host_to_target32 ((grub_uint32_t) -rom_size);
292
memcpy (rom_img + rom_size - boot_size, boot_img, boot_size);
296
core_size = rom_size;
303
#ifdef GRUB_KERNEL_MACHINE_TOTAL_MODULE_SIZE
304
*((grub_uint32_t *) (core_img + GRUB_KERNEL_MACHINE_TOTAL_MODULE_SIZE))
305
= grub_host_to_target32 (total_module_size);
307
*((grub_uint32_t *) (core_img + GRUB_KERNEL_MACHINE_KERNEL_IMAGE_SIZE))
308
= grub_host_to_target32 (kernel_size);
309
#ifdef GRUB_KERNEL_MACHINE_COMPRESSED_SIZE
310
*((grub_uint32_t *) (core_img + GRUB_KERNEL_MACHINE_COMPRESSED_SIZE))
311
= grub_host_to_target32 (core_size - GRUB_KERNEL_MACHINE_RAW_SIZE);
314
#if defined(GRUB_KERNEL_MACHINE_INSTALL_DOS_PART) && defined(GRUB_KERNEL_MACHINE_INSTALL_BSD_PART)
315
/* If we included a drive in our prefix, let GRUB know it doesn't have to
316
prepend the drive told by BIOS. */
317
if (prefix[0] == '(')
319
*((grub_int32_t *) (core_img + GRUB_KERNEL_MACHINE_INSTALL_DOS_PART))
320
= grub_host_to_target32 (-2);
321
*((grub_int32_t *) (core_img + GRUB_KERNEL_MACHINE_INSTALL_BSD_PART))
322
= grub_host_to_target32 (-2);
326
#ifdef GRUB_MACHINE_PCBIOS
327
if (GRUB_KERNEL_MACHINE_LINK_ADDR + core_size > GRUB_MEMORY_MACHINE_UPPER)
328
grub_util_error (_("core image is too big (%p > %p)"),
329
GRUB_KERNEL_MACHINE_LINK_ADDR + core_size,
330
GRUB_MEMORY_MACHINE_UPPER);
333
#if defined(GRUB_MACHINE_MIPS)
334
if (format == GRUB_PLATFORM_IMAGE_ELF)
340
grub_uint32_t target_addr;
342
program_size = ALIGN_UP (core_size, 4);
344
elf_img = xmalloc (program_size + sizeof (*ehdr) + sizeof (*phdr));
345
memset (elf_img, 0, program_size + sizeof (*ehdr) + sizeof (*phdr));
346
memcpy (elf_img + sizeof (*ehdr) + sizeof (*phdr), core_img, core_size);
347
ehdr = (void *) elf_img;
348
phdr = (void *) (elf_img + sizeof (*ehdr));
349
memcpy (ehdr->e_ident, ELFMAG, SELFMAG);
350
ehdr->e_ident[EI_CLASS] = ELFCLASS32;
351
#ifdef GRUB_CPU_MIPSEL
352
ehdr->e_ident[EI_DATA] = ELFDATA2LSB;
354
ehdr->e_ident[EI_DATA] = ELFDATA2MSB;
356
ehdr->e_ident[EI_VERSION] = EV_CURRENT;
357
ehdr->e_ident[EI_OSABI] = ELFOSABI_NONE;
358
ehdr->e_type = grub_host_to_target16 (ET_EXEC);
359
ehdr->e_machine = grub_host_to_target16 (EM_MIPS);
360
ehdr->e_version = grub_host_to_target32 (EV_CURRENT);
362
ehdr->e_phoff = grub_host_to_target32 ((char *) phdr - (char *) ehdr);
363
ehdr->e_phentsize = grub_host_to_target16 (sizeof (*phdr));
364
ehdr->e_phnum = grub_host_to_target16 (1);
366
/* No section headers. */
367
ehdr->e_shoff = grub_host_to_target32 (0);
368
ehdr->e_shentsize = grub_host_to_target16 (0);
369
ehdr->e_shnum = grub_host_to_target16 (0);
370
ehdr->e_shstrndx = grub_host_to_target16 (0);
372
ehdr->e_ehsize = grub_host_to_target16 (sizeof (*ehdr));
374
phdr->p_type = grub_host_to_target32 (PT_LOAD);
375
phdr->p_offset = grub_host_to_target32 (sizeof (*ehdr) + sizeof (*phdr));
376
phdr->p_flags = grub_host_to_target32 (PF_R | PF_W | PF_X);
378
target_addr = ALIGN_UP (GRUB_KERNEL_MACHINE_LINK_ADDR
379
+ kernel_size + total_module_size, 32);
380
ehdr->e_entry = grub_host_to_target32 (target_addr);
381
phdr->p_vaddr = grub_host_to_target32 (target_addr);
382
phdr->p_paddr = grub_host_to_target32 (target_addr);
383
phdr->p_align = grub_host_to_target32 (GRUB_KERNEL_MACHINE_LINK_ALIGN);
384
ehdr->e_flags = grub_host_to_target32 (0x1000 | EF_MIPS_NOREORDER
385
| EF_MIPS_PIC | EF_MIPS_CPIC);
386
phdr->p_filesz = grub_host_to_target32 (core_size);
387
phdr->p_memsz = grub_host_to_target32 (core_size);
391
core_size = program_size + sizeof (*ehdr) + sizeof (*phdr);
395
grub_util_write_image (core_img, core_size, out);
402
next = path_list->next;
403
free ((void *) path_list->name);
411
static struct option options[] =
413
{"directory", required_argument, 0, 'd'},
414
{"prefix", required_argument, 0, 'p'},
415
{"memdisk", required_argument, 0, 'm'},
416
{"font", required_argument, 0, 'f'},
417
{"config", required_argument, 0, 'c'},
418
{"output", required_argument, 0, 'o'},
419
#ifdef GRUB_PLATFORM_IMAGE_DEFAULT
420
{"format", required_argument, 0, 'O'},
422
{"help", no_argument, 0, 'h'},
423
{"version", no_argument, 0, 'V'},
424
{"verbose", no_argument, 0, 'v'},
432
fprintf (stderr, _("Try `%s --help' for more information.\n"), program_name);
435
Usage: %s [OPTION]... [MODULES]\n\
437
Make a bootable image of GRUB.\n\
439
-d, --directory=DIR use images and modules under DIR [default=%s]\n\
440
-p, --prefix=DIR set grub_prefix directory [default=%s]\n\
441
-m, --memdisk=FILE embed FILE as a memdisk image\n\
442
-f, --font=FILE embed FILE as a boot font\n\
443
-c, --config=FILE embed FILE as boot config\n\
444
-o, --output=FILE output a generated image to FILE [default=stdout]\n"
445
#ifdef GRUB_PLATFORM_IMAGE_DEFAULT
447
-O, --format=FORMAT generate an image in format [default="
448
GRUB_PLATFORM_IMAGE_DEFAULT_FORMAT "]\n \
450
GRUB_PLATFORM_IMAGE_FORMATS "\n"
453
-h, --help display this message and exit\n\
454
-V, --version print version information and exit\n\
455
-v, --verbose print verbose messages\n\
457
Report bugs to <%s>.\n\
458
"), program_name, GRUB_LIBDIR, DEFAULT_DIRECTORY, PACKAGE_BUGREPORT);
464
main (int argc, char *argv[])
469
char *memdisk = NULL;
473
#ifdef GRUB_PLATFORM_IMAGE_DEFAULT
474
grub_platform_image_format_t format = GRUB_PLATFORM_IMAGE_DEFAULT;
477
grub_util_init_nls ();
481
int c = getopt_long (argc, argv, "d:p:m:c:o:O:f:hVv", options, 0);
492
output = xstrdup (optarg);
495
#ifdef GRUB_PLATFORM_IMAGE_DEFAULT
497
#ifdef GRUB_PLATFORM_IMAGE_RAW
498
if (strcmp (optarg, "raw") == 0)
499
format = GRUB_PLATFORM_IMAGE_RAW;
502
#ifdef GRUB_PLATFORM_IMAGE_ELF
503
if (strcmp (optarg, "elf") == 0)
504
format = GRUB_PLATFORM_IMAGE_ELF;
515
dir = xstrdup (optarg);
522
memdisk = xstrdup (optarg);
527
prefix = xstrdup ("(memdisk)/boot/grub");
534
font = xstrdup (optarg);
541
config = xstrdup (optarg);
552
prefix = xstrdup (optarg);
556
printf ("grub-mkimage (%s) %s\n", PACKAGE_NAME, PACKAGE_VERSION);
571
fp = fopen (output, "wb");
573
grub_util_error (_("cannot open %s"), output);
577
generate_image (dir ? : GRUB_LIBDIR, prefix ? : DEFAULT_DIRECTORY, fp,
578
argv + optind, memdisk, font, config,
579
#ifdef GRUB_PLATFORM_IMAGE_DEFAULT