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>
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 if (kernel_size
< GRUB_KERNEL_MACHINE_RAW_SIZE
)
63 grub_util_error ("the core image is too small");
65 if (lzo_init () != LZO_E_OK
)
66 grub_util_error ("cannot initialize LZO");
68 *core_img
= xmalloc (kernel_size
+ kernel_size
/ 64 + 16 + 3);
69 wrkmem
= xmalloc (LZO1X_999_MEM_COMPRESS
);
71 memcpy (*core_img
, kernel_img
, GRUB_KERNEL_MACHINE_RAW_SIZE
);
73 grub_util_info ("compressing the core image");
74 if (lzo1x_999_compress ((const lzo_byte
*) (kernel_img
75 + GRUB_KERNEL_MACHINE_RAW_SIZE
),
76 kernel_size
- GRUB_KERNEL_MACHINE_RAW_SIZE
,
77 (lzo_byte
*) (*core_img
78 + GRUB_KERNEL_MACHINE_RAW_SIZE
),
81 grub_util_error ("cannot compress the kernel image");
85 *core_size
= (size_t) size
+ GRUB_KERNEL_MACHINE_RAW_SIZE
;
88 #elif defined(ENABLE_LZMA)
90 static void *SzAlloc(void *p
, size_t size
) { p
= p
; return xmalloc(size
); }
91 static void SzFree(void *p
, void *address
) { p
= p
; free(address
); }
92 static ISzAlloc g_Alloc
= { SzAlloc
, SzFree
};
95 compress_kernel (char *kernel_img
, size_t kernel_size
,
96 char **core_img
, size_t *core_size
)
99 unsigned char out_props
[5];
100 size_t out_props_size
= 5;
102 LzmaEncProps_Init(&props
);
103 props
.dictSize
= 1 << 16;
107 props
.numThreads
= 1;
109 if (kernel_size
< GRUB_KERNEL_MACHINE_RAW_SIZE
)
110 grub_util_error ("the core image is too small");
112 *core_img
= xmalloc (kernel_size
);
113 memcpy (*core_img
, kernel_img
, GRUB_KERNEL_MACHINE_RAW_SIZE
);
115 *core_size
= kernel_size
- GRUB_KERNEL_MACHINE_RAW_SIZE
;
116 if (LzmaEncode((unsigned char *) *core_img
+ GRUB_KERNEL_MACHINE_RAW_SIZE
,
118 (unsigned char *) kernel_img
+ GRUB_KERNEL_MACHINE_RAW_SIZE
,
119 kernel_size
- GRUB_KERNEL_MACHINE_RAW_SIZE
,
120 &props
, out_props
, &out_props_size
,
121 0, NULL
, &g_Alloc
, &g_Alloc
) != SZ_OK
)
122 grub_util_error ("cannot compress the kernel image");
124 *core_size
+= GRUB_KERNEL_MACHINE_RAW_SIZE
;
130 generate_image (const char *dir
, char *prefix
, FILE *out
, char *mods
[],
131 char *memdisk_path
, char *config_path
)
133 char *kernel_img
, *boot_img
, *core_img
;
134 size_t kernel_size
, boot_size
, total_module_size
, core_size
;
135 size_t memdisk_size
= 0, config_size
= 0;
136 char *kernel_path
, *boot_path
;
139 struct grub_util_path_list
*path_list
, *p
, *next
;
140 struct grub_module_info
*modinfo
;
142 path_list
= grub_util_resolve_dependencies (dir
, "moddep.lst", mods
);
144 kernel_path
= grub_util_get_path (dir
, "kernel.img");
145 kernel_size
= grub_util_get_image_size (kernel_path
);
147 total_module_size
= sizeof (struct grub_module_info
);
151 memdisk_size
= ALIGN_UP(grub_util_get_image_size (memdisk_path
), 512);
152 grub_util_info ("the size of memory disk is 0x%x", memdisk_size
);
153 total_module_size
+= memdisk_size
+ sizeof (struct grub_module_header
);
158 config_size
= grub_util_get_image_size (config_path
) + 1;
159 grub_util_info ("the size of config file is 0x%x", config_size
);
160 total_module_size
+= config_size
+ sizeof (struct grub_module_header
);
163 for (p
= path_list
; p
; p
= p
->next
)
164 total_module_size
+= (grub_util_get_image_size (p
->name
)
165 + sizeof (struct grub_module_header
));
167 grub_util_info ("the total module size is 0x%x", total_module_size
);
169 kernel_img
= xmalloc (kernel_size
+ total_module_size
);
170 grub_util_load_image (kernel_path
, kernel_img
);
172 if (GRUB_KERNEL_MACHINE_PREFIX
+ strlen (prefix
) + 1 > GRUB_KERNEL_MACHINE_DATA_END
)
173 grub_util_error ("prefix too long");
174 strcpy (kernel_img
+ GRUB_KERNEL_MACHINE_PREFIX
, prefix
);
176 /* Fill in the grub_module_info structure. */
177 modinfo
= (struct grub_module_info
*) (kernel_img
+ kernel_size
);
178 memset (modinfo
, 0, sizeof (struct grub_module_info
));
179 modinfo
->magic
= GRUB_MODULE_MAGIC
;
180 modinfo
->offset
= sizeof (struct grub_module_info
);
181 modinfo
->size
= total_module_size
;
183 offset
= kernel_size
+ sizeof (struct grub_module_info
);
184 for (p
= path_list
; p
; p
= p
->next
)
186 struct grub_module_header
*header
;
189 mod_size
= grub_util_get_image_size (p
->name
);
191 header
= (struct grub_module_header
*) (kernel_img
+ offset
);
192 memset (header
, 0, sizeof (struct grub_module_header
));
193 header
->type
= grub_cpu_to_le32 (OBJ_TYPE_ELF
);
194 header
->size
= grub_cpu_to_le32 (mod_size
+ sizeof (*header
));
195 offset
+= sizeof (*header
);
197 grub_util_load_image (p
->name
, kernel_img
+ offset
);
203 struct grub_module_header
*header
;
205 header
= (struct grub_module_header
*) (kernel_img
+ offset
);
206 memset (header
, 0, sizeof (struct grub_module_header
));
207 header
->type
= grub_cpu_to_le32 (OBJ_TYPE_MEMDISK
);
208 header
->size
= grub_cpu_to_le32 (memdisk_size
+ sizeof (*header
));
209 offset
+= sizeof (*header
);
211 grub_util_load_image (memdisk_path
, kernel_img
+ offset
);
212 offset
+= memdisk_size
;
217 struct grub_module_header
*header
;
219 header
= (struct grub_module_header
*) (kernel_img
+ offset
);
220 memset (header
, 0, sizeof (struct grub_module_header
));
221 header
->type
= grub_cpu_to_le32 (OBJ_TYPE_CONFIG
);
222 header
->size
= grub_cpu_to_le32 (config_size
+ sizeof (*header
));
223 offset
+= sizeof (*header
);
225 grub_util_load_image (config_path
, kernel_img
+ offset
);
226 offset
+= config_size
;
227 *(kernel_img
+ offset
- 1) = 0;
230 grub_util_info ("kernel_img=%p, kernel_size=0x%x", kernel_img
, kernel_size
);
231 compress_kernel (kernel_img
, kernel_size
+ total_module_size
,
232 &core_img
, &core_size
);
234 grub_util_info ("the core size is 0x%x", core_size
);
236 num
= ((core_size
+ GRUB_DISK_SECTOR_SIZE
- 1) >> GRUB_DISK_SECTOR_BITS
);
238 grub_util_error ("the core image is too big");
240 boot_path
= grub_util_get_path (dir
, "diskboot.img");
241 boot_size
= grub_util_get_image_size (boot_path
);
242 if (boot_size
!= GRUB_DISK_SECTOR_SIZE
)
243 grub_util_error ("diskboot.img is not one sector size");
245 boot_img
= grub_util_read_image (boot_path
);
247 /* i386 is a little endian architecture. */
248 *((grub_uint16_t
*) (boot_img
+ GRUB_DISK_SECTOR_SIZE
249 - GRUB_BOOT_MACHINE_LIST_SIZE
+ 8))
250 = grub_cpu_to_le16 (num
);
252 grub_util_write_image (boot_img
, boot_size
, out
);
256 *((grub_uint32_t
*) (core_img
+ GRUB_KERNEL_MACHINE_TOTAL_MODULE_SIZE
))
257 = grub_cpu_to_le32 (total_module_size
);
258 *((grub_uint32_t
*) (core_img
+ GRUB_KERNEL_MACHINE_KERNEL_IMAGE_SIZE
))
259 = grub_cpu_to_le32 (kernel_size
);
260 *((grub_uint32_t
*) (core_img
+ GRUB_KERNEL_MACHINE_COMPRESSED_SIZE
))
261 = grub_cpu_to_le32 (core_size
- GRUB_KERNEL_MACHINE_RAW_SIZE
);
263 /* If we included a drive in our prefix, let GRUB know it doesn't have to
264 prepend the drive told by BIOS. */
265 if (prefix
[0] == '(')
267 *((grub_int32_t
*) (core_img
+ GRUB_KERNEL_MACHINE_INSTALL_DOS_PART
))
268 = grub_cpu_to_le32 (-2);
269 *((grub_int32_t
*) (core_img
+ GRUB_KERNEL_MACHINE_INSTALL_BSD_PART
))
270 = grub_cpu_to_le32 (-2);
273 if (GRUB_KERNEL_MACHINE_LINK_ADDR
+ core_size
> GRUB_MEMORY_MACHINE_UPPER
)
274 grub_util_error ("Core image is too big (%p > %p)\n",
275 GRUB_KERNEL_MACHINE_LINK_ADDR
+ core_size
, GRUB_MEMORY_MACHINE_UPPER
);
277 grub_util_write_image (core_img
, core_size
, out
);
284 next
= path_list
->next
;
285 free ((void *) path_list
->name
);
293 static struct option options
[] =
295 {"directory", required_argument
, 0, 'd'},
296 {"prefix", required_argument
, 0, 'p'},
297 {"memdisk", required_argument
, 0, 'm'},
298 {"config", required_argument
, 0, 'c'},
299 {"output", required_argument
, 0, 'o'},
300 {"help", no_argument
, 0, 'h'},
301 {"version", no_argument
, 0, 'V'},
302 {"verbose", no_argument
, 0, 'v'},
310 fprintf (stderr
, "Try ``grub-mkimage --help'' for more information.\n");
313 Usage: grub-mkimage [OPTION]... [MODULES]\n\
315 Make a bootable image of GRUB.\n\
317 -d, --directory=DIR use images and modules under DIR [default=%s]\n\
318 -p, --prefix=DIR set grub_prefix directory [default=%s]\n\
319 -m, --memdisk=FILE embed FILE as a memdisk image\n\
320 -c, --config=FILE embed FILE as boot config\n\
321 -o, --output=FILE output a generated image to FILE [default=stdout]\n\
322 -h, --help display this message and exit\n\
323 -V, --version print version information and exit\n\
324 -v, --verbose print verbose messages\n\
326 Report bugs to <%s>.\n\
327 ", GRUB_LIBDIR
, DEFAULT_DIRECTORY
, PACKAGE_BUGREPORT
);
333 main (int argc
, char *argv
[])
338 char *memdisk
= NULL
;
342 progname
= "grub-mkimage";
346 int c
= getopt_long (argc
, argv
, "d:p:m:c:o:hVv", options
, 0);
357 output
= xstrdup (optarg
);
364 dir
= xstrdup (optarg
);
371 memdisk
= xstrdup (optarg
);
376 prefix
= xstrdup ("(memdisk)/boot/grub");
383 config
= xstrdup (optarg
);
394 prefix
= xstrdup (optarg
);
398 printf ("grub-mkimage (%s) %s\n", PACKAGE_NAME
, PACKAGE_VERSION
);
413 fp
= fopen (output
, "wb");
415 grub_util_error ("cannot open %s", output
);
419 generate_image (dir
? : GRUB_LIBDIR
, prefix
? : DEFAULT_DIRECTORY
, fp
,
420 argv
+ optind
, memdisk
, config
);