source: grub-pc/trunk/fuentes/grub-core/loader/i386/linux.c @ 22

Last change on this file since 22 was 22, checked in by mabarracus, 4 years ago

updated version and apply net.ifnames=0 into debian/rules

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