1 /* grub-mkimage.c - make a bootable image */
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2002,2003,2004,2005,2006,2007,2008 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>
39 #if defined(ENABLE_LZO)
41 #if defined(HAVE_LZO_LZO1X_H)
42 # include <lzo/lzo1x.h>
43 #elif defined(HAVE_LZO1X_H)
47 #elif defined(ENABLE_LZMA)
49 #include <grub/lib/LzmaEnc.h>
53 #if defined(ENABLE_LZO)
56 compress_kernel (char *kernel_img
, size_t kernel_size
,
57 char **core_img
, size_t *core_size
)
62 grub_util_info ("kernel_img=%p, kernel_size=0x%x", kernel_img
, kernel_size
);
63 if (kernel_size
< GRUB_KERNEL_MACHINE_RAW_SIZE
)
64 grub_util_error ("the core image is too small");
66 if (lzo_init () != LZO_E_OK
)
67 grub_util_error ("cannot initialize LZO");
69 *core_img
= xmalloc (kernel_size
+ kernel_size
/ 64 + 16 + 3);
70 wrkmem
= xmalloc (LZO1X_999_MEM_COMPRESS
);
72 memcpy (*core_img
, kernel_img
, GRUB_KERNEL_MACHINE_RAW_SIZE
);
74 grub_util_info ("compressing the core image");
75 if (lzo1x_999_compress ((const lzo_byte
*) (kernel_img
76 + GRUB_KERNEL_MACHINE_RAW_SIZE
),
77 kernel_size
- GRUB_KERNEL_MACHINE_RAW_SIZE
,
78 (lzo_byte
*) (*core_img
79 + GRUB_KERNEL_MACHINE_RAW_SIZE
),
82 grub_util_error ("cannot compress the kernel image");
86 *core_size
= (size_t) size
+ GRUB_KERNEL_MACHINE_RAW_SIZE
;
89 #elif defined(ENABLE_LZMA)
91 static void *SzAlloc(void *p
, size_t size
) { p
= p
; return xmalloc(size
); }
92 static void SzFree(void *p
, void *address
) { p
= p
; free(address
); }
93 static ISzAlloc g_Alloc
= { SzAlloc
, SzFree
};
96 compress_kernel (char *kernel_img
, size_t kernel_size
,
97 char **core_img
, size_t *core_size
)
100 unsigned char out_props
[5];
101 size_t out_props_size
= 5;
103 LzmaEncProps_Init(&props
);
104 props
.dictSize
= 1 << 16;
108 props
.numThreads
= 1;
110 grub_util_info ("kernel_img=%p, kernel_size=0x%x", kernel_img
, kernel_size
);
111 if (kernel_size
< GRUB_KERNEL_MACHINE_RAW_SIZE
)
112 grub_util_error ("the core image is too small");
114 *core_img
= xmalloc (kernel_size
);
115 memcpy (*core_img
, kernel_img
, GRUB_KERNEL_MACHINE_RAW_SIZE
);
117 *core_size
= kernel_size
- GRUB_KERNEL_MACHINE_RAW_SIZE
;
118 if (LzmaEncode((unsigned char *) *core_img
+ GRUB_KERNEL_MACHINE_RAW_SIZE
,
120 (unsigned char *) kernel_img
+ GRUB_KERNEL_MACHINE_RAW_SIZE
,
121 kernel_size
- GRUB_KERNEL_MACHINE_RAW_SIZE
,
122 &props
, out_props
, &out_props_size
,
123 0, NULL
, &g_Alloc
, &g_Alloc
) != SZ_OK
)
124 grub_util_error ("cannot compress the kernel image");
126 *core_size
+= GRUB_KERNEL_MACHINE_RAW_SIZE
;
132 generate_image (const char *dir
, char *prefix
, FILE *out
, char *mods
[], char *memdisk_path
)
134 grub_addr_t module_addr
= 0;
135 char *kernel_img
, *boot_img
, *core_img
;
136 size_t kernel_size
, boot_size
, total_module_size
, core_size
, memdisk_size
= 0;
137 char *kernel_path
, *boot_path
;
140 struct grub_util_path_list
*path_list
, *p
, *next
;
141 struct grub_module_info
*modinfo
;
143 path_list
= grub_util_resolve_dependencies (dir
, "moddep.lst", mods
);
145 kernel_path
= grub_util_get_path (dir
, "kernel.img");
146 kernel_size
= grub_util_get_image_size (kernel_path
);
148 total_module_size
= sizeof (struct grub_module_info
);
152 memdisk_size
= ALIGN_UP(grub_util_get_image_size (memdisk_path
), 512);
153 grub_util_info ("the size of memory disk is 0x%x", memdisk_size
);
154 total_module_size
+= memdisk_size
+ sizeof (struct grub_module_header
);
157 for (p
= path_list
; p
; p
= p
->next
)
158 total_module_size
+= (grub_util_get_image_size (p
->name
)
159 + sizeof (struct grub_module_header
));
161 grub_util_info ("the total module size is 0x%x", total_module_size
);
163 kernel_img
= xmalloc (kernel_size
+ total_module_size
);
164 grub_util_load_image (kernel_path
, kernel_img
);
166 if (GRUB_KERNEL_MACHINE_PREFIX
+ strlen (prefix
) + 1 > GRUB_KERNEL_MACHINE_DATA_END
)
167 grub_util_error ("prefix too long");
168 strcpy (kernel_img
+ GRUB_KERNEL_MACHINE_PREFIX
, prefix
);
170 /* Fill in the grub_module_info structure. */
171 modinfo
= (struct grub_module_info
*) (kernel_img
+ kernel_size
);
172 modinfo
->magic
= GRUB_MODULE_MAGIC
;
173 modinfo
->offset
= sizeof (struct grub_module_info
);
174 modinfo
->size
= total_module_size
;
176 offset
= kernel_size
+ sizeof (struct grub_module_info
);
177 for (p
= path_list
; p
; p
= p
->next
)
179 struct grub_module_header
*header
;
182 mod_size
= grub_util_get_image_size (p
->name
);
184 header
= (struct grub_module_header
*) (kernel_img
+ offset
);
185 header
->type
= grub_cpu_to_le32 (OBJ_TYPE_ELF
);
186 header
->size
= grub_cpu_to_le32 (mod_size
+ sizeof (*header
));
187 offset
+= sizeof (*header
);
189 grub_util_load_image (p
->name
, kernel_img
+ offset
);
195 struct grub_module_header
*header
;
197 header
= (struct grub_module_header
*) (kernel_img
+ offset
);
198 header
->type
= grub_cpu_to_le32 (OBJ_TYPE_MEMDISK
);
199 header
->size
= grub_cpu_to_le32 (memdisk_size
+ sizeof (*header
));
200 offset
+= sizeof (*header
);
202 grub_util_load_image (memdisk_path
, kernel_img
+ offset
);
203 offset
+= memdisk_size
;
206 compress_kernel (kernel_img
, kernel_size
+ total_module_size
,
207 &core_img
, &core_size
);
209 grub_util_info ("the core size is 0x%x", core_size
);
211 num
= ((core_size
+ GRUB_DISK_SECTOR_SIZE
- 1) >> GRUB_DISK_SECTOR_BITS
);
213 grub_util_error ("the core image is too big");
215 boot_path
= grub_util_get_path (dir
, "diskboot.img");
216 boot_size
= grub_util_get_image_size (boot_path
);
217 if (boot_size
!= GRUB_DISK_SECTOR_SIZE
)
218 grub_util_error ("diskboot.img is not one sector size");
220 boot_img
= grub_util_read_image (boot_path
);
222 /* i386 is a little endian architecture. */
223 *((grub_uint16_t
*) (boot_img
+ GRUB_DISK_SECTOR_SIZE
224 - GRUB_BOOT_MACHINE_LIST_SIZE
+ 8))
225 = grub_cpu_to_le16 (num
);
227 grub_util_write_image (boot_img
, boot_size
, out
);
231 module_addr
= (path_list
232 ? (GRUB_BOOT_MACHINE_KERNEL_ADDR
+ GRUB_DISK_SECTOR_SIZE
236 grub_util_info ("the first module address is 0x%x", module_addr
);
237 *((grub_uint32_t
*) (core_img
+ GRUB_KERNEL_MACHINE_TOTAL_MODULE_SIZE
))
238 = grub_cpu_to_le32 (total_module_size
);
239 *((grub_uint32_t
*) (core_img
+ GRUB_KERNEL_MACHINE_KERNEL_IMAGE_SIZE
))
240 = grub_cpu_to_le32 (kernel_size
);
241 *((grub_uint32_t
*) (core_img
+ GRUB_KERNEL_MACHINE_COMPRESSED_SIZE
))
242 = grub_cpu_to_le32 (core_size
- GRUB_KERNEL_MACHINE_RAW_SIZE
);
244 /* If we included a drive in our prefix, let GRUB know it doesn't have to
245 prepend the drive told by BIOS. */
246 if (prefix
[0] == '(')
248 *((grub_int32_t
*) (core_img
+ GRUB_KERNEL_MACHINE_INSTALL_DOS_PART
))
249 = grub_cpu_to_le32 (-2);
250 *((grub_int32_t
*) (core_img
+ GRUB_KERNEL_MACHINE_INSTALL_BSD_PART
))
251 = grub_cpu_to_le32 (-2);
254 if (core_size
> GRUB_MEMORY_MACHINE_UPPER
- GRUB_MEMORY_MACHINE_LINK_ADDR
)
255 grub_util_error ("Core image is too big (%p > %p)\n", core_size
,
256 GRUB_MEMORY_MACHINE_UPPER
- GRUB_MEMORY_MACHINE_LINK_ADDR
);
258 grub_util_write_image (core_img
, core_size
, out
);
265 next
= path_list
->next
;
266 free ((void *) path_list
->name
);
274 static struct option options
[] =
276 {"directory", required_argument
, 0, 'd'},
277 {"prefix", required_argument
, 0, 'p'},
278 {"memdisk", required_argument
, 0, 'm'},
279 {"output", required_argument
, 0, 'o'},
280 {"help", no_argument
, 0, 'h'},
281 {"version", no_argument
, 0, 'V'},
282 {"verbose", no_argument
, 0, 'v'},
290 fprintf (stderr
, "Try ``grub-mkimage --help'' for more information.\n");
293 Usage: grub-mkimage [OPTION]... [MODULES]\n\
295 Make a bootable image of GRUB.\n\
297 -d, --directory=DIR use images and modules under DIR [default=%s]\n\
298 -p, --prefix=DIR set grub_prefix directory [default=%s]\n\
299 -m, --memdisk=FILE embed FILE as a memdisk image\n\
300 -o, --output=FILE output a generated image to FILE [default=stdout]\n\
301 -h, --help display this message and exit\n\
302 -V, --version print version information and exit\n\
303 -v, --verbose print verbose messages\n\
305 Report bugs to <%s>.\n\
306 ", GRUB_LIBDIR
, DEFAULT_DIRECTORY
, PACKAGE_BUGREPORT
);
312 main (int argc
, char *argv
[])
317 char *memdisk
= NULL
;
320 progname
= "grub-mkimage";
324 int c
= getopt_long (argc
, argv
, "d:p:m:o:hVv", options
, 0);
335 output
= xstrdup (optarg
);
342 dir
= xstrdup (optarg
);
349 memdisk
= xstrdup (optarg
);
354 prefix
= xstrdup ("(memdisk)/boot/grub");
365 prefix
= xstrdup (optarg
);
369 printf ("grub-mkimage (%s) %s\n", PACKAGE_NAME
, PACKAGE_VERSION
);
384 fp
= fopen (output
, "wb");
386 grub_util_error ("cannot open %s", output
);
389 generate_image (dir
? : GRUB_LIBDIR
, prefix
? : DEFAULT_DIRECTORY
, fp
, argv
+ optind
, memdisk
);