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

« back to all changes in this revision

Viewing changes to loader/i386/efi/linux.c

  • Committer: Bazaar Package Importer
  • Author(s): Colin Watson, Colin Watson, Robert Millan, Updated translations
  • Date: 2010-11-22 12:24:56 UTC
  • mfrom: (1.26.4 upstream) (17.3.36 sid)
  • mto: (17.3.43 sid)
  • mto: This revision was merged to the branch mainline in revision 89.
  • Revision ID: james.westby@ubuntu.com-20101122122456-y82z3sfb7k4zfdcc
Tags: 1.99~20101122-1
[ Colin Watson ]
* New Bazaar snapshot.  Too many changes to list in full, but some of the
  more user-visible ones are as follows:
  - GRUB script:
    + Function parameters, "break", "continue", "shift", "setparams",
      "return", and "!".
    + "export" command supports multiple variable names.
    + Multi-line quoted strings support.
    + Wildcard expansion.
  - sendkey support.
  - USB hotunplugging and USB serial support.
  - Rename CD-ROM to cd on BIOS.
  - Add new --boot-directory option to grub-install, grub-reboot, and
    grub-set-default; the old --root-directory option is still accepted
    but was often confusing.
  - Basic btrfs detection/UUID support (but no file reading yet).
  - bash-completion for utilities.
  - If a device is listed in device.map, always assume that it is
    BIOS-visible rather than using extra layers such as LVM or RAID.
  - Add grub-mknetdir script (closes: #550658).
  - Remove deprecated "root" command.
  - Handle RAID devices containing virtio components.
  - GRUB Legacy configuration file support (via grub-menulst2cfg).
  - Keyboard layout support (via grub-mklayout and grub-kbdcomp).
  - Check generated grub.cfg for syntax errors before saving.
  - Pause execution for at most ten seconds if any errors are displayed,
    so that the user has a chance to see them.
  - Support submenus.
  - Write embedding zone using Reed-Solomon, so that it's robust against
    being partially overwritten (closes: #550702, #591416, #593347).
  - GRUB_DISABLE_LINUX_RECOVERY and GRUB_DISABLE_NETBSD_RECOVERY merged
    into a single GRUB_DISABLE_RECOVERY variable.
  - Fix loader memory allocation failure (closes: #551627).
  - Don't call savedefault on recovery entries (closes: #589325).
  - Support triple-indirect blocks on ext2 (closes: #543924).
  - Recognise DDF1 fake RAID (closes: #603354).

[ Robert Millan ]
* Use dpkg architecture wildcards.

[ Updated translations ]
* Slovenian (Vanja Cvelbar).  Closes: #604003
* Dzongkha (dawa pemo via Tenzin Dendup).  Closes: #604102

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/machine/loader.h>
21
 
#include <grub/file.h>
22
 
#include <grub/disk.h>
23
 
#include <grub/err.h>
24
 
#include <grub/misc.h>
25
 
#include <grub/types.h>
26
 
#include <grub/dl.h>
27
 
#include <grub/mm.h>
28
 
#include <grub/term.h>
29
 
#include <grub/cpu/linux.h>
30
 
#include <grub/efi/api.h>
31
 
#include <grub/efi/efi.h>
32
 
#include <grub/command.h>
33
 
#include <grub/memory.h>
34
 
#include <grub/env.h>
35
 
#include <grub/video.h>
36
 
#include <grub/time.h>
37
 
#include <grub/i18n.h>
38
 
 
39
 
#define GRUB_LINUX_CL_OFFSET            0x1000
40
 
#define GRUB_LINUX_CL_END_OFFSET        0x2000
41
 
 
42
 
#define NEXT_MEMORY_DESCRIPTOR(desc, size)      \
43
 
  ((grub_efi_memory_descriptor_t *) ((char *) (desc) + (size)))
44
 
 
45
 
static grub_dl_t my_mod;
46
 
 
47
 
static grub_size_t linux_mem_size;
48
 
static int loaded;
49
 
static void *real_mode_mem;
50
 
static void *prot_mode_mem;
51
 
static void *initrd_mem;
52
 
static grub_efi_uintn_t real_mode_pages;
53
 
static grub_efi_uintn_t prot_mode_pages;
54
 
static grub_efi_uintn_t initrd_pages;
55
 
static void *mmap_buf;
56
 
 
57
 
static grub_uint8_t gdt[] __attribute__ ((aligned(16))) =
58
 
  {
59
 
    /* NULL.  */
60
 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
61
 
    /* Reserved.  */
62
 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
63
 
    /* Code segment.  */
64
 
    0xFF, 0xFF, 0x00, 0x00, 0x00, 0x9A, 0xCF, 0x00,
65
 
    /* Data segment.  */
66
 
    0xFF, 0xFF, 0x00, 0x00, 0x00, 0x92, 0xCF, 0x00
67
 
  };
68
 
 
69
 
struct gdt_descriptor
70
 
{
71
 
  grub_uint16_t limit;
72
 
  void *base;
73
 
} __attribute__ ((packed));
74
 
 
75
 
static struct gdt_descriptor gdt_desc =
76
 
  {
77
 
    sizeof (gdt) - 1,
78
 
    gdt
79
 
  };
80
 
 
81
 
struct idt_descriptor
82
 
{
83
 
  grub_uint16_t limit;
84
 
  void *base;
85
 
} __attribute__ ((packed));
86
 
 
87
 
static struct idt_descriptor idt_desc =
88
 
  {
89
 
    0,
90
 
    0
91
 
  };
92
 
 
93
 
static inline grub_size_t
94
 
page_align (grub_size_t size)
95
 
{
96
 
  return (size + (1 << 12) - 1) & (~((1 << 12) - 1));
97
 
}
98
 
 
99
 
/* Find the optimal number of pages for the memory map. Is it better to
100
 
   move this code to efi/mm.c?  */
101
 
static grub_efi_uintn_t
102
 
find_mmap_size (void)
103
 
{
104
 
  static grub_efi_uintn_t mmap_size = 0;
105
 
 
106
 
  if (mmap_size != 0)
107
 
    return mmap_size;
108
 
 
109
 
  mmap_size = (1 << 12);
110
 
  while (1)
111
 
    {
112
 
      int ret;
113
 
      grub_efi_memory_descriptor_t *mmap;
114
 
      grub_efi_uintn_t desc_size;
115
 
 
116
 
      mmap = grub_malloc (mmap_size);
117
 
      if (! mmap)
118
 
        return 0;
119
 
 
120
 
      ret = grub_efi_get_memory_map (&mmap_size, mmap, 0, &desc_size, 0);
121
 
      grub_free (mmap);
122
 
 
123
 
      if (ret < 0)
124
 
        grub_fatal ("cannot get memory map");
125
 
      else if (ret > 0)
126
 
        break;
127
 
 
128
 
      mmap_size += (1 << 12);
129
 
    }
130
 
 
131
 
  /* Increase the size a bit for safety, because GRUB allocates more on
132
 
     later, and EFI itself may allocate more.  */
133
 
  mmap_size += (1 << 12);
134
 
 
135
 
  return page_align (mmap_size);
136
 
}
137
 
 
138
 
static void
139
 
free_pages (void)
140
 
{
141
 
  if (real_mode_mem)
142
 
    {
143
 
      grub_efi_free_pages ((grub_addr_t) real_mode_mem, real_mode_pages);
144
 
      real_mode_mem = 0;
145
 
    }
146
 
 
147
 
  if (prot_mode_mem)
148
 
    {
149
 
      grub_efi_free_pages ((grub_addr_t) prot_mode_mem, prot_mode_pages);
150
 
      prot_mode_mem = 0;
151
 
    }
152
 
 
153
 
  if (initrd_mem)
154
 
    {
155
 
      grub_efi_free_pages ((grub_addr_t) initrd_mem, initrd_pages);
156
 
      initrd_mem = 0;
157
 
    }
158
 
}
159
 
 
160
 
/* Allocate pages for the real mode code and the protected mode code
161
 
   for linux as well as a memory map buffer.  */
162
 
static int
163
 
allocate_pages (grub_size_t prot_size)
164
 
{
165
 
  grub_efi_uintn_t desc_size;
166
 
  grub_efi_memory_descriptor_t *mmap, *mmap_end;
167
 
  grub_efi_uintn_t mmap_size, tmp_mmap_size;
168
 
  grub_efi_memory_descriptor_t *desc;
169
 
  grub_size_t real_size;
170
 
 
171
 
  /* Make sure that each size is aligned to a page boundary.  */
172
 
  real_size = GRUB_LINUX_CL_END_OFFSET;
173
 
  prot_size = page_align (prot_size);
174
 
  mmap_size = find_mmap_size ();
175
 
 
176
 
  grub_dprintf ("linux", "real_size = %x, prot_size = %x, mmap_size = %x\n",
177
 
                (unsigned) real_size, (unsigned) prot_size, (unsigned) mmap_size);
178
 
 
179
 
  /* Calculate the number of pages; Combine the real mode code with
180
 
     the memory map buffer for simplicity.  */
181
 
  real_mode_pages = ((real_size + mmap_size) >> 12);
182
 
  prot_mode_pages = (prot_size >> 12);
183
 
 
184
 
  /* Initialize the memory pointers with NULL for convenience.  */
185
 
  real_mode_mem = 0;
186
 
  prot_mode_mem = 0;
187
 
 
188
 
  /* Read the memory map temporarily, to find free space.  */
189
 
  mmap = grub_malloc (mmap_size);
190
 
  if (! mmap)
191
 
    return 0;
192
 
 
193
 
  tmp_mmap_size = mmap_size;
194
 
  if (grub_efi_get_memory_map (&tmp_mmap_size, mmap, 0, &desc_size, 0) <= 0)
195
 
    grub_fatal ("cannot get memory map");
196
 
 
197
 
  mmap_end = NEXT_MEMORY_DESCRIPTOR (mmap, tmp_mmap_size);
198
 
 
199
 
  /* First, find free pages for the real mode code
200
 
     and the memory map buffer.  */
201
 
  for (desc = mmap;
202
 
       desc < mmap_end;
203
 
       desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size))
204
 
    {
205
 
      /* Probably it is better to put the real mode code in the traditional
206
 
         space for safety.  */
207
 
      if (desc->type == GRUB_EFI_CONVENTIONAL_MEMORY
208
 
          && desc->physical_start <= 0x90000
209
 
          && desc->num_pages >= real_mode_pages)
210
 
        {
211
 
          grub_efi_physical_address_t physical_end;
212
 
          grub_efi_physical_address_t addr;
213
 
 
214
 
          physical_end = desc->physical_start + (desc->num_pages << 12);
215
 
          if (physical_end > 0x90000)
216
 
            physical_end = 0x90000;
217
 
 
218
 
          grub_dprintf ("linux", "physical_start = %x, physical_end = %x\n",
219
 
                        (unsigned) desc->physical_start,
220
 
                        (unsigned) physical_end);
221
 
          addr = physical_end - real_size - mmap_size;
222
 
          if (addr < 0x10000)
223
 
            continue;
224
 
 
225
 
          grub_dprintf ("linux", "trying to allocate %u pages at %lx\n",
226
 
                        (unsigned) real_mode_pages, (unsigned long) addr);
227
 
          real_mode_mem = grub_efi_allocate_pages (addr, real_mode_pages);
228
 
          if (! real_mode_mem)
229
 
            grub_fatal ("cannot allocate pages");
230
 
 
231
 
          desc->num_pages -= real_mode_pages;
232
 
          break;
233
 
        }
234
 
    }
235
 
 
236
 
  if (! real_mode_mem)
237
 
    {
238
 
      grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate real mode pages");
239
 
      goto fail;
240
 
    }
241
 
 
242
 
  mmap_buf = (void *) ((char *) real_mode_mem + real_size);
243
 
 
244
 
  /* Next, find free pages for the protected mode code.  */
245
 
  /* XXX what happens if anything is using this address?  */
246
 
  prot_mode_mem = grub_efi_allocate_pages (0x100000, prot_mode_pages + 1);
247
 
  if (! prot_mode_mem)
248
 
    {
249
 
      grub_error (GRUB_ERR_OUT_OF_MEMORY,
250
 
                  "cannot allocate protected mode pages");
251
 
      goto fail;
252
 
    }
253
 
 
254
 
  grub_dprintf ("linux", "real_mode_mem = %lx, real_mode_pages = %x, "
255
 
                "prot_mode_mem = %lx, prot_mode_pages = %x\n",
256
 
                (unsigned long) real_mode_mem, (unsigned) real_mode_pages,
257
 
                (unsigned long) prot_mode_mem, (unsigned) prot_mode_pages);
258
 
 
259
 
  grub_free (mmap);
260
 
  return 1;
261
 
 
262
 
 fail:
263
 
  grub_free (mmap);
264
 
  free_pages ();
265
 
  return 0;
266
 
}
267
 
 
268
 
static void
269
 
grub_e820_add_region (struct grub_e820_mmap *e820_map, int *e820_num,
270
 
                      grub_uint64_t start, grub_uint64_t size,
271
 
                      grub_uint32_t type)
272
 
{
273
 
  int n = *e820_num;
274
 
 
275
 
  if (n >= GRUB_E820_MAX_ENTRY)
276
 
    grub_fatal ("Too many e820 memory map entries");
277
 
 
278
 
  if ((n > 0) && (e820_map[n - 1].addr + e820_map[n - 1].size == start) &&
279
 
      (e820_map[n - 1].type == type))
280
 
      e820_map[n - 1].size += size;
281
 
  else
282
 
    {
283
 
      e820_map[n].addr = start;
284
 
      e820_map[n].size = size;
285
 
      e820_map[n].type = type;
286
 
      (*e820_num)++;
287
 
    }
288
 
}
289
 
 
290
 
static grub_err_t
291
 
grub_linux_setup_video (struct linux_kernel_params *params)
292
 
{
293
 
  struct grub_video_mode_info mode_info;
294
 
  void *framebuffer;
295
 
  grub_err_t err;
296
 
 
297
 
  err = grub_video_get_info_and_fini (&mode_info, &framebuffer);
298
 
 
299
 
  if (err)
300
 
    return err;
301
 
 
302
 
  params->lfb_width = mode_info.width;
303
 
  params->lfb_height = mode_info.height;
304
 
  params->lfb_depth = mode_info.bpp;
305
 
  params->lfb_line_len = mode_info.pitch;
306
 
 
307
 
  params->lfb_base = (grub_size_t) framebuffer;
308
 
  params->lfb_size = (params->lfb_line_len * params->lfb_height + 65535) >> 16;
309
 
 
310
 
  params->red_mask_size = mode_info.red_mask_size;
311
 
  params->red_field_pos = mode_info.red_field_pos;
312
 
  params->green_mask_size = mode_info.green_mask_size;
313
 
  params->green_field_pos = mode_info.green_field_pos;
314
 
  params->blue_mask_size = mode_info.blue_mask_size;
315
 
  params->blue_field_pos = mode_info.blue_field_pos;
316
 
  params->reserved_mask_size = mode_info.reserved_mask_size;
317
 
  params->reserved_field_pos = mode_info.reserved_field_pos;
318
 
 
319
 
  params->have_vga = GRUB_VIDEO_LINUX_TYPE_SIMPLE;
320
 
 
321
 
#ifdef GRUB_MACHINE_PCBIOS
322
 
  /* VESA packed modes may come with zeroed mask sizes, which need
323
 
     to be set here according to DAC Palette width.  If we don't,
324
 
     this results in Linux displaying a black screen.  */
325
 
  if (mode_info.bpp <= 8)
326
 
    {
327
 
      struct grub_vbe_info_block controller_info;
328
 
      int status;
329
 
      int width = 8;
330
 
 
331
 
      status = grub_vbe_bios_get_controller_info (&controller_info);
332
 
 
333
 
      if (status == GRUB_VBE_STATUS_OK &&
334
 
          (controller_info.capabilities & GRUB_VBE_CAPABILITY_DACWIDTH))
335
 
        status = grub_vbe_bios_set_dac_palette_width (&width);
336
 
 
337
 
      if (status != GRUB_VBE_STATUS_OK)
338
 
        /* 6 is default after mode reset.  */
339
 
        width = 6;
340
 
 
341
 
      params->red_mask_size = params->green_mask_size
342
 
        = params->blue_mask_size = width;
343
 
      params->reserved_mask_size = 0;
344
 
    }
345
 
#endif
346
 
 
347
 
  return 0;
348
 
}
349
 
 
350
 
#ifdef __x86_64__
351
 
extern grub_uint8_t grub_linux_trampoline_start[];
352
 
extern grub_uint8_t grub_linux_trampoline_end[];
353
 
#endif
354
 
 
355
 
static grub_err_t
356
 
grub_linux_boot (void)
357
 
{
358
 
  struct linux_kernel_params *params;
359
 
  grub_efi_uintn_t mmap_size;
360
 
  grub_efi_uintn_t map_key;
361
 
  grub_efi_uintn_t desc_size;
362
 
  grub_efi_uint32_t desc_version;
363
 
  int e820_num;
364
 
  const char *modevar;
365
 
  char *tmp;
366
 
  grub_err_t err;
367
 
 
368
 
  params = real_mode_mem;
369
 
 
370
 
  grub_printf ("%d\n", __LINE__);
371
 
 
372
 
  grub_dprintf ("linux", "code32_start = %x, idt_desc = %lx, gdt_desc = %lx\n",
373
 
                (unsigned) params->code32_start,
374
 
                (unsigned long) &(idt_desc.limit),
375
 
                (unsigned long) &(gdt_desc.limit));
376
 
  grub_dprintf ("linux", "idt = %x:%lx, gdt = %x:%lx\n",
377
 
                (unsigned) idt_desc.limit, (unsigned long) idt_desc.base,
378
 
                (unsigned) gdt_desc.limit, (unsigned long) gdt_desc.base);
379
 
 
380
 
  grub_printf ("%d\n", __LINE__);
381
 
 
382
 
  auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, grub_uint32_t);
383
 
  int NESTED_FUNC_ATTR hook (grub_uint64_t addr, grub_uint64_t size, grub_uint32_t type)
384
 
    {
385
 
      switch (type)
386
 
        {
387
 
        case GRUB_MACHINE_MEMORY_AVAILABLE:
388
 
          grub_e820_add_region (params->e820_map, &e820_num,
389
 
                                addr, size, GRUB_E820_RAM);
390
 
          break;
391
 
 
392
 
#ifdef GRUB_MACHINE_MEMORY_ACPI
393
 
        case GRUB_MACHINE_MEMORY_ACPI:
394
 
          grub_e820_add_region (params->e820_map, &e820_num,
395
 
                                addr, size, GRUB_E820_ACPI);
396
 
          break;
397
 
#endif
398
 
 
399
 
#ifdef GRUB_MACHINE_MEMORY_NVS
400
 
        case GRUB_MACHINE_MEMORY_NVS:
401
 
          grub_e820_add_region (params->e820_map, &e820_num,
402
 
                                addr, size, GRUB_E820_NVS);
403
 
          break;
404
 
#endif
405
 
 
406
 
#ifdef GRUB_MACHINE_MEMORY_CODE
407
 
        case GRUB_MACHINE_MEMORY_CODE:
408
 
          grub_e820_add_region (params->e820_map, &e820_num,
409
 
                                addr, size, GRUB_E820_EXEC_CODE);
410
 
          break;
411
 
#endif
412
 
 
413
 
        default:
414
 
          grub_e820_add_region (params->e820_map, &e820_num,
415
 
                                addr, size, GRUB_E820_RESERVED);
416
 
        }
417
 
      return 0;
418
 
    }
419
 
 
420
 
  grub_printf ("%d\n", __LINE__);
421
 
 
422
 
  e820_num = 0;
423
 
  grub_mmap_iterate (hook);
424
 
  params->mmap_size = e820_num;
425
 
 
426
 
  grub_printf ("Trampoline at %p. code32=%x, real_mode_mem=%p\n",
427
 
               ((char *) prot_mode_mem + (prot_mode_pages << 12)),
428
 
               (unsigned) params->code32_start, real_mode_mem);
429
 
 
430
 
  modevar = grub_env_get ("gfxpayload");
431
 
 
432
 
  /* Now all graphical modes are acceptable.
433
 
     May change in future if we have modes without framebuffer.  */
434
 
  if (modevar && *modevar != 0)
435
 
    {
436
 
      tmp = grub_xasprintf ("%s;auto", modevar);
437
 
      if (! tmp)
438
 
        return grub_errno;
439
 
      err = grub_video_set_mode (tmp, GRUB_VIDEO_MODE_TYPE_PURE_TEXT, 0);
440
 
      grub_free (tmp);
441
 
    }
442
 
  else
443
 
    err = grub_video_set_mode ("auto", GRUB_VIDEO_MODE_TYPE_PURE_TEXT, 0);
444
 
 
445
 
  if (!err)
446
 
    err = grub_linux_setup_video (params);
447
 
 
448
 
  if (err)
449
 
    {
450
 
      grub_print_error ();
451
 
      grub_printf ("Booting however\n");
452
 
      grub_errno = GRUB_ERR_NONE;
453
 
    }
454
 
 
455
 
  mmap_size = find_mmap_size ();
456
 
  if (grub_efi_get_memory_map (&mmap_size, mmap_buf, &map_key,
457
 
                               &desc_size, &desc_version) <= 0)
458
 
    grub_fatal ("cannot get memory map");
459
 
 
460
 
  if (! grub_efi_exit_boot_services (map_key))
461
 
     grub_fatal ("cannot exit boot services");
462
 
 
463
 
  /* Note that no boot services are available from here.  */
464
 
 
465
 
  /* Pass EFI parameters.  */
466
 
  if (grub_le_to_cpu16 (params->version) >= 0x0206)
467
 
    {
468
 
      params->v0206.efi_mem_desc_size = desc_size;
469
 
      params->v0206.efi_mem_desc_version = desc_version;
470
 
      params->v0206.efi_mmap = (grub_uint32_t) (unsigned long) mmap_buf;
471
 
      params->v0206.efi_mmap_size = mmap_size;
472
 
#ifdef __x86_64__
473
 
      params->v0206.efi_mmap_hi = (grub_uint32_t) ((grub_uint64_t) mmap_buf >> 32);
474
 
#endif
475
 
    }
476
 
  else if (grub_le_to_cpu16 (params->version) >= 0x0204)
477
 
    {
478
 
      params->v0204.efi_mem_desc_size = desc_size;
479
 
      params->v0204.efi_mem_desc_version = desc_version;
480
 
      params->v0204.efi_mmap = (grub_uint32_t) (unsigned long) mmap_buf;
481
 
      params->v0204.efi_mmap_size = mmap_size;
482
 
    }
483
 
 
484
 
#ifdef __x86_64__
485
 
 
486
 
  grub_memcpy ((char *) prot_mode_mem + (prot_mode_pages << 12),
487
 
               grub_linux_trampoline_start,
488
 
               grub_linux_trampoline_end - grub_linux_trampoline_start);
489
 
 
490
 
  ((void (*) (unsigned long, void *)) ((char *) prot_mode_mem
491
 
                                     + (prot_mode_pages << 12)))
492
 
    (params->code32_start, real_mode_mem);
493
 
 
494
 
#else
495
 
 
496
 
  /* Hardware interrupts are not safe any longer.  */
497
 
  asm volatile ("cli" : : );
498
 
 
499
 
  /* Load the IDT and the GDT for the bootstrap.  */
500
 
  asm volatile ("lidt %0" : : "m" (idt_desc));
501
 
  asm volatile ("lgdt %0" : : "m" (gdt_desc));
502
 
 
503
 
  /* Pass parameters.  */
504
 
  asm volatile ("movl %0, %%ecx" : : "m" (params->code32_start));
505
 
  asm volatile ("movl %0, %%esi" : : "m" (real_mode_mem));
506
 
 
507
 
  asm volatile ("xorl %%ebx, %%ebx" : : );
508
 
 
509
 
  /* Enter Linux.  */
510
 
  asm volatile ("jmp *%%ecx" : : );
511
 
 
512
 
#endif
513
 
 
514
 
  /* Never reach here.  */
515
 
  return GRUB_ERR_NONE;
516
 
}
517
 
 
518
 
static grub_err_t
519
 
grub_linux_unload (void)
520
 
{
521
 
  free_pages ();
522
 
  grub_dl_unref (my_mod);
523
 
  loaded = 0;
524
 
  return GRUB_ERR_NONE;
525
 
}
526
 
 
527
 
static grub_err_t
528
 
grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
529
 
                int argc, char *argv[])
530
 
{
531
 
  grub_file_t file = 0;
532
 
  struct linux_kernel_header lh;
533
 
  struct linux_kernel_params *params;
534
 
  grub_uint8_t setup_sects;
535
 
  grub_size_t real_size, prot_size;
536
 
  grub_ssize_t len;
537
 
  int i;
538
 
  char *dest;
539
 
 
540
 
  grub_dl_ref (my_mod);
541
 
 
542
 
  if (argc == 0)
543
 
    {
544
 
      grub_error (GRUB_ERR_BAD_ARGUMENT, "no kernel specified");
545
 
      goto fail;
546
 
    }
547
 
 
548
 
  file = grub_file_open (argv[0]);
549
 
  if (! file)
550
 
    goto fail;
551
 
 
552
 
  if (grub_file_read (file, &lh, sizeof (lh)) != sizeof (lh))
553
 
    {
554
 
      grub_error (GRUB_ERR_READ_ERROR, "cannot read the Linux header");
555
 
      goto fail;
556
 
    }
557
 
 
558
 
  if (lh.boot_flag != grub_cpu_to_le16 (0xaa55))
559
 
    {
560
 
      grub_error (GRUB_ERR_BAD_OS, "invalid magic number");
561
 
      goto fail;
562
 
    }
563
 
 
564
 
  if (lh.setup_sects > GRUB_LINUX_MAX_SETUP_SECTS)
565
 
    {
566
 
      grub_error (GRUB_ERR_BAD_OS, "too many setup sectors");
567
 
      goto fail;
568
 
    }
569
 
 
570
 
  /* EFI support is quite new, so reject old versions.  */
571
 
  if (lh.header != grub_cpu_to_le32 (GRUB_LINUX_MAGIC_SIGNATURE)
572
 
      || grub_le_to_cpu16 (lh.version) < 0x0203)
573
 
    {
574
 
      grub_error (GRUB_ERR_BAD_OS, "too old version");
575
 
      goto fail;
576
 
    }
577
 
 
578
 
  /* I'm not sure how to support zImage on EFI.  */
579
 
  if (! (lh.loadflags & GRUB_LINUX_FLAG_BIG_KERNEL))
580
 
    {
581
 
      grub_error (GRUB_ERR_BAD_OS, "zImage is not supported");
582
 
      goto fail;
583
 
    }
584
 
 
585
 
  setup_sects = lh.setup_sects;
586
 
 
587
 
  /* If SETUP_SECTS is not set, set it to the default (4).  */
588
 
  if (! setup_sects)
589
 
    setup_sects = GRUB_LINUX_DEFAULT_SETUP_SECTS;
590
 
 
591
 
  real_size = setup_sects << GRUB_DISK_SECTOR_BITS;
592
 
  prot_size = grub_file_size (file) - real_size - GRUB_DISK_SECTOR_SIZE;
593
 
 
594
 
  if (! allocate_pages (prot_size))
595
 
    goto fail;
596
 
 
597
 
  params = (struct linux_kernel_params *) real_mode_mem;
598
 
  grub_memset (params, 0, GRUB_LINUX_CL_END_OFFSET);
599
 
  grub_memcpy (&params->setup_sects, &lh.setup_sects, sizeof (lh) - 0x1F1);
600
 
 
601
 
  params->ps_mouse = params->padding10 =  0;
602
 
 
603
 
  len = 0x400 - sizeof (lh);
604
 
  if (grub_file_read (file, (char *) real_mode_mem + sizeof (lh), len) != len)
605
 
    {
606
 
      grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file");
607
 
      goto fail;
608
 
    }
609
 
 
610
 
  params->type_of_loader = (LINUX_LOADER_ID_GRUB << 4);
611
 
 
612
 
  params->cl_magic = GRUB_LINUX_CL_MAGIC;
613
 
  params->cl_offset = 0x1000;
614
 
  params->cmd_line_ptr = (unsigned long) real_mode_mem + 0x1000;
615
 
  params->ramdisk_image = 0;
616
 
  params->ramdisk_size = 0;
617
 
 
618
 
  params->heap_end_ptr = GRUB_LINUX_HEAP_END_OFFSET;
619
 
  params->loadflags |= GRUB_LINUX_FLAG_CAN_USE_HEAP;
620
 
 
621
 
  /* These are not needed to be precise, because Linux uses these values
622
 
     only to raise an error when the decompression code cannot find good
623
 
     space.  */
624
 
  params->ext_mem = ((32 * 0x100000) >> 10);
625
 
  params->alt_mem = ((32 * 0x100000) >> 10);
626
 
 
627
 
  {
628
 
    grub_term_output_t term;
629
 
    int found = 0;
630
 
    FOR_ACTIVE_TERM_OUTPUTS(term)
631
 
      if (grub_strcmp (term->name, "vga_text") == 0
632
 
          || grub_strcmp (term->name, "console") == 0)
633
 
        {
634
 
          grub_uint16_t pos = grub_term_getxy (term);
635
 
          params->video_cursor_x = pos >> 8;
636
 
          params->video_cursor_y = pos & 0xff;
637
 
          params->video_width = grub_term_width (term);
638
 
          params->video_height = grub_term_height (term);
639
 
          found = 1;
640
 
          break;
641
 
        }
642
 
    if (!found)
643
 
      {
644
 
        params->video_cursor_x = 0;
645
 
        params->video_cursor_y = 0;
646
 
        params->video_width = 80;
647
 
        params->video_height = 25;
648
 
      }
649
 
  }
650
 
  params->video_page = 0; /* ??? */
651
 
  params->video_mode = grub_efi_system_table->con_out->mode->mode;
652
 
  params->video_ega_bx = 0;
653
 
  params->have_vga = 0;
654
 
  params->font_size = 16; /* XXX */
655
 
 
656
 
  if (grub_le_to_cpu16 (params->version) >= 0x0206)
657
 
    {
658
 
      params->v0206.efi_signature = GRUB_LINUX_EFI_SIGNATURE;
659
 
      params->v0206.efi_system_table = (grub_uint32_t) (unsigned long) grub_efi_system_table;
660
 
#ifdef __x86_64__
661
 
      params->v0206.efi_system_table_hi = (grub_uint32_t) ((grub_uint64_t) grub_efi_system_table >> 32);
662
 
#endif
663
 
    }
664
 
  else if (grub_le_to_cpu16 (params->version) >= 0x0204)
665
 
    {
666
 
      params->v0204.efi_signature = GRUB_LINUX_EFI_SIGNATURE_0204;
667
 
      params->v0204.efi_system_table = (grub_uint32_t) (unsigned long) grub_efi_system_table;
668
 
    }
669
 
 
670
 
#if 0
671
 
  /* The structure is zeroed already.  */
672
 
 
673
 
  /* No VBE on EFI.  */
674
 
  params->lfb_width = 0;
675
 
  params->lfb_height = 0;
676
 
  params->lfb_depth = 0;
677
 
  params->lfb_base = 0;
678
 
  params->lfb_size = 0;
679
 
  params->lfb_line_len = 0;
680
 
  params->red_mask_size = 0;
681
 
  params->red_field_pos = 0;
682
 
  params->green_mask_size = 0;
683
 
  params->green_field_pos = 0;
684
 
  params->blue_mask_size = 0;
685
 
  params->blue_field_pos = 0;
686
 
  params->reserved_mask_size = 0;
687
 
  params->reserved_field_pos = 0;
688
 
  params->vesapm_segment = 0;
689
 
  params->vesapm_offset = 0;
690
 
  params->lfb_pages = 0;
691
 
  params->vesa_attrib = 0;
692
 
 
693
 
  /* No APM on EFI.  */
694
 
  params->apm_version = 0;
695
 
  params->apm_code_segment = 0;
696
 
  params->apm_entry = 0;
697
 
  params->apm_16bit_code_segment = 0;
698
 
  params->apm_data_segment = 0;
699
 
  params->apm_flags = 0;
700
 
  params->apm_code_len = 0;
701
 
  params->apm_data_len = 0;
702
 
 
703
 
  /* XXX is there any way to use SpeedStep on EFI?  */
704
 
  params->ist_signature = 0;
705
 
  params->ist_command = 0;
706
 
  params->ist_event = 0;
707
 
  params->ist_perf_level = 0;
708
 
 
709
 
  /* Let the kernel probe the information.  */
710
 
  grub_memset (params->hd0_drive_info, 0, sizeof (params->hd0_drive_info));
711
 
  grub_memset (params->hd1_drive_info, 0, sizeof (params->hd1_drive_info));
712
 
 
713
 
  /* No MCA on EFI.  */
714
 
  params->rom_config_len = 0;
715
 
 
716
 
  /* No need to fake the BIOS's memory map.  */
717
 
  params->mmap_size = 0;
718
 
 
719
 
  /* Let the kernel probe the information.  */
720
 
  params->ps_mouse = 0;
721
 
 
722
 
  /* Clear padding for future compatibility.  */
723
 
  grub_memset (params->padding1, 0, sizeof (params->padding1));
724
 
  grub_memset (params->padding2, 0, sizeof (params->padding2));
725
 
  grub_memset (params->padding3, 0, sizeof (params->padding3));
726
 
  grub_memset (params->padding4, 0, sizeof (params->padding4));
727
 
  grub_memset (params->padding5, 0, sizeof (params->padding5));
728
 
  grub_memset (params->padding6, 0, sizeof (params->padding6));
729
 
  grub_memset (params->padding7, 0, sizeof (params->padding7));
730
 
  grub_memset (params->padding8, 0, sizeof (params->padding8));
731
 
  grub_memset (params->padding9, 0, sizeof (params->padding9));
732
 
 
733
 
#endif
734
 
 
735
 
  /* The other EFI parameters are filled when booting.  */
736
 
 
737
 
  grub_file_seek (file, real_size + GRUB_DISK_SECTOR_SIZE);
738
 
 
739
 
  /* XXX there is no way to know if the kernel really supports EFI.  */
740
 
  grub_printf ("   [Linux-bzImage, setup=0x%x, size=0x%x]\n",
741
 
               (unsigned) real_size, (unsigned) prot_size);
742
 
 
743
 
  /* Detect explicitly specified memory size, if any.  */
744
 
  linux_mem_size = 0;
745
 
  for (i = 1; i < argc; i++)
746
 
    if (grub_memcmp (argv[i], "mem=", 4) == 0)
747
 
      {
748
 
        char *val = argv[i] + 4;
749
 
 
750
 
        linux_mem_size = grub_strtoul (val, &val, 0);
751
 
 
752
 
        if (grub_errno)
753
 
          {
754
 
            grub_errno = GRUB_ERR_NONE;
755
 
            linux_mem_size = 0;
756
 
          }
757
 
        else
758
 
          {
759
 
            int shift = 0;
760
 
 
761
 
            switch (grub_tolower (val[0]))
762
 
              {
763
 
              case 'g':
764
 
                shift += 10;
765
 
              case 'm':
766
 
                shift += 10;
767
 
              case 'k':
768
 
                shift += 10;
769
 
              default:
770
 
                break;
771
 
              }
772
 
 
773
 
            /* Check an overflow.  */
774
 
            if (linux_mem_size > (~0UL >> shift))
775
 
              linux_mem_size = 0;
776
 
            else
777
 
              linux_mem_size <<= shift;
778
 
          }
779
 
      }
780
 
    else if (grub_memcmp (argv[i], "video=efifb", 11) == 0)
781
 
      {
782
 
        if (params->have_vga)
783
 
          params->have_vga = GRUB_VIDEO_LINUX_TYPE_SIMPLE;
784
 
      }
785
 
 
786
 
  /* Specify the boot file.  */
787
 
  dest = grub_stpcpy ((char *) real_mode_mem + GRUB_LINUX_CL_OFFSET,
788
 
                      "BOOT_IMAGE=");
789
 
  dest = grub_stpcpy (dest, argv[0]);
790
 
 
791
 
  /* Copy kernel parameters.  */
792
 
  for (i = 1;
793
 
       i < argc
794
 
         && dest + grub_strlen (argv[i]) + 1 < ((char *) real_mode_mem
795
 
                                                + GRUB_LINUX_CL_END_OFFSET);
796
 
       i++)
797
 
    {
798
 
      *dest++ = ' ';
799
 
      dest = grub_stpcpy (dest, argv[i]);
800
 
    }
801
 
 
802
 
  len = prot_size;
803
 
  if (grub_file_read (file, (void *) GRUB_LINUX_BZIMAGE_ADDR, len) != len)
804
 
    grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file");
805
 
 
806
 
  if (grub_errno == GRUB_ERR_NONE)
807
 
    {
808
 
      grub_loader_set (grub_linux_boot, grub_linux_unload, 0);
809
 
      loaded = 1;
810
 
    }
811
 
 
812
 
 fail:
813
 
 
814
 
  if (file)
815
 
    grub_file_close (file);
816
 
 
817
 
  if (grub_errno != GRUB_ERR_NONE)
818
 
    {
819
 
      grub_dl_unref (my_mod);
820
 
      loaded = 0;
821
 
    }
822
 
 
823
 
  return grub_errno;
824
 
}
825
 
 
826
 
static grub_err_t
827
 
grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
828
 
                 int argc, char *argv[])
829
 
{
830
 
  grub_file_t file = 0;
831
 
  grub_ssize_t size;
832
 
  grub_addr_t addr_min, addr_max;
833
 
  grub_addr_t addr;
834
 
  grub_efi_uintn_t mmap_size;
835
 
  grub_efi_memory_descriptor_t *desc;
836
 
  grub_efi_uintn_t desc_size;
837
 
  struct linux_kernel_header *lh;
838
 
 
839
 
  if (argc == 0)
840
 
    {
841
 
      grub_error (GRUB_ERR_BAD_ARGUMENT, "no module specified");
842
 
      goto fail;
843
 
    }
844
 
 
845
 
  if (! loaded)
846
 
    {
847
 
      grub_error (GRUB_ERR_BAD_ARGUMENT, "you need to load the kernel first");
848
 
      goto fail;
849
 
    }
850
 
 
851
 
  file = grub_file_open (argv[0]);
852
 
  if (! file)
853
 
    goto fail;
854
 
 
855
 
  size = grub_file_size (file);
856
 
  initrd_pages = (page_align (size) >> 12);
857
 
 
858
 
  lh = (struct linux_kernel_header *) real_mode_mem;
859
 
 
860
 
  addr_max = (grub_cpu_to_le32 (lh->initrd_addr_max) << 10);
861
 
  if (linux_mem_size != 0 && linux_mem_size < addr_max)
862
 
    addr_max = linux_mem_size;
863
 
 
864
 
  /* Linux 2.3.xx has a bug in the memory range check, so avoid
865
 
     the last page.
866
 
     Linux 2.2.xx has a bug in the memory range check, which is
867
 
     worse than that of Linux 2.3.xx, so avoid the last 64kb.  */
868
 
  addr_max -= 0x10000;
869
 
 
870
 
  /* Usually, the compression ratio is about 50%.  */
871
 
  addr_min = (grub_addr_t) prot_mode_mem + ((prot_mode_pages * 3) << 12)
872
 
             + page_align (size);
873
 
 
874
 
  /* Find the highest address to put the initrd.  */
875
 
  mmap_size = find_mmap_size ();
876
 
  if (grub_efi_get_memory_map (&mmap_size, mmap_buf, 0, &desc_size, 0) <= 0)
877
 
    grub_fatal ("cannot get memory map");
878
 
 
879
 
  addr = 0;
880
 
  for (desc = mmap_buf;
881
 
       desc < NEXT_MEMORY_DESCRIPTOR (mmap_buf, mmap_size);
882
 
       desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size))
883
 
    {
884
 
      if (desc->type == GRUB_EFI_CONVENTIONAL_MEMORY
885
 
          && desc->num_pages >= initrd_pages)
886
 
        {
887
 
          grub_efi_physical_address_t physical_end;
888
 
 
889
 
          physical_end = desc->physical_start + (desc->num_pages << 12);
890
 
          if (physical_end > addr_max)
891
 
            physical_end = addr_max;
892
 
 
893
 
          if (physical_end < page_align (size))
894
 
            continue;
895
 
 
896
 
          physical_end -= page_align (size);
897
 
 
898
 
          if ((physical_end >= addr_min) &&
899
 
              (physical_end >= desc->physical_start) &&
900
 
              (physical_end > addr))
901
 
            addr = physical_end;
902
 
        }
903
 
    }
904
 
 
905
 
  if (addr == 0)
906
 
    {
907
 
      grub_error (GRUB_ERR_OUT_OF_MEMORY, "no free pages available");
908
 
      goto fail;
909
 
    }
910
 
 
911
 
  initrd_mem = grub_efi_allocate_pages (addr, initrd_pages);
912
 
  if (! initrd_mem)
913
 
    grub_fatal ("cannot allocate pages");
914
 
 
915
 
  if (grub_file_read (file, initrd_mem, size) != size)
916
 
    {
917
 
      grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file");
918
 
      goto fail;
919
 
    }
920
 
 
921
 
  grub_printf ("   [Initrd, addr=0x%x, size=0x%x]\n",
922
 
               (unsigned) addr, (unsigned) size);
923
 
 
924
 
  lh->ramdisk_image = addr;
925
 
  lh->ramdisk_size = size;
926
 
  lh->root_dev = 0x0100; /* XXX */
927
 
 
928
 
 fail:
929
 
  if (file)
930
 
    grub_file_close (file);
931
 
 
932
 
  return grub_errno;
933
 
}
934
 
 
935
 
static grub_command_t cmd_linux, cmd_initrd;
936
 
 
937
 
GRUB_MOD_INIT(linux)
938
 
{
939
 
  cmd_linux = grub_register_command ("linux", grub_cmd_linux,
940
 
                                     0, N_("Load Linux."));
941
 
  cmd_initrd = grub_register_command ("initrd", grub_cmd_initrd,
942
 
                                      0, N_("Load initrd."));
943
 
  my_mod = mod;
944
 
}
945
 
 
946
 
GRUB_MOD_FINI(linux)
947
 
{
948
 
  grub_unregister_command (cmd_linux);
949
 
  grub_unregister_command (cmd_initrd);
950
 
}