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
;
106 size_t offset
, total_module_size
, memdisk_size
;
108 path_list
= grub_util_resolve_dependencies (dir
, "moddep.lst", mods
);
110 offset
= sizeof (struct grub_module_info
);
111 total_module_size
= sizeof (struct grub_module_info
);
115 memdisk_size
= ALIGN_UP(grub_util_get_image_size (memdisk_path
), 512);
116 grub_util_info ("the size of memory disk is 0x%x", memdisk_size
);
117 total_module_size
+= memdisk_size
+ sizeof (struct grub_module_header
);
120 for (p
= path_list
; p
; p
= p
->next
)
122 total_module_size
+= (grub_util_get_image_size (p
->name
)
123 + sizeof (struct grub_module_header
));
126 grub_util_info ("the total module size is 0x%x", total_module_size
);
128 module_img
= xmalloc (total_module_size
);
129 modinfo
= (struct grub_module_info
*) module_img
;
130 modinfo
->magic
= grub_host_to_target32 (GRUB_MODULE_MAGIC
);
131 modinfo
->offset
= grub_host_to_target32 (sizeof (struct grub_module_info
));
132 modinfo
->size
= grub_host_to_target32 (total_module_size
);
134 /* Load all the modules, with headers, into module_img. */
135 for (p
= path_list
; p
; p
= p
->next
)
137 struct grub_module_header
*header
;
140 grub_util_info ("adding module %s", p
->name
);
142 mod_size
= grub_util_get_image_size (p
->name
);
144 header
= (struct grub_module_header
*) (module_img
+ offset
);
145 header
->type
= grub_host_to_target32 (OBJ_TYPE_ELF
);
146 header
->size
= grub_host_to_target32 (mod_size
+ sizeof (*header
));
148 grub_util_load_image (p
->name
, module_img
+ offset
+ sizeof (*header
));
150 offset
+= sizeof (*header
) + mod_size
;
155 struct grub_module_header
*header
;
157 header
= (struct grub_module_header
*) (module_img
+ offset
);
158 header
->type
= grub_cpu_to_le32 (OBJ_TYPE_MEMDISK
);
159 header
->size
= grub_cpu_to_le32 (memdisk_size
+ sizeof (*header
));
160 offset
+= sizeof (*header
);
162 grub_util_load_image (memdisk_path
, module_img
+ offset
);
163 offset
+= memdisk_size
;
167 /* Write the module data to the new segment. */
168 grub_util_write_image_at (module_img
, total_module_size
,
169 grub_host_to_target32 (phdr
->p_offset
), out
);
171 /* Fill in the rest of the segment header. */
172 phdr
->p_type
= grub_host_to_target32 (PT_LOAD
);
173 phdr
->p_flags
= grub_host_to_target32 (PF_R
| PF_W
| PF_X
);
174 phdr
->p_align
= grub_host_to_target32 (GRUB_TARGET_SIZEOF_LONG
);
175 phdr
->p_vaddr
= grub_host_to_target32 (modbase
);
176 phdr
->p_paddr
= grub_host_to_target32 (modbase
);
177 phdr
->p_filesz
= grub_host_to_target32 (total_module_size
);
178 phdr
->p_memsz
= grub_host_to_target32 (total_module_size
);
182 add_segments (char *dir
, char *prefix
, FILE *out
, int chrp
, char *mods
[], char *memdisk_path
)
185 Elf32_Phdr
*phdrs
= NULL
;
189 grub_addr_t grub_end
= 0;
190 off_t offset
, first_segment
;
193 /* Read ELF header. */
194 kernel_path
= grub_util_get_path (dir
, "kernel.elf");
195 in
= fopen (kernel_path
, "rb");
197 grub_util_error ("cannot open %s", kernel_path
);
199 grub_util_read_at (&ehdr
, sizeof (ehdr
), 0, in
);
201 offset
= ALIGN_UP (sizeof (ehdr
), GRUB_TARGET_SIZEOF_LONG
);
202 ehdr
.e_phoff
= grub_host_to_target32 (offset
);
204 phdr_size
= (grub_target_to_host16 (ehdr
.e_phentsize
) *
205 grub_target_to_host16 (ehdr
.e_phnum
));
208 phdr_size
+= grub_target_to_host16 (ehdr
.e_phentsize
);
211 phdr_size
+= grub_target_to_host16 (ehdr
.e_phentsize
);
213 phdrs
= xmalloc (phdr_size
);
214 offset
+= ALIGN_UP (phdr_size
, GRUB_TARGET_SIZEOF_LONG
);
216 first_segment
= offset
;
218 /* Copy all existing segments. */
219 for (i
= 0; i
< grub_target_to_host16 (ehdr
.e_phnum
); i
++)
222 grub_size_t segment_end
;
226 /* Read segment header. */
227 grub_util_read_at (phdr
, sizeof (Elf32_Phdr
),
228 (grub_target_to_host32 (ehdr
.e_phoff
)
229 + (i
* grub_target_to_host16 (ehdr
.e_phentsize
))),
231 grub_util_info ("copying segment %d, type %d", i
,
232 grub_target_to_host32 (phdr
->p_type
));
235 segment_end
= grub_target_to_host32 (phdr
->p_paddr
)
236 + grub_target_to_host32 (phdr
->p_memsz
);
237 grub_util_info ("segment %u end 0x%lx", i
, segment_end
);
238 if (segment_end
> grub_end
)
239 grub_end
= segment_end
;
241 /* Read segment data and write it to new file. */
242 segment_img
= xmalloc (grub_target_to_host32 (phdr
->p_filesz
));
244 grub_util_read_at (segment_img
, grub_target_to_host32 (phdr
->p_filesz
),
245 grub_target_to_host32 (phdr
->p_offset
), in
);
247 phdr
->p_offset
= grub_host_to_target32 (offset
);
248 grub_util_write_image_at (segment_img
, grub_target_to_host32 (phdr
->p_filesz
),
250 offset
+= ALIGN_UP (grub_target_to_host32 (phdr
->p_filesz
),
251 GRUB_TARGET_SIZEOF_LONG
);
260 /* Place modules just after grub segment. */
261 modbase
= ALIGN_UP(grub_end
+ GRUB_MOD_GAP
, GRUB_MOD_ALIGN
);
263 /* Construct new segment header for modules. */
264 phdr
= phdrs
+ grub_target_to_host16 (ehdr
.e_phnum
);
265 ehdr
.e_phnum
= grub_host_to_target16 (grub_target_to_host16 (ehdr
.e_phnum
) + 1);
267 /* Fill in p_offset so the callees know where to write. */
268 phdr
->p_offset
= grub_host_to_target32 (ALIGN_UP (grub_util_get_fp_size (out
),
269 GRUB_TARGET_SIZEOF_LONG
));
271 load_modules (modbase
, phdr
, dir
, mods
, out
, memdisk_path
);
276 /* Construct new segment header for the CHRP note. */
277 phdr
= phdrs
+ grub_target_to_host16 (ehdr
.e_phnum
);
278 ehdr
.e_phnum
= grub_host_to_target16 (grub_target_to_host16 (ehdr
.e_phnum
) + 1);
280 /* Fill in p_offset so the callees know where to write. */
281 phdr
->p_offset
= grub_host_to_target32 (ALIGN_UP (grub_util_get_fp_size (out
),
282 GRUB_TARGET_SIZEOF_LONG
));
284 load_note (phdr
, out
);
287 /* Don't bother preserving the section headers. */
292 /* Write entire segment table to the file. */
293 grub_util_write_image_at (phdrs
, phdr_size
, grub_target_to_host32 (ehdr
.e_phoff
), out
);
295 /* Write ELF header. */
296 grub_util_write_image_at (&ehdr
, sizeof (ehdr
), 0, out
);
300 if (GRUB_KERNEL_CPU_PREFIX
+ strlen (prefix
) + 1 > GRUB_KERNEL_CPU_DATA_END
)
301 grub_util_error ("prefix too long");
302 grub_util_write_image_at (prefix
, strlen (prefix
) + 1, first_segment
+ GRUB_KERNEL_CPU_PREFIX
, out
);
309 static struct option options
[] =
311 {"directory", required_argument
, 0, 'd'},
312 {"prefix", required_argument
, 0, 'p'},
313 {"memdisk", required_argument
, 0, 'm'},
314 {"output", required_argument
, 0, 'o'},
315 {"help", no_argument
, 0, 'h'},
316 {"note", no_argument
, 0, 'n'},
317 {"version", no_argument
, 0, 'V'},
318 {"verbose", no_argument
, 0, 'v'},
326 fprintf (stderr
, "Try ``grub-mkimage --help'' for more information.\n");
329 Usage: grub-mkimage -o FILE [OPTION]... [MODULES]\n\
331 Make a bootable image of GRUB.\n\
333 -d, --directory=DIR use images and modules under DIR [default=%s]\n\
334 -p, --prefix=DIR set grub_prefix directory\n\
335 -m, --memdisk=FILE embed FILE as a memdisk image\n\
336 -o, --output=FILE output a generated image to FILE\n\
337 -h, --help display this message and exit\n\
338 -n, --note add NOTE segment for CHRP Open Firmware\n\
339 -V, --version print version information and exit\n\
340 -v, --verbose print verbose messages\n\
342 Report bugs to <%s>.\n\
343 ", GRUB_LIBDIR
, PACKAGE_BUGREPORT
);
349 main (int argc
, char *argv
[])
355 char *memdisk
= NULL
;
358 progname
= "grub-mkimage";
362 int c
= getopt_long (argc
, argv
, "d:p:m:o:hVvn", options
, 0);
371 dir
= xstrdup (optarg
);
376 prefix
= xstrdup (optarg
);
381 memdisk
= xstrdup (optarg
);
385 prefix
= xstrdup ("(memdisk)/boot/grub");
397 output
= xstrdup (optarg
);
400 printf ("grub-mkimage (%s) %s\n", PACKAGE_NAME
, PACKAGE_VERSION
);
414 fp
= fopen (output
, "wb");
416 grub_util_error ("cannot open %s", output
);
418 add_segments (dir
? : GRUB_LIBDIR
, prefix
, fp
, chrp
, argv
+ optind
, memdisk
);