1
/* linux.c - boot Linux */
3
* GRUB -- GRand Unified Bootloader
4
* Copyright (C) 2003, 2004, 2005, 2007, 2009 Free Software Foundation, Inc.
6
* GRUB is free software: you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation, either version 3 of the License, or
9
* (at your option) any later version.
11
* GRUB is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
21
#include <grub/elfload.h>
22
#include <grub/loader.h>
25
#include <grub/misc.h>
26
#include <grub/ieee1275/ieee1275.h>
27
#include <grub/machine/loader.h>
28
#include <grub/gzio.h>
29
#include <grub/command.h>
30
#include <grub/i18n.h>
32
static grub_dl_t my_mod;
36
/* /virtual-memory/translations property layout */
37
struct grub_ieee1275_translation {
43
static struct grub_ieee1275_translation *of_trans;
44
static int of_num_trans;
46
static grub_addr_t phys_base;
47
static grub_addr_t grub_phys_start;
48
static grub_addr_t grub_phys_end;
50
static grub_addr_t initrd_addr;
51
static grub_addr_t initrd_paddr;
52
static grub_size_t initrd_size;
54
static Elf64_Addr linux_entry;
55
static grub_addr_t linux_addr;
56
static grub_addr_t linux_paddr;
57
static grub_size_t linux_size;
59
static char *linux_args;
61
struct linux_bootstr_info {
67
/* All HdrS versions support these fields. */
68
unsigned int start_insns[2];
69
char magic[4]; /* "HdrS" */
70
unsigned int linux_kernel_version; /* LINUX_VERSION_CODE */
71
unsigned short hdrs_version;
72
unsigned short root_flags;
73
unsigned short root_dev;
74
unsigned short ram_flags;
75
unsigned int __deprecated_ramdisk_image;
76
unsigned int ramdisk_size;
78
/* HdrS versions 0x0201 and higher only */
81
/* HdrS versions 0x0202 and higher only */
82
struct linux_bootstr_info *bootstr_info;
84
/* HdrS versions 0x0301 and higher only */
85
unsigned long ramdisk_image;
89
grub_linux_boot (void)
91
struct linux_bootstr_info *bp;
92
struct linux_hdrs *hp;
95
hp = (struct linux_hdrs *) linux_addr;
97
/* Any pointer we dereference in the kernel image must be relocated
98
to where we actually loaded the kernel. */
99
addr = (grub_addr_t) hp->bootstr_info;
100
addr += (linux_addr - linux_entry);
101
bp = (struct linux_bootstr_info *) addr;
103
/* Set the command line arguments, unless the kernel has been
104
built with a fixed CONFIG_CMDLINE. */
107
int len = grub_strlen (linux_args) + 1;
110
memcpy(bp->buf, linux_args, len);
111
bp->buf[len-1] = '\0';
117
/* The kernel expects the physical address, adjusted relative
118
to the lowest address advertised in "/memory"'s available
121
The history of this is that back when the kernel only supported
122
specifying a 32-bit ramdisk address, this was the way to still
123
be able to specify the ramdisk physical address even if memory
124
started at some place above 4GB.
126
The magic 0x400000 is KERNBASE, I have no idea why SILO adds
127
that term into the address, but it does and thus we have to do
128
it too as this is what the kernel expects. */
129
hp->ramdisk_image = initrd_paddr - phys_base + 0x400000;
130
hp->ramdisk_size = initrd_size;
133
grub_dprintf ("loader", "Entry point: 0x%lx\n", linux_addr);
134
grub_dprintf ("loader", "Initrd at: 0x%lx, size 0x%lx\n", initrd_addr,
136
grub_dprintf ("loader", "Boot arguments: %s\n", linux_args);
137
grub_dprintf ("loader", "Jumping to Linux...\n");
139
/* Boot the kernel. */
140
asm volatile ("sethi %hi(grub_ieee1275_entry_fn), %o1\n"
141
"ldx [%o1 + %lo(grub_ieee1275_entry_fn)], %o4\n"
142
"sethi %hi(grub_ieee1275_original_stack), %o1\n"
143
"ldx [%o1 + %lo(grub_ieee1275_original_stack)], %o6\n"
144
"sethi %hi(linux_addr), %o1\n"
145
"ldx [%o1 + %lo(linux_addr)], %o5\n"
152
return GRUB_ERR_NONE;
156
grub_linux_release_mem (void)
158
grub_free (linux_args);
163
return GRUB_ERR_NONE;
167
grub_linux_unload (void)
171
err = grub_linux_release_mem ();
172
grub_dl_unref (my_mod);
179
#define FOUR_MB (4 * 1024 * 1024)
182
alloc_phys (grub_addr_t size)
184
grub_addr_t ret = (grub_addr_t) -1;
186
auto int NESTED_FUNC_ATTR choose (grub_uint64_t addr, grub_uint64_t len __attribute__((unused)), grub_uint32_t type);
187
int NESTED_FUNC_ATTR choose (grub_uint64_t addr, grub_uint64_t len __attribute__((unused)), grub_uint32_t type)
189
grub_addr_t end = addr + len;
194
addr = ALIGN_UP (addr, FOUR_MB);
195
if (addr + size >= end)
198
if (addr >= grub_phys_start && addr < grub_phys_end)
200
addr = ALIGN_UP (grub_phys_end, FOUR_MB);
201
if (addr + size >= end)
204
if ((addr + size) >= grub_phys_start
205
&& (addr + size) < grub_phys_end)
207
addr = ALIGN_UP (grub_phys_end, FOUR_MB);
208
if (addr + size >= end)
214
grub_addr_t linux_end = ALIGN_UP (linux_paddr + linux_size, FOUR_MB);
216
if (addr >= linux_paddr && addr < linux_end)
219
if (addr + size >= end)
222
if ((addr + size) >= linux_paddr
223
&& (addr + size) < linux_end)
226
if (addr + size >= end)
235
grub_machine_mmap_iterate (choose);
241
grub_linux_load64 (grub_elf_t elf)
243
grub_addr_t off, paddr, base;
246
linux_entry = elf->ehdr.ehdr64.e_entry;
247
linux_addr = 0x40004000;
249
linux_size = grub_elf64_size (elf, 0);
253
grub_dprintf ("loader", "Attempting to claim at 0x%lx, size 0x%lx.\n",
254
linux_addr, linux_size);
256
paddr = alloc_phys (linux_size + off);
257
if (paddr == (grub_addr_t) -1)
258
return grub_error (GRUB_ERR_OUT_OF_MEMORY,
259
"couldn't allocate physical memory");
260
ret = grub_ieee1275_map (paddr, linux_addr - off,
261
linux_size + off, IEEE1275_MAP_DEFAULT);
263
return grub_error (GRUB_ERR_OUT_OF_MEMORY,
264
"couldn't map physical memory");
266
grub_dprintf ("loader", "Loading Linux at vaddr 0x%lx, paddr 0x%lx, size 0x%lx\n",
267
linux_addr, paddr, linux_size);
271
base = linux_entry - off;
273
/* Now load the segments into the area we claimed. */
274
auto grub_err_t offset_phdr (Elf64_Phdr *phdr, grub_addr_t *addr, int *do_load);
275
grub_err_t offset_phdr (Elf64_Phdr *phdr, grub_addr_t *addr, int *do_load)
277
if (phdr->p_type != PT_LOAD)
284
/* Adjust the program load address to linux_addr. */
285
*addr = (phdr->p_paddr - base) + (linux_addr - off);
288
return grub_elf64_load (elf, offset_phdr, 0, 0);
292
grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
293
int argc, char *argv[])
295
grub_file_t file = 0;
301
grub_dl_ref (my_mod);
305
grub_error (GRUB_ERR_BAD_ARGUMENT, "no kernel specified");
309
file = grub_gzfile_open (argv[0], 1);
313
elf = grub_elf_file (file);
317
if (elf->ehdr.ehdr32.e_type != ET_EXEC)
319
grub_error (GRUB_ERR_UNKNOWN_OS,
320
"this ELF file is not of the right type");
324
/* Release the previously used memory. */
325
grub_loader_unset ();
327
if (grub_elf_is_elf64 (elf))
328
grub_linux_load64 (elf);
331
grub_error (GRUB_ERR_BAD_FILE_TYPE, "unknown ELF class");
335
size = sizeof ("BOOT_IMAGE=") + grub_strlen (argv[0]);
336
for (i = 0; i < argc; i++)
337
size += grub_strlen (argv[i]) + 1;
339
linux_args = grub_malloc (size);
343
/* Specify the boot file. */
344
dest = grub_stpcpy (linux_args, "BOOT_IMAGE=");
345
dest = grub_stpcpy (dest, argv[0]);
347
for (i = 1; i < argc; i++)
350
dest = grub_stpcpy (dest, argv[i]);
355
grub_elf_close (elf);
357
grub_file_close (file);
359
if (grub_errno != GRUB_ERR_NONE)
361
grub_linux_release_mem ();
362
grub_dl_unref (my_mod);
367
grub_loader_set (grub_linux_boot, grub_linux_unload, 1);
376
grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
377
int argc, char *argv[])
379
grub_file_t file = 0;
387
grub_error (GRUB_ERR_BAD_ARGUMENT, "no initrd specified");
393
grub_error (GRUB_ERR_BAD_ARGUMENT, "you need to load the kernel first");
397
file = grub_file_open (argv[0]);
402
size = grub_file_size (file);
404
paddr = alloc_phys (size);
405
if (paddr == (grub_addr_t) -1)
407
grub_error (GRUB_ERR_OUT_OF_MEMORY,
408
"couldn't allocate physical memory");
411
ret = grub_ieee1275_map (paddr, addr, size, IEEE1275_MAP_DEFAULT);
414
grub_error (GRUB_ERR_OUT_OF_MEMORY,
415
"couldn't map physical memory");
419
grub_dprintf ("loader", "Loading initrd at vaddr 0x%lx, paddr 0x%lx, size 0x%lx\n",
422
if (grub_file_read (file, (void *) addr, size) != size)
424
grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file");
429
initrd_paddr = paddr;
434
grub_file_close (file);
440
determine_phys_base (void)
442
auto int NESTED_FUNC_ATTR get_physbase (grub_uint64_t addr, grub_uint64_t len __attribute__((unused)), grub_uint32_t type);
443
int NESTED_FUNC_ATTR get_physbase (grub_uint64_t addr, grub_uint64_t len __attribute__((unused)), grub_uint32_t type)
447
if (addr < phys_base)
452
phys_base = ~(grub_uint64_t) 0;
453
grub_machine_mmap_iterate (get_physbase);
457
fetch_translations (void)
459
grub_ieee1275_phandle_t node;
463
if (grub_ieee1275_finddevice ("/virtual-memory", &node))
465
grub_printf ("Cannot find /virtual-memory node.\n");
469
if (grub_ieee1275_get_property_length (node, "translations", &actual))
471
grub_printf ("Cannot find /virtual-memory/translations size.\n");
475
of_trans = grub_malloc (actual);
478
grub_printf ("Cannot allocate translations buffer.\n");
482
if (grub_ieee1275_get_property (node, "translations", of_trans, actual, &actual))
484
grub_printf ("Cannot fetch /virtual-memory/translations property.\n");
488
of_num_trans = actual / sizeof(struct grub_ieee1275_translation);
490
for (i = 0; i < of_num_trans; i++)
492
struct grub_ieee1275_translation *p = &of_trans[i];
494
if (p->vaddr == 0x2000)
496
grub_addr_t phys, tte = p->data;
498
phys = tte & ~(0xff00000000001fffULL);
500
grub_phys_start = phys;
501
grub_phys_end = grub_phys_start + p->size;
502
grub_dprintf ("loader", "Grub lives at phys_start[%lx] phys_end[%lx]\n",
503
(unsigned long) grub_phys_start,
504
(unsigned long) grub_phys_end);
511
static grub_command_t cmd_linux, cmd_initrd;
515
determine_phys_base ();
516
fetch_translations ();
518
cmd_linux = grub_register_command ("linux", grub_cmd_linux,
519
0, N_("Load Linux."));
520
cmd_initrd = grub_register_command ("initrd", grub_cmd_initrd,
521
0, N_("Load initrd."));
527
grub_unregister_command (cmd_linux);
528
grub_unregister_command (cmd_initrd);