~ubuntu-branches/ubuntu/trusty/grub2/trusty-updates

« back to all changes in this revision

Viewing changes to util/elf/grub-mkimage.c

  • Committer: Bazaar Package Importer
  • Author(s): Robert Millan
  • Date: 2007-11-01 13:18:51 UTC
  • mto: (17.3.1 squeeze) (1.9.1 upstream)
  • mto: This revision was merged to the branch mainline in revision 15.
  • Revision ID: james.westby@ubuntu.com-20071101131851-63uqsb4dax2h1cbm
Tags: upstream-1.95+20071101
ImportĀ upstreamĀ versionĀ 1.95+20071101

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *  GRUB  --  GRand Unified Bootloader
 
3
 *  Copyright (C) 2004,2005,2006,2007  Free Software Foundation, Inc.
 
4
 *
 
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.
 
9
 *
 
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.
 
14
 *
 
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/>.
 
17
 */
 
18
 
 
19
#include <config.h>
 
20
 
 
21
#include <stdio.h>
 
22
#include <stdint.h>
 
23
#include <unistd.h>
 
24
#include <fcntl.h>
 
25
#include <getopt.h>
 
26
#include <stdlib.h>
 
27
#include <string.h>
 
28
#include <grub/elf.h>
 
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>
 
34
 
 
35
#define GRUB_IEEE1275_NOTE_NAME "PowerPC"
 
36
#define GRUB_IEEE1275_NOTE_TYPE 0x1275
 
37
 
 
38
/* These structures are defined according to the CHRP binding to IEEE1275,
 
39
   "Client Program Format" section.  */
 
40
 
 
41
struct grub_ieee1275_note_hdr
 
42
{
 
43
  grub_uint32_t namesz;
 
44
  grub_uint32_t descsz;
 
45
  grub_uint32_t type;
 
46
  char name[sizeof (GRUB_IEEE1275_NOTE_NAME)];
 
47
};
 
48
 
 
49
struct grub_ieee1275_note_desc
 
50
{
 
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;
 
57
};
 
58
 
 
59
struct grub_ieee1275_note
 
60
{
 
61
  struct grub_ieee1275_note_hdr header;
 
62
  struct grub_ieee1275_note_desc descriptor;
 
63
};
 
64
 
 
65
void
 
66
load_note (Elf32_Phdr *phdr, FILE *out)
 
67
{
 
68
  struct grub_ieee1275_note note;
 
69
  int note_size = sizeof (struct grub_ieee1275_note);
 
70
 
 
71
  grub_util_info ("adding CHRP NOTE segment");
 
72
 
 
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);
 
83
 
 
84
  /* Write the note data to the new segment.  */
 
85
  grub_util_write_image_at (&note, note_size,
 
86
                            grub_target_to_host32 (phdr->p_offset), out);
 
87
 
 
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));
 
92
  phdr->p_vaddr = 0;
 
93
  phdr->p_paddr = 0;
 
94
  phdr->p_filesz = grub_host_to_target32 (note_size);
 
95
  phdr->p_memsz = 0;
 
96
}
 
97
 
 
98
void
 
99
load_modules (grub_addr_t modbase, Elf32_Phdr *phdr, const char *dir,
 
100
              char *mods[], FILE *out)
 
101
{
 
102
  char *module_img;
 
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;
 
107
  size_t total_module_size;
 
108
 
 
109
  path_list = grub_util_resolve_dependencies (dir, "moddep.lst", mods);
 
110
 
 
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)
 
114
    {
 
115
      total_module_size += (grub_util_get_image_size (p->name)
 
116
          + sizeof (struct grub_module_header));
 
117
    }
 
118
 
 
119
  grub_util_info ("the total module size is 0x%x", total_module_size);
 
120
 
 
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);
 
126
 
 
127
  /* Load all the modules, with headers, into module_img.  */
 
128
  for (p = path_list; p; p = p->next)
 
129
    {
 
130
      struct grub_module_header *header;
 
131
      size_t mod_size;
 
132
 
 
133
      grub_util_info ("adding module %s", p->name);
 
134
 
 
135
      mod_size = grub_util_get_image_size (p->name);
 
136
 
 
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));
 
140
 
 
141
      grub_util_load_image (p->name, module_img + offset + sizeof (*header));
 
142
 
 
143
      offset += sizeof (*header) + mod_size;
 
144
    }
 
145
 
 
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);
 
149
 
 
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);
 
158
}
 
159
 
 
160
void
 
161
add_segments (char *dir, FILE *out, int chrp, char *mods[])
 
162
{
 
163
  Elf32_Ehdr ehdr;
 
164
  Elf32_Phdr *phdrs = NULL;
 
165
  Elf32_Phdr *phdr;
 
166
  FILE *in;
 
167
  char *kernel_path;
 
168
  grub_addr_t grub_end = 0;
 
169
  off_t phdroff;
 
170
  int i;
 
171
 
 
172
  /* Read ELF header.  */
 
173
  kernel_path = grub_util_get_path (dir, "kernel.elf");
 
174
  in = fopen (kernel_path, "rb");
 
175
  if (! in)
 
176
    grub_util_error ("cannot open %s", kernel_path);
 
177
 
 
178
  grub_util_read_at (&ehdr, sizeof (ehdr), 0, in);
 
179
  
 
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++)
 
184
    {
 
185
      char *segment_img;
 
186
      grub_size_t segment_end;
 
187
 
 
188
      phdr = phdrs + i;
 
189
 
 
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))),
 
194
                         in);
 
195
      grub_util_info ("copying segment %d, type %d", i,
 
196
                      grub_target_to_host32 (phdr->p_type));
 
197
 
 
198
      /* Locate _end.  */
 
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;
 
204
 
 
205
      /* Read segment data and write it to new file.  */
 
206
      segment_img = xmalloc (grub_target_to_host32 (phdr->p_filesz));
 
207
  
 
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);
 
212
 
 
213
      free (segment_img);
 
214
    }
 
215
 
 
216
  if (mods[0] != NULL)
 
217
    {
 
218
      grub_addr_t modbase;
 
219
 
 
220
      /* Place modules just after grub segment.  */
 
221
      modbase = ALIGN_UP(grub_end, GRUB_MOD_ALIGN);
 
222
 
 
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);
 
226
 
 
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),
 
229
                                                   sizeof (long)));
 
230
 
 
231
      load_modules (modbase, phdr, dir, mods, out);
 
232
    }
 
233
 
 
234
  if (chrp)
 
235
    {
 
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);
 
239
 
 
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),
 
242
                                                   sizeof (long)));
 
243
 
 
244
      load_note (phdr, out);
 
245
    }
 
246
 
 
247
  /* Don't bother preserving the section headers.  */
 
248
  ehdr.e_shoff = 0;
 
249
  ehdr.e_shnum = 0;
 
250
  ehdr.e_shstrndx = 0;
 
251
 
 
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,
 
256
                            out);
 
257
 
 
258
  /* Write ELF header.  */
 
259
  ehdr.e_phoff = grub_host_to_target32 (phdroff);
 
260
  grub_util_write_image_at (&ehdr, sizeof (ehdr), 0, out);
 
261
 
 
262
  free (phdrs);
 
263
  free (kernel_path);
 
264
}
 
265
 
 
266
static struct option options[] =
 
267
  {
 
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'},
 
274
    { 0, 0, 0, 0 },
 
275
  };
 
276
 
 
277
static void
 
278
usage (int status)
 
279
{
 
280
  if (status)
 
281
    fprintf (stderr, "Try ``grub-mkimage --help'' for more information.\n");
 
282
  else
 
283
    printf ("\
 
284
Usage: grub-mkimage -o FILE [OPTION]... [MODULES]\n\
 
285
\n\
 
286
Make a bootable image of GRUB.\n\
 
287
\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\
 
294
\n\
 
295
Report bugs to <%s>.\n\
 
296
", GRUB_LIBDIR, PACKAGE_BUGREPORT);
 
297
 
 
298
  exit (status);
 
299
}
 
300
 
 
301
int
 
302
main (int argc, char *argv[])
 
303
{
 
304
  FILE *fp;
 
305
  char *output = NULL;
 
306
  char *dir = NULL;
 
307
  int chrp = 0;
 
308
 
 
309
  progname = "grub-mkimage";
 
310
 
 
311
  while (1)
 
312
    {
 
313
      int c = getopt_long (argc, argv, "d:o:hVvn", options, 0);
 
314
      if (c == -1)
 
315
        break;
 
316
 
 
317
      switch (c)
 
318
        {
 
319
          case 'd':
 
320
            if (dir)
 
321
              free (dir);
 
322
            dir = xstrdup (optarg);
 
323
            break;
 
324
          case 'h':
 
325
            usage (0);
 
326
            break;
 
327
          case 'n':
 
328
            chrp = 1;
 
329
            break;
 
330
          case 'o':
 
331
            if (output)
 
332
              free (output);
 
333
            output = xstrdup (optarg);
 
334
            break;
 
335
          case 'V':
 
336
            printf ("grub-mkimage (%s) %s\n", PACKAGE_NAME, PACKAGE_VERSION);
 
337
            return 0;
 
338
          case 'v':
 
339
            verbosity++;
 
340
            break;
 
341
          default:
 
342
            usage (1);
 
343
            break;
 
344
        }
 
345
  }
 
346
 
 
347
  if (!output)
 
348
    usage (1);
 
349
 
 
350
  fp = fopen (output, "wb");
 
351
  if (! fp)
 
352
    grub_util_error ("cannot open %s", output);
 
353
 
 
354
  add_segments (dir ? : GRUB_LIBDIR, fp, chrp, argv + optind);
 
355
 
 
356
  fclose (fp);
 
357
 
 
358
  return 0;
 
359
}