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/command.h>
28 #include <grub/i18n.h>
29 #include <grub/memory.h>
30 #include <grub/lib/cmdline.h>
32 GRUB_MOD_LICENSE ("GPLv3+");
34 static grub_dl_t my_mod
;
38 /* /virtual-memory/translations property layout */
39 struct grub_ieee1275_translation
{
45 static struct grub_ieee1275_translation
*of_trans
;
46 static int of_num_trans
;
48 static grub_addr_t phys_base
;
49 static grub_addr_t grub_phys_start
;
50 static grub_addr_t grub_phys_end
;
52 static grub_addr_t initrd_addr
;
53 static grub_addr_t initrd_paddr
;
54 static grub_size_t initrd_size
;
56 static Elf64_Addr linux_entry
;
57 static grub_addr_t linux_addr
;
58 static grub_addr_t linux_paddr
;
59 static grub_size_t linux_size
;
61 static char *linux_args
;
63 struct linux_bootstr_info
{
69 /* All HdrS versions support these fields. */
70 unsigned int start_insns
[2];
71 char magic
[4]; /* "HdrS" */
72 unsigned int linux_kernel_version
; /* LINUX_VERSION_CODE */
73 unsigned short hdrs_version
;
74 unsigned short root_flags
;
75 unsigned short root_dev
;
76 unsigned short ram_flags
;
77 unsigned int __deprecated_ramdisk_image
;
78 unsigned int ramdisk_size
;
80 /* HdrS versions 0x0201 and higher only */
83 /* HdrS versions 0x0202 and higher only */
84 struct linux_bootstr_info
*bootstr_info
;
86 /* HdrS versions 0x0301 and higher only */
87 unsigned long ramdisk_image
;
91 grub_linux_boot (void)
93 struct linux_bootstr_info
*bp
;
94 struct linux_hdrs
*hp
;
97 hp
= (struct linux_hdrs
*) linux_addr
;
99 /* Any pointer we dereference in the kernel image must be relocated
100 to where we actually loaded the kernel. */
101 addr
= (grub_addr_t
) hp
->bootstr_info
;
102 addr
+= (linux_addr
- linux_entry
);
103 bp
= (struct linux_bootstr_info
*) addr
;
105 /* Set the command line arguments, unless the kernel has been
106 built with a fixed CONFIG_CMDLINE. */
109 int len
= grub_strlen (linux_args
) + 1;
112 memcpy(bp
->buf
, linux_args
, len
);
113 bp
->buf
[len
-1] = '\0';
119 /* The kernel expects the physical address, adjusted relative
120 to the lowest address advertised in "/memory"'s available
123 The history of this is that back when the kernel only supported
124 specifying a 32-bit ramdisk address, this was the way to still
125 be able to specify the ramdisk physical address even if memory
126 started at some place above 4GB.
128 The magic 0x400000 is KERNBASE, I have no idea why SILO adds
129 that term into the address, but it does and thus we have to do
130 it too as this is what the kernel expects. */
131 hp
->ramdisk_image
= initrd_paddr
- phys_base
+ 0x400000;
132 hp
->ramdisk_size
= initrd_size
;
135 grub_dprintf ("loader", "Entry point: 0x%lx\n", linux_addr
);
136 grub_dprintf ("loader", "Initrd at: 0x%lx, size 0x%lx\n", initrd_addr
,
138 grub_dprintf ("loader", "Boot arguments: %s\n", linux_args
);
139 grub_dprintf ("loader", "Jumping to Linux...\n");
141 /* Boot the kernel. */
142 asm volatile ("sethi %hi(grub_ieee1275_entry_fn), %o1\n"
143 "ldx [%o1 + %lo(grub_ieee1275_entry_fn)], %o4\n"
144 "sethi %hi(grub_ieee1275_original_stack), %o1\n"
145 "ldx [%o1 + %lo(grub_ieee1275_original_stack)], %o6\n"
146 "sethi %hi(linux_addr), %o1\n"
147 "ldx [%o1 + %lo(linux_addr)], %o5\n"
154 return GRUB_ERR_NONE
;
158 grub_linux_release_mem (void)
160 grub_free (linux_args
);
165 return GRUB_ERR_NONE
;
169 grub_linux_unload (void)
173 err
= grub_linux_release_mem ();
174 grub_dl_unref (my_mod
);
181 #define FOUR_MB (4 * 1024 * 1024)
184 alloc_phys (grub_addr_t size
)
186 grub_addr_t ret
= (grub_addr_t
) -1;
188 auto int NESTED_FUNC_ATTR
choose (grub_uint64_t addr
, grub_uint64_t len
,
189 grub_memory_type_t type
);
190 int NESTED_FUNC_ATTR
choose (grub_uint64_t addr
, grub_uint64_t len
,
191 grub_memory_type_t type
)
193 grub_addr_t end
= addr
+ len
;
198 addr
= ALIGN_UP (addr
, FOUR_MB
);
199 if (addr
+ size
>= end
)
202 if (addr
>= grub_phys_start
&& addr
< grub_phys_end
)
204 addr
= ALIGN_UP (grub_phys_end
, FOUR_MB
);
205 if (addr
+ size
>= end
)
208 if ((addr
+ size
) >= grub_phys_start
209 && (addr
+ size
) < grub_phys_end
)
211 addr
= ALIGN_UP (grub_phys_end
, FOUR_MB
);
212 if (addr
+ size
>= end
)
218 grub_addr_t linux_end
= ALIGN_UP (linux_paddr
+ linux_size
, FOUR_MB
);
220 if (addr
>= linux_paddr
&& addr
< linux_end
)
223 if (addr
+ size
>= end
)
226 if ((addr
+ size
) >= linux_paddr
227 && (addr
+ size
) < linux_end
)
230 if (addr
+ size
>= end
)
239 grub_machine_mmap_iterate (choose
);
245 grub_linux_load64 (grub_elf_t elf
, const char *filename
)
247 grub_addr_t off
, paddr
, base
;
250 linux_entry
= elf
->ehdr
.ehdr64
.e_entry
;
251 linux_addr
= 0x40004000;
253 linux_size
= grub_elf64_size (elf
, filename
, 0, 0);
257 grub_dprintf ("loader", "Attempting to claim at 0x%lx, size 0x%lx.\n",
258 linux_addr
, linux_size
);
260 paddr
= alloc_phys (linux_size
+ off
);
261 if (paddr
== (grub_addr_t
) -1)
262 return grub_error (GRUB_ERR_OUT_OF_MEMORY
,
263 "couldn't allocate physical memory");
264 ret
= grub_ieee1275_map (paddr
, linux_addr
- off
,
265 linux_size
+ off
, IEEE1275_MAP_DEFAULT
);
267 return grub_error (GRUB_ERR_OUT_OF_MEMORY
,
268 "couldn't map physical memory");
270 grub_dprintf ("loader", "Loading Linux at vaddr 0x%lx, paddr 0x%lx, size 0x%lx\n",
271 linux_addr
, paddr
, linux_size
);
275 base
= linux_entry
- off
;
277 /* Now load the segments into the area we claimed. */
278 auto grub_err_t
offset_phdr (Elf64_Phdr
*phdr
, grub_addr_t
*addr
, int *do_load
);
279 grub_err_t
offset_phdr (Elf64_Phdr
*phdr
, grub_addr_t
*addr
, int *do_load
)
281 if (phdr
->p_type
!= PT_LOAD
)
288 /* Adjust the program load address to linux_addr. */
289 *addr
= (phdr
->p_paddr
- base
) + (linux_addr
- off
);
292 return grub_elf64_load (elf
, filename
, offset_phdr
, 0, 0);
296 grub_cmd_linux (grub_command_t cmd
__attribute__ ((unused
)),
297 int argc
, char *argv
[])
299 grub_file_t file
= 0;
303 grub_dl_ref (my_mod
);
307 grub_error (GRUB_ERR_BAD_ARGUMENT
, N_("filename expected"));
311 file
= grub_file_open (argv
[0]);
315 elf
= grub_elf_file (file
, argv
[0]);
319 if (elf
->ehdr
.ehdr32
.e_type
!= ET_EXEC
)
321 grub_error (GRUB_ERR_UNKNOWN_OS
,
322 N_("this ELF file is not of the right type"));
326 /* Release the previously used memory. */
327 grub_loader_unset ();
329 if (grub_elf_is_elf64 (elf
))
330 grub_linux_load64 (elf
, argv
[0]);
333 grub_error (GRUB_ERR_BAD_FILE_TYPE
, N_("invalid arch-dependent ELF magic"));
337 size
= grub_loader_cmdline_size(argc
, argv
);
339 linux_args
= grub_malloc (size
+ sizeof (LINUX_IMAGE
));
343 /* Create kernel command line. */
344 grub_memcpy (linux_args
, LINUX_IMAGE
, sizeof (LINUX_IMAGE
));
345 grub_create_loader_cmdline (argc
, argv
, linux_args
+ sizeof (LINUX_IMAGE
) - 1,
350 grub_elf_close (elf
);
352 grub_file_close (file
);
354 if (grub_errno
!= GRUB_ERR_NONE
)
356 grub_linux_release_mem ();
357 grub_dl_unref (my_mod
);
362 grub_loader_set (grub_linux_boot
, grub_linux_unload
, 1);
371 grub_cmd_initrd (grub_command_t cmd
__attribute__ ((unused
)),
372 int argc
, char *argv
[])
374 grub_file_t
*files
= 0;
375 grub_size_t size
= 0;
385 grub_error (GRUB_ERR_BAD_ARGUMENT
, N_("filename expected"));
391 grub_error (GRUB_ERR_BAD_ARGUMENT
, N_("you need to load the kernel first"));
395 files
= grub_zalloc (argc
* sizeof (files
[0]));
399 for (i
= 0; i
< argc
; i
++)
401 grub_file_filter_disable_compression ();
402 files
[i
] = grub_file_open (argv
[i
]);
406 size
+= ALIGN_UP(grub_file_size (files
[i
]), 4);
411 paddr
= alloc_phys (size
);
412 if (paddr
== (grub_addr_t
) -1)
414 grub_error (GRUB_ERR_OUT_OF_MEMORY
,
415 "couldn't allocate physical memory");
418 ret
= grub_ieee1275_map (paddr
, addr
, size
, IEEE1275_MAP_DEFAULT
);
421 grub_error (GRUB_ERR_OUT_OF_MEMORY
,
422 "couldn't map physical memory");
426 grub_dprintf ("loader", "Loading initrd at vaddr 0x%lx, paddr 0x%lx, size 0x%lx\n",
430 for (i
= 0; i
< nfiles
; i
++)
432 grub_ssize_t cursize
= grub_file_size (files
[i
]);
433 if (grub_file_read (files
[i
], ptr
, cursize
) != cursize
)
436 grub_error (GRUB_ERR_FILE_READ_ERROR
, N_("premature end of file %s"),
441 grub_memset (ptr
, 0, ALIGN_UP_OVERHEAD (cursize
, 4));
442 ptr
+= ALIGN_UP_OVERHEAD (cursize
, 4);
446 initrd_paddr
= paddr
;
450 for (i
= 0; i
< nfiles
; i
++)
451 grub_file_close (files
[i
]);
458 determine_phys_base (void)
460 auto int NESTED_FUNC_ATTR
get_physbase (grub_uint64_t addr
, grub_uint64_t len
__attribute__((unused
)), grub_uint32_t type
);
461 int NESTED_FUNC_ATTR
get_physbase (grub_uint64_t addr
, grub_uint64_t len
__attribute__((unused
)), grub_uint32_t type
)
465 if (addr
< phys_base
)
470 phys_base
= ~(grub_uint64_t
) 0;
471 grub_machine_mmap_iterate (get_physbase
);
475 fetch_translations (void)
477 grub_ieee1275_phandle_t node
;
481 if (grub_ieee1275_finddevice ("/virtual-memory", &node
))
483 grub_printf ("Cannot find /virtual-memory node.\n");
487 if (grub_ieee1275_get_property_length (node
, "translations", &actual
))
489 grub_printf ("Cannot find /virtual-memory/translations size.\n");
493 of_trans
= grub_malloc (actual
);
496 grub_printf ("Cannot allocate translations buffer.\n");
500 if (grub_ieee1275_get_property (node
, "translations", of_trans
, actual
, &actual
))
502 grub_printf ("Cannot fetch /virtual-memory/translations property.\n");
506 of_num_trans
= actual
/ sizeof(struct grub_ieee1275_translation
);
508 for (i
= 0; i
< of_num_trans
; i
++)
510 struct grub_ieee1275_translation
*p
= &of_trans
[i
];
512 if (p
->vaddr
== 0x2000)
514 grub_addr_t phys
, tte
= p
->data
;
516 phys
= tte
& ~(0xff00000000001fffULL
);
518 grub_phys_start
= phys
;
519 grub_phys_end
= grub_phys_start
+ p
->size
;
520 grub_dprintf ("loader", "Grub lives at phys_start[%lx] phys_end[%lx]\n",
521 (unsigned long) grub_phys_start
,
522 (unsigned long) grub_phys_end
);
529 static grub_command_t cmd_linux
, cmd_initrd
;
533 determine_phys_base ();
534 fetch_translations ();
536 cmd_linux
= grub_register_command ("linux", grub_cmd_linux
,
537 0, N_("Load Linux."));
538 cmd_initrd
= grub_register_command ("initrd", grub_cmd_initrd
,
539 0, N_("Load initrd."));
545 grub_unregister_command (cmd_linux
);
546 grub_unregister_command (cmd_initrd
);