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