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/machine/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 (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
)
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
;
109 path_list
= grub_util_resolve_dependencies (dir
, "moddep.lst", mods
);
111 offset
= sizeof (struct grub_module_info
);
112 total_module_size
= sizeof (struct grub_module_info
);
113 for (p
= path_list
; p
; p
= p
->next
)
115 total_module_size
+= (grub_util_get_image_size (p
->name
)
116 + sizeof (struct grub_module_header
));
119 grub_util_info ("the total module size is 0x%x", total_module_size
);
121 module_img
= xmalloc (total_module_size
);
122 modinfo
= (struct grub_module_info
*) module_img
;
123 modinfo
->magic
= grub_host_to_target32 (GRUB_MODULE_MAGIC
);
124 modinfo
->offset
= grub_host_to_target32 (sizeof (struct grub_module_info
));
125 modinfo
->size
= grub_host_to_target32 (total_module_size
);
127 /* Load all the modules, with headers, into module_img. */
128 for (p
= path_list
; p
; p
= p
->next
)
130 struct grub_module_header
*header
;
133 grub_util_info ("adding module %s", p
->name
);
135 mod_size
= grub_util_get_image_size (p
->name
);
137 header
= (struct grub_module_header
*) (module_img
+ offset
);
138 header
->offset
= grub_host_to_target32 (sizeof (*header
));
139 header
->size
= grub_host_to_target32 (mod_size
+ sizeof (*header
));
141 grub_util_load_image (p
->name
, module_img
+ offset
+ sizeof (*header
));
143 offset
+= sizeof (*header
) + mod_size
;
146 /* Write the module data to the new segment. */
147 grub_util_write_image_at (module_img
, total_module_size
,
148 grub_host_to_target32 (phdr
->p_offset
), out
);
150 /* Fill in the rest of the segment header. */
151 phdr
->p_type
= grub_host_to_target32 (PT_LOAD
);
152 phdr
->p_flags
= grub_host_to_target32 (PF_R
| PF_W
| PF_X
);
153 phdr
->p_align
= grub_host_to_target32 (sizeof (long));
154 phdr
->p_vaddr
= grub_host_to_target32 (modbase
);
155 phdr
->p_paddr
= grub_host_to_target32 (modbase
);
156 phdr
->p_filesz
= grub_host_to_target32 (total_module_size
);
157 phdr
->p_memsz
= grub_host_to_target32 (total_module_size
);
161 add_segments (char *dir
, FILE *out
, int chrp
, char *mods
[])
164 Elf32_Phdr
*phdrs
= NULL
;
168 grub_addr_t grub_end
= 0;
172 /* Read ELF header. */
173 kernel_path
= grub_util_get_path (dir
, "kernel.elf");
174 in
= fopen (kernel_path
, "rb");
176 grub_util_error ("cannot open %s", kernel_path
);
178 grub_util_read_at (&ehdr
, sizeof (ehdr
), 0, in
);
180 phdrs
= xmalloc (grub_target_to_host16 (ehdr
.e_phentsize
)
181 * (grub_target_to_host16 (ehdr
.e_phnum
) + 2));
182 /* Copy all existing segments. */
183 for (i
= 0; i
< grub_target_to_host16 (ehdr
.e_phnum
); i
++)
186 grub_size_t segment_end
;
190 /* Read segment header. */
191 grub_util_read_at (phdr
, sizeof (Elf32_Phdr
),
192 (grub_target_to_host32 (ehdr
.e_phoff
)
193 + (i
* grub_target_to_host16 (ehdr
.e_phentsize
))),
195 grub_util_info ("copying segment %d, type %d", i
,
196 grub_target_to_host32 (phdr
->p_type
));
199 segment_end
= grub_target_to_host32 (phdr
->p_paddr
)
200 + grub_target_to_host32 (phdr
->p_memsz
);
201 grub_util_info ("segment %u end 0x%lx", i
, segment_end
);
202 if (segment_end
> grub_end
)
203 grub_end
= segment_end
;
205 /* Read segment data and write it to new file. */
206 segment_img
= xmalloc (grub_target_to_host32 (phdr
->p_filesz
));
208 grub_util_read_at (segment_img
, grub_target_to_host32 (phdr
->p_filesz
),
209 grub_target_to_host32 (phdr
->p_offset
), in
);
210 grub_util_write_image_at (segment_img
, grub_target_to_host32 (phdr
->p_filesz
),
211 grub_target_to_host32 (phdr
->p_offset
), out
);
220 /* Place modules just after grub segment. */
221 modbase
= ALIGN_UP(grub_end
+ GRUB_MOD_GAP
, GRUB_MOD_ALIGN
);
223 /* Construct new segment header for modules. */
224 phdr
= phdrs
+ grub_target_to_host16 (ehdr
.e_phnum
);
225 ehdr
.e_phnum
= grub_host_to_target16 (grub_target_to_host16 (ehdr
.e_phnum
) + 1);
227 /* Fill in p_offset so the callees know where to write. */
228 phdr
->p_offset
= grub_host_to_target32 (ALIGN_UP (grub_util_get_fp_size (out
),
231 load_modules (modbase
, phdr
, dir
, mods
, out
);
236 /* Construct new segment header for the CHRP note. */
237 phdr
= phdrs
+ grub_target_to_host16 (ehdr
.e_phnum
);
238 ehdr
.e_phnum
= grub_host_to_target16 (grub_target_to_host16 (ehdr
.e_phnum
) + 1);
240 /* Fill in p_offset so the callees know where to write. */
241 phdr
->p_offset
= grub_host_to_target32 (ALIGN_UP (grub_util_get_fp_size (out
),
244 load_note (phdr
, out
);
247 /* Don't bother preserving the section headers. */
252 /* Append entire segment table to the file. */
253 phdroff
= ALIGN_UP (grub_util_get_fp_size (out
), sizeof (long));
254 grub_util_write_image_at (phdrs
, grub_target_to_host16 (ehdr
.e_phentsize
)
255 * grub_target_to_host16 (ehdr
.e_phnum
), phdroff
,
258 /* Write ELF header. */
259 ehdr
.e_phoff
= grub_host_to_target32 (phdroff
);
260 grub_util_write_image_at (&ehdr
, sizeof (ehdr
), 0, out
);
266 static struct option options
[] =
268 {"directory", required_argument
, 0, 'd'},
269 {"output", required_argument
, 0, 'o'},
270 {"help", no_argument
, 0, 'h'},
271 {"note", no_argument
, 0, 'n'},
272 {"version", no_argument
, 0, 'V'},
273 {"verbose", no_argument
, 0, 'v'},
281 fprintf (stderr
, "Try ``grub-mkimage --help'' for more information.\n");
284 Usage: grub-mkimage -o FILE [OPTION]... [MODULES]\n\
286 Make a bootable image of GRUB.\n\
288 -d, --directory=DIR use images and modules under DIR [default=%s]\n\
289 -o, --output=FILE output a generated image to FILE\n\
290 -h, --help display this message and exit\n\
291 -n, --note add NOTE segment for CHRP Open Firmware\n\
292 -V, --version print version information and exit\n\
293 -v, --verbose print verbose messages\n\
295 Report bugs to <%s>.\n\
296 ", GRUB_LIBDIR
, PACKAGE_BUGREPORT
);
302 main (int argc
, char *argv
[])
309 progname
= "grub-mkimage";
313 int c
= getopt_long (argc
, argv
, "d:o:hVvn", options
, 0);
322 dir
= xstrdup (optarg
);
333 output
= xstrdup (optarg
);
336 printf ("grub-mkimage (%s) %s\n", PACKAGE_NAME
, PACKAGE_VERSION
);
350 fp
= fopen (output
, "wb");
352 grub_util_error ("cannot open %s", output
);
354 add_segments (dir
? : GRUB_LIBDIR
, fp
, chrp
, argv
+ optind
);