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

« back to all changes in this revision

Viewing changes to grub-core/loader/powerpc/ieee1275/linux.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
/* linux.c - boot Linux */
 
2
/*
 
3
 *  GRUB  --  GRand Unified Bootloader
 
4
 *  Copyright (C) 2003,2004,2005,2007,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/elf.h>
 
21
#include <grub/elfload.h>
 
22
#include <grub/loader.h>
 
23
#include <grub/dl.h>
 
24
#include <grub/mm.h>
 
25
#include <grub/misc.h>
 
26
#include <grub/ieee1275/ieee1275.h>
 
27
#include <grub/command.h>
 
28
#include <grub/i18n.h>
 
29
#include <grub/memory.h>
 
30
 
 
31
#define ELF32_LOADMASK (0xc0000000UL)
 
32
#define ELF64_LOADMASK (0xc000000000000000ULL)
 
33
 
 
34
static grub_dl_t my_mod;
 
35
 
 
36
static int loaded;
 
37
 
 
38
static grub_addr_t initrd_addr;
 
39
static grub_size_t initrd_size;
 
40
 
 
41
static grub_addr_t linux_addr;
 
42
static grub_size_t linux_size;
 
43
 
 
44
static char *linux_args;
 
45
 
 
46
typedef void (*kernel_entry_t) (void *, unsigned long, int (void *),
 
47
                                unsigned long, unsigned long);
 
48
 
 
49
static grub_addr_t
 
50
grub_linux_claimmap_iterate (grub_addr_t target, grub_size_t size,
 
51
                             grub_size_t align)
 
52
{
 
53
  grub_addr_t found_addr = (grub_addr_t) -1;
 
54
 
 
55
  auto int NESTED_FUNC_ATTR alloc_mem (grub_uint64_t addr, grub_uint64_t len,
 
56
                                       grub_memory_type_t type);
 
57
  int NESTED_FUNC_ATTR alloc_mem (grub_uint64_t addr, grub_uint64_t len,
 
58
                                  grub_memory_type_t type)
 
59
  {
 
60
    grub_uint64_t end = addr + len;
 
61
    addr = ALIGN_UP (addr, align);
 
62
    target = ALIGN_UP (target, align);
 
63
 
 
64
    /* Target above the memory chunk.  */
 
65
    if (type != GRUB_MEMORY_AVAILABLE || target > end)
 
66
      return 0;
 
67
 
 
68
    /* Target inside the memory chunk.  */
 
69
    if (target >= addr && target < end && size <= end - target)
 
70
      {
 
71
        if (grub_claimmap (target, size) == GRUB_ERR_NONE)
 
72
          {
 
73
            found_addr = target;
 
74
            return 1;
 
75
          }
 
76
      }
 
77
    /* Target below the memory chunk.  */
 
78
    if (target < addr && addr + size <= end)
 
79
      {
 
80
        if (grub_claimmap (addr, size) == GRUB_ERR_NONE)
 
81
          {
 
82
            found_addr = addr;
 
83
            return 1;
 
84
          }
 
85
      }
 
86
    return 0;
 
87
  }
 
88
 
 
89
  grub_machine_mmap_iterate (alloc_mem);
 
90
 
 
91
  return found_addr;
 
92
}
 
93
 
 
94
static grub_err_t
 
95
grub_linux_boot (void)
 
96
{
 
97
  kernel_entry_t linuxmain;
 
98
  grub_ssize_t actual;
 
99
 
 
100
  /* Set the command line arguments.  */
 
101
  grub_ieee1275_set_property (grub_ieee1275_chosen, "bootargs", linux_args,
 
102
                              grub_strlen (linux_args) + 1, &actual);
 
103
 
 
104
  grub_dprintf ("loader", "Entry point: 0x%x\n", linux_addr);
 
105
  grub_dprintf ("loader", "Initrd at: 0x%x, size 0x%x\n", initrd_addr,
 
106
                initrd_size);
 
107
  grub_dprintf ("loader", "Boot arguments: %s\n", linux_args);
 
108
  grub_dprintf ("loader", "Jumping to Linux...\n");
 
109
 
 
110
  /* Boot the kernel.  */
 
111
  linuxmain = (kernel_entry_t) linux_addr;
 
112
  linuxmain ((void *) initrd_addr, initrd_size, grub_ieee1275_entry_fn, 0, 0);
 
113
 
 
114
  return GRUB_ERR_NONE;
 
115
}
 
116
 
 
117
static grub_err_t
 
118
grub_linux_release_mem (void)
 
119
{
 
120
  grub_free (linux_args);
 
121
  linux_args = 0;
 
122
 
 
123
  if (linux_addr && grub_ieee1275_release (linux_addr, linux_size))
 
124
    return grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot release memory");
 
125
 
 
126
  if (initrd_addr && grub_ieee1275_release (initrd_addr, initrd_size))
 
127
    return grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot release memory");
 
128
 
 
129
  linux_addr = 0;
 
130
  initrd_addr = 0;
 
131
 
 
132
  return GRUB_ERR_NONE;
 
133
}
 
134
 
 
135
static grub_err_t
 
136
grub_linux_unload (void)
 
137
{
 
138
  grub_err_t err;
 
139
 
 
140
  err = grub_linux_release_mem ();
 
141
  grub_dl_unref (my_mod);
 
142
 
 
143
  loaded = 0;
 
144
 
 
145
  return err;
 
146
}
 
147
 
 
148
static grub_err_t
 
149
grub_linux_load32 (grub_elf_t elf)
 
150
{
 
151
  Elf32_Addr base_addr;
 
152
  grub_addr_t seg_addr;
 
153
  grub_uint32_t align;
 
154
  int offset;
 
155
 
 
156
  linux_size = grub_elf32_size (elf, &base_addr, &align);
 
157
  if (linux_size == 0)
 
158
    return grub_errno;
 
159
  /* Pad it; the kernel scribbles over memory beyond its load address.  */
 
160
  linux_size += 0x100000;
 
161
 
 
162
  offset = elf->ehdr.ehdr32.e_entry - base_addr;
 
163
  /* Linux's incorrectly contains a virtual address.  */
 
164
  base_addr &= ~ELF32_LOADMASK;
 
165
 
 
166
  /* On some systems, firmware occupies the memory we're trying to use.
 
167
   * Happily, Linux can be loaded anywhere (it relocates itself).  Iterate
 
168
   * until we find an open area.  */
 
169
  seg_addr = grub_linux_claimmap_iterate (base_addr & ~ELF32_LOADMASK, linux_size, align);
 
170
  if (seg_addr == (grub_addr_t) -1)
 
171
    return grub_error (GRUB_ERR_OUT_OF_MEMORY, "couldn't claim memory");
 
172
 
 
173
  linux_addr = seg_addr + offset;
 
174
 
 
175
  /* Now load the segments into the area we claimed.  */
 
176
  auto grub_err_t offset_phdr (Elf32_Phdr *phdr, grub_addr_t *addr, int *do_load);
 
177
  grub_err_t offset_phdr (Elf32_Phdr *phdr, grub_addr_t *addr, int *do_load)
 
178
    {
 
179
      if (phdr->p_type != PT_LOAD)
 
180
        {
 
181
          *do_load = 0;
 
182
          return 0;
 
183
        }
 
184
      *do_load = 1;
 
185
 
 
186
      *addr = (phdr->p_paddr - base_addr) + seg_addr;
 
187
      return 0;
 
188
    }
 
189
  return grub_elf32_load (elf, offset_phdr, 0, 0);
 
190
}
 
191
 
 
192
static grub_err_t
 
193
grub_linux_load64 (grub_elf_t elf)
 
194
{
 
195
  Elf64_Addr base_addr;
 
196
  grub_addr_t seg_addr;
 
197
  grub_uint64_t align;
 
198
  int offset;
 
199
 
 
200
  linux_size = grub_elf64_size (elf, &base_addr, &align);
 
201
  if (linux_size == 0)
 
202
    return grub_errno;
 
203
  /* Pad it; the kernel scribbles over memory beyond its load address.  */
 
204
  linux_size += 0x100000;
 
205
 
 
206
  offset = elf->ehdr.ehdr64.e_entry - base_addr;
 
207
  /* Linux's incorrectly contains a virtual address.  */
 
208
  base_addr &= ~ELF64_LOADMASK;
 
209
 
 
210
  /* On some systems, firmware occupies the memory we're trying to use.
 
211
   * Happily, Linux can be loaded anywhere (it relocates itself).  Iterate
 
212
   * until we find an open area.  */
 
213
  seg_addr = grub_linux_claimmap_iterate (base_addr & ~ELF64_LOADMASK, linux_size, align);
 
214
  if (seg_addr == (grub_addr_t) -1)
 
215
    return grub_error (GRUB_ERR_OUT_OF_MEMORY, "couldn't claim memory");
 
216
 
 
217
  linux_addr = seg_addr + offset;
 
218
 
 
219
  /* Now load the segments into the area we claimed.  */
 
220
  auto grub_err_t offset_phdr (Elf64_Phdr *phdr, grub_addr_t *addr, int *do_load);
 
221
  grub_err_t offset_phdr (Elf64_Phdr *phdr, grub_addr_t *addr, int *do_load)
 
222
    {
 
223
      if (phdr->p_type != PT_LOAD)
 
224
        {
 
225
          *do_load = 0;
 
226
          return 0;
 
227
        }
 
228
      *do_load = 1;
 
229
 
 
230
      *addr = (phdr->p_paddr - base_addr) + seg_addr;
 
231
      return 0;
 
232
    }
 
233
  return grub_elf64_load (elf, offset_phdr, 0, 0);
 
234
}
 
235
 
 
236
static grub_err_t
 
237
grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
 
238
                int argc, char *argv[])
 
239
{
 
240
  grub_elf_t elf = 0;
 
241
  int i;
 
242
  int size;
 
243
  char *dest;
 
244
 
 
245
  grub_dl_ref (my_mod);
 
246
 
 
247
  if (argc == 0)
 
248
    {
 
249
      grub_error (GRUB_ERR_BAD_ARGUMENT, "no kernel specified");
 
250
      goto out;
 
251
    }
 
252
 
 
253
  elf = grub_elf_open (argv[0]);
 
254
  if (! elf)
 
255
    goto out;
 
256
 
 
257
  if (elf->ehdr.ehdr32.e_type != ET_EXEC && elf->ehdr.ehdr32.e_type != ET_DYN)
 
258
    {
 
259
      grub_error (GRUB_ERR_UNKNOWN_OS,
 
260
                  "this ELF file is not of the right type");
 
261
      goto out;
 
262
    }
 
263
 
 
264
  /* Release the previously used memory.  */
 
265
  grub_loader_unset ();
 
266
 
 
267
  if (grub_elf_is_elf32 (elf))
 
268
    grub_linux_load32 (elf);
 
269
  else
 
270
  if (grub_elf_is_elf64 (elf))
 
271
    grub_linux_load64 (elf);
 
272
  else
 
273
    {
 
274
      grub_error (GRUB_ERR_BAD_FILE_TYPE, "unknown ELF class");
 
275
      goto out;
 
276
    }
 
277
 
 
278
  size = sizeof ("BOOT_IMAGE=") + grub_strlen (argv[0]);
 
279
  for (i = 0; i < argc; i++)
 
280
    size += grub_strlen (argv[i]) + 1;
 
281
 
 
282
  linux_args = grub_malloc (size);
 
283
  if (! linux_args)
 
284
    goto out;
 
285
 
 
286
  /* Specify the boot file.  */
 
287
  dest = grub_stpcpy (linux_args, "BOOT_IMAGE=");
 
288
  dest = grub_stpcpy (dest, argv[0]);
 
289
 
 
290
  for (i = 1; i < argc; i++)
 
291
    {
 
292
      *dest++ = ' ';
 
293
      dest = grub_stpcpy (dest, argv[i]);
 
294
    }
 
295
 
 
296
out:
 
297
 
 
298
  if (elf)
 
299
    grub_elf_close (elf);
 
300
 
 
301
  if (grub_errno != GRUB_ERR_NONE)
 
302
    {
 
303
      grub_linux_release_mem ();
 
304
      grub_dl_unref (my_mod);
 
305
      loaded = 0;
 
306
    }
 
307
  else
 
308
    {
 
309
      grub_loader_set (grub_linux_boot, grub_linux_unload, 1);
 
310
      initrd_addr = 0;
 
311
      loaded = 1;
 
312
    }
 
313
 
 
314
  return grub_errno;
 
315
}
 
316
 
 
317
static grub_err_t
 
318
grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
 
319
                 int argc, char *argv[])
 
320
{
 
321
  grub_file_t file = 0;
 
322
  grub_ssize_t size;
 
323
  grub_addr_t first_addr;
 
324
  grub_addr_t addr;
 
325
 
 
326
  if (argc == 0)
 
327
    {
 
328
      grub_error (GRUB_ERR_BAD_ARGUMENT, "no initrd specified");
 
329
      goto fail;
 
330
    }
 
331
 
 
332
  if (!loaded)
 
333
    {
 
334
      grub_error (GRUB_ERR_BAD_ARGUMENT, "you need to load the kernel first");
 
335
      goto fail;
 
336
    }
 
337
 
 
338
  grub_file_filter_disable_compression ();
 
339
  file = grub_file_open (argv[0]);
 
340
  if (! file)
 
341
    goto fail;
 
342
 
 
343
  first_addr = linux_addr + linux_size;
 
344
  size = grub_file_size (file);
 
345
 
 
346
  /* Attempt to claim at a series of addresses until successful in
 
347
     the same way that grub_rescue_cmd_linux does.  */
 
348
  addr = grub_linux_claimmap_iterate (first_addr, size, 0x100000);
 
349
  if (addr == (grub_addr_t) -1)
 
350
     goto fail;
 
351
 
 
352
  grub_dprintf ("loader", "Loading initrd at 0x%x, size 0x%x\n", addr, size);
 
353
 
 
354
  if (grub_file_read (file, (void *) addr, size) != size)
 
355
    {
 
356
      grub_ieee1275_release (addr, size);
 
357
      grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file");
 
358
      goto fail;
 
359
    }
 
360
 
 
361
  initrd_addr = addr;
 
362
  initrd_size = size;
 
363
 
 
364
 fail:
 
365
  if (file)
 
366
    grub_file_close (file);
 
367
 
 
368
  return grub_errno;
 
369
}
 
370
 
 
371
static grub_command_t cmd_linux, cmd_initrd;
 
372
 
 
373
GRUB_MOD_INIT(linux)
 
374
{
 
375
  cmd_linux = grub_register_command ("linux", grub_cmd_linux,
 
376
                                     0, N_("Load Linux."));
 
377
  cmd_initrd = grub_register_command ("initrd", grub_cmd_initrd,
 
378
                                      0, N_("Load initrd."));
 
379
  my_mod = mod;
 
380
}
 
381
 
 
382
GRUB_MOD_FINI(linux)
 
383
{
 
384
  grub_unregister_command (cmd_linux);
 
385
  grub_unregister_command (cmd_initrd);
 
386
}