~darkmuggle-deactivatedaccount/ubuntu/quantal/grub2/fix-872244

« back to all changes in this revision

Viewing changes to loader/sparc64/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/machine/loader.h>
28
 
#include <grub/gzio.h>
29
 
#include <grub/command.h>
30
 
#include <grub/i18n.h>
31
 
 
32
 
static grub_dl_t my_mod;
33
 
 
34
 
static int loaded;
35
 
 
36
 
/* /virtual-memory/translations property layout  */
37
 
struct grub_ieee1275_translation {
38
 
  grub_uint64_t vaddr;
39
 
  grub_uint64_t size;
40
 
  grub_uint64_t data;
41
 
};
42
 
 
43
 
static struct grub_ieee1275_translation *of_trans;
44
 
static int of_num_trans;
45
 
 
46
 
static grub_addr_t phys_base;
47
 
static grub_addr_t grub_phys_start;
48
 
static grub_addr_t grub_phys_end;
49
 
 
50
 
static grub_addr_t initrd_addr;
51
 
static grub_addr_t initrd_paddr;
52
 
static grub_size_t initrd_size;
53
 
 
54
 
static Elf64_Addr linux_entry;
55
 
static grub_addr_t linux_addr;
56
 
static grub_addr_t linux_paddr;
57
 
static grub_size_t linux_size;
58
 
 
59
 
static char *linux_args;
60
 
 
61
 
struct linux_bootstr_info {
62
 
        int len, valid;
63
 
        char buf[];
64
 
};
65
 
 
66
 
struct linux_hdrs {
67
 
        /* All HdrS versions support these fields.  */
68
 
        unsigned int start_insns[2];
69
 
        char magic[4]; /* "HdrS" */
70
 
        unsigned int linux_kernel_version; /* LINUX_VERSION_CODE */
71
 
        unsigned short hdrs_version;
72
 
        unsigned short root_flags;
73
 
        unsigned short root_dev;
74
 
        unsigned short ram_flags;
75
 
        unsigned int __deprecated_ramdisk_image;
76
 
        unsigned int ramdisk_size;
77
 
 
78
 
        /* HdrS versions 0x0201 and higher only */
79
 
        char *reboot_command;
80
 
 
81
 
        /* HdrS versions 0x0202 and higher only */
82
 
        struct linux_bootstr_info *bootstr_info;
83
 
 
84
 
        /* HdrS versions 0x0301 and higher only */
85
 
        unsigned long ramdisk_image;
86
 
};
87
 
 
88
 
static grub_err_t
89
 
grub_linux_boot (void)
90
 
{
91
 
  struct linux_bootstr_info *bp;
92
 
  struct linux_hdrs *hp;
93
 
  grub_addr_t addr;
94
 
 
95
 
  hp = (struct linux_hdrs *) linux_addr;
96
 
 
97
 
  /* Any pointer we dereference in the kernel image must be relocated
98
 
     to where we actually loaded the kernel.  */
99
 
  addr = (grub_addr_t) hp->bootstr_info;
100
 
  addr += (linux_addr - linux_entry);
101
 
  bp = (struct linux_bootstr_info *) addr;
102
 
 
103
 
  /* Set the command line arguments, unless the kernel has been
104
 
     built with a fixed CONFIG_CMDLINE.  */
105
 
  if (!bp->valid)
106
 
    {
107
 
      int len = grub_strlen (linux_args) + 1;
108
 
      if (bp->len < len)
109
 
        len = bp->len;
110
 
      memcpy(bp->buf, linux_args, len);
111
 
      bp->buf[len-1] = '\0';
112
 
      bp->valid = 1;
113
 
    }
114
 
 
115
 
  if (initrd_addr)
116
 
    {
117
 
      /* The kernel expects the physical address, adjusted relative
118
 
         to the lowest address advertised in "/memory"'s available
119
 
         property.
120
 
 
121
 
         The history of this is that back when the kernel only supported
122
 
         specifying a 32-bit ramdisk address, this was the way to still
123
 
         be able to specify the ramdisk physical address even if memory
124
 
         started at some place above 4GB.
125
 
 
126
 
         The magic 0x400000 is KERNBASE, I have no idea why SILO adds
127
 
         that term into the address, but it does and thus we have to do
128
 
         it too as this is what the kernel expects.  */
129
 
      hp->ramdisk_image = initrd_paddr - phys_base + 0x400000;
130
 
      hp->ramdisk_size = initrd_size;
131
 
    }
132
 
 
133
 
  grub_dprintf ("loader", "Entry point: 0x%lx\n", linux_addr);
134
 
  grub_dprintf ("loader", "Initrd at: 0x%lx, size 0x%lx\n", initrd_addr,
135
 
                initrd_size);
136
 
  grub_dprintf ("loader", "Boot arguments: %s\n", linux_args);
137
 
  grub_dprintf ("loader", "Jumping to Linux...\n");
138
 
 
139
 
  /* Boot the kernel.  */
140
 
  asm volatile ("sethi  %hi(grub_ieee1275_entry_fn), %o1\n"
141
 
                "ldx    [%o1 + %lo(grub_ieee1275_entry_fn)], %o4\n"
142
 
                "sethi  %hi(grub_ieee1275_original_stack), %o1\n"
143
 
                "ldx    [%o1 + %lo(grub_ieee1275_original_stack)], %o6\n"
144
 
                "sethi  %hi(linux_addr), %o1\n"
145
 
                "ldx    [%o1 + %lo(linux_addr)], %o5\n"
146
 
                "mov    %g0, %o0\n"
147
 
                "mov    %g0, %o2\n"
148
 
                "mov    %g0, %o3\n"
149
 
                "jmp    %o5\n"
150
 
                "mov    %g0, %o1\n");
151
 
 
152
 
  return GRUB_ERR_NONE;
153
 
}
154
 
 
155
 
static grub_err_t
156
 
grub_linux_release_mem (void)
157
 
{
158
 
  grub_free (linux_args);
159
 
  linux_args = 0;
160
 
  linux_addr = 0;
161
 
  initrd_addr = 0;
162
 
 
163
 
  return GRUB_ERR_NONE;
164
 
}
165
 
 
166
 
static grub_err_t
167
 
grub_linux_unload (void)
168
 
{
169
 
  grub_err_t err;
170
 
 
171
 
  err = grub_linux_release_mem ();
172
 
  grub_dl_unref (my_mod);
173
 
 
174
 
  loaded = 0;
175
 
 
176
 
  return err;
177
 
}
178
 
 
179
 
#define FOUR_MB (4 * 1024 * 1024)
180
 
 
181
 
static grub_addr_t
182
 
alloc_phys (grub_addr_t size)
183
 
{
184
 
  grub_addr_t ret = (grub_addr_t) -1;
185
 
 
186
 
  auto int NESTED_FUNC_ATTR choose (grub_uint64_t addr, grub_uint64_t len __attribute__((unused)), grub_uint32_t type);
187
 
  int NESTED_FUNC_ATTR choose (grub_uint64_t addr, grub_uint64_t len __attribute__((unused)), grub_uint32_t type)
188
 
  {
189
 
    grub_addr_t end = addr + len;
190
 
 
191
 
    if (type != 1)
192
 
      return 0;
193
 
 
194
 
    addr = ALIGN_UP (addr, FOUR_MB);
195
 
    if (addr + size >= end)
196
 
      return 0;
197
 
 
198
 
    if (addr >= grub_phys_start && addr < grub_phys_end)
199
 
      {
200
 
        addr = ALIGN_UP (grub_phys_end, FOUR_MB);
201
 
        if (addr + size >= end)
202
 
          return 0;
203
 
      }
204
 
    if ((addr + size) >= grub_phys_start
205
 
        && (addr + size) < grub_phys_end)
206
 
      {
207
 
        addr = ALIGN_UP (grub_phys_end, FOUR_MB);
208
 
        if (addr + size >= end)
209
 
          return 0;
210
 
      }
211
 
 
212
 
    if (loaded)
213
 
      {
214
 
        grub_addr_t linux_end = ALIGN_UP (linux_paddr + linux_size, FOUR_MB);
215
 
 
216
 
        if (addr >= linux_paddr && addr < linux_end)
217
 
          {
218
 
            addr = linux_end;
219
 
            if (addr + size >= end)
220
 
              return 0;
221
 
          }
222
 
        if ((addr + size) >= linux_paddr
223
 
            && (addr + size) < linux_end)
224
 
          {
225
 
            addr = linux_end;
226
 
            if (addr + size >= end)
227
 
              return 0;
228
 
          }
229
 
      }
230
 
 
231
 
    ret = addr;
232
 
    return 1;
233
 
  }
234
 
 
235
 
  grub_machine_mmap_iterate (choose);
236
 
 
237
 
  return ret;
238
 
}
239
 
 
240
 
static grub_err_t
241
 
grub_linux_load64 (grub_elf_t elf)
242
 
{
243
 
  grub_addr_t off, paddr, base;
244
 
  int ret;
245
 
 
246
 
  linux_entry = elf->ehdr.ehdr64.e_entry;
247
 
  linux_addr = 0x40004000;
248
 
  off = 0x4000;
249
 
  linux_size = grub_elf64_size (elf, 0);
250
 
  if (linux_size == 0)
251
 
    return grub_errno;
252
 
 
253
 
  grub_dprintf ("loader", "Attempting to claim at 0x%lx, size 0x%lx.\n",
254
 
                linux_addr, linux_size);
255
 
 
256
 
  paddr = alloc_phys (linux_size + off);
257
 
  if (paddr == (grub_addr_t) -1)
258
 
    return grub_error (GRUB_ERR_OUT_OF_MEMORY,
259
 
                       "couldn't allocate physical memory");
260
 
  ret = grub_ieee1275_map (paddr, linux_addr - off,
261
 
                           linux_size + off, IEEE1275_MAP_DEFAULT);
262
 
  if (ret)
263
 
    return grub_error (GRUB_ERR_OUT_OF_MEMORY,
264
 
                       "couldn't map physical memory");
265
 
 
266
 
  grub_dprintf ("loader", "Loading Linux at vaddr 0x%lx, paddr 0x%lx, size 0x%lx\n",
267
 
                linux_addr, paddr, linux_size);
268
 
 
269
 
  linux_paddr = paddr;
270
 
 
271
 
  base = linux_entry - off;
272
 
 
273
 
  /* Now load the segments into the area we claimed.  */
274
 
  auto grub_err_t offset_phdr (Elf64_Phdr *phdr, grub_addr_t *addr, int *do_load);
275
 
  grub_err_t offset_phdr (Elf64_Phdr *phdr, grub_addr_t *addr, int *do_load)
276
 
    {
277
 
      if (phdr->p_type != PT_LOAD)
278
 
        {
279
 
          *do_load = 0;
280
 
          return 0;
281
 
        }
282
 
      *do_load = 1;
283
 
 
284
 
      /* Adjust the program load address to linux_addr.  */
285
 
      *addr = (phdr->p_paddr - base) + (linux_addr - off);
286
 
      return 0;
287
 
    }
288
 
  return grub_elf64_load (elf, offset_phdr, 0, 0);
289
 
}
290
 
 
291
 
static grub_err_t
292
 
grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
293
 
                int argc, char *argv[])
294
 
{
295
 
  grub_file_t file = 0;
296
 
  grub_elf_t elf = 0;
297
 
  int i;
298
 
  int size;
299
 
  char *dest;
300
 
 
301
 
  grub_dl_ref (my_mod);
302
 
 
303
 
  if (argc == 0)
304
 
    {
305
 
      grub_error (GRUB_ERR_BAD_ARGUMENT, "no kernel specified");
306
 
      goto out;
307
 
    }
308
 
 
309
 
  file = grub_gzfile_open (argv[0], 1);
310
 
  if (!file)
311
 
    goto out;
312
 
 
313
 
  elf = grub_elf_file (file);
314
 
  if (! elf)
315
 
    goto out;
316
 
 
317
 
  if (elf->ehdr.ehdr32.e_type != ET_EXEC)
318
 
    {
319
 
      grub_error (GRUB_ERR_UNKNOWN_OS,
320
 
                  "this ELF file is not of the right type");
321
 
      goto out;
322
 
    }
323
 
 
324
 
  /* Release the previously used memory.  */
325
 
  grub_loader_unset ();
326
 
 
327
 
  if (grub_elf_is_elf64 (elf))
328
 
    grub_linux_load64 (elf);
329
 
  else
330
 
    {
331
 
      grub_error (GRUB_ERR_BAD_FILE_TYPE, "unknown ELF class");
332
 
      goto out;
333
 
    }
334
 
 
335
 
  size = sizeof ("BOOT_IMAGE=") + grub_strlen (argv[0]);
336
 
  for (i = 0; i < argc; i++)
337
 
    size += grub_strlen (argv[i]) + 1;
338
 
 
339
 
  linux_args = grub_malloc (size);
340
 
  if (! linux_args)
341
 
    goto out;
342
 
 
343
 
  /* Specify the boot file.  */
344
 
  dest = grub_stpcpy (linux_args, "BOOT_IMAGE=");
345
 
  dest = grub_stpcpy (dest, argv[0]);
346
 
 
347
 
  for (i = 1; i < argc; i++)
348
 
    {
349
 
      *dest++ = ' ';
350
 
      dest = grub_stpcpy (dest, argv[i]);
351
 
    }
352
 
 
353
 
out:
354
 
  if (elf)
355
 
    grub_elf_close (elf);
356
 
  else if (file)
357
 
    grub_file_close (file);
358
 
 
359
 
  if (grub_errno != GRUB_ERR_NONE)
360
 
    {
361
 
      grub_linux_release_mem ();
362
 
      grub_dl_unref (my_mod);
363
 
      loaded = 0;
364
 
    }
365
 
  else
366
 
    {
367
 
      grub_loader_set (grub_linux_boot, grub_linux_unload, 1);
368
 
      initrd_addr = 0;
369
 
      loaded = 1;
370
 
    }
371
 
 
372
 
  return grub_errno;
373
 
}
374
 
 
375
 
static grub_err_t
376
 
grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
377
 
                 int argc, char *argv[])
378
 
{
379
 
  grub_file_t file = 0;
380
 
  grub_ssize_t size;
381
 
  grub_addr_t paddr;
382
 
  grub_addr_t addr;
383
 
  int ret;
384
 
 
385
 
  if (argc == 0)
386
 
    {
387
 
      grub_error (GRUB_ERR_BAD_ARGUMENT, "no initrd specified");
388
 
      goto fail;
389
 
    }
390
 
 
391
 
  if (!loaded)
392
 
    {
393
 
      grub_error (GRUB_ERR_BAD_ARGUMENT, "you need to load the kernel first");
394
 
      goto fail;
395
 
    }
396
 
 
397
 
  file = grub_file_open (argv[0]);
398
 
  if (! file)
399
 
    goto fail;
400
 
 
401
 
  addr = 0x60000000;
402
 
  size = grub_file_size (file);
403
 
 
404
 
  paddr = alloc_phys (size);
405
 
  if (paddr == (grub_addr_t) -1)
406
 
    {
407
 
      grub_error (GRUB_ERR_OUT_OF_MEMORY,
408
 
                  "couldn't allocate physical memory");
409
 
      goto fail;
410
 
    }
411
 
  ret = grub_ieee1275_map (paddr, addr, size, IEEE1275_MAP_DEFAULT);
412
 
  if (ret)
413
 
    {
414
 
      grub_error (GRUB_ERR_OUT_OF_MEMORY,
415
 
                  "couldn't map physical memory");
416
 
      goto fail;
417
 
    }
418
 
 
419
 
  grub_dprintf ("loader", "Loading initrd at vaddr 0x%lx, paddr 0x%lx, size 0x%lx\n",
420
 
                addr, paddr, size);
421
 
 
422
 
  if (grub_file_read (file, (void *) addr, size) != size)
423
 
    {
424
 
      grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file");
425
 
      goto fail;
426
 
    }
427
 
 
428
 
  initrd_addr = addr;
429
 
  initrd_paddr = paddr;
430
 
  initrd_size = size;
431
 
 
432
 
 fail:
433
 
  if (file)
434
 
    grub_file_close (file);
435
 
 
436
 
  return grub_errno;
437
 
}
438
 
 
439
 
static void
440
 
determine_phys_base (void)
441
 
{
442
 
  auto int NESTED_FUNC_ATTR get_physbase (grub_uint64_t addr, grub_uint64_t len __attribute__((unused)), grub_uint32_t type);
443
 
  int NESTED_FUNC_ATTR get_physbase (grub_uint64_t addr, grub_uint64_t len __attribute__((unused)), grub_uint32_t type)
444
 
  {
445
 
    if (type != 1)
446
 
      return 0;
447
 
    if (addr < phys_base)
448
 
      phys_base = addr;
449
 
    return 0;
450
 
  }
451
 
 
452
 
  phys_base = ~(grub_uint64_t) 0;
453
 
  grub_machine_mmap_iterate (get_physbase);
454
 
}
455
 
 
456
 
static void
457
 
fetch_translations (void)
458
 
{
459
 
  grub_ieee1275_phandle_t node;
460
 
  grub_ssize_t actual;
461
 
  int i;
462
 
 
463
 
  if (grub_ieee1275_finddevice ("/virtual-memory", &node))
464
 
    {
465
 
      grub_printf ("Cannot find /virtual-memory node.\n");
466
 
      return;
467
 
    }
468
 
 
469
 
  if (grub_ieee1275_get_property_length (node, "translations", &actual))
470
 
    {
471
 
      grub_printf ("Cannot find /virtual-memory/translations size.\n");
472
 
      return;
473
 
    }
474
 
 
475
 
  of_trans = grub_malloc (actual);
476
 
  if (!of_trans)
477
 
    {
478
 
      grub_printf ("Cannot allocate translations buffer.\n");
479
 
      return;
480
 
    }
481
 
 
482
 
  if (grub_ieee1275_get_property (node, "translations", of_trans, actual, &actual))
483
 
    {
484
 
      grub_printf ("Cannot fetch /virtual-memory/translations property.\n");
485
 
      return;
486
 
    }
487
 
 
488
 
  of_num_trans = actual / sizeof(struct grub_ieee1275_translation);
489
 
 
490
 
  for (i = 0; i < of_num_trans; i++)
491
 
    {
492
 
      struct grub_ieee1275_translation *p = &of_trans[i];
493
 
 
494
 
      if (p->vaddr == 0x2000)
495
 
        {
496
 
          grub_addr_t phys, tte = p->data;
497
 
 
498
 
          phys = tte & ~(0xff00000000001fffULL);
499
 
 
500
 
          grub_phys_start = phys;
501
 
          grub_phys_end = grub_phys_start + p->size;
502
 
          grub_dprintf ("loader", "Grub lives at phys_start[%lx] phys_end[%lx]\n",
503
 
                        (unsigned long) grub_phys_start,
504
 
                        (unsigned long) grub_phys_end);
505
 
          break;
506
 
        }
507
 
    }
508
 
}
509
 
 
510
 
 
511
 
static grub_command_t cmd_linux, cmd_initrd;
512
 
 
513
 
GRUB_MOD_INIT(linux)
514
 
{
515
 
  determine_phys_base ();
516
 
  fetch_translations ();
517
 
 
518
 
  cmd_linux = grub_register_command ("linux", grub_cmd_linux,
519
 
                                     0, N_("Load Linux."));
520
 
  cmd_initrd = grub_register_command ("initrd", grub_cmd_initrd,
521
 
                                      0, N_("Load initrd."));
522
 
  my_mod = mod;
523
 
}
524
 
 
525
 
GRUB_MOD_FINI(linux)
526
 
{
527
 
  grub_unregister_command (cmd_linux);
528
 
  grub_unregister_command (cmd_initrd);
529
 
}