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

« back to all changes in this revision

Viewing changes to loader/i386/linux.c

  • Committer: Bazaar Package Importer
  • Author(s): Colin Watson, Colin Watson, Evan Broder, Mario Limonciello
  • Date: 2010-11-24 13:59:55 UTC
  • mfrom: (1.17.6 upstream) (17.6.15 experimental)
  • Revision ID: james.westby@ubuntu.com-20101124135955-r6ii5sepayr7jt53
Tags: 1.99~20101124-1ubuntu1
[ Colin Watson ]
* Resynchronise with Debian experimental.  Remaining changes:
  - Adjust for default Ubuntu boot options ("quiet splash").
  - Default to hiding the menu; holding down Shift at boot will show it.
  - Set a monochromatic theme for Ubuntu.
  - Apply Ubuntu GRUB Legacy changes to legacy update-grub script: title,
    recovery mode, quiet option, tweak how memtest86+ is displayed, and
    use UUIDs where appropriate.
  - Fix backslash-escaping in merge_debconf_into_conf.
  - Remove "GNU/Linux" from default distributor string.
  - Add crashkernel= options if kdump and makedumpfile are available.
  - If other operating systems are installed, then automatically unhide
    the menu.  Otherwise, if GRUB_HIDDEN_TIMEOUT is 0, then use keystatus
    if available to check whether Shift is pressed.  If it is, show the
    menu, otherwise boot immediately.  If keystatus is not available, then
    fall back to a short delay interruptible with Escape.
  - Allow Shift to interrupt 'sleep --interruptible'.
  - Don't display introductory message about line editing unless we're
    actually offering a shell prompt.  Don't clear the screen just before
    booting if we never drew the menu in the first place.
  - Remove some verbose messages printed before reading the configuration
    file.
  - Suppress progress messages as the kernel and initrd load for
    non-recovery kernel menu entries.
  - Change prepare_grub_to_access_device to handle filesystems
    loop-mounted on file images.
  - Ignore devices loop-mounted from files in 10_linux.
  - Show the boot menu if the previous boot failed, that is if it failed
    to get to the end of one of the normal runlevels.
  - Don't generate /boot/grub/device.map during grub-install or
    grub-mkconfig by default.
  - Adjust upgrade version checks for Ubuntu.
  - Don't display "GRUB loading" unless Shift is held down.
  - Adjust versions of grub-doc and grub-legacy-doc conflicts to tolerate
    our backport of the grub-doc split.
  - Fix LVM/RAID probing in the absence of /boot/grub/device.map.
  - Look for .mo files in /usr/share/locale-langpack as well, in
    preference.
  - Make sure GRUB_TIMEOUT isn't quoted unnecessarily.
  - Probe all devices in 'grub-probe --target=drive' if
    /boot/grub/device.map is missing.
  - Build-depend on qemu-kvm rather than qemu-system for grub-pc tests.
  - Use qemu rather than qemu-system-i386.
  - Program vesafb on BIOS systems rather than efifb.
  - Add a grub-rescue-efi-amd64 package containing a rescue CD-ROM image
    for EFI-AMD64.
  - On Wubi, don't ask for an install device, but just update wubildr
    using the diverted grub-install.
  - When embedding the core image in a post-MBR gap, check for and avoid
    sectors matching any of a list of known signatures.
  - Disable video_bochs and video_cirrus on PC BIOS systems, as probing
    PCI space seems to break on some systems.
* Downgrade "ACPI shutdown failed" error to a debug message, since it can
  cause spurious test failures.

[ Evan Broder ]
* Enable lua from grub-extras.
* Incorporate the bitop library into lua.
* Add enum_pci function to grub module in lua.
* Switch back to gfxpayload=keep by default, unless the video hardware
  is known to not support it.

[ Mario Limonciello ]
* Built part_msdos and vfat into bootx64.efi (LP: #677758)

Show diffs side-by-side

added added

removed removed

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