~ubuntu-branches/debian/sid/grub2/sid-200907171846

« back to all changes in this revision

Viewing changes to efiemu/loadcore.c

  • Committer: Bazaar Package Importer
  • Author(s): Felix Zielcke, Updated translations
  • Date: 2009-03-17 14:42:10 UTC
  • mfrom: (1.1.11 upstream)
  • Revision ID: james.westby@ubuntu.com-20090317144210-nbg2w4aitrb24v99
Tags: 1.96+20090317-1
* New SVN snapshot.
  - Fix loading of files with underscore in HFS. (Closes: #516458)

* Update Standards version to 3.8.1. No changes need.

[ Updated translations ]
* Brazilian Portuguese (pt_BR.po) by Flamarion Jorge. (Closes: #519417)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* Load runtime image of EFIemu. Functions specific to 32/64-bit mode */
2
 
/*
3
 
 *  GRUB  --  GRand Unified Bootloader
4
 
 *  Copyright (C) 2009  Free Software Foundation, Inc.
5
 
 *
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.
10
 
 *
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.
15
 
 *
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/>.
18
 
 */
19
 
 
20
 
#include <grub/err.h>
21
 
#include <grub/mm.h>
22
 
#include <grub/misc.h>
23
 
#include <grub/efiemu/efiemu.h>
24
 
#include <grub/cpu/efiemu.h>
25
 
#include <grub/machine/efiemu.h>
26
 
#include <grub/elf.h>
27
 
 
28
 
/* ELF symbols and their values */
29
 
static struct grub_efiemu_elf_sym *grub_efiemu_elfsyms = 0;
30
 
static int grub_efiemu_nelfsyms = 0;
31
 
 
32
 
/* Return the address of a section whose index is N.  */
33
 
static grub_err_t
34
 
grub_efiemu_get_section_addr (grub_efiemu_segment_t segs, unsigned n,
35
 
                              int *handle, grub_off_t *off)
36
 
{
37
 
  grub_efiemu_segment_t seg;
38
 
 
39
 
  for (seg = segs; seg; seg = seg->next)
40
 
    if (seg->section == n)
41
 
      {
42
 
        *handle = seg->handle;
43
 
        *off = seg->off;
44
 
        return GRUB_ERR_NONE;
45
 
      }
46
 
 
47
 
  return grub_error (GRUB_ERR_BAD_OS, "section %d not found", n);
48
 
}
49
 
 
50
 
grub_err_t
51
 
SUFFIX (grub_efiemu_loadcore_unload) (void)
52
 
{
53
 
  grub_free (grub_efiemu_elfsyms);
54
 
  grub_efiemu_elfsyms = 0;
55
 
  return GRUB_ERR_NONE;
56
 
}
57
 
 
58
 
/* Check if EHDR is a valid ELF header.  */
59
 
int
60
 
SUFFIX (grub_efiemu_check_header) (void *ehdr, grub_size_t size)
61
 
{
62
 
  Elf_Ehdr *e = ehdr;
63
 
 
64
 
  /* Check the header size.  */
65
 
  if (size < sizeof (Elf_Ehdr))
66
 
    return 0;
67
 
 
68
 
  /* Check the magic numbers.  */
69
 
  if (!SUFFIX (grub_arch_efiemu_check_header) (ehdr)
70
 
      || e->e_ident[EI_MAG0] != ELFMAG0
71
 
      || e->e_ident[EI_MAG1] != ELFMAG1
72
 
      || e->e_ident[EI_MAG2] != ELFMAG2
73
 
      || e->e_ident[EI_MAG3] != ELFMAG3
74
 
      || e->e_ident[EI_VERSION] != EV_CURRENT
75
 
      || e->e_version != EV_CURRENT)
76
 
    return 0;
77
 
 
78
 
  return 1;
79
 
}
80
 
 
81
 
/* Load all segments from memory specified by E.  */
82
 
static grub_err_t
83
 
grub_efiemu_load_segments (grub_efiemu_segment_t segs, const Elf_Ehdr *e)
84
 
{
85
 
  Elf_Shdr *s;
86
 
  grub_efiemu_segment_t cur;
87
 
 
88
 
  grub_dprintf ("efiemu", "loading segments\n");
89
 
 
90
 
  for (cur=segs; cur; cur = cur->next)
91
 
    {
92
 
      s = (Elf_Shdr *)cur->srcptr;
93
 
 
94
 
      if ((s->sh_flags & SHF_ALLOC) && s->sh_size)
95
 
        {
96
 
          void *addr;
97
 
 
98
 
          addr = (grub_uint8_t *) grub_efiemu_mm_obtain_request (cur->handle)
99
 
            + cur->off;
100
 
 
101
 
          switch (s->sh_type)
102
 
            {
103
 
            case SHT_PROGBITS:
104
 
              grub_memcpy (addr, (char *) e + s->sh_offset, s->sh_size);
105
 
              break;
106
 
            case SHT_NOBITS:
107
 
              grub_memset (addr, 0, s->sh_size);
108
 
              break;
109
 
            }
110
 
        }
111
 
    }
112
 
 
113
 
  return GRUB_ERR_NONE;
114
 
}
115
 
 
116
 
/* Get a string at offset OFFSET from strtab */
117
 
static char *
118
 
grub_efiemu_get_string (unsigned offset, const Elf_Ehdr *e)
119
 
{
120
 
  unsigned i;
121
 
  Elf_Shdr *s;
122
 
 
123
 
  for (i = 0, s = (Elf_Shdr *)((char *) e + e->e_shoff);
124
 
       i < e->e_shnum;
125
 
       i++, s = (Elf_Shdr *)((char *) s + e->e_shentsize))
126
 
    if (s->sh_type == SHT_STRTAB && offset < s->sh_size)
127
 
      return (char *) e + s->sh_offset + offset;
128
 
  return 0;
129
 
}
130
 
 
131
 
/* Request memory for segments and fill segments info */
132
 
static grub_err_t
133
 
grub_efiemu_init_segments (grub_efiemu_segment_t *segs, const Elf_Ehdr *e)
134
 
{
135
 
  unsigned i;
136
 
  Elf_Shdr *s;
137
 
 
138
 
  for (i = 0, s = (Elf_Shdr *)((char *) e + e->e_shoff);
139
 
       i < e->e_shnum;
140
 
       i++, s = (Elf_Shdr *)((char *) s + e->e_shentsize))
141
 
    {
142
 
      if (s->sh_flags & SHF_ALLOC)
143
 
        {
144
 
          grub_efiemu_segment_t seg;
145
 
          seg = (grub_efiemu_segment_t) grub_malloc (sizeof (*seg));
146
 
          if (! seg)
147
 
            return grub_errno;
148
 
 
149
 
          if (s->sh_size)
150
 
            {
151
 
              seg->handle
152
 
                = grub_efiemu_request_memalign
153
 
                (s->sh_addralign, s->sh_size,
154
 
                 s->sh_flags & SHF_EXECINSTR ? GRUB_EFI_RUNTIME_SERVICES_CODE
155
 
                 : GRUB_EFI_RUNTIME_SERVICES_DATA);
156
 
              if (seg->handle < 0)
157
 
                return grub_errno;
158
 
              seg->off = 0;
159
 
            }
160
 
 
161
 
          /*
162
 
             .text-physical doesn't need to be relocated when switching to
163
 
             virtual mode
164
 
           */
165
 
          if (!grub_strcmp (grub_efiemu_get_string (s->sh_name, e),
166
 
                            ".text-physical"))
167
 
            seg->ptv_rel_needed = 0;
168
 
          else
169
 
            seg->ptv_rel_needed = 1;
170
 
          seg->size = s->sh_size;
171
 
          seg->section = i;
172
 
          seg->next = *segs;
173
 
          seg->srcptr = s;
174
 
          *segs = seg;
175
 
        }
176
 
    }
177
 
 
178
 
  return GRUB_ERR_NONE;
179
 
}
180
 
 
181
 
/* Count symbols and relocators and allocate/request memory for them */
182
 
static grub_err_t
183
 
grub_efiemu_count_symbols (const Elf_Ehdr *e)
184
 
{
185
 
  unsigned i;
186
 
  Elf_Shdr *s;
187
 
  int num = 0;
188
 
 
189
 
  /* Symbols */
190
 
  for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff);
191
 
       i < e->e_shnum;
192
 
       i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize))
193
 
    if (s->sh_type == SHT_SYMTAB)
194
 
      break;
195
 
 
196
 
  if (i == e->e_shnum)
197
 
    return grub_error (GRUB_ERR_BAD_OS, "no symbol table");
198
 
 
199
 
  grub_efiemu_nelfsyms = (unsigned) s->sh_size / (unsigned) s->sh_entsize;
200
 
  grub_efiemu_elfsyms = (struct grub_efiemu_elf_sym *)
201
 
    grub_malloc (sizeof (struct grub_efiemu_elf_sym) * grub_efiemu_nelfsyms);
202
 
 
203
 
  /* Relocators */
204
 
  for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff);
205
 
       i < e->e_shnum;
206
 
       i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize))
207
 
    if (s->sh_type == SHT_REL || s->sh_type == SHT_RELA)
208
 
      num += ((unsigned) s->sh_size) / ((unsigned) s->sh_entsize);
209
 
 
210
 
  grub_efiemu_request_symbols (num);
211
 
 
212
 
  return GRUB_ERR_NONE;
213
 
}
214
 
 
215
 
/* Fill grub_efiemu_elfsyms with symbol values */
216
 
static grub_err_t
217
 
grub_efiemu_resolve_symbols (grub_efiemu_segment_t segs, Elf_Ehdr *e)
218
 
{
219
 
  unsigned i;
220
 
  Elf_Shdr *s;
221
 
  Elf_Sym *sym;
222
 
  const char *str;
223
 
  Elf_Word size, entsize;
224
 
 
225
 
  grub_dprintf ("efiemu", "resolving symbols\n");
226
 
 
227
 
  for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff);
228
 
       i < e->e_shnum;
229
 
       i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize))
230
 
    if (s->sh_type == SHT_SYMTAB)
231
 
      break;
232
 
 
233
 
  if (i == e->e_shnum)
234
 
    return grub_error (GRUB_ERR_BAD_OS, "no symbol table");
235
 
 
236
 
  sym = (Elf_Sym *) ((char *) e + s->sh_offset);
237
 
  size = s->sh_size;
238
 
  entsize = s->sh_entsize;
239
 
 
240
 
  s = (Elf_Shdr *) ((char *) e + e->e_shoff + e->e_shentsize * s->sh_link);
241
 
  str = (char *) e + s->sh_offset;
242
 
 
243
 
  for (i = 0;
244
 
       i < size / entsize;
245
 
       i++, sym = (Elf_Sym *) ((char *) sym + entsize))
246
 
    {
247
 
      unsigned char type = ELF_ST_TYPE (sym->st_info);
248
 
      unsigned char bind = ELF_ST_BIND (sym->st_info);
249
 
      int handle;
250
 
      grub_off_t off;
251
 
      grub_err_t err;
252
 
      const char *name = str + sym->st_name;
253
 
      grub_efiemu_elfsyms[i].section = sym->st_shndx;
254
 
      switch (type)
255
 
        {
256
 
        case STT_NOTYPE:
257
 
          /* Resolve a global symbol.  */
258
 
          if (sym->st_name != 0 && sym->st_shndx == 0)
259
 
            {
260
 
              if ((err = grub_efiemu_resolve_symbol (name, &handle, &off)))
261
 
                return err;
262
 
              grub_efiemu_elfsyms[i].handle = handle;
263
 
              grub_efiemu_elfsyms[i].off = off;
264
 
            }
265
 
          else
266
 
            sym->st_value = 0;
267
 
          break;
268
 
 
269
 
        case STT_OBJECT:
270
 
          if ((err = grub_efiemu_get_section_addr
271
 
               (segs, sym->st_shndx, &handle, &off)))
272
 
            return err;
273
 
 
274
 
          off += sym->st_value;
275
 
          if (bind != STB_LOCAL)
276
 
            if ((err = grub_efiemu_register_symbol (name, handle, off)))
277
 
              return err;
278
 
          grub_efiemu_elfsyms[i].handle = handle;
279
 
          grub_efiemu_elfsyms[i].off = off;
280
 
          break;
281
 
 
282
 
        case STT_FUNC:
283
 
          if ((err = grub_efiemu_get_section_addr
284
 
               (segs, sym->st_shndx, &handle, &off)))
285
 
            return err;
286
 
 
287
 
          off += sym->st_value;
288
 
          if (bind != STB_LOCAL)
289
 
            if ((err = grub_efiemu_register_symbol (name, handle, off)))
290
 
              return err;
291
 
          grub_efiemu_elfsyms[i].handle = handle;
292
 
          grub_efiemu_elfsyms[i].off = off;
293
 
          break;
294
 
 
295
 
        case STT_SECTION:
296
 
          if ((err = grub_efiemu_get_section_addr
297
 
               (segs, sym->st_shndx, &handle, &off)))
298
 
            {
299
 
              grub_efiemu_elfsyms[i].handle = 0;
300
 
              grub_efiemu_elfsyms[i].off = 0;
301
 
              grub_errno = GRUB_ERR_NONE;
302
 
              break;
303
 
            }
304
 
 
305
 
          grub_efiemu_elfsyms[i].handle = handle;
306
 
          grub_efiemu_elfsyms[i].off = off;
307
 
          break;
308
 
 
309
 
        case STT_FILE:
310
 
          grub_efiemu_elfsyms[i].handle = 0;
311
 
          grub_efiemu_elfsyms[i].off = 0;
312
 
          break;
313
 
 
314
 
        default:
315
 
          return grub_error (GRUB_ERR_BAD_MODULE,
316
 
                             "unknown symbol type `%d'", (int) type);
317
 
        }
318
 
    }
319
 
 
320
 
  return GRUB_ERR_NONE;
321
 
}
322
 
 
323
 
/* Load runtime to the memory and request memory for definitive location*/
324
 
grub_err_t
325
 
SUFFIX (grub_efiemu_loadcore_init) (void *core, grub_size_t core_size,
326
 
                                    grub_efiemu_segment_t *segments)
327
 
{
328
 
  Elf_Ehdr *e = (Elf_Ehdr *) core;
329
 
  grub_err_t err;
330
 
 
331
 
  if (e->e_type != ET_REL)
332
 
    return grub_error (GRUB_ERR_BAD_MODULE, "invalid ELF file type");
333
 
 
334
 
  /* Make sure that every section is within the core.  */
335
 
  if ((grub_size_t) core_size < e->e_shoff + e->e_shentsize * e->e_shnum)
336
 
    return grub_error (GRUB_ERR_BAD_OS, "ELF sections outside core");
337
 
 
338
 
  if ((err = grub_efiemu_init_segments (segments, core)))
339
 
    return err;
340
 
  if ((err = grub_efiemu_count_symbols (core)))
341
 
    return err;
342
 
 
343
 
  grub_efiemu_request_symbols (1);
344
 
  return GRUB_ERR_NONE;
345
 
}
346
 
 
347
 
/* Load runtime definitively */
348
 
grub_err_t
349
 
SUFFIX (grub_efiemu_loadcore_load) (void *core,
350
 
                                    grub_size_t core_size
351
 
                                    __attribute__ ((unused)),
352
 
                                    grub_efiemu_segment_t segments)
353
 
{
354
 
  grub_err_t err;
355
 
  if ((err = grub_efiemu_load_segments (segments, core)))
356
 
    return err;
357
 
  if ((err = grub_efiemu_resolve_symbols (segments, core)))
358
 
    return err;
359
 
  if ((err = SUFFIX (grub_arch_efiemu_relocate_symbols) (segments,
360
 
                                                         grub_efiemu_elfsyms,
361
 
                                                         core)))
362
 
    return err;
363
 
 
364
 
  return GRUB_ERR_NONE;
365
 
}