2 * GRUB -- GRand Unified Bootloader
3 * Copyright (C) 2004,2005,2006,2007,2008 Free Software Foundation, Inc.
5 * GRUB is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * GRUB is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
29 #include <grub/misc.h>
30 #include <grub/util/misc.h>
31 #include <grub/util/resolve.h>
32 #include <grub/kernel.h>
33 #include <grub/cpu/kernel.h>
35 #define GRUB_IEEE1275_NOTE_NAME "PowerPC"
36 #define GRUB_IEEE1275_NOTE_TYPE 0x1275
38 /* These structures are defined according to the CHRP binding to IEEE1275,
39 "Client Program Format" section. */
41 struct grub_ieee1275_note_hdr
46 char name
[sizeof (GRUB_IEEE1275_NOTE_NAME
)];
49 struct grub_ieee1275_note_desc
51 grub_uint32_t real_mode
;
52 grub_uint32_t real_base
;
53 grub_uint32_t real_size
;
54 grub_uint32_t virt_base
;
55 grub_uint32_t virt_size
;
56 grub_uint32_t load_base
;
59 struct grub_ieee1275_note
61 struct grub_ieee1275_note_hdr header
;
62 struct grub_ieee1275_note_desc descriptor
;
66 load_note (Elf32_Phdr
*phdr
, FILE *out
)
68 struct grub_ieee1275_note note
;
69 int note_size
= sizeof (struct grub_ieee1275_note
);
71 grub_util_info ("adding CHRP NOTE segment");
73 note
.header
.namesz
= grub_host_to_target32 (sizeof (GRUB_IEEE1275_NOTE_NAME
));
74 note
.header
.descsz
= grub_host_to_target32 (note_size
);
75 note
.header
.type
= grub_host_to_target32 (GRUB_IEEE1275_NOTE_TYPE
);
76 strcpy (note
.header
.name
, GRUB_IEEE1275_NOTE_NAME
);
77 note
.descriptor
.real_mode
= grub_host_to_target32 (0xffffffff);
78 note
.descriptor
.real_base
= grub_host_to_target32 (0x00c00000);
79 note
.descriptor
.real_size
= grub_host_to_target32 (0xffffffff);
80 note
.descriptor
.virt_base
= grub_host_to_target32 (0xffffffff);
81 note
.descriptor
.virt_size
= grub_host_to_target32 (0xffffffff);
82 note
.descriptor
.load_base
= grub_host_to_target32 (0x00004000);
84 /* Write the note data to the new segment. */
85 grub_util_write_image_at (¬e
, note_size
,
86 grub_target_to_host32 (phdr
->p_offset
), out
);
88 /* Fill in the rest of the segment header. */
89 phdr
->p_type
= grub_host_to_target32 (PT_NOTE
);
90 phdr
->p_flags
= grub_host_to_target32 (PF_R
);
91 phdr
->p_align
= grub_host_to_target32 (GRUB_TARGET_SIZEOF_LONG
);
94 phdr
->p_filesz
= grub_host_to_target32 (note_size
);
99 load_modules (grub_addr_t modbase
, Elf32_Phdr
*phdr
, const char *dir
,
100 char *mods
[], FILE *out
, char *memdisk_path
)
103 struct grub_util_path_list
*path_list
;
104 struct grub_util_path_list
*p
;
105 struct grub_module_info
*modinfo
;
107 size_t total_module_size
;
108 size_t memdisk_size
= 0;
110 path_list
= grub_util_resolve_dependencies (dir
, "moddep.lst", mods
);
112 offset
= sizeof (struct grub_module_info
);
113 total_module_size
= sizeof (struct grub_module_info
);
117 memdisk_size
= ALIGN_UP(grub_util_get_image_size (memdisk_path
), 512);
118 grub_util_info ("the size of memory disk is 0x%x", memdisk_size
);
119 total_module_size
+= memdisk_size
+ sizeof (struct grub_module_header
);
122 for (p
= path_list
; p
; p
= p
->next
)
124 total_module_size
+= (grub_util_get_image_size (p
->name
)
125 + sizeof (struct grub_module_header
));
128 grub_util_info ("the total module size is 0x%x", total_module_size
);
130 module_img
= xmalloc (total_module_size
);
131 modinfo
= (struct grub_module_info
*) module_img
;
132 modinfo
->magic
= grub_host_to_target32 (GRUB_MODULE_MAGIC
);
133 modinfo
->offset
= grub_host_to_target32 (sizeof (struct grub_module_info
));
134 modinfo
->size
= grub_host_to_target32 (total_module_size
);
136 /* Load all the modules, with headers, into module_img. */
137 for (p
= path_list
; p
; p
= p
->next
)
139 struct grub_module_header
*header
;
142 grub_util_info ("adding module %s", p
->name
);
144 mod_size
= grub_util_get_image_size (p
->name
);
146 header
= (struct grub_module_header
*) (module_img
+ offset
);
147 header
->type
= grub_host_to_target32 (OBJ_TYPE_ELF
);
148 header
->size
= grub_host_to_target32 (mod_size
+ sizeof (*header
));
150 grub_util_load_image (p
->name
, module_img
+ offset
+ sizeof (*header
));
152 offset
+= sizeof (*header
) + mod_size
;
157 struct grub_module_header
*header
;
159 header
= (struct grub_module_header
*) (module_img
+ offset
);
160 header
->type
= grub_cpu_to_le32 (OBJ_TYPE_MEMDISK
);
161 header
->size
= grub_cpu_to_le32 (memdisk_size
+ sizeof (*header
));
162 offset
+= sizeof (*header
);
164 grub_util_load_image (memdisk_path
, module_img
+ offset
);
165 offset
+= memdisk_size
;
169 /* Write the module data to the new segment. */
170 grub_util_write_image_at (module_img
, total_module_size
,
171 grub_host_to_target32 (phdr
->p_offset
), out
);
173 /* Fill in the rest of the segment header. */
174 phdr
->p_type
= grub_host_to_target32 (PT_LOAD
);
175 phdr
->p_flags
= grub_host_to_target32 (PF_R
| PF_W
| PF_X
);
176 phdr
->p_align
= grub_host_to_target32 (GRUB_TARGET_SIZEOF_LONG
);
177 phdr
->p_vaddr
= grub_host_to_target32 (modbase
);
178 phdr
->p_paddr
= grub_host_to_target32 (modbase
);
179 phdr
->p_filesz
= grub_host_to_target32 (total_module_size
);
180 phdr
->p_memsz
= grub_host_to_target32 (total_module_size
);
184 add_segments (char *dir
, char *prefix
, FILE *out
, int chrp
, char *mods
[], char *memdisk_path
)
187 Elf32_Phdr
*phdrs
= NULL
;
191 grub_addr_t grub_end
= 0;
192 off_t offset
, first_segment
;
195 /* Read ELF header. */
196 kernel_path
= grub_util_get_path (dir
, "kernel.img");
197 in
= fopen (kernel_path
, "rb");
199 grub_util_error ("cannot open %s", kernel_path
);
201 grub_util_read_at (&ehdr
, sizeof (ehdr
), 0, in
);
203 offset
= ALIGN_UP (sizeof (ehdr
), GRUB_TARGET_SIZEOF_LONG
);
204 ehdr
.e_phoff
= grub_host_to_target32 (offset
);
206 phdr_size
= (grub_target_to_host16 (ehdr
.e_phentsize
) *
207 grub_target_to_host16 (ehdr
.e_phnum
));
210 phdr_size
+= grub_target_to_host16 (ehdr
.e_phentsize
);
213 phdr_size
+= grub_target_to_host16 (ehdr
.e_phentsize
);
215 phdrs
= xmalloc (phdr_size
);
216 offset
+= ALIGN_UP (phdr_size
, GRUB_TARGET_SIZEOF_LONG
);
218 first_segment
= offset
;
220 /* Copy all existing segments. */
221 for (i
= 0; i
< grub_target_to_host16 (ehdr
.e_phnum
); i
++)
224 grub_size_t segment_end
;
228 /* Read segment header. */
229 grub_util_read_at (phdr
, sizeof (Elf32_Phdr
),
230 (grub_target_to_host32 (ehdr
.e_phoff
)
231 + (i
* grub_target_to_host16 (ehdr
.e_phentsize
))),
233 grub_util_info ("copying segment %d, type %d", i
,
234 grub_target_to_host32 (phdr
->p_type
));
237 segment_end
= grub_target_to_host32 (phdr
->p_paddr
)
238 + grub_target_to_host32 (phdr
->p_memsz
);
239 grub_util_info ("segment %u end 0x%lx", i
, segment_end
);
240 if (segment_end
> grub_end
)
241 grub_end
= segment_end
;
243 /* Read segment data and write it to new file. */
244 segment_img
= xmalloc (grub_target_to_host32 (phdr
->p_filesz
));
246 grub_util_read_at (segment_img
, grub_target_to_host32 (phdr
->p_filesz
),
247 grub_target_to_host32 (phdr
->p_offset
), in
);
249 phdr
->p_offset
= grub_host_to_target32 (offset
);
250 grub_util_write_image_at (segment_img
, grub_target_to_host32 (phdr
->p_filesz
),
252 offset
+= ALIGN_UP (grub_target_to_host32 (phdr
->p_filesz
),
253 GRUB_TARGET_SIZEOF_LONG
);
262 /* Place modules just after grub segment. */
263 modbase
= ALIGN_UP(grub_end
+ GRUB_MOD_GAP
, GRUB_MOD_ALIGN
);
265 /* Construct new segment header for modules. */
266 phdr
= phdrs
+ grub_target_to_host16 (ehdr
.e_phnum
);
267 ehdr
.e_phnum
= grub_host_to_target16 (grub_target_to_host16 (ehdr
.e_phnum
) + 1);
269 /* Fill in p_offset so the callees know where to write. */
270 phdr
->p_offset
= grub_host_to_target32 (ALIGN_UP (grub_util_get_fp_size (out
),
271 GRUB_TARGET_SIZEOF_LONG
));
273 load_modules (modbase
, phdr
, dir
, mods
, out
, memdisk_path
);
278 /* Construct new segment header for the CHRP note. */
279 phdr
= phdrs
+ grub_target_to_host16 (ehdr
.e_phnum
);
280 ehdr
.e_phnum
= grub_host_to_target16 (grub_target_to_host16 (ehdr
.e_phnum
) + 1);
282 /* Fill in p_offset so the callees know where to write. */
283 phdr
->p_offset
= grub_host_to_target32 (ALIGN_UP (grub_util_get_fp_size (out
),
284 GRUB_TARGET_SIZEOF_LONG
));
286 load_note (phdr
, out
);
289 /* Don't bother preserving the section headers. */
294 /* Write entire segment table to the file. */
295 grub_util_write_image_at (phdrs
, phdr_size
, grub_target_to_host32 (ehdr
.e_phoff
), out
);
297 /* Write ELF header. */
298 grub_util_write_image_at (&ehdr
, sizeof (ehdr
), 0, out
);
302 if (GRUB_KERNEL_CPU_PREFIX
+ strlen (prefix
) + 1 > GRUB_KERNEL_CPU_DATA_END
)
303 grub_util_error ("prefix too long");
304 grub_util_write_image_at (prefix
, strlen (prefix
) + 1, first_segment
+ GRUB_KERNEL_CPU_PREFIX
, out
);
311 static struct option options
[] =
313 {"directory", required_argument
, 0, 'd'},
314 {"prefix", required_argument
, 0, 'p'},
315 {"memdisk", required_argument
, 0, 'm'},
316 {"output", required_argument
, 0, 'o'},
317 {"help", no_argument
, 0, 'h'},
318 {"note", no_argument
, 0, 'n'},
319 {"version", no_argument
, 0, 'V'},
320 {"verbose", no_argument
, 0, 'v'},
328 fprintf (stderr
, "Try ``grub-mkimage --help'' for more information.\n");
331 Usage: grub-mkimage -o FILE [OPTION]... [MODULES]\n\
333 Make a bootable image of GRUB.\n\
335 -d, --directory=DIR use images and modules under DIR [default=%s]\n\
336 -p, --prefix=DIR set grub_prefix directory\n\
337 -m, --memdisk=FILE embed FILE as a memdisk image\n\
338 -o, --output=FILE output a generated image to FILE\n\
339 -h, --help display this message and exit\n\
340 -n, --note add NOTE segment for CHRP Open Firmware\n\
341 -V, --version print version information and exit\n\
342 -v, --verbose print verbose messages\n\
344 Report bugs to <%s>.\n\
345 ", GRUB_LIBDIR
, PACKAGE_BUGREPORT
);
351 main (int argc
, char *argv
[])
357 char *memdisk
= NULL
;
360 progname
= "grub-mkimage";
364 int c
= getopt_long (argc
, argv
, "d:p:m:o:hVvn", options
, 0);
373 dir
= xstrdup (optarg
);
378 prefix
= xstrdup (optarg
);
383 memdisk
= xstrdup (optarg
);
387 prefix
= xstrdup ("(memdisk)/boot/grub");
399 output
= xstrdup (optarg
);
402 printf ("grub-mkimage (%s) %s\n", PACKAGE_NAME
, PACKAGE_VERSION
);
416 fp
= fopen (output
, "wb");
418 grub_util_error ("cannot open %s", output
);
420 add_segments (dir
? : GRUB_LIBDIR
, prefix
, fp
, chrp
, argv
+ optind
, memdisk
);