~hamo/ubuntu/precise/grub2/grub2.hi_res

« back to all changes in this revision

Viewing changes to grub-core/efiemu/loadcore.c

  • Committer: Bazaar Package Importer
  • Author(s): Colin Watson, Colin Watson, Evan Broder, Mario Limonciello
  • Date: 2010-11-24 13:59:55 UTC
  • mfrom: (1.17.6 upstream) (17.6.15 experimental)
  • Revision ID: james.westby@ubuntu.com-20101124135955-r6ii5sepayr7jt53
Tags: 1.99~20101124-1ubuntu1
[ Colin Watson ]
* Resynchronise with Debian experimental.  Remaining changes:
  - Adjust for default Ubuntu boot options ("quiet splash").
  - Default to hiding the menu; holding down Shift at boot will show it.
  - Set a monochromatic theme for Ubuntu.
  - Apply Ubuntu GRUB Legacy changes to legacy update-grub script: title,
    recovery mode, quiet option, tweak how memtest86+ is displayed, and
    use UUIDs where appropriate.
  - Fix backslash-escaping in merge_debconf_into_conf.
  - Remove "GNU/Linux" from default distributor string.
  - Add crashkernel= options if kdump and makedumpfile are available.
  - If other operating systems are installed, then automatically unhide
    the menu.  Otherwise, if GRUB_HIDDEN_TIMEOUT is 0, then use keystatus
    if available to check whether Shift is pressed.  If it is, show the
    menu, otherwise boot immediately.  If keystatus is not available, then
    fall back to a short delay interruptible with Escape.
  - Allow Shift to interrupt 'sleep --interruptible'.
  - Don't display introductory message about line editing unless we're
    actually offering a shell prompt.  Don't clear the screen just before
    booting if we never drew the menu in the first place.
  - Remove some verbose messages printed before reading the configuration
    file.
  - Suppress progress messages as the kernel and initrd load for
    non-recovery kernel menu entries.
  - Change prepare_grub_to_access_device to handle filesystems
    loop-mounted on file images.
  - Ignore devices loop-mounted from files in 10_linux.
  - Show the boot menu if the previous boot failed, that is if it failed
    to get to the end of one of the normal runlevels.
  - Don't generate /boot/grub/device.map during grub-install or
    grub-mkconfig by default.
  - Adjust upgrade version checks for Ubuntu.
  - Don't display "GRUB loading" unless Shift is held down.
  - Adjust versions of grub-doc and grub-legacy-doc conflicts to tolerate
    our backport of the grub-doc split.
  - Fix LVM/RAID probing in the absence of /boot/grub/device.map.
  - Look for .mo files in /usr/share/locale-langpack as well, in
    preference.
  - Make sure GRUB_TIMEOUT isn't quoted unnecessarily.
  - Probe all devices in 'grub-probe --target=drive' if
    /boot/grub/device.map is missing.
  - Build-depend on qemu-kvm rather than qemu-system for grub-pc tests.
  - Use qemu rather than qemu-system-i386.
  - Program vesafb on BIOS systems rather than efifb.
  - Add a grub-rescue-efi-amd64 package containing a rescue CD-ROM image
    for EFI-AMD64.
  - On Wubi, don't ask for an install device, but just update wubildr
    using the diverted grub-install.
  - When embedding the core image in a post-MBR gap, check for and avoid
    sectors matching any of a list of known signatures.
  - Disable video_bochs and video_cirrus on PC BIOS systems, as probing
    PCI space seems to break on some systems.
* Downgrade "ACPI shutdown failed" error to a debug message, since it can
  cause spurious test failures.

[ Evan Broder ]
* Enable lua from grub-extras.
* Incorporate the bitop library into lua.
* Add enum_pci function to grub module in lua.
* Switch back to gfxpayload=keep by default, unless the video hardware
  is known to not support it.

[ Mario Limonciello ]
* Built part_msdos and vfat into bootx64.efi (LP: #677758)

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