~psusi/ubuntu/saucy/grub2/fix-dmraid

« back to all changes in this revision

Viewing changes to .pc/ubuntu_initrd_addr_min.patch/grub-core/loader/i386/linux.c

  • Committer: Package Import Robot
  • Author(s): Colin Watson
  • Date: 2013-01-03 11:40:44 UTC
  • mfrom: (17.6.31 experimental)
  • Revision ID: package-import@ubuntu.com-20130103114044-et8gar9lol415wc9
Tags: 2.00-10ubuntu1
* Resynchronise with Debian.  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 and an appropriate background for Ubuntu.
  - Apply Ubuntu GRUB Legacy changes to legacy update-grub script.
  - Fix backslash-escaping in merge_debconf_into_conf.
  - Remove "GNU/Linux" from default distributor string.
  - Add crashkernel option.
  - Bypass menu unless other OSes are installed or Shift is pressed.
  - Allow Shift to interrupt 'sleep --interruptible'.
  - Reduce visual clutter in normal mode.
  - Remove verbose messages printed before reading configuration.
  - Suppress kernel/initrd progress messages, except in recovery mode.
  - Show the boot menu if the previous boot failed.
  - Adjust upgrade version checks for Ubuntu.
  - Suppress "GRUB loading" message unless Shift is held down.
  - Adjust versions of grub-doc and grub-legacy-doc conflicts.
  - Build-depend on qemu-kvm rather than qemu-system for grub-pc tests.
  - Check hardware support before using gfxpayload=keep.
  - Set vt.handoff=7 for smooth handoff to kernel graphical mode.
  - In recovery mode, add nomodeset to the Linux kernel arguments, and
    remove the 'set gfxpayload=keep' command.
  - Skip Windows os-prober entries on Wubi systems, and suppress the menu
    by default if those are the only other-OS entries.
  - Handle probing striped DM-RAID devices.
  - Replace 'single' by 'recovery' when friendly-recovery is installed.
  - Disable cursor as early as possible in grub_main.
  - Apply patch from Fedora to add a "linuxefi" loader.
  - Automatically call linuxefi from linux when necessary.
  - On amd64, add raw-uefi custom upload tarballs for signing.
  - Generate configuration for signed UEFI kernels if available.
  - Install signed images if UEFI Secure Boot is enabled.
  - Output a menu entry for firmware setup on UEFI FastBoot systems.
  - Stop using the /usr/share/images/desktop-base/desktop-grub.png
    alternative as the fallback background.
  - If the postinst is running in a container, skip grub-install and all
    its associated questions.

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
 
#include <grub/lib/cmdline.h>
37
 
 
38
 
GRUB_MOD_LICENSE ("GPLv3+");
39
 
 
40
 
#ifdef GRUB_MACHINE_PCBIOS
41
 
#include <grub/i386/pc/vesa_modes_table.h>
42
 
#endif
43
 
 
44
 
#ifdef GRUB_MACHINE_EFI
45
 
#include <grub/efi/efi.h>
46
 
#define HAS_VGA_TEXT 0
47
 
#define DEFAULT_VIDEO_MODE "auto"
48
 
#define ACCEPTS_PURE_TEXT 0
49
 
#elif defined (GRUB_MACHINE_IEEE1275)
50
 
#include <grub/ieee1275/ieee1275.h>
51
 
#define HAS_VGA_TEXT 0
52
 
#define DEFAULT_VIDEO_MODE "text"
53
 
#define ACCEPTS_PURE_TEXT 1
54
 
#else
55
 
#include <grub/i386/pc/vbe.h>
56
 
#include <grub/i386/pc/console.h>
57
 
#define HAS_VGA_TEXT 1
58
 
#define DEFAULT_VIDEO_MODE "text"
59
 
#define ACCEPTS_PURE_TEXT 1
60
 
#endif
61
 
 
62
 
static grub_dl_t my_mod;
63
 
 
64
 
static grub_size_t linux_mem_size;
65
 
static int loaded;
66
 
static void *prot_mode_mem;
67
 
static grub_addr_t prot_mode_target;
68
 
static void *initrd_mem;
69
 
static grub_addr_t initrd_mem_target;
70
 
static grub_size_t prot_init_space;
71
 
static grub_uint32_t initrd_pages;
72
 
static struct grub_relocator *relocator = NULL;
73
 
static void *efi_mmap_buf;
74
 
static grub_size_t maximal_cmdline_size;
75
 
static struct linux_kernel_params linux_params;
76
 
static char *linux_cmdline;
77
 
#ifdef GRUB_MACHINE_EFI
78
 
static int using_linuxefi;
79
 
static grub_command_t initrdefi_cmd;
80
 
static grub_efi_uintn_t efi_mmap_size;
81
 
#else
82
 
static const grub_size_t efi_mmap_size = 0;
83
 
#endif
84
 
 
85
 
/* FIXME */
86
 
#if 0
87
 
struct idt_descriptor
88
 
{
89
 
  grub_uint16_t limit;
90
 
  void *base;
91
 
} __attribute__ ((packed));
92
 
 
93
 
static struct idt_descriptor idt_desc =
94
 
  {
95
 
    0,
96
 
    0
97
 
  };
98
 
#endif
99
 
 
100
 
static inline grub_size_t
101
 
page_align (grub_size_t size)
102
 
{
103
 
  return (size + (1 << 12) - 1) & (~((1 << 12) - 1));
104
 
}
105
 
 
106
 
#ifdef GRUB_MACHINE_EFI
107
 
/* Find the optimal number of pages for the memory map. Is it better to
108
 
   move this code to efi/mm.c?  */
109
 
static grub_efi_uintn_t
110
 
find_efi_mmap_size (void)
111
 
{
112
 
  static grub_efi_uintn_t mmap_size = 0;
113
 
 
114
 
  if (mmap_size != 0)
115
 
    return mmap_size;
116
 
 
117
 
  mmap_size = (1 << 12);
118
 
  while (1)
119
 
    {
120
 
      int ret;
121
 
      grub_efi_memory_descriptor_t *mmap;
122
 
      grub_efi_uintn_t desc_size;
123
 
      grub_efi_uintn_t cur_mmap_size = mmap_size;
124
 
 
125
 
      mmap = grub_malloc (cur_mmap_size);
126
 
      if (! mmap)
127
 
        return 0;
128
 
 
129
 
      ret = grub_efi_get_memory_map (&cur_mmap_size, mmap, 0, &desc_size, 0);
130
 
      grub_free (mmap);
131
 
 
132
 
      if (ret < 0)
133
 
        {
134
 
          grub_error (GRUB_ERR_IO, "cannot get memory map");
135
 
          return 0;
136
 
        }
137
 
      else if (ret > 0)
138
 
        break;
139
 
 
140
 
      if (mmap_size < cur_mmap_size)
141
 
        mmap_size = cur_mmap_size;
142
 
      mmap_size += (1 << 12);
143
 
    }
144
 
 
145
 
  /* Increase the size a bit for safety, because GRUB allocates more on
146
 
     later, and EFI itself may allocate more.  */
147
 
  mmap_size += (3 << 12);
148
 
 
149
 
  mmap_size = page_align (mmap_size);
150
 
  return mmap_size;
151
 
}
152
 
 
153
 
#endif
154
 
 
155
 
/* Find the optimal number of pages for the memory map. */
156
 
static grub_size_t
157
 
find_mmap_size (void)
158
 
{
159
 
  grub_size_t count = 0, mmap_size;
160
 
 
161
 
  auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t,
162
 
                                  grub_memory_type_t);
163
 
  int NESTED_FUNC_ATTR hook (grub_uint64_t addr __attribute__ ((unused)),
164
 
                             grub_uint64_t size __attribute__ ((unused)),
165
 
                             grub_memory_type_t type __attribute__ ((unused)))
166
 
    {
167
 
      count++;
168
 
      return 0;
169
 
    }
170
 
 
171
 
  grub_mmap_iterate (hook);
172
 
 
173
 
  mmap_size = count * sizeof (struct grub_e820_mmap);
174
 
 
175
 
  /* Increase the size a bit for safety, because GRUB allocates more on
176
 
     later.  */
177
 
  mmap_size += (1 << 12);
178
 
 
179
 
  return page_align (mmap_size);
180
 
}
181
 
 
182
 
static void
183
 
free_pages (void)
184
 
{
185
 
  grub_relocator_unload (relocator);
186
 
  relocator = NULL;
187
 
  prot_mode_mem = initrd_mem = 0;
188
 
  prot_mode_target = initrd_mem_target = 0;
189
 
}
190
 
 
191
 
/* Allocate pages for the real mode code and the protected mode code
192
 
   for linux as well as a memory map buffer.  */
193
 
static grub_err_t
194
 
allocate_pages (grub_size_t prot_size, grub_size_t *align,
195
 
                grub_size_t min_align, int relocatable,
196
 
                grub_uint64_t prefered_address)
197
 
{
198
 
  grub_err_t err;
199
 
 
200
 
  prot_size = page_align (prot_size);
201
 
 
202
 
  /* Initialize the memory pointers with NULL for convenience.  */
203
 
  free_pages ();
204
 
 
205
 
  relocator = grub_relocator_new ();
206
 
  if (!relocator)
207
 
    {
208
 
      err = grub_errno;
209
 
      goto fail;
210
 
    }
211
 
 
212
 
  /* FIXME: Should request low memory from the heap when this feature is
213
 
     implemented.  */
214
 
 
215
 
  {
216
 
    grub_relocator_chunk_t ch;
217
 
    if (relocatable)
218
 
      {
219
 
        err = grub_relocator_alloc_chunk_align (relocator, &ch,
220
 
                                                prefered_address,
221
 
                                                prefered_address,
222
 
                                                prot_size, 1,
223
 
                                                GRUB_RELOCATOR_PREFERENCE_LOW,
224
 
                                                1);
225
 
        for (; err && *align + 1 > min_align; (*align)--)
226
 
          {
227
 
            grub_errno = GRUB_ERR_NONE;
228
 
            err = grub_relocator_alloc_chunk_align (relocator, &ch,
229
 
                                                    0x1000000,
230
 
                                                    0xffffffff & ~prot_size,
231
 
                                                    prot_size, 1 << *align,
232
 
                                                    GRUB_RELOCATOR_PREFERENCE_LOW,
233
 
                                                    1);
234
 
          }
235
 
        if (err)
236
 
          goto fail;
237
 
      }
238
 
    else
239
 
      err = grub_relocator_alloc_chunk_addr (relocator, &ch,
240
 
                                             prefered_address,
241
 
                                             prot_size);
242
 
    if (err)
243
 
      goto fail;
244
 
    prot_mode_mem = get_virtual_current_address (ch);
245
 
    prot_mode_target = get_physical_target_address (ch);
246
 
  }
247
 
 
248
 
  grub_dprintf ("linux", "prot_mode_mem = %lx, prot_mode_target = %lx, prot_size = %x\n",
249
 
                (unsigned long) prot_mode_mem, (unsigned long) prot_mode_target,
250
 
                (unsigned) prot_size);
251
 
  return GRUB_ERR_NONE;
252
 
 
253
 
 fail:
254
 
  free_pages ();
255
 
  return err;
256
 
}
257
 
 
258
 
static grub_err_t
259
 
grub_e820_add_region (struct grub_e820_mmap *e820_map, int *e820_num,
260
 
                      grub_uint64_t start, grub_uint64_t size,
261
 
                      grub_uint32_t type)
262
 
{
263
 
  int n = *e820_num;
264
 
 
265
 
  if ((n > 0) && (e820_map[n - 1].addr + e820_map[n - 1].size == start) &&
266
 
      (e820_map[n - 1].type == type))
267
 
      e820_map[n - 1].size += size;
268
 
  else
269
 
    {
270
 
      e820_map[n].addr = start;
271
 
      e820_map[n].size = size;
272
 
      e820_map[n].type = type;
273
 
      (*e820_num)++;
274
 
    }
275
 
  return GRUB_ERR_NONE;
276
 
}
277
 
 
278
 
static grub_err_t
279
 
grub_linux_setup_video (struct linux_kernel_params *params)
280
 
{
281
 
  struct grub_video_mode_info mode_info;
282
 
  void *framebuffer;
283
 
  grub_err_t err;
284
 
  grub_video_driver_id_t driver_id;
285
 
  const char *gfxlfbvar = grub_env_get ("gfxpayloadforcelfb");
286
 
 
287
 
  driver_id = grub_video_get_driver_id ();
288
 
 
289
 
  if (driver_id == GRUB_VIDEO_DRIVER_NONE)
290
 
    return 1;
291
 
 
292
 
  err = grub_video_get_info_and_fini (&mode_info, &framebuffer);
293
 
 
294
 
  if (err)
295
 
    {
296
 
      grub_errno = GRUB_ERR_NONE;
297
 
      return 1;
298
 
    }
299
 
 
300
 
  params->lfb_width = mode_info.width;
301
 
  params->lfb_height = mode_info.height;
302
 
  params->lfb_depth = mode_info.bpp;
303
 
  params->lfb_line_len = mode_info.pitch;
304
 
 
305
 
  params->lfb_base = (grub_size_t) framebuffer;
306
 
  params->lfb_size = ALIGN_UP (params->lfb_line_len * params->lfb_height, 65536);
307
 
 
308
 
  params->red_mask_size = mode_info.red_mask_size;
309
 
  params->red_field_pos = mode_info.red_field_pos;
310
 
  params->green_mask_size = mode_info.green_mask_size;
311
 
  params->green_field_pos = mode_info.green_field_pos;
312
 
  params->blue_mask_size = mode_info.blue_mask_size;
313
 
  params->blue_field_pos = mode_info.blue_field_pos;
314
 
  params->reserved_mask_size = mode_info.reserved_mask_size;
315
 
  params->reserved_field_pos = mode_info.reserved_field_pos;
316
 
 
317
 
  if (gfxlfbvar && (gfxlfbvar[0] == '1' || gfxlfbvar[0] == 'y'))
318
 
    params->have_vga = GRUB_VIDEO_LINUX_TYPE_SIMPLE;
319
 
  else
320
 
    {
321
 
      switch (driver_id)
322
 
        {
323
 
        case GRUB_VIDEO_DRIVER_VBE:
324
 
          params->lfb_size >>= 16;
325
 
          params->have_vga = GRUB_VIDEO_LINUX_TYPE_VESA;
326
 
          break;
327
 
        
328
 
        case GRUB_VIDEO_DRIVER_EFI_UGA:
329
 
        case GRUB_VIDEO_DRIVER_EFI_GOP:
330
 
          params->have_vga = GRUB_VIDEO_LINUX_TYPE_EFIFB;
331
 
          break;
332
 
 
333
 
          /* FIXME: check if better id is available.  */
334
 
        case GRUB_VIDEO_DRIVER_SM712:
335
 
        case GRUB_VIDEO_DRIVER_SIS315PRO:
336
 
        case GRUB_VIDEO_DRIVER_VGA:
337
 
        case GRUB_VIDEO_DRIVER_CIRRUS:
338
 
        case GRUB_VIDEO_DRIVER_BOCHS:
339
 
        case GRUB_VIDEO_DRIVER_RADEON_FULOONG2E:
340
 
          /* Make gcc happy. */
341
 
        case GRUB_VIDEO_DRIVER_SDL:
342
 
        case GRUB_VIDEO_DRIVER_NONE:
343
 
          params->have_vga = GRUB_VIDEO_LINUX_TYPE_SIMPLE;
344
 
          break;
345
 
        }
346
 
    }
347
 
 
348
 
#ifdef GRUB_MACHINE_PCBIOS
349
 
  /* VESA packed modes may come with zeroed mask sizes, which need
350
 
     to be set here according to DAC Palette width.  If we don't,
351
 
     this results in Linux displaying a black screen.  */
352
 
  if (driver_id == GRUB_VIDEO_DRIVER_VBE && mode_info.bpp <= 8)
353
 
    {
354
 
      struct grub_vbe_info_block controller_info;
355
 
      int status;
356
 
      int width = 8;
357
 
 
358
 
      status = grub_vbe_bios_get_controller_info (&controller_info);
359
 
 
360
 
      if (status == GRUB_VBE_STATUS_OK &&
361
 
          (controller_info.capabilities & GRUB_VBE_CAPABILITY_DACWIDTH))
362
 
        status = grub_vbe_bios_set_dac_palette_width (&width);
363
 
 
364
 
      if (status != GRUB_VBE_STATUS_OK)
365
 
        /* 6 is default after mode reset.  */
366
 
        width = 6;
367
 
 
368
 
      params->red_mask_size = params->green_mask_size
369
 
        = params->blue_mask_size = width;
370
 
      params->reserved_mask_size = 0;
371
 
    }
372
 
#endif
373
 
 
374
 
  return GRUB_ERR_NONE;
375
 
}
376
 
 
377
 
static grub_err_t
378
 
grub_linux_boot (void)
379
 
{
380
 
  int e820_num;
381
 
  grub_err_t err = 0;
382
 
  const char *modevar;
383
 
  char *tmp;
384
 
  struct grub_relocator32_state state;
385
 
  void *real_mode_mem;
386
 
  grub_addr_t real_mode_target = 0;
387
 
  grub_size_t real_size, mmap_size;
388
 
  grub_size_t cl_offset;
389
 
 
390
 
#ifdef GRUB_MACHINE_IEEE1275
391
 
  {
392
 
    const char *bootpath;
393
 
    grub_ssize_t len;
394
 
 
395
 
    bootpath = grub_env_get ("root");
396
 
    if (bootpath)
397
 
      grub_ieee1275_set_property (grub_ieee1275_chosen,
398
 
                                  "bootpath", bootpath,
399
 
                                  grub_strlen (bootpath) + 1,
400
 
                                  &len);
401
 
    linux_params.ofw_signature = GRUB_LINUX_OFW_SIGNATURE;
402
 
    linux_params.ofw_num_items = 1;
403
 
    linux_params.ofw_cif_handler = (grub_uint32_t) grub_ieee1275_entry_fn;
404
 
    linux_params.ofw_idt = 0;
405
 
  }
406
 
#endif
407
 
 
408
 
  modevar = grub_env_get ("gfxpayload");
409
 
 
410
 
  /* Now all graphical modes are acceptable.
411
 
     May change in future if we have modes without framebuffer.  */
412
 
  if (modevar && *modevar != 0)
413
 
    {
414
 
      tmp = grub_xasprintf ("%s;" DEFAULT_VIDEO_MODE, modevar);
415
 
      if (! tmp)
416
 
        return grub_errno;
417
 
#if ACCEPTS_PURE_TEXT
418
 
      err = grub_video_set_mode (tmp, 0, 0);
419
 
#else
420
 
      err = grub_video_set_mode (tmp, GRUB_VIDEO_MODE_TYPE_PURE_TEXT, 0);
421
 
#endif
422
 
      grub_free (tmp);
423
 
    }
424
 
  else
425
 
    {
426
 
#if ACCEPTS_PURE_TEXT
427
 
      err = grub_video_set_mode (DEFAULT_VIDEO_MODE, 0, 0);
428
 
#else
429
 
      err = grub_video_set_mode (DEFAULT_VIDEO_MODE,
430
 
                                 GRUB_VIDEO_MODE_TYPE_PURE_TEXT, 0);
431
 
#endif
432
 
    }
433
 
 
434
 
  if (err)
435
 
    {
436
 
      grub_print_error ();
437
 
      grub_puts_ (N_("Booting in blind mode"));
438
 
      grub_errno = GRUB_ERR_NONE;
439
 
    }
440
 
 
441
 
  if (grub_linux_setup_video (&linux_params))
442
 
    {
443
 
#if defined (GRUB_MACHINE_PCBIOS) || defined (GRUB_MACHINE_COREBOOT) || defined (GRUB_MACHINE_QEMU)
444
 
      linux_params.have_vga = GRUB_VIDEO_LINUX_TYPE_TEXT;
445
 
      linux_params.video_mode = 0x3;
446
 
#else
447
 
      linux_params.have_vga = 0;
448
 
      linux_params.video_mode = 0;
449
 
      linux_params.video_width = 0;
450
 
      linux_params.video_height = 0;
451
 
#endif
452
 
    }
453
 
 
454
 
 
455
 
#ifndef GRUB_MACHINE_IEEE1275
456
 
  if (linux_params.have_vga == GRUB_VIDEO_LINUX_TYPE_TEXT)
457
 
#endif
458
 
    {
459
 
      grub_term_output_t term;
460
 
      int found = 0;
461
 
      FOR_ACTIVE_TERM_OUTPUTS(term)
462
 
        if (grub_strcmp (term->name, "vga_text") == 0
463
 
            || grub_strcmp (term->name, "console") == 0
464
 
            || grub_strcmp (term->name, "ofconsole") == 0)
465
 
          {
466
 
            grub_uint16_t pos = grub_term_getxy (term);
467
 
            linux_params.video_cursor_x = pos >> 8;
468
 
            linux_params.video_cursor_y = pos & 0xff;
469
 
            linux_params.video_width = grub_term_width (term);
470
 
            linux_params.video_height = grub_term_height (term);
471
 
            found = 1;
472
 
            break;
473
 
          }
474
 
      if (!found)
475
 
        {
476
 
          linux_params.video_cursor_x = 0;
477
 
          linux_params.video_cursor_y = 0;
478
 
          linux_params.video_width = 80;
479
 
          linux_params.video_height = 25;
480
 
        }
481
 
    }
482
 
 
483
 
  mmap_size = find_mmap_size ();
484
 
  /* Make sure that each size is aligned to a page boundary.  */
485
 
  cl_offset = ALIGN_UP (mmap_size + sizeof (linux_params), 4096);
486
 
  if (cl_offset < ((grub_size_t) linux_params.setup_sects << GRUB_DISK_SECTOR_BITS))
487
 
    cl_offset = ALIGN_UP ((grub_size_t) (linux_params.setup_sects
488
 
                                         << GRUB_DISK_SECTOR_BITS), 4096);
489
 
  real_size = ALIGN_UP (cl_offset + maximal_cmdline_size, 4096);
490
 
 
491
 
#ifdef GRUB_MACHINE_EFI
492
 
  efi_mmap_size = find_efi_mmap_size ();
493
 
  if (efi_mmap_size == 0)
494
 
    return grub_errno;
495
 
#endif
496
 
 
497
 
  grub_dprintf ("linux", "real_size = %x, mmap_size = %x\n",
498
 
                (unsigned) real_size, (unsigned) mmap_size);
499
 
 
500
 
  auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t,
501
 
                                  grub_memory_type_t);
502
 
  int NESTED_FUNC_ATTR hook (grub_uint64_t addr, grub_uint64_t size,
503
 
                             grub_memory_type_t type)
504
 
    {
505
 
      /* We must put real mode code in the traditional space.  */
506
 
      if (type != GRUB_MEMORY_AVAILABLE || addr > 0x90000)
507
 
        return 0;
508
 
 
509
 
      if (addr + size < 0x10000)
510
 
        return 0;
511
 
 
512
 
      if (addr < 0x10000)
513
 
        {
514
 
          size += addr - 0x10000;
515
 
          addr = 0x10000;
516
 
        }
517
 
 
518
 
      if (addr + size > 0x90000)
519
 
        size = 0x90000 - addr;
520
 
 
521
 
      if (real_size + efi_mmap_size > size)
522
 
        return 0;
523
 
 
524
 
      grub_dprintf ("linux", "addr = %lx, size = %x, need_size = %x\n",
525
 
                    (unsigned long) addr,
526
 
                    (unsigned) size,
527
 
                    (unsigned) (real_size + efi_mmap_size));
528
 
      real_mode_target = ((addr + size) - (real_size + efi_mmap_size));
529
 
      return 1;
530
 
    }
531
 
#ifdef GRUB_MACHINE_EFI
532
 
  grub_efi_mmap_iterate (hook, 1);
533
 
  if (! real_mode_target)
534
 
    grub_efi_mmap_iterate (hook, 0);
535
 
#else
536
 
  grub_mmap_iterate (hook);
537
 
#endif
538
 
  grub_dprintf ("linux", "real_mode_target = %lx, real_size = %x, efi_mmap_size = %x\n",
539
 
                (unsigned long) real_mode_target,
540
 
                (unsigned) real_size,
541
 
                (unsigned) efi_mmap_size);
542
 
 
543
 
  if (! real_mode_target)
544
 
    return grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate real mode pages");
545
 
 
546
 
  {
547
 
    grub_relocator_chunk_t ch;
548
 
    err = grub_relocator_alloc_chunk_addr (relocator, &ch,
549
 
                                           real_mode_target,
550
 
                                           (real_size + efi_mmap_size));
551
 
    if (err)
552
 
     return err;
553
 
    real_mode_mem = get_virtual_current_address (ch);
554
 
  }
555
 
  efi_mmap_buf = (grub_uint8_t *) real_mode_mem + real_size;
556
 
 
557
 
  grub_dprintf ("linux", "real_mode_mem = %lx\n",
558
 
                (unsigned long) real_mode_mem);
559
 
 
560
 
  struct linux_kernel_params *params;
561
 
 
562
 
  params = real_mode_mem;
563
 
 
564
 
  *params = linux_params;
565
 
  params->cmd_line_ptr = real_mode_target + cl_offset;
566
 
  grub_memcpy ((char *) params + cl_offset, linux_cmdline,
567
 
               maximal_cmdline_size);
568
 
 
569
 
  grub_dprintf ("linux", "code32_start = %x\n",
570
 
                (unsigned) params->code32_start);
571
 
 
572
 
  auto int NESTED_FUNC_ATTR hook_fill (grub_uint64_t, grub_uint64_t,
573
 
                                  grub_memory_type_t);
574
 
  int NESTED_FUNC_ATTR hook_fill (grub_uint64_t addr, grub_uint64_t size, 
575
 
                                  grub_memory_type_t type)
576
 
    {
577
 
      grub_uint32_t e820_type;
578
 
      switch (type)
579
 
        {
580
 
        case GRUB_MEMORY_AVAILABLE:
581
 
          e820_type = GRUB_E820_RAM;
582
 
          break;
583
 
 
584
 
        case GRUB_MEMORY_ACPI:
585
 
          e820_type = GRUB_E820_ACPI;
586
 
          break;
587
 
 
588
 
        case GRUB_MEMORY_NVS:
589
 
          e820_type = GRUB_E820_NVS;
590
 
          break;
591
 
 
592
 
        case GRUB_MEMORY_BADRAM:
593
 
          e820_type = GRUB_E820_BADRAM;
594
 
          break;
595
 
 
596
 
        default:
597
 
          e820_type = GRUB_E820_RESERVED;
598
 
        }
599
 
      if (grub_e820_add_region (params->e820_map, &e820_num,
600
 
                                addr, size, e820_type))
601
 
        return 1;
602
 
 
603
 
      return 0;
604
 
    }
605
 
 
606
 
  e820_num = 0;
607
 
  if (grub_mmap_iterate (hook_fill))
608
 
    return grub_errno;
609
 
  params->mmap_size = e820_num;
610
 
 
611
 
#ifdef GRUB_MACHINE_EFI
612
 
  {
613
 
    grub_efi_uintn_t efi_desc_size;
614
 
    grub_size_t efi_mmap_target;
615
 
    grub_efi_uint32_t efi_desc_version;
616
 
    err = grub_efi_finish_boot_services (&efi_mmap_size, efi_mmap_buf, NULL,
617
 
                                         &efi_desc_size, &efi_desc_version);
618
 
    if (err)
619
 
      return err;
620
 
    
621
 
    /* Note that no boot services are available from here.  */
622
 
    efi_mmap_target = real_mode_target 
623
 
      + ((grub_uint8_t *) efi_mmap_buf - (grub_uint8_t *) real_mode_mem);
624
 
    /* Pass EFI parameters.  */
625
 
    if (grub_le_to_cpu16 (params->version) >= 0x0208)
626
 
      {
627
 
        params->v0208.efi_mem_desc_size = efi_desc_size;
628
 
        params->v0208.efi_mem_desc_version = efi_desc_version;
629
 
        params->v0208.efi_mmap = efi_mmap_target;
630
 
        params->v0208.efi_mmap_size = efi_mmap_size;
631
 
 
632
 
#ifdef __x86_64__
633
 
        params->v0208.efi_mmap_hi = (efi_mmap_target >> 32);
634
 
#endif
635
 
      }
636
 
    else if (grub_le_to_cpu16 (params->version) >= 0x0206)
637
 
      {
638
 
        params->v0206.efi_mem_desc_size = efi_desc_size;
639
 
        params->v0206.efi_mem_desc_version = efi_desc_version;
640
 
        params->v0206.efi_mmap = efi_mmap_target;
641
 
        params->v0206.efi_mmap_size = efi_mmap_size;
642
 
      }
643
 
    else if (grub_le_to_cpu16 (params->version) >= 0x0204)
644
 
      {
645
 
        params->v0204.efi_mem_desc_size = efi_desc_size;
646
 
        params->v0204.efi_mem_desc_version = efi_desc_version;
647
 
        params->v0204.efi_mmap = efi_mmap_target;
648
 
        params->v0204.efi_mmap_size = efi_mmap_size;
649
 
      }
650
 
  }
651
 
#endif
652
 
 
653
 
  /* FIXME.  */
654
 
  /*  asm volatile ("lidt %0" : : "m" (idt_desc)); */
655
 
  state.ebp = state.edi = state.ebx = 0;
656
 
  state.esi = real_mode_target;
657
 
  state.esp = real_mode_target;
658
 
  state.eip = params->code32_start;
659
 
  return grub_relocator32_boot (relocator, state, 0);
660
 
}
661
 
 
662
 
static grub_err_t
663
 
grub_linux_unload (void)
664
 
{
665
 
  grub_dl_unref (my_mod);
666
 
  loaded = 0;
667
 
  grub_free (linux_cmdline);
668
 
  linux_cmdline = 0;
669
 
  return GRUB_ERR_NONE;
670
 
}
671
 
 
672
 
static grub_err_t
673
 
grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
674
 
                int argc, char *argv[])
675
 
{
676
 
  grub_file_t file = 0;
677
 
  struct linux_kernel_header lh;
678
 
  struct linux_kernel_params *params;
679
 
  grub_uint8_t setup_sects;
680
 
  grub_size_t real_size, prot_size, prot_file_size;
681
 
  grub_ssize_t len;
682
 
  int i;
683
 
  grub_size_t align, min_align;
684
 
  int relocatable;
685
 
  grub_uint64_t preffered_address = GRUB_LINUX_BZIMAGE_ADDR;
686
 
 
687
 
  grub_dl_ref (my_mod);
688
 
 
689
 
#ifdef GRUB_MACHINE_EFI
690
 
  using_linuxefi = 0;
691
 
  if (grub_efi_secure_boot ())
692
 
    {
693
 
      /* Try linuxefi first, which will require a successful signature check
694
 
         and then hand over to the kernel without calling ExitBootServices.
695
 
         If that fails, however, fall back to calling ExitBootServices
696
 
         ourselves and then booting an unsigned kernel.  */
697
 
      grub_dl_t mod;
698
 
      grub_command_t linuxefi_cmd;
699
 
 
700
 
      grub_dprintf ("linux", "Secure Boot enabled: trying linuxefi\n");
701
 
 
702
 
      mod = grub_dl_load ("linuxefi");
703
 
      if (mod)
704
 
        {
705
 
          grub_dl_ref (mod);
706
 
          linuxefi_cmd = grub_command_find ("linuxefi");
707
 
          initrdefi_cmd = grub_command_find ("initrdefi");
708
 
          if (linuxefi_cmd && initrdefi_cmd)
709
 
            {
710
 
              (linuxefi_cmd->func) (linuxefi_cmd, argc, argv);
711
 
              if (grub_errno == GRUB_ERR_NONE)
712
 
                {
713
 
                  grub_dprintf ("linux", "Handing off to linuxefi\n");
714
 
                  using_linuxefi = 1;
715
 
                  return GRUB_ERR_NONE;
716
 
                }
717
 
              grub_dprintf ("linux", "linuxefi failed (%d)\n", grub_errno);
718
 
              grub_errno = GRUB_ERR_NONE;
719
 
            }
720
 
        }
721
 
    }
722
 
#endif
723
 
 
724
 
  if (argc == 0)
725
 
    {
726
 
      grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
727
 
      goto fail;
728
 
    }
729
 
 
730
 
  file = grub_file_open (argv[0]);
731
 
  if (! file)
732
 
    goto fail;
733
 
 
734
 
  if (grub_file_read (file, &lh, sizeof (lh)) != sizeof (lh))
735
 
    {
736
 
      if (!grub_errno)
737
 
        grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
738
 
                    argv[0]);
739
 
      goto fail;
740
 
    }
741
 
 
742
 
  if (lh.boot_flag != grub_cpu_to_le16 (0xaa55))
743
 
    {
744
 
      grub_error (GRUB_ERR_BAD_OS, "invalid magic number");
745
 
      goto fail;
746
 
    }
747
 
 
748
 
  if (lh.setup_sects > GRUB_LINUX_MAX_SETUP_SECTS)
749
 
    {
750
 
      grub_error (GRUB_ERR_BAD_OS, "too many setup sectors");
751
 
      goto fail;
752
 
    }
753
 
 
754
 
  /* FIXME: 2.03 is not always good enough (Linux 2.4 can be 2.03 and
755
 
     still not support 32-bit boot.  */
756
 
  if (lh.header != grub_cpu_to_le32 (GRUB_LINUX_MAGIC_SIGNATURE)
757
 
      || grub_le_to_cpu16 (lh.version) < 0x0203)
758
 
    {
759
 
      grub_error (GRUB_ERR_BAD_OS, "version too old for 32-bit boot"
760
 
#ifdef GRUB_MACHINE_PCBIOS
761
 
                  " (try with `linux16')"
762
 
#endif
763
 
                  );
764
 
      goto fail;
765
 
    }
766
 
 
767
 
  if (! (lh.loadflags & GRUB_LINUX_FLAG_BIG_KERNEL))
768
 
    {
769
 
      grub_error (GRUB_ERR_BAD_OS, "zImage doesn't support 32-bit boot"
770
 
#ifdef GRUB_MACHINE_PCBIOS
771
 
                  " (try with `linux16')"
772
 
#endif
773
 
                  );
774
 
      goto fail;
775
 
    }
776
 
 
777
 
  if (grub_le_to_cpu16 (lh.version) >= 0x0206)
778
 
    maximal_cmdline_size = grub_le_to_cpu32 (lh.cmdline_size) + 1;
779
 
  else
780
 
    maximal_cmdline_size = 256;
781
 
 
782
 
  if (maximal_cmdline_size < 128)
783
 
    maximal_cmdline_size = 128;
784
 
 
785
 
  setup_sects = lh.setup_sects;
786
 
 
787
 
  /* If SETUP_SECTS is not set, set it to the default (4).  */
788
 
  if (! setup_sects)
789
 
    setup_sects = GRUB_LINUX_DEFAULT_SETUP_SECTS;
790
 
 
791
 
  real_size = setup_sects << GRUB_DISK_SECTOR_BITS;
792
 
  prot_file_size = grub_file_size (file) - real_size - GRUB_DISK_SECTOR_SIZE;
793
 
 
794
 
  if (grub_le_to_cpu16 (lh.version) >= 0x205
795
 
      && lh.kernel_alignment != 0
796
 
      && ((lh.kernel_alignment - 1) & lh.kernel_alignment) == 0)
797
 
    {
798
 
      for (align = 0; align < 32; align++)
799
 
        if (grub_le_to_cpu32 (lh.kernel_alignment) & (1 << align))
800
 
          break;
801
 
      relocatable = grub_le_to_cpu32 (lh.relocatable);
802
 
    }
803
 
  else
804
 
    {
805
 
      align = 0;
806
 
      relocatable = 0;
807
 
    }
808
 
    
809
 
  if (grub_le_to_cpu16 (lh.version) >= 0x020a)
810
 
    {
811
 
      min_align = lh.min_alignment;
812
 
      prot_size = grub_le_to_cpu32 (lh.init_size);
813
 
      prot_init_space = page_align (prot_size);
814
 
      if (relocatable)
815
 
        preffered_address = grub_le_to_cpu64 (lh.pref_address);
816
 
      else
817
 
        preffered_address = GRUB_LINUX_BZIMAGE_ADDR;
818
 
    }
819
 
  else
820
 
    {
821
 
      min_align = align;
822
 
      prot_size = prot_file_size;
823
 
      preffered_address = GRUB_LINUX_BZIMAGE_ADDR;
824
 
      /* Usually, the compression ratio is about 50%.  */
825
 
      prot_init_space = page_align (prot_size) * 3;
826
 
    }
827
 
 
828
 
  if (allocate_pages (prot_size, &align,
829
 
                      min_align, relocatable,
830
 
                      preffered_address))
831
 
    goto fail;
832
 
 
833
 
  params = (struct linux_kernel_params *) &linux_params;
834
 
  grub_memset (params, 0, sizeof (*params));
835
 
  grub_memcpy (&params->setup_sects, &lh.setup_sects, sizeof (lh) - 0x1F1);
836
 
 
837
 
  params->code32_start = prot_mode_target + lh.code32_start - GRUB_LINUX_BZIMAGE_ADDR;
838
 
  params->kernel_alignment = (1 << align);
839
 
  params->ps_mouse = params->padding10 =  0;
840
 
 
841
 
  len = sizeof (*params) - sizeof (lh);
842
 
  if (grub_file_read (file, (char *) params + sizeof (lh), len) != len)
843
 
    {
844
 
      if (!grub_errno)
845
 
        grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
846
 
                    argv[0]);
847
 
      goto fail;
848
 
    }
849
 
 
850
 
  params->type_of_loader = GRUB_LINUX_BOOT_LOADER_TYPE;
851
 
 
852
 
  /* These two are used (instead of cmd_line_ptr) by older versions of Linux,
853
 
     and otherwise ignored.  */
854
 
  params->cl_magic = GRUB_LINUX_CL_MAGIC;
855
 
  params->cl_offset = 0x1000;
856
 
 
857
 
  params->ramdisk_image = 0;
858
 
  params->ramdisk_size = 0;
859
 
 
860
 
  params->heap_end_ptr = GRUB_LINUX_HEAP_END_OFFSET;
861
 
  params->loadflags |= GRUB_LINUX_FLAG_CAN_USE_HEAP;
862
 
 
863
 
  /* These are not needed to be precise, because Linux uses these values
864
 
     only to raise an error when the decompression code cannot find good
865
 
     space.  */
866
 
  params->ext_mem = ((32 * 0x100000) >> 10);
867
 
  params->alt_mem = ((32 * 0x100000) >> 10);
868
 
 
869
 
  /* Ignored by Linux.  */
870
 
  params->video_page = 0;
871
 
 
872
 
  /* Only used when `video_mode == 0x7', otherwise ignored.  */
873
 
  params->video_ega_bx = 0;
874
 
 
875
 
  params->font_size = 16; /* XXX */
876
 
 
877
 
#ifdef GRUB_MACHINE_EFI
878
 
#ifdef __x86_64__
879
 
  if (grub_le_to_cpu16 (params->version < 0x0208) &&
880
 
      ((grub_addr_t) grub_efi_system_table >> 32) != 0)
881
 
    return grub_error(GRUB_ERR_BAD_OS,
882
 
                      "kernel does not support 64-bit addressing");
883
 
#endif
884
 
 
885
 
  if (grub_le_to_cpu16 (params->version) >= 0x0208)
886
 
    {
887
 
      params->v0208.efi_signature = GRUB_LINUX_EFI_SIGNATURE;
888
 
      params->v0208.efi_system_table = (grub_uint32_t) (unsigned long) grub_efi_system_table;
889
 
#ifdef __x86_64__
890
 
      params->v0208.efi_system_table_hi = (grub_uint32_t) ((grub_uint64_t) grub_efi_system_table >> 32);
891
 
#endif
892
 
    }
893
 
  else if (grub_le_to_cpu16 (params->version) >= 0x0206)
894
 
    {
895
 
      params->v0206.efi_signature = GRUB_LINUX_EFI_SIGNATURE;
896
 
      params->v0206.efi_system_table = (grub_uint32_t) (unsigned long) grub_efi_system_table;
897
 
    }
898
 
  else if (grub_le_to_cpu16 (params->version) >= 0x0204)
899
 
    {
900
 
      params->v0204.efi_signature = GRUB_LINUX_EFI_SIGNATURE_0204;
901
 
      params->v0204.efi_system_table = (grub_uint32_t) (unsigned long) grub_efi_system_table;
902
 
    }
903
 
#endif
904
 
 
905
 
  /* The other parameters are filled when booting.  */
906
 
 
907
 
  grub_file_seek (file, real_size + GRUB_DISK_SECTOR_SIZE);
908
 
 
909
 
  grub_dprintf ("linux", "bzImage, setup=0x%x, size=0x%x\n",
910
 
                (unsigned) real_size, (unsigned) prot_size);
911
 
 
912
 
  /* Look for memory size and video mode specified on the command line.  */
913
 
  linux_mem_size = 0;
914
 
  for (i = 1; i < argc; i++)
915
 
#ifdef GRUB_MACHINE_PCBIOS
916
 
    if (grub_memcmp (argv[i], "vga=", 4) == 0)
917
 
      {
918
 
        /* Video mode selection support.  */
919
 
        char *val = argv[i] + 4;
920
 
        unsigned vid_mode = GRUB_LINUX_VID_MODE_NORMAL;
921
 
        struct grub_vesa_mode_table_entry *linux_mode;
922
 
        grub_err_t err;
923
 
        char *buf;
924
 
 
925
 
        grub_dl_load ("vbe");
926
 
 
927
 
        if (grub_strcmp (val, "normal") == 0)
928
 
          vid_mode = GRUB_LINUX_VID_MODE_NORMAL;
929
 
        else if (grub_strcmp (val, "ext") == 0)
930
 
          vid_mode = GRUB_LINUX_VID_MODE_EXTENDED;
931
 
        else if (grub_strcmp (val, "ask") == 0)
932
 
          {
933
 
            grub_puts_ (N_("Legacy `ask' parameter no longer supported."));
934
 
 
935
 
            /* We usually would never do this in a loader, but "vga=ask" means user
936
 
               requested interaction, so it can't hurt to request keyboard input.  */
937
 
            grub_wait_after_message ();
938
 
 
939
 
            goto fail;
940
 
          }
941
 
        else
942
 
          vid_mode = (grub_uint16_t) grub_strtoul (val, 0, 0);
943
 
 
944
 
        switch (vid_mode)
945
 
          {
946
 
          case 0:
947
 
          case GRUB_LINUX_VID_MODE_NORMAL:
948
 
            grub_env_set ("gfxpayload", "text");
949
 
            grub_printf_ (N_("%s is deprecated. "
950
 
                             "Use set gfxpayload=%s before "
951
 
                             "linux command instead.\n"), "text",
952
 
                          argv[i]);
953
 
            break;
954
 
 
955
 
          case 1:
956
 
          case GRUB_LINUX_VID_MODE_EXTENDED:
957
 
            /* FIXME: support 80x50 text. */
958
 
            grub_env_set ("gfxpayload", "text");
959
 
            grub_printf_ (N_("%s is deprecated. "
960
 
                             "Use set gfxpayload=%s before "
961
 
                             "linux command instead.\n"), "text",
962
 
                          argv[i]);
963
 
            break;
964
 
          default:
965
 
            /* Ignore invalid values.  */
966
 
            if (vid_mode < GRUB_VESA_MODE_TABLE_START ||
967
 
                vid_mode > GRUB_VESA_MODE_TABLE_END)
968
 
              {
969
 
                grub_env_set ("gfxpayload", "text");
970
 
                /* TRANSLATORS: "x" has to be entered in, like an identifier,
971
 
                   so please don't use better Unicode codepoints.  */
972
 
                grub_printf_ (N_("%s is deprecated. VGA mode %d isn't recognized. "
973
 
                                 "Use set gfxpayload=WIDTHxHEIGHT[xDEPTH] "
974
 
                                 "before linux command instead.\n"),
975
 
                             argv[i], vid_mode);
976
 
                break;
977
 
              }
978
 
 
979
 
            linux_mode = &grub_vesa_mode_table[vid_mode
980
 
                                               - GRUB_VESA_MODE_TABLE_START];
981
 
 
982
 
            buf = grub_xasprintf ("%ux%ux%u,%ux%u",
983
 
                                 linux_mode->width, linux_mode->height,
984
 
                                 linux_mode->depth,
985
 
                                 linux_mode->width, linux_mode->height);
986
 
            if (! buf)
987
 
              goto fail;
988
 
 
989
 
            grub_printf_ (N_("%s is deprecated. "
990
 
                             "Use set gfxpayload=%s before "
991
 
                             "linux command instead.\n"),
992
 
                         argv[i], buf);
993
 
            err = grub_env_set ("gfxpayload", buf);
994
 
            grub_free (buf);
995
 
            if (err)
996
 
              goto fail;
997
 
          }
998
 
      }
999
 
    else
1000
 
#endif /* GRUB_MACHINE_PCBIOS */
1001
 
    if (grub_memcmp (argv[i], "mem=", 4) == 0)
1002
 
      {
1003
 
        char *val = argv[i] + 4;
1004
 
 
1005
 
        linux_mem_size = grub_strtoul (val, &val, 0);
1006
 
 
1007
 
        if (grub_errno)
1008
 
          {
1009
 
            grub_errno = GRUB_ERR_NONE;
1010
 
            linux_mem_size = 0;
1011
 
          }
1012
 
        else
1013
 
          {
1014
 
            int shift = 0;
1015
 
 
1016
 
            switch (grub_tolower (val[0]))
1017
 
              {
1018
 
              case 'g':
1019
 
                shift += 10;
1020
 
              case 'm':
1021
 
                shift += 10;
1022
 
              case 'k':
1023
 
                shift += 10;
1024
 
              default:
1025
 
                break;
1026
 
              }
1027
 
 
1028
 
            /* Check an overflow.  */
1029
 
            if (linux_mem_size > (~0UL >> shift))
1030
 
              linux_mem_size = 0;
1031
 
            else
1032
 
              linux_mem_size <<= shift;
1033
 
          }
1034
 
      }
1035
 
    else if (grub_memcmp (argv[i], "quiet", sizeof ("quiet") - 1) == 0)
1036
 
      {
1037
 
        params->loadflags |= GRUB_LINUX_FLAG_QUIET;
1038
 
      }
1039
 
 
1040
 
  /* Create kernel command line.  */
1041
 
  linux_cmdline = grub_zalloc (maximal_cmdline_size + 1);
1042
 
  if (!linux_cmdline)
1043
 
    goto fail;
1044
 
  grub_memcpy (linux_cmdline, LINUX_IMAGE, sizeof (LINUX_IMAGE));
1045
 
  grub_create_loader_cmdline (argc, argv,
1046
 
                              linux_cmdline
1047
 
                              + sizeof (LINUX_IMAGE) - 1,
1048
 
                              maximal_cmdline_size
1049
 
                              - (sizeof (LINUX_IMAGE) - 1));
1050
 
 
1051
 
  len = prot_file_size;
1052
 
  if (grub_file_read (file, prot_mode_mem, len) != len && !grub_errno)
1053
 
    grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
1054
 
                argv[0]);
1055
 
 
1056
 
  if (grub_errno == GRUB_ERR_NONE)
1057
 
    {
1058
 
      grub_loader_set (grub_linux_boot, grub_linux_unload,
1059
 
                       0 /* set noreturn=0 in order to avoid grub_console_fini() */);
1060
 
      loaded = 1;
1061
 
    }
1062
 
 
1063
 
 fail:
1064
 
 
1065
 
  if (file)
1066
 
    grub_file_close (file);
1067
 
 
1068
 
  if (grub_errno != GRUB_ERR_NONE)
1069
 
    {
1070
 
      grub_dl_unref (my_mod);
1071
 
      loaded = 0;
1072
 
    }
1073
 
 
1074
 
  return grub_errno;
1075
 
}
1076
 
 
1077
 
static grub_err_t
1078
 
grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
1079
 
                 int argc, char *argv[])
1080
 
{
1081
 
  grub_file_t *files = 0;
1082
 
  grub_size_t size = 0;
1083
 
  grub_addr_t addr_min, addr_max;
1084
 
  grub_addr_t addr;
1085
 
  grub_err_t err;
1086
 
  int i;
1087
 
  int nfiles = 0;
1088
 
  grub_uint8_t *ptr;
1089
 
 
1090
 
#ifdef GRUB_MACHINE_EFI
1091
 
  /* If we're using linuxefi, just forward to initrdefi.  */
1092
 
  if (using_linuxefi && initrdefi_cmd)
1093
 
    return (initrdefi_cmd->func) (initrdefi_cmd, argc, argv);
1094
 
#endif
1095
 
 
1096
 
  if (argc == 0)
1097
 
    {
1098
 
      grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
1099
 
      goto fail;
1100
 
    }
1101
 
 
1102
 
  if (! loaded)
1103
 
    {
1104
 
      grub_error (GRUB_ERR_BAD_ARGUMENT, N_("you need to load the kernel first"));
1105
 
      goto fail;
1106
 
    }
1107
 
 
1108
 
  files = grub_zalloc (argc * sizeof (files[0]));
1109
 
  if (!files)
1110
 
    goto fail;
1111
 
 
1112
 
  for (i = 0; i < argc; i++)
1113
 
    {
1114
 
      grub_file_filter_disable_compression ();
1115
 
      files[i] = grub_file_open (argv[i]);
1116
 
      if (! files[i])
1117
 
        goto fail;
1118
 
      nfiles++;
1119
 
      size += ALIGN_UP (grub_file_size (files[i]), 4);
1120
 
    }
1121
 
 
1122
 
  initrd_pages = (page_align (size) >> 12);
1123
 
 
1124
 
  /* Get the highest address available for the initrd.  */
1125
 
  if (grub_le_to_cpu16 (linux_params.version) >= 0x0203)
1126
 
    {
1127
 
      addr_max = grub_cpu_to_le32 (linux_params.initrd_addr_max);
1128
 
 
1129
 
      /* XXX in reality, Linux specifies a bogus value, so
1130
 
         it is necessary to make sure that ADDR_MAX does not exceed
1131
 
         0x3fffffff.  */
1132
 
      if (addr_max > GRUB_LINUX_INITRD_MAX_ADDRESS)
1133
 
        addr_max = GRUB_LINUX_INITRD_MAX_ADDRESS;
1134
 
    }
1135
 
  else
1136
 
    addr_max = GRUB_LINUX_INITRD_MAX_ADDRESS;
1137
 
 
1138
 
  if (linux_mem_size != 0 && linux_mem_size < addr_max)
1139
 
    addr_max = linux_mem_size;
1140
 
 
1141
 
  /* Linux 2.3.xx has a bug in the memory range check, so avoid
1142
 
     the last page.
1143
 
     Linux 2.2.xx has a bug in the memory range check, which is
1144
 
     worse than that of Linux 2.3.xx, so avoid the last 64kb.  */
1145
 
  addr_max -= 0x10000;
1146
 
 
1147
 
  addr_min = (grub_addr_t) prot_mode_target + prot_init_space
1148
 
             + page_align (size);
1149
 
 
1150
 
  /* Put the initrd as high as possible, 4KiB aligned.  */
1151
 
  addr = (addr_max - size) & ~0xFFF;
1152
 
 
1153
 
  if (addr < addr_min)
1154
 
    {
1155
 
      grub_error (GRUB_ERR_OUT_OF_RANGE, "the initrd is too big");
1156
 
      goto fail;
1157
 
    }
1158
 
 
1159
 
  {
1160
 
    grub_relocator_chunk_t ch;
1161
 
    err = grub_relocator_alloc_chunk_align (relocator, &ch,
1162
 
                                            addr_min, addr, size, 0x1000,
1163
 
                                            GRUB_RELOCATOR_PREFERENCE_HIGH,
1164
 
                                            1);
1165
 
    if (err)
1166
 
      return err;
1167
 
    initrd_mem = get_virtual_current_address (ch);
1168
 
    initrd_mem_target = get_physical_target_address (ch);
1169
 
  }
1170
 
 
1171
 
  ptr = initrd_mem;
1172
 
  for (i = 0; i < nfiles; i++)
1173
 
    {
1174
 
      grub_ssize_t cursize = grub_file_size (files[i]);
1175
 
      if (grub_file_read (files[i], ptr, cursize) != cursize)
1176
 
        {
1177
 
          if (!grub_errno)
1178
 
            grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"),
1179
 
                        argv[i]);
1180
 
          goto fail;
1181
 
        }
1182
 
      ptr += cursize;
1183
 
      grub_memset (ptr, 0, ALIGN_UP_OVERHEAD (cursize, 4));
1184
 
      ptr += ALIGN_UP_OVERHEAD (cursize, 4);
1185
 
    }
1186
 
 
1187
 
  grub_dprintf ("linux", "Initrd, addr=0x%x, size=0x%x\n",
1188
 
                (unsigned) addr, (unsigned) size);
1189
 
 
1190
 
  linux_params.ramdisk_image = initrd_mem_target;
1191
 
  linux_params.ramdisk_size = size;
1192
 
  linux_params.root_dev = 0x0100; /* XXX */
1193
 
 
1194
 
 fail:
1195
 
  for (i = 0; i < nfiles; i++)
1196
 
    grub_file_close (files[i]);
1197
 
  grub_free (files);
1198
 
 
1199
 
  return grub_errno;
1200
 
}
1201
 
 
1202
 
static grub_command_t cmd_linux, cmd_initrd;
1203
 
 
1204
 
GRUB_MOD_INIT(linux)
1205
 
{
1206
 
  cmd_linux = grub_register_command ("linux", grub_cmd_linux,
1207
 
                                     0, N_("Load Linux."));
1208
 
  cmd_initrd = grub_register_command ("initrd", grub_cmd_initrd,
1209
 
                                      0, N_("Load initrd."));
1210
 
  my_mod = mod;
1211
 
}
1212
 
 
1213
 
GRUB_MOD_FINI(linux)
1214
 
{
1215
 
  grub_unregister_command (cmd_linux);
1216
 
  grub_unregister_command (cmd_initrd);
1217
 
}