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

« back to all changes in this revision

Viewing changes to grub-core/loader/i386/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
/*
 
2
 *  GRUB  --  GRand Unified Bootloader
 
3
 *  Copyright (C) 2006,2007,2008,2009,2010  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 <grub/loader.h>
 
20
#include <grub/memory.h>
 
21
#include <grub/normal.h>
 
22
#include <grub/file.h>
 
23
#include <grub/disk.h>
 
24
#include <grub/err.h>
 
25
#include <grub/misc.h>
 
26
#include <grub/types.h>
 
27
#include <grub/dl.h>
 
28
#include <grub/mm.h>
 
29
#include <grub/term.h>
 
30
#include <grub/cpu/linux.h>
 
31
#include <grub/video.h>
 
32
#include <grub/video_fb.h>
 
33
#include <grub/command.h>
 
34
#include <grub/i386/relocator.h>
 
35
#include <grub/i18n.h>
 
36
 
 
37
#ifdef GRUB_MACHINE_PCBIOS
 
38
#include <grub/i386/pc/vesa_modes_table.h>
 
39
#endif
 
40
 
 
41
#ifdef GRUB_MACHINE_EFI
 
42
#include <grub/efi/efi.h>
 
43
#define HAS_VGA_TEXT 0
 
44
#define DEFAULT_VIDEO_MODE "auto"
 
45
#elif defined (GRUB_MACHINE_IEEE1275)
 
46
#include <grub/ieee1275/ieee1275.h>
 
47
#define HAS_VGA_TEXT 0
 
48
#define DEFAULT_VIDEO_MODE "text"
 
49
#else
 
50
#include <grub/i386/pc/vbe.h>
 
51
#include <grub/i386/pc/console.h>
 
52
#define HAS_VGA_TEXT 1
 
53
#define DEFAULT_VIDEO_MODE "text"
 
54
#endif
 
55
 
 
56
#define GRUB_LINUX_CL_OFFSET            0x1000
 
57
#define GRUB_LINUX_CL_END_OFFSET        0x2000
 
58
 
 
59
static grub_dl_t my_mod;
 
60
 
 
61
static grub_size_t linux_mem_size;
 
62
static int loaded;
 
63
static void *real_mode_mem;
 
64
static grub_addr_t real_mode_target;
 
65
static void *prot_mode_mem;
 
66
static grub_addr_t prot_mode_target;
 
67
static void *initrd_mem;
 
68
static grub_addr_t initrd_mem_target;
 
69
static grub_uint32_t real_mode_pages;
 
70
static grub_uint32_t prot_mode_pages;
 
71
static grub_uint32_t initrd_pages;
 
72
static struct grub_relocator *relocator = NULL;
 
73
static void *efi_mmap_buf;
 
74
#ifdef GRUB_MACHINE_EFI
 
75
static grub_efi_uintn_t efi_mmap_size;
 
76
#else
 
77
static const grub_size_t efi_mmap_size = 0;
 
78
#endif
 
79
 
 
80
/* FIXME */
 
81
#if 0
 
82
struct idt_descriptor
 
83
{
 
84
  grub_uint16_t limit;
 
85
  void *base;
 
86
} __attribute__ ((packed));
 
87
 
 
88
static struct idt_descriptor idt_desc =
 
89
  {
 
90
    0,
 
91
    0
 
92
  };
 
93
#endif
 
94
 
 
95
static inline grub_size_t
 
96
page_align (grub_size_t size)
 
97
{
 
98
  return (size + (1 << 12) - 1) & (~((1 << 12) - 1));
 
99
}
 
100
 
 
101
#ifdef GRUB_MACHINE_EFI
 
102
/* Find the optimal number of pages for the memory map. Is it better to
 
103
   move this code to efi/mm.c?  */
 
104
static grub_efi_uintn_t
 
105
find_efi_mmap_size (void)
 
106
{
 
107
  static grub_efi_uintn_t mmap_size = 0;
 
108
 
 
109
  if (mmap_size != 0)
 
110
    return mmap_size;
 
111
 
 
112
  mmap_size = (1 << 12);
 
113
  while (1)
 
114
    {
 
115
      int ret;
 
116
      grub_efi_memory_descriptor_t *mmap;
 
117
      grub_efi_uintn_t desc_size;
 
118
 
 
119
      mmap = grub_malloc (mmap_size);
 
120
      if (! mmap)
 
121
        return 0;
 
122
 
 
123
      ret = grub_efi_get_memory_map (&mmap_size, mmap, 0, &desc_size, 0);
 
124
      grub_free (mmap);
 
125
 
 
126
      if (ret < 0)
 
127
        grub_fatal ("cannot get memory map");
 
128
      else if (ret > 0)
 
129
        break;
 
130
 
 
131
      mmap_size += (1 << 12);
 
132
    }
 
133
 
 
134
  /* Increase the size a bit for safety, because GRUB allocates more on
 
135
     later, and EFI itself may allocate more.  */
 
136
  mmap_size += (1 << 12);
 
137
 
 
138
  return page_align (mmap_size);
 
139
}
 
140
 
 
141
#endif
 
142
 
 
143
/* Find the optimal number of pages for the memory map. */
 
144
static grub_size_t
 
145
find_mmap_size (void)
 
146
{
 
147
  grub_size_t count = 0, mmap_size;
 
148
 
 
149
  auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t,
 
150
                                  grub_memory_type_t);
 
151
  int NESTED_FUNC_ATTR hook (grub_uint64_t addr __attribute__ ((unused)),
 
152
                             grub_uint64_t size __attribute__ ((unused)),
 
153
                             grub_memory_type_t type __attribute__ ((unused)))
 
154
    {
 
155
      count++;
 
156
      return 0;
 
157
    }
 
158
 
 
159
  grub_mmap_iterate (hook);
 
160
 
 
161
  mmap_size = count * sizeof (struct grub_e820_mmap);
 
162
 
 
163
  /* Increase the size a bit for safety, because GRUB allocates more on
 
164
     later.  */
 
165
  mmap_size += (1 << 12);
 
166
 
 
167
  return page_align (mmap_size);
 
168
}
 
169
 
 
170
static void
 
171
free_pages (void)
 
172
{
 
173
  grub_relocator_unload (relocator);
 
174
  relocator = NULL;
 
175
  real_mode_mem = prot_mode_mem = initrd_mem = 0;
 
176
  real_mode_target = prot_mode_target = initrd_mem_target = 0;
 
177
}
 
178
 
 
179
/* Allocate pages for the real mode code and the protected mode code
 
180
   for linux as well as a memory map buffer.  */
 
181
static grub_err_t
 
182
allocate_pages (grub_size_t prot_size)
 
183
{
 
184
  grub_size_t real_size, mmap_size;
 
185
  grub_err_t err;
 
186
 
 
187
  /* Make sure that each size is aligned to a page boundary.  */
 
188
  real_size = GRUB_LINUX_CL_END_OFFSET;
 
189
  prot_size = page_align (prot_size);
 
190
  mmap_size = find_mmap_size ();
 
191
 
 
192
#ifdef GRUB_MACHINE_EFI
 
193
  efi_mmap_size = find_efi_mmap_size ();
 
194
#endif
 
195
 
 
196
  grub_dprintf ("linux", "real_size = %x, prot_size = %x, mmap_size = %x\n",
 
197
                (unsigned) real_size, (unsigned) prot_size, (unsigned) mmap_size);
 
198
 
 
199
  /* Calculate the number of pages; Combine the real mode code with
 
200
     the memory map buffer for simplicity.  */
 
201
  real_mode_pages = ((real_size + mmap_size + efi_mmap_size) >> 12);
 
202
  prot_mode_pages = (prot_size >> 12);
 
203
 
 
204
  /* Initialize the memory pointers with NULL for convenience.  */
 
205
  free_pages ();
 
206
 
 
207
  relocator = grub_relocator_new ();
 
208
  if (!relocator)
 
209
    {
 
210
      err = grub_errno;
 
211
      goto fail;
 
212
    }
 
213
 
 
214
  /* FIXME: Should request low memory from the heap when this feature is
 
215
     implemented.  */
 
216
 
 
217
  auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t,
 
218
                                  grub_memory_type_t);
 
219
  int NESTED_FUNC_ATTR hook (grub_uint64_t addr, grub_uint64_t size,
 
220
                             grub_memory_type_t type)
 
221
    {
 
222
      /* We must put real mode code in the traditional space.  */
 
223
 
 
224
      if (type == GRUB_MEMORY_AVAILABLE
 
225
          && addr <= 0x90000)
 
226
        {
 
227
          if (addr < 0x10000)
 
228
            {
 
229
              size += addr - 0x10000;
 
230
              addr = 0x10000;
 
231
            }
 
232
 
 
233
          if (addr + size > 0x90000)
 
234
            size = 0x90000 - addr;
 
235
 
 
236
          if (real_size + mmap_size + efi_mmap_size > size)
 
237
            return 0;
 
238
 
 
239
          real_mode_target = ((addr + size) - (real_size + mmap_size + efi_mmap_size));
 
240
          return 1;
 
241
        }
 
242
 
 
243
      return 0;
 
244
    }
 
245
  grub_mmap_iterate (hook);
 
246
  if (! real_mode_target)
 
247
    {
 
248
      err = grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate real mode pages");
 
249
      goto fail;
 
250
    }
 
251
 
 
252
  {
 
253
    grub_relocator_chunk_t ch;
 
254
    err = grub_relocator_alloc_chunk_addr (relocator, &ch,
 
255
                                           real_mode_target,
 
256
                                           (real_size + mmap_size 
 
257
                                            + efi_mmap_size));
 
258
    if (err)
 
259
      goto fail;
 
260
    real_mode_mem = get_virtual_current_address (ch);
 
261
  }
 
262
  efi_mmap_buf = (grub_uint8_t *) real_mode_mem + real_size + mmap_size;
 
263
 
 
264
  prot_mode_target = GRUB_LINUX_BZIMAGE_ADDR;
 
265
 
 
266
  {
 
267
    grub_relocator_chunk_t ch;
 
268
    err = grub_relocator_alloc_chunk_addr (relocator, &ch,
 
269
                                           prot_mode_target, prot_size);
 
270
    if (err)
 
271
      goto fail;
 
272
    prot_mode_mem = get_virtual_current_address (ch);
 
273
  }
 
274
 
 
275
  grub_dprintf ("linux", "real_mode_mem = %lx, real_mode_pages = %x, "
 
276
                "prot_mode_mem = %lx, prot_mode_pages = %x\n",
 
277
                (unsigned long) real_mode_mem, (unsigned) real_mode_pages,
 
278
                (unsigned long) prot_mode_mem, (unsigned) prot_mode_pages);
 
279
 
 
280
  return GRUB_ERR_NONE;
 
281
 
 
282
 fail:
 
283
  free_pages ();
 
284
  return err;
 
285
}
 
286
 
 
287
static void
 
288
grub_e820_add_region (struct grub_e820_mmap *e820_map, int *e820_num,
 
289
                      grub_uint64_t start, grub_uint64_t size,
 
290
                      grub_uint32_t type)
 
291
{
 
292
  int n = *e820_num;
 
293
 
 
294
  if (n >= GRUB_E820_MAX_ENTRY)
 
295
    grub_fatal ("Too many e820 memory map entries");
 
296
 
 
297
  if ((n > 0) && (e820_map[n - 1].addr + e820_map[n - 1].size == start) &&
 
298
      (e820_map[n - 1].type == type))
 
299
      e820_map[n - 1].size += size;
 
300
  else
 
301
    {
 
302
      e820_map[n].addr = start;
 
303
      e820_map[n].size = size;
 
304
      e820_map[n].type = type;
 
305
      (*e820_num)++;
 
306
    }
 
307
}
 
308
 
 
309
static grub_err_t
 
310
grub_linux_setup_video (struct linux_kernel_params *params)
 
311
{
 
312
  struct grub_video_mode_info mode_info;
 
313
  void *framebuffer;
 
314
  grub_err_t err;
 
315
 
 
316
  err = grub_video_get_info_and_fini (&mode_info, &framebuffer);
 
317
 
 
318
  if (err)
 
319
    {
 
320
      grub_errno = GRUB_ERR_NONE;
 
321
      return 1;
 
322
    }
 
323
 
 
324
  params->lfb_width = mode_info.width;
 
325
  params->lfb_height = mode_info.height;
 
326
  params->lfb_depth = mode_info.bpp;
 
327
  params->lfb_line_len = mode_info.pitch;
 
328
 
 
329
  params->lfb_base = (grub_size_t) framebuffer;
 
330
  params->lfb_size = ALIGN_UP (params->lfb_line_len * params->lfb_height, 65536);
 
331
 
 
332
  params->red_mask_size = mode_info.red_mask_size;
 
333
  params->red_field_pos = mode_info.red_field_pos;
 
334
  params->green_mask_size = mode_info.green_mask_size;
 
335
  params->green_field_pos = mode_info.green_field_pos;
 
336
  params->blue_mask_size = mode_info.blue_mask_size;
 
337
  params->blue_field_pos = mode_info.blue_field_pos;
 
338
  params->reserved_mask_size = mode_info.reserved_mask_size;
 
339
  params->reserved_field_pos = mode_info.reserved_field_pos;
 
340
 
 
341
 
 
342
#ifdef GRUB_MACHINE_PCBIOS
 
343
  /* VESA packed modes may come with zeroed mask sizes, which need
 
344
     to be set here according to DAC Palette width.  If we don't,
 
345
     this results in Linux displaying a black screen.  */
 
346
  if (mode_info.bpp <= 8)
 
347
    {
 
348
      struct grub_vbe_info_block controller_info;
 
349
      int status;
 
350
      int width = 8;
 
351
 
 
352
      status = grub_vbe_bios_get_controller_info (&controller_info);
 
353
 
 
354
      if (status == GRUB_VBE_STATUS_OK &&
 
355
          (controller_info.capabilities & GRUB_VBE_CAPABILITY_DACWIDTH))
 
356
        status = grub_vbe_bios_set_dac_palette_width (&width);
 
357
 
 
358
      if (status != GRUB_VBE_STATUS_OK)
 
359
        /* 6 is default after mode reset.  */
 
360
        width = 6;
 
361
 
 
362
      params->red_mask_size = params->green_mask_size
 
363
        = params->blue_mask_size = width;
 
364
      params->reserved_mask_size = 0;
 
365
    }
 
366
#endif
 
367
 
 
368
  return GRUB_ERR_NONE;
 
369
}
 
370
 
 
371
static grub_err_t
 
372
grub_linux_boot (void)
 
373
{
 
374
  struct linux_kernel_params *params;
 
375
  int e820_num;
 
376
  grub_err_t err = 0;
 
377
  char *modevar, *tmp;
 
378
  struct grub_relocator32_state state;
 
379
 
 
380
  params = real_mode_mem;
 
381
 
 
382
#ifdef GRUB_MACHINE_IEEE1275
 
383
  {
 
384
    char *bootpath;
 
385
    grub_ssize_t len;
 
386
 
 
387
    bootpath = grub_env_get ("root");
 
388
    if (bootpath)
 
389
      grub_ieee1275_set_property (grub_ieee1275_chosen,
 
390
                                  "bootpath", bootpath,
 
391
                                  grub_strlen (bootpath) + 1,
 
392
                                  &len);
 
393
  }
 
394
#endif
 
395
 
 
396
  grub_dprintf ("linux", "code32_start = %x\n",
 
397
                (unsigned) params->code32_start);
 
398
 
 
399
  auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t,
 
400
                                  grub_memory_type_t);
 
401
  int NESTED_FUNC_ATTR hook (grub_uint64_t addr, grub_uint64_t size, 
 
402
                             grub_memory_type_t type)
 
403
    {
 
404
      switch (type)
 
405
        {
 
406
        case GRUB_MEMORY_AVAILABLE:
 
407
          grub_e820_add_region (params->e820_map, &e820_num,
 
408
                                addr, size, GRUB_E820_RAM);
 
409
          break;
 
410
 
 
411
        case GRUB_MEMORY_ACPI:
 
412
          grub_e820_add_region (params->e820_map, &e820_num,
 
413
                                addr, size, GRUB_E820_ACPI);
 
414
          break;
 
415
 
 
416
        case GRUB_MEMORY_NVS:
 
417
          grub_e820_add_region (params->e820_map, &e820_num,
 
418
                                addr, size, GRUB_E820_NVS);
 
419
          break;
 
420
 
 
421
        case GRUB_MEMORY_CODE:
 
422
          grub_e820_add_region (params->e820_map, &e820_num,
 
423
                                addr, size, GRUB_E820_EXEC_CODE);
 
424
          break;
 
425
 
 
426
        default:
 
427
          grub_e820_add_region (params->e820_map, &e820_num,
 
428
                                addr, size, GRUB_E820_RESERVED);
 
429
        }
 
430
      return 0;
 
431
    }
 
432
 
 
433
  e820_num = 0;
 
434
  grub_mmap_iterate (hook);
 
435
  params->mmap_size = e820_num;
 
436
 
 
437
  modevar = grub_env_get ("gfxpayload");
 
438
 
 
439
  /* Now all graphical modes are acceptable.
 
440
     May change in future if we have modes without framebuffer.  */
 
441
  if (modevar && *modevar != 0)
 
442
    {
 
443
      tmp = grub_xasprintf ("%s;" DEFAULT_VIDEO_MODE, modevar);
 
444
      if (! tmp)
 
445
        return grub_errno;
 
446
      err = grub_video_set_mode (tmp, 0, 0);
 
447
      grub_free (tmp);
 
448
    }
 
449
  else
 
450
    err = grub_video_set_mode (DEFAULT_VIDEO_MODE, 0, 0);
 
451
 
 
452
  if (err)
 
453
    {
 
454
      grub_print_error ();
 
455
      grub_printf ("Booting however\n");
 
456
      grub_errno = GRUB_ERR_NONE;
 
457
    }
 
458
 
 
459
  if (! grub_linux_setup_video (params))
 
460
    {
 
461
      /* Use generic framebuffer unless VESA is known to be supported.  */
 
462
      if (params->have_vga != GRUB_VIDEO_LINUX_TYPE_VESA)
 
463
        params->have_vga = GRUB_VIDEO_LINUX_TYPE_SIMPLE;
 
464
      else
 
465
        params->lfb_size >>= 16;
 
466
    }
 
467
  else
 
468
    {
 
469
#if defined (GRUB_MACHINE_PCBIOS) || defined (GRUB_MACHINE_COREBOOT) || defined (GRUB_MACHINE_QEMU)
 
470
      params->have_vga = GRUB_VIDEO_LINUX_TYPE_TEXT;
 
471
      params->video_mode = 0x3;
 
472
#else
 
473
      params->have_vga = 0;
 
474
      params->video_mode = 0;
 
475
      params->video_width = 0;
 
476
      params->video_height = 0;
 
477
#endif
 
478
    }
 
479
 
 
480
  /* Initialize these last, because terminal position could be affected by printfs above.  */
 
481
#ifndef GRUB_MACHINE_IEEE1275
 
482
  if (params->have_vga == GRUB_VIDEO_LINUX_TYPE_TEXT)
 
483
#endif
 
484
    {
 
485
      grub_term_output_t term;
 
486
      int found = 0;
 
487
      FOR_ACTIVE_TERM_OUTPUTS(term)
 
488
        if (grub_strcmp (term->name, "vga_text") == 0
 
489
            || grub_strcmp (term->name, "console") == 0
 
490
            || grub_strcmp (term->name, "ofconsole") == 0)
 
491
          {
 
492
            grub_uint16_t pos = grub_term_getxy (term);
 
493
            params->video_cursor_x = pos >> 8;
 
494
            params->video_cursor_y = pos & 0xff;
 
495
            params->video_width = grub_term_width (term);
 
496
            params->video_height = grub_term_height (term);
 
497
            found = 1;
 
498
            break;
 
499
          }
 
500
      if (!found)
 
501
        {
 
502
          params->video_cursor_x = 0;
 
503
          params->video_cursor_y = 0;
 
504
          params->video_width = 80;
 
505
          params->video_height = 25;
 
506
        }
 
507
    }
 
508
 
 
509
#ifdef GRUB_MACHINE_IEEE1275
 
510
  {
 
511
    params->ofw_signature = GRUB_LINUX_OFW_SIGNATURE;
 
512
    params->ofw_num_items = 1;
 
513
    params->ofw_cif_handler = (grub_uint32_t) grub_ieee1275_entry_fn;
 
514
    params->ofw_idt = 0;
 
515
  }
 
516
#endif
 
517
 
 
518
#ifdef GRUB_MACHINE_EFI
 
519
  {
 
520
    grub_efi_uintn_t efi_desc_size;
 
521
    grub_efi_uint32_t efi_desc_version;
 
522
    err = grub_efi_finish_boot_services (&efi_mmap_size, efi_mmap_buf, NULL,
 
523
                                         &efi_desc_size, &efi_desc_version);
 
524
    if (err)
 
525
      return err;
 
526
    
 
527
    /* Note that no boot services are available from here.  */
 
528
 
 
529
    /* Pass EFI parameters.  */
 
530
    if (grub_le_to_cpu16 (params->version) >= 0x0206)
 
531
      {
 
532
        params->v0206.efi_mem_desc_size = efi_desc_size;
 
533
        params->v0206.efi_mem_desc_version = efi_desc_version;
 
534
        params->v0206.efi_mmap = (grub_uint32_t) (unsigned long) efi_mmap_buf;
 
535
        params->v0206.efi_mmap_size = efi_mmap_size;
 
536
#ifdef __x86_64__
 
537
        params->v0206.efi_mmap_hi = (grub_uint32_t) ((grub_uint64_t) efi_mmap_buf >> 32);
 
538
#endif
 
539
      }
 
540
    else if (grub_le_to_cpu16 (params->version) >= 0x0204)
 
541
      {
 
542
        params->v0204.efi_mem_desc_size = efi_desc_size;
 
543
        params->v0204.efi_mem_desc_version = efi_desc_version;
 
544
        params->v0204.efi_mmap = (grub_uint32_t) (unsigned long) efi_mmap_buf;
 
545
        params->v0204.efi_mmap_size = efi_mmap_size;
 
546
      }
 
547
  }
 
548
#endif
 
549
 
 
550
  /* FIXME.  */
 
551
  /*  asm volatile ("lidt %0" : : "m" (idt_desc)); */
 
552
  state.ebp = state.edi = state.ebx = 0;
 
553
  state.esi = real_mode_target;
 
554
  state.esp = real_mode_target;
 
555
  state.eip = params->code32_start;
 
556
  return grub_relocator32_boot (relocator, state);
 
557
}
 
558
 
 
559
static grub_err_t
 
560
grub_linux_unload (void)
 
561
{
 
562
  grub_dl_unref (my_mod);
 
563
  loaded = 0;
 
564
  return GRUB_ERR_NONE;
 
565
}
 
566
 
 
567
static grub_err_t
 
568
grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
 
569
                int argc, char *argv[])
 
570
{
 
571
  grub_file_t file = 0;
 
572
  struct linux_kernel_header lh;
 
573
  struct linux_kernel_params *params;
 
574
  grub_uint8_t setup_sects;
 
575
  grub_size_t real_size, prot_size;
 
576
  grub_ssize_t len;
 
577
  int i;
 
578
  char *dest;
 
579
 
 
580
  grub_dl_ref (my_mod);
 
581
 
 
582
  if (argc == 0)
 
583
    {
 
584
      grub_error (GRUB_ERR_BAD_ARGUMENT, "no kernel specified");
 
585
      goto fail;
 
586
    }
 
587
 
 
588
  file = grub_file_open (argv[0]);
 
589
  if (! file)
 
590
    goto fail;
 
591
 
 
592
  if (grub_file_read (file, &lh, sizeof (lh)) != sizeof (lh))
 
593
    {
 
594
      grub_error (GRUB_ERR_READ_ERROR, "cannot read the Linux header");
 
595
      goto fail;
 
596
    }
 
597
 
 
598
  if (lh.boot_flag != grub_cpu_to_le16 (0xaa55))
 
599
    {
 
600
      grub_error (GRUB_ERR_BAD_OS, "invalid magic number");
 
601
      goto fail;
 
602
    }
 
603
 
 
604
  if (lh.setup_sects > GRUB_LINUX_MAX_SETUP_SECTS)
 
605
    {
 
606
      grub_error (GRUB_ERR_BAD_OS, "too many setup sectors");
 
607
      goto fail;
 
608
    }
 
609
 
 
610
  if (! (lh.loadflags & GRUB_LINUX_FLAG_BIG_KERNEL))
 
611
    {
 
612
      grub_error (GRUB_ERR_BAD_OS, "zImage doesn't support 32-bit boot"
 
613
#ifdef GRUB_MACHINE_PCBIOS
 
614
                  " (try with `linux16')"
 
615
#endif
 
616
                  );
 
617
      goto fail;
 
618
    }
 
619
 
 
620
  /* FIXME: 2.03 is not always good enough (Linux 2.4 can be 2.03 and
 
621
     still not support 32-bit boot.  */
 
622
  if (lh.header != grub_cpu_to_le32 (GRUB_LINUX_MAGIC_SIGNATURE)
 
623
      || grub_le_to_cpu16 (lh.version) < 0x0203)
 
624
    {
 
625
      grub_error (GRUB_ERR_BAD_OS, "version too old for 32-bit boot"
 
626
#ifdef GRUB_MACHINE_PCBIOS
 
627
                  " (try with `linux16')"
 
628
#endif
 
629
                  );
 
630
      goto fail;
 
631
    }
 
632
 
 
633
  setup_sects = lh.setup_sects;
 
634
 
 
635
  /* If SETUP_SECTS is not set, set it to the default (4).  */
 
636
  if (! setup_sects)
 
637
    setup_sects = GRUB_LINUX_DEFAULT_SETUP_SECTS;
 
638
 
 
639
  real_size = setup_sects << GRUB_DISK_SECTOR_BITS;
 
640
  prot_size = grub_file_size (file) - real_size - GRUB_DISK_SECTOR_SIZE;
 
641
 
 
642
  if (allocate_pages (prot_size))
 
643
    goto fail;
 
644
 
 
645
  params = (struct linux_kernel_params *) real_mode_mem;
 
646
  grub_memset (params, 0, GRUB_LINUX_CL_END_OFFSET);
 
647
  grub_memcpy (&params->setup_sects, &lh.setup_sects, sizeof (lh) - 0x1F1);
 
648
 
 
649
  params->ps_mouse = params->padding10 =  0;
 
650
 
 
651
  len = 0x400 - sizeof (lh);
 
652
  if (grub_file_read (file, (char *) real_mode_mem + sizeof (lh), len) != len)
 
653
    {
 
654
      grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file");
 
655
      goto fail;
 
656
    }
 
657
 
 
658
  params->type_of_loader = GRUB_LINUX_BOOT_LOADER_TYPE;
 
659
 
 
660
  /* These two are used (instead of cmd_line_ptr) by older versions of Linux,
 
661
     and otherwise ignored.  */
 
662
  params->cl_magic = GRUB_LINUX_CL_MAGIC;
 
663
  params->cl_offset = 0x1000;
 
664
 
 
665
  params->cmd_line_ptr = real_mode_target + 0x1000;
 
666
  params->ramdisk_image = 0;
 
667
  params->ramdisk_size = 0;
 
668
 
 
669
  params->heap_end_ptr = GRUB_LINUX_HEAP_END_OFFSET;
 
670
  params->loadflags |= GRUB_LINUX_FLAG_CAN_USE_HEAP;
 
671
 
 
672
  /* These are not needed to be precise, because Linux uses these values
 
673
     only to raise an error when the decompression code cannot find good
 
674
     space.  */
 
675
  params->ext_mem = ((32 * 0x100000) >> 10);
 
676
  params->alt_mem = ((32 * 0x100000) >> 10);
 
677
 
 
678
  /* Ignored by Linux.  */
 
679
  params->video_page = 0;
 
680
 
 
681
  /* Only used when `video_mode == 0x7', otherwise ignored.  */
 
682
  params->video_ega_bx = 0;
 
683
 
 
684
  params->font_size = 16; /* XXX */
 
685
 
 
686
#ifdef GRUB_MACHINE_EFI
 
687
  if (grub_le_to_cpu16 (params->version) >= 0x0206)
 
688
    {
 
689
      params->v0206.efi_signature = GRUB_LINUX_EFI_SIGNATURE;
 
690
      params->v0206.efi_system_table = (grub_uint32_t) (unsigned long) grub_efi_system_table;
 
691
#ifdef __x86_64__
 
692
      params->v0206.efi_system_table_hi = (grub_uint32_t) ((grub_uint64_t) grub_efi_system_table >> 32);
 
693
#endif
 
694
    }
 
695
  else if (grub_le_to_cpu16 (params->version) >= 0x0204)
 
696
    {
 
697
      params->v0204.efi_signature = GRUB_LINUX_EFI_SIGNATURE_0204;
 
698
      params->v0204.efi_system_table = (grub_uint32_t) (unsigned long) grub_efi_system_table;
 
699
    }
 
700
#endif
 
701
 
 
702
  /* The other parameters are filled when booting.  */
 
703
 
 
704
  grub_file_seek (file, real_size + GRUB_DISK_SECTOR_SIZE);
 
705
 
 
706
  grub_dprintf ("linux", "bzImage, setup=0x%x, size=0x%x\n",
 
707
                (unsigned) real_size, (unsigned) prot_size);
 
708
 
 
709
  /* Look for memory size and video mode specified on the command line.  */
 
710
  linux_mem_size = 0;
 
711
  for (i = 1; i < argc; i++)
 
712
#ifdef GRUB_MACHINE_PCBIOS
 
713
    if (grub_memcmp (argv[i], "vga=", 4) == 0)
 
714
      {
 
715
        /* Video mode selection support.  */
 
716
        char *val = argv[i] + 4;
 
717
        unsigned vid_mode = GRUB_LINUX_VID_MODE_NORMAL;
 
718
        struct grub_vesa_mode_table_entry *linux_mode;
 
719
        grub_err_t err;
 
720
        char *buf;
 
721
 
 
722
        grub_dl_load ("vbe");
 
723
 
 
724
        if (grub_strcmp (val, "normal") == 0)
 
725
          vid_mode = GRUB_LINUX_VID_MODE_NORMAL;
 
726
        else if (grub_strcmp (val, "ext") == 0)
 
727
          vid_mode = GRUB_LINUX_VID_MODE_EXTENDED;
 
728
        else if (grub_strcmp (val, "ask") == 0)
 
729
          {
 
730
            grub_printf ("Legacy `ask' parameter no longer supported.\n");
 
731
 
 
732
            /* We usually would never do this in a loader, but "vga=ask" means user
 
733
               requested interaction, so it can't hurt to request keyboard input.  */
 
734
            grub_wait_after_message ();
 
735
 
 
736
            goto fail;
 
737
          }
 
738
        else
 
739
          vid_mode = (grub_uint16_t) grub_strtoul (val, 0, 0);
 
740
 
 
741
        switch (vid_mode)
 
742
          {
 
743
          case 0:
 
744
          case GRUB_LINUX_VID_MODE_NORMAL:
 
745
            grub_env_set ("gfxpayload", "text");
 
746
            grub_printf ("%s is deprecated. "
 
747
                         "Use set gfxpayload=text before "
 
748
                         "linux command instead.\n",
 
749
                         argv[i]);
 
750
            break;
 
751
 
 
752
          case 1:
 
753
          case GRUB_LINUX_VID_MODE_EXTENDED:
 
754
            /* FIXME: support 80x50 text. */
 
755
            grub_env_set ("gfxpayload", "text");
 
756
            grub_printf ("%s is deprecated. "
 
757
                         "Use set gfxpayload=text before "
 
758
                         "linux command instead.\n",
 
759
                         argv[i]);
 
760
            break;
 
761
          default:
 
762
            /* Ignore invalid values.  */
 
763
            if (vid_mode < GRUB_VESA_MODE_TABLE_START ||
 
764
                vid_mode > GRUB_VESA_MODE_TABLE_END)
 
765
              {
 
766
                grub_env_set ("gfxpayload", "text");
 
767
                grub_printf ("%s is deprecated. Mode %d isn't recognized. "
 
768
                             "Use set gfxpayload=WIDTHxHEIGHT[xDEPTH] before "
 
769
                             "linux command instead.\n",
 
770
                             argv[i], vid_mode);
 
771
                break;
 
772
              }
 
773
 
 
774
            /* We can't detect VESA, but user is implicitly telling us that it
 
775
               is built-in because `vga=' parameter was used.  */
 
776
            params->have_vga = GRUB_VIDEO_LINUX_TYPE_VESA;
 
777
 
 
778
            linux_mode = &grub_vesa_mode_table[vid_mode
 
779
                                               - GRUB_VESA_MODE_TABLE_START];
 
780
 
 
781
            buf = grub_xasprintf ("%ux%ux%u,%ux%u",
 
782
                                 linux_mode->width, linux_mode->height,
 
783
                                 linux_mode->depth,
 
784
                                 linux_mode->width, linux_mode->height);
 
785
            if (! buf)
 
786
              goto fail;
 
787
 
 
788
            grub_printf ("%s is deprecated. "
 
789
                         "Use set gfxpayload=%s before "
 
790
                         "linux command instead.\n",
 
791
                         argv[i], buf);
 
792
            err = grub_env_set ("gfxpayload", buf);
 
793
            grub_free (buf);
 
794
            if (err)
 
795
              goto fail;
 
796
          }
 
797
      }
 
798
    else
 
799
#endif /* GRUB_MACHINE_PCBIOS */
 
800
    if (grub_memcmp (argv[i], "mem=", 4) == 0)
 
801
      {
 
802
        char *val = argv[i] + 4;
 
803
 
 
804
        linux_mem_size = grub_strtoul (val, &val, 0);
 
805
 
 
806
        if (grub_errno)
 
807
          {
 
808
            grub_errno = GRUB_ERR_NONE;
 
809
            linux_mem_size = 0;
 
810
          }
 
811
        else
 
812
          {
 
813
            int shift = 0;
 
814
 
 
815
            switch (grub_tolower (val[0]))
 
816
              {
 
817
              case 'g':
 
818
                shift += 10;
 
819
              case 'm':
 
820
                shift += 10;
 
821
              case 'k':
 
822
                shift += 10;
 
823
              default:
 
824
                break;
 
825
              }
 
826
 
 
827
            /* Check an overflow.  */
 
828
            if (linux_mem_size > (~0UL >> shift))
 
829
              linux_mem_size = 0;
 
830
            else
 
831
              linux_mem_size <<= shift;
 
832
          }
 
833
      }
 
834
    else if (grub_memcmp (argv[i], "quiet", sizeof ("quiet") - 1) == 0)
 
835
      {
 
836
        params->loadflags |= GRUB_LINUX_FLAG_QUIET;
 
837
      }
 
838
 
 
839
 
 
840
  /* Specify the boot file.  */
 
841
  dest = grub_stpcpy ((char *) real_mode_mem + GRUB_LINUX_CL_OFFSET,
 
842
                      "BOOT_IMAGE=");
 
843
  dest = grub_stpcpy (dest, argv[0]);
 
844
 
 
845
  /* Copy kernel parameters.  */
 
846
  for (i = 1;
 
847
       i < argc
 
848
         && dest + grub_strlen (argv[i]) + 1 < ((char *) real_mode_mem
 
849
                                                + GRUB_LINUX_CL_END_OFFSET);
 
850
       i++)
 
851
    {
 
852
      *dest++ = ' ';
 
853
      dest = grub_stpcpy (dest, argv[i]);
 
854
    }
 
855
 
 
856
  len = prot_size;
 
857
  if (grub_file_read (file, prot_mode_mem, len) != len)
 
858
    grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file");
 
859
 
 
860
  if (grub_errno == GRUB_ERR_NONE)
 
861
    {
 
862
      grub_loader_set (grub_linux_boot, grub_linux_unload,
 
863
                       0 /* set noreturn=0 in order to avoid grub_console_fini() */);
 
864
      loaded = 1;
 
865
    }
 
866
 
 
867
 fail:
 
868
 
 
869
  if (file)
 
870
    grub_file_close (file);
 
871
 
 
872
  if (grub_errno != GRUB_ERR_NONE)
 
873
    {
 
874
      grub_dl_unref (my_mod);
 
875
      loaded = 0;
 
876
    }
 
877
 
 
878
  return grub_errno;
 
879
}
 
880
 
 
881
static grub_err_t
 
882
grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
 
883
                 int argc, char *argv[])
 
884
{
 
885
  grub_file_t file = 0;
 
886
  grub_ssize_t size;
 
887
  grub_addr_t addr_min, addr_max;
 
888
  grub_addr_t addr;
 
889
  grub_err_t err;
 
890
  struct linux_kernel_header *lh;
 
891
 
 
892
  if (argc == 0)
 
893
    {
 
894
      grub_error (GRUB_ERR_BAD_ARGUMENT, "no module specified");
 
895
      goto fail;
 
896
    }
 
897
 
 
898
  if (! loaded)
 
899
    {
 
900
      grub_error (GRUB_ERR_BAD_ARGUMENT, "you need to load the kernel first");
 
901
      goto fail;
 
902
    }
 
903
 
 
904
  grub_file_filter_disable_compression ();
 
905
  file = grub_file_open (argv[0]);
 
906
  if (! file)
 
907
    goto fail;
 
908
 
 
909
  size = grub_file_size (file);
 
910
  initrd_pages = (page_align (size) >> 12);
 
911
 
 
912
  lh = (struct linux_kernel_header *) real_mode_mem;
 
913
 
 
914
  /* Get the highest address available for the initrd.  */
 
915
  if (grub_le_to_cpu16 (lh->version) >= 0x0203)
 
916
    {
 
917
      addr_max = grub_cpu_to_le32 (lh->initrd_addr_max);
 
918
 
 
919
      /* XXX in reality, Linux specifies a bogus value, so
 
920
         it is necessary to make sure that ADDR_MAX does not exceed
 
921
         0x3fffffff.  */
 
922
      if (addr_max > GRUB_LINUX_INITRD_MAX_ADDRESS)
 
923
        addr_max = GRUB_LINUX_INITRD_MAX_ADDRESS;
 
924
    }
 
925
  else
 
926
    addr_max = GRUB_LINUX_INITRD_MAX_ADDRESS;
 
927
 
 
928
  if (linux_mem_size != 0 && linux_mem_size < addr_max)
 
929
    addr_max = linux_mem_size;
 
930
 
 
931
  /* Linux 2.3.xx has a bug in the memory range check, so avoid
 
932
     the last page.
 
933
     Linux 2.2.xx has a bug in the memory range check, which is
 
934
     worse than that of Linux 2.3.xx, so avoid the last 64kb.  */
 
935
  addr_max -= 0x10000;
 
936
 
 
937
  /* Usually, the compression ratio is about 50%.  */
 
938
  addr_min = (grub_addr_t) prot_mode_target + ((prot_mode_pages * 3) << 12)
 
939
             + page_align (size);
 
940
 
 
941
  /* Put the initrd as high as possible, 4KiB aligned.  */
 
942
  addr = (addr_max - size) & ~0xFFF;
 
943
 
 
944
  if (addr < addr_min)
 
945
    {
 
946
      grub_error (GRUB_ERR_OUT_OF_RANGE, "the initrd is too big");
 
947
      goto fail;
 
948
    }
 
949
 
 
950
  {
 
951
    grub_relocator_chunk_t ch;
 
952
    err = grub_relocator_alloc_chunk_align (relocator, &ch,
 
953
                                            addr_min, addr, size, 0x1000,
 
954
                                            GRUB_RELOCATOR_PREFERENCE_HIGH);
 
955
    if (err)
 
956
      return err;
 
957
    initrd_mem = get_virtual_current_address (ch);
 
958
    initrd_mem_target = get_physical_target_address (ch);
 
959
  }
 
960
 
 
961
  if (grub_file_read (file, initrd_mem, size) != size)
 
962
    {
 
963
      grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file");
 
964
      goto fail;
 
965
    }
 
966
 
 
967
  grub_dprintf ("linux", "Initrd, addr=0x%x, size=0x%x\n",
 
968
                (unsigned) addr, (unsigned) size);
 
969
 
 
970
  lh->ramdisk_image = initrd_mem_target;
 
971
  lh->ramdisk_size = size;
 
972
  lh->root_dev = 0x0100; /* XXX */
 
973
 
 
974
 fail:
 
975
  if (file)
 
976
    grub_file_close (file);
 
977
 
 
978
  return grub_errno;
 
979
}
 
980
 
 
981
static grub_command_t cmd_linux, cmd_initrd;
 
982
 
 
983
GRUB_MOD_INIT(linux)
 
984
{
 
985
  cmd_linux = grub_register_command ("linux", grub_cmd_linux,
 
986
                                     0, N_("Load Linux."));
 
987
  cmd_initrd = grub_register_command ("initrd", grub_cmd_initrd,
 
988
                                      0, N_("Load initrd."));
 
989
  my_mod = mod;
 
990
}
 
991
 
 
992
GRUB_MOD_FINI(linux)
 
993
{
 
994
  grub_unregister_command (cmd_linux);
 
995
  grub_unregister_command (cmd_initrd);
 
996
}