]>
Commit | Line | Data |
---|---|---|
ea818634 | 1 | /* linux.c - boot Linux */ |
2 | /* | |
3 | * GRUB -- GRand Unified Bootloader | |
ff989071 | 4 | * Copyright (C) 2003,2004,2005,2007,2009,2010 Free Software Foundation, Inc. |
ea818634 | 5 | * |
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. | |
10 | * | |
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. | |
15 | * | |
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/>. | |
18 | */ | |
19 | ||
20 | #include <grub/elf.h> | |
21 | #include <grub/elfload.h> | |
22 | #include <grub/loader.h> | |
23 | #include <grub/dl.h> | |
24 | #include <grub/mm.h> | |
25 | #include <grub/misc.h> | |
ea818634 | 26 | #include <grub/command.h> |
27 | #include <grub/mips/relocator.h> | |
df3df23d | 28 | #include <grub/memory.h> |
47d5f3c1 | 29 | #include <grub/i18n.h> |
dc16af03 | 30 | #include <grub/lib/cmdline.h> |
0f355bc6 | 31 | |
e745cf0c VS |
32 | GRUB_MOD_LICENSE ("GPLv3+"); |
33 | ||
0f355bc6 | 34 | /* For frequencies. */ |
d114e89c | 35 | #include <grub/machine/time.h> |
ea818634 | 36 | |
54da1feb | 37 | #ifdef GRUB_MACHINE_MIPS_LOONGSON |
12ce749d | 38 | #include <grub/pci.h> |
74eea126 VS |
39 | #include <grub/machine/kernel.h> |
40 | ||
41 | const char loongson_machtypes[][60] = | |
42 | { | |
43 | [GRUB_ARCH_MACHINE_YEELOONG] = "machtype=lemote-yeeloong-2f-8.9inches", | |
14a2562c VS |
44 | [GRUB_ARCH_MACHINE_FULOONG2F] = "machtype=lemote-fuloong-2f-unknown", |
45 | [GRUB_ARCH_MACHINE_FULOONG2E] = "machtype=lemote-fuloong-2e-unknown" | |
74eea126 | 46 | }; |
b9b3839f RM |
47 | #endif |
48 | ||
ea818634 | 49 | static grub_dl_t my_mod; |
50 | ||
51 | static int loaded; | |
52 | ||
ea818634 | 53 | static grub_size_t linux_size; |
54 | ||
7d8c9ec6 | 55 | static struct grub_relocator *relocator; |
ea818634 | 56 | static grub_uint8_t *playground; |
96c210da | 57 | static grub_addr_t target_addr, entry_addr; |
dc16af03 VS |
58 | #ifdef GRUB_MACHINE_MIPS_QEMU_MIPS |
59 | static char *params; | |
60 | #else | |
368a0c61 | 61 | static int linux_argc; |
12ce749d | 62 | static grub_off_t argv_off; |
bee1aeb9 | 63 | #ifdef GRUB_MACHINE_MIPS_LOONGSON |
12ce749d VS |
64 | static grub_off_t envp_off; |
65 | #endif | |
96c210da | 66 | static grub_off_t rd_addr_arg_off, rd_size_arg_off; |
dc16af03 | 67 | #endif |
96c210da | 68 | static int initrd_loaded = 0; |
ea818634 | 69 | |
70 | static grub_err_t | |
71 | grub_linux_boot (void) | |
72 | { | |
ea818634 | 73 | struct grub_relocator32_state state; |
74 | ||
dc16af03 VS |
75 | grub_memset (&state, 0, sizeof (state)); |
76 | ||
ea818634 | 77 | /* Boot the kernel. */ |
78 | state.gpr[1] = entry_addr; | |
dc16af03 VS |
79 | |
80 | #ifdef GRUB_MACHINE_MIPS_QEMU_MIPS | |
81 | { | |
82 | grub_err_t err; | |
83 | grub_relocator_chunk_t ch; | |
566a1917 VS |
84 | grub_uint32_t *memsize; |
85 | grub_uint32_t *magic; | |
86 | char *str; | |
dc16af03 VS |
87 | |
88 | err = grub_relocator_alloc_chunk_addr (relocator, &ch, | |
566a1917 VS |
89 | ((16 << 20) - 264), |
90 | grub_strlen (params) + 1 + 8); | |
dc16af03 VS |
91 | if (err) |
92 | return err; | |
566a1917 VS |
93 | memsize = get_virtual_current_address (ch); |
94 | magic = memsize + 1; | |
95 | *memsize = grub_mmap_get_lower (); | |
96 | *magic = 0x12345678; | |
97 | str = (char *) (magic + 1); | |
98 | grub_strcpy (str, params); | |
dc16af03 VS |
99 | } |
100 | #endif | |
101 | ||
102 | #ifndef GRUB_MACHINE_MIPS_QEMU_MIPS | |
368a0c61 | 103 | state.gpr[4] = linux_argc; |
96c210da | 104 | state.gpr[5] = target_addr + argv_off; |
bee1aeb9 | 105 | #ifdef GRUB_MACHINE_MIPS_LOONGSON |
96c210da | 106 | state.gpr[6] = target_addr + envp_off; |
12ce749d VS |
107 | #else |
108 | state.gpr[6] = 0; | |
109 | #endif | |
110 | state.gpr[7] = 0; | |
dc16af03 | 111 | #endif |
ea818634 | 112 | state.jumpreg = 1; |
7d8c9ec6 | 113 | grub_relocator32_boot (relocator, state); |
ea818634 | 114 | |
115 | return GRUB_ERR_NONE; | |
116 | } | |
117 | ||
118 | static grub_err_t | |
119 | grub_linux_unload (void) | |
120 | { | |
7d8c9ec6 | 121 | grub_relocator_unload (relocator); |
ea818634 | 122 | grub_dl_unref (my_mod); |
123 | ||
dc16af03 VS |
124 | #ifdef GRUB_MACHINE_MIPS_QEMU_MIPS |
125 | grub_free (params); | |
126 | params = 0; | |
127 | #endif | |
128 | ||
ea818634 | 129 | loaded = 0; |
130 | ||
7d8c9ec6 | 131 | return GRUB_ERR_NONE; |
ea818634 | 132 | } |
133 | ||
134 | static grub_err_t | |
bb272a0f | 135 | grub_linux_load32 (grub_elf_t elf, void **extra_mem, grub_size_t extra_size) |
ea818634 | 136 | { |
137 | Elf32_Addr base; | |
bb272a0f | 138 | int extraoff; |
7d8c9ec6 | 139 | grub_err_t err; |
ea818634 | 140 | |
141 | /* Linux's entry point incorrectly contains a virtual address. */ | |
530a4814 | 142 | entry_addr = elf->ehdr.ehdr32.e_entry; |
ea818634 | 143 | |
9c4cf53b | 144 | linux_size = grub_elf32_size (elf, &base, 0); |
ea818634 | 145 | if (linux_size == 0) |
146 | return grub_errno; | |
147 | target_addr = base; | |
148 | /* Pad it; the kernel scribbles over memory beyond its load address. */ | |
149 | linux_size += 0x100000; | |
bb272a0f | 150 | linux_size = ALIGN_UP (base + linux_size, 4) - base; |
151 | extraoff = linux_size; | |
152 | linux_size += extra_size; | |
ea818634 | 153 | |
7d8c9ec6 VS |
154 | relocator = grub_relocator_new (); |
155 | if (!relocator) | |
ea818634 | 156 | return grub_errno; |
157 | ||
530a4814 VS |
158 | { |
159 | grub_relocator_chunk_t ch; | |
160 | err = grub_relocator_alloc_chunk_addr (relocator, &ch, | |
161 | target_addr & 0x1fffffff, | |
162 | linux_size); | |
163 | if (err) | |
164 | return err; | |
165 | playground = get_virtual_current_address (ch); | |
166 | } | |
7d8c9ec6 | 167 | |
bb272a0f | 168 | *extra_mem = playground + extraoff; |
ea818634 | 169 | |
170 | /* Now load the segments into the area we claimed. */ | |
171 | auto grub_err_t offset_phdr (Elf32_Phdr *phdr, grub_addr_t *addr, int *do_load); | |
172 | grub_err_t offset_phdr (Elf32_Phdr *phdr, grub_addr_t *addr, int *do_load) | |
173 | { | |
174 | if (phdr->p_type != PT_LOAD) | |
175 | { | |
176 | *do_load = 0; | |
177 | return 0; | |
178 | } | |
179 | *do_load = 1; | |
180 | ||
181 | /* Linux's program headers incorrectly contain virtual addresses. | |
182 | * Translate those to physical, and offset to the area we claimed. */ | |
a45337b5 | 183 | *addr = (grub_addr_t) (phdr->p_paddr - base + playground); |
ea818634 | 184 | return 0; |
185 | } | |
186 | return grub_elf32_load (elf, offset_phdr, 0, 0); | |
187 | } | |
188 | ||
189 | static grub_err_t | |
bb272a0f | 190 | grub_linux_load64 (grub_elf_t elf, void **extra_mem, grub_size_t extra_size) |
ea818634 | 191 | { |
192 | Elf64_Addr base; | |
bb272a0f | 193 | int extraoff; |
7d8c9ec6 | 194 | grub_err_t err; |
ea818634 | 195 | |
196 | /* Linux's entry point incorrectly contains a virtual address. */ | |
530a4814 | 197 | entry_addr = elf->ehdr.ehdr64.e_entry; |
ea818634 | 198 | |
9c4cf53b | 199 | linux_size = grub_elf64_size (elf, &base, 0); |
ea818634 | 200 | if (linux_size == 0) |
201 | return grub_errno; | |
202 | target_addr = base; | |
203 | /* Pad it; the kernel scribbles over memory beyond its load address. */ | |
204 | linux_size += 0x100000; | |
bb272a0f | 205 | linux_size = ALIGN_UP (base + linux_size, 4) - base; |
206 | extraoff = linux_size; | |
207 | linux_size += extra_size; | |
ea818634 | 208 | |
7d8c9ec6 VS |
209 | relocator = grub_relocator_new (); |
210 | if (!relocator) | |
ea818634 | 211 | return grub_errno; |
212 | ||
530a4814 VS |
213 | { |
214 | grub_relocator_chunk_t ch; | |
215 | err = grub_relocator_alloc_chunk_addr (relocator, &ch, | |
216 | target_addr & 0x1fffffff, | |
217 | linux_size); | |
218 | if (err) | |
219 | return err; | |
220 | playground = get_virtual_current_address (ch); | |
221 | } | |
7d8c9ec6 | 222 | |
bb272a0f | 223 | *extra_mem = playground + extraoff; |
ea818634 | 224 | |
225 | /* Now load the segments into the area we claimed. */ | |
226 | auto grub_err_t offset_phdr (Elf64_Phdr *phdr, grub_addr_t *addr, int *do_load); | |
227 | grub_err_t offset_phdr (Elf64_Phdr *phdr, grub_addr_t *addr, int *do_load) | |
228 | { | |
229 | if (phdr->p_type != PT_LOAD) | |
230 | { | |
231 | *do_load = 0; | |
232 | return 0; | |
233 | } | |
234 | *do_load = 1; | |
235 | /* Linux's program headers incorrectly contain virtual addresses. | |
236 | * Translate those to physical, and offset to the area we claimed. */ | |
a45337b5 | 237 | *addr = (grub_addr_t) (phdr->p_paddr - base + playground); |
ea818634 | 238 | return 0; |
239 | } | |
240 | return grub_elf64_load (elf, offset_phdr, 0, 0); | |
241 | } | |
242 | ||
243 | static grub_err_t | |
244 | grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), | |
245 | int argc, char *argv[]) | |
246 | { | |
247 | grub_elf_t elf = 0; | |
ea818634 | 248 | int size; |
3478d0aa | 249 | void *extra = NULL; |
dc16af03 VS |
250 | #ifndef GRUB_MACHINE_MIPS_QEMU_MIPS |
251 | int i; | |
12ce749d VS |
252 | grub_uint32_t *linux_argv; |
253 | char *linux_args; | |
dc16af03 | 254 | #endif |
bb272a0f | 255 | grub_err_t err; |
bee1aeb9 | 256 | #ifdef GRUB_MACHINE_MIPS_LOONGSON |
12ce749d VS |
257 | char *linux_envs; |
258 | grub_uint32_t *linux_envp; | |
259 | #endif | |
ea818634 | 260 | |
261 | if (argc == 0) | |
bb272a0f | 262 | return grub_error (GRUB_ERR_BAD_ARGUMENT, "no kernel specified"); |
ea818634 | 263 | |
264 | elf = grub_elf_open (argv[0]); | |
265 | if (! elf) | |
bb272a0f | 266 | return grub_errno; |
ea818634 | 267 | |
268 | if (elf->ehdr.ehdr32.e_type != ET_EXEC) | |
269 | { | |
bb272a0f | 270 | grub_elf_close (elf); |
271 | return grub_error (GRUB_ERR_UNKNOWN_OS, | |
67951a53 | 272 | "this ELF file is not of the right type\n"); |
ea818634 | 273 | } |
274 | ||
275 | /* Release the previously used memory. */ | |
276 | grub_loader_unset (); | |
bb272a0f | 277 | loaded = 0; |
ea818634 | 278 | |
dc16af03 VS |
279 | #ifdef GRUB_MACHINE_MIPS_QEMU_MIPS |
280 | size = 0; | |
281 | #else | |
368a0c61 VS |
282 | /* For arguments. */ |
283 | linux_argc = argc; | |
54da1feb | 284 | #ifdef GRUB_MACHINE_MIPS_LOONGSON |
b9b3839f RM |
285 | linux_argc++; |
286 | #endif | |
96c210da | 287 | /* Main arguments. */ |
52d67f54 | 288 | size = (linux_argc) * sizeof (grub_uint32_t); |
96c210da VS |
289 | /* Initrd address and size. */ |
290 | size += 2 * sizeof (grub_uint32_t); | |
291 | /* NULL terminator. */ | |
292 | size += sizeof (grub_uint32_t); | |
293 | ||
52d67f54 | 294 | /* First argument is always "a0". */ |
96c210da | 295 | size += ALIGN_UP (sizeof ("a0"), 4); |
96c210da | 296 | /* Normal arguments. */ |
ea818634 | 297 | for (i = 1; i < argc; i++) |
bb272a0f | 298 | size += ALIGN_UP (grub_strlen (argv[i]) + 1, 4); |
54da1feb | 299 | #ifdef GRUB_MACHINE_MIPS_LOONGSON |
74eea126 | 300 | size += ALIGN_UP (sizeof (loongson_machtypes[0]), 4); |
b9b3839f RM |
301 | #endif |
302 | ||
96c210da VS |
303 | /* rd arguments. */ |
304 | size += ALIGN_UP (sizeof ("rd_start=0xXXXXXXXXXXXXXXXX"), 4); | |
305 | size += ALIGN_UP (sizeof ("rd_size=0xXXXXXXXXXXXXXXXX"), 4); | |
ea818634 | 306 | |
368a0c61 | 307 | /* For the environment. */ |
0f355bc6 VS |
308 | size += sizeof (grub_uint32_t); |
309 | size += 4 * sizeof (grub_uint32_t); | |
310 | size += ALIGN_UP (sizeof ("memsize=XXXXXXXXXXXXXXXXXXXX"), 4) | |
311 | + ALIGN_UP (sizeof ("highmemsize=XXXXXXXXXXXXXXXXXXXX"), 4) | |
312 | + ALIGN_UP (sizeof ("busclock=XXXXXXXXXX"), 4) | |
313 | + ALIGN_UP (sizeof ("cpuclock=XXXXXXXXXX"), 4); | |
dc16af03 | 314 | #endif |
368a0c61 | 315 | |
ea818634 | 316 | if (grub_elf_is_elf32 (elf)) |
bb272a0f | 317 | err = grub_linux_load32 (elf, &extra, size); |
ea818634 | 318 | else |
319 | if (grub_elf_is_elf64 (elf)) | |
bb272a0f | 320 | err = grub_linux_load64 (elf, &extra, size); |
ea818634 | 321 | else |
67951a53 | 322 | err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "unknown ELF class"); |
bb272a0f | 323 | |
324 | grub_elf_close (elf); | |
325 | ||
326 | if (err) | |
327 | return err; | |
368a0c61 | 328 | |
dc16af03 VS |
329 | #ifdef GRUB_MACHINE_MIPS_QEMU_MIPS |
330 | /* Create kernel command line. */ | |
331 | size = grub_loader_cmdline_size(argc, argv); | |
332 | params = grub_malloc (size + sizeof (LINUX_IMAGE)); | |
333 | if (! params) | |
334 | { | |
335 | grub_linux_unload (); | |
336 | return grub_errno; | |
337 | } | |
338 | ||
339 | grub_memcpy (params, LINUX_IMAGE, sizeof (LINUX_IMAGE)); | |
340 | grub_create_loader_cmdline (argc, argv, params + sizeof (LINUX_IMAGE) - 1, | |
341 | size); | |
342 | #else | |
bb272a0f | 343 | linux_argv = extra; |
96c210da | 344 | argv_off = (grub_uint8_t *) linux_argv - (grub_uint8_t *) playground; |
52d67f54 | 345 | extra = linux_argv + (linux_argc + 1 + 2); |
bb272a0f | 346 | linux_args = extra; |
96c210da VS |
347 | |
348 | grub_memcpy (linux_args, "a0", sizeof ("a0")); | |
7c8f6c18 | 349 | *linux_argv = (grub_uint8_t *) linux_args - (grub_uint8_t *) playground |
350 | + target_addr; | |
bb272a0f | 351 | linux_argv++; |
96c210da VS |
352 | linux_args += ALIGN_UP (sizeof ("a0"), 4); |
353 | ||
54da1feb | 354 | #ifdef GRUB_MACHINE_MIPS_LOONGSON |
74eea126 VS |
355 | { |
356 | unsigned mtype = grub_arch_machine; | |
357 | if (mtype >= ARRAY_SIZE (loongson_machtypes)) | |
358 | mtype = 0; | |
359 | /* In Loongson platform, it is the responsibility of the bootloader/firmware | |
360 | to supply the OS kernel with machine type information. */ | |
361 | grub_memcpy (linux_args, loongson_machtypes[mtype], | |
362 | sizeof (loongson_machtypes[mtype])); | |
363 | *linux_argv = (grub_uint8_t *) linux_args - (grub_uint8_t *) playground | |
364 | + target_addr; | |
365 | linux_argv++; | |
366 | linux_args += ALIGN_UP (sizeof (loongson_machtypes[mtype]), 4); | |
367 | } | |
b9b3839f RM |
368 | #endif |
369 | ||
bb272a0f | 370 | for (i = 1; i < argc; i++) |
ea818634 | 371 | { |
368a0c61 | 372 | grub_memcpy (linux_args, argv[i], grub_strlen (argv[i]) + 1); |
7c8f6c18 | 373 | *linux_argv = (grub_uint8_t *) linux_args - (grub_uint8_t *) playground |
374 | + target_addr; | |
bb272a0f | 375 | linux_argv++; |
368a0c61 | 376 | linux_args += ALIGN_UP (grub_strlen (argv[i]) + 1, 4); |
ea818634 | 377 | } |
96c210da VS |
378 | |
379 | /* Reserve space for rd arguments. */ | |
380 | rd_addr_arg_off = (grub_uint8_t *) linux_args - (grub_uint8_t *) playground; | |
381 | linux_args += ALIGN_UP (sizeof ("rd_start=0xXXXXXXXXXXXXXXXX"), 4); | |
382 | *linux_argv = 0; | |
383 | linux_argv++; | |
384 | ||
385 | rd_size_arg_off = (grub_uint8_t *) linux_args - (grub_uint8_t *) playground; | |
386 | linux_args += ALIGN_UP (sizeof ("rd_size=0xXXXXXXXXXXXXXXXX"), 4); | |
387 | *linux_argv = 0; | |
388 | linux_argv++; | |
389 | ||
368a0c61 | 390 | *linux_argv = 0; |
96c210da | 391 | |
7c8f6c18 | 392 | extra = linux_args; |
368a0c61 | 393 | |
bee1aeb9 | 394 | #ifdef GRUB_MACHINE_MIPS_LOONGSON |
7c8f6c18 | 395 | linux_envp = extra; |
96c210da | 396 | envp_off = (grub_uint8_t *) linux_envp - (grub_uint8_t *) playground; |
0f355bc6 | 397 | linux_envs = (char *) (linux_envp + 5); |
adb893f2 | 398 | grub_snprintf (linux_envs, sizeof ("memsize=XXXXXXXXXXXXXXXXXXXX"), |
2d49abe9 VS |
399 | "memsize=%lld", |
400 | (unsigned long long) grub_mmap_get_lower () >> 20); | |
0f355bc6 VS |
401 | linux_envp[0] = (grub_uint8_t *) linux_envs - (grub_uint8_t *) playground |
402 | + target_addr; | |
403 | linux_envs += ALIGN_UP (grub_strlen (linux_envs) + 1, 4); | |
2d49abe9 VS |
404 | grub_snprintf (linux_envs, sizeof ("highmemsize=XXXXXXXXXXXXXXXXXXXX"), |
405 | "highmemsize=%lld", | |
406 | (unsigned long long) grub_mmap_get_upper () >> 20); | |
0f355bc6 VS |
407 | linux_envp[1] = (grub_uint8_t *) linux_envs - (grub_uint8_t *) playground |
408 | + target_addr; | |
409 | linux_envs += ALIGN_UP (grub_strlen (linux_envs) + 1, 4); | |
410 | ||
adb893f2 | 411 | grub_snprintf (linux_envs, sizeof ("busclock=XXXXXXXXXX"), |
2d49abe9 | 412 | "busclock=%d", grub_arch_busclock); |
0f355bc6 VS |
413 | linux_envp[2] = (grub_uint8_t *) linux_envs - (grub_uint8_t *) playground |
414 | + target_addr; | |
415 | linux_envs += ALIGN_UP (grub_strlen (linux_envs) + 1, 4); | |
adb893f2 | 416 | grub_snprintf (linux_envs, sizeof ("cpuclock=XXXXXXXXXX"), |
2d49abe9 | 417 | "cpuclock=%d", grub_arch_cpuclock); |
0f355bc6 VS |
418 | linux_envp[3] = (grub_uint8_t *) linux_envs - (grub_uint8_t *) playground |
419 | + target_addr; | |
420 | linux_envs += ALIGN_UP (grub_strlen (linux_envs) + 1, 4); | |
421 | ||
0f355bc6 | 422 | linux_envp[4] = 0; |
dc16af03 | 423 | #endif |
12ce749d | 424 | #endif |
7c8f6c18 | 425 | |
bb272a0f | 426 | grub_loader_set (grub_linux_boot, grub_linux_unload, 1); |
96c210da | 427 | initrd_loaded = 0; |
bb272a0f | 428 | loaded = 1; |
429 | grub_dl_ref (my_mod); | |
430 | ||
431 | return GRUB_ERR_NONE; | |
ea818634 | 432 | } |
433 | ||
434 | static grub_err_t | |
435 | grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), | |
436 | int argc, char *argv[]) | |
437 | { | |
438 | grub_file_t file = 0; | |
439 | grub_ssize_t size; | |
7d8c9ec6 VS |
440 | void *initrd_src; |
441 | grub_addr_t initrd_dest; | |
442 | grub_err_t err; | |
ea818634 | 443 | |
444 | if (argc == 0) | |
67951a53 | 445 | return grub_error (GRUB_ERR_BAD_ARGUMENT, "no initrd specified"); |
ea818634 | 446 | |
447 | if (!loaded) | |
67951a53 | 448 | return grub_error (GRUB_ERR_BAD_ARGUMENT, "you need to load Linux first."); |
ea818634 | 449 | |
96c210da | 450 | if (initrd_loaded) |
67951a53 | 451 | return grub_error (GRUB_ERR_BAD_ARGUMENT, "only one initrd can be loaded."); |
96c210da | 452 | |
fc2ef117 | 453 | grub_file_filter_disable_compression (); |
ea818634 | 454 | file = grub_file_open (argv[0]); |
455 | if (! file) | |
456 | return grub_errno; | |
457 | ||
458 | size = grub_file_size (file); | |
459 | ||
530a4814 VS |
460 | { |
461 | grub_relocator_chunk_t ch; | |
462 | ||
463 | err = grub_relocator_alloc_chunk_align (relocator, &ch, | |
b01abe3e VS |
464 | (target_addr & 0x1fffffff) |
465 | + linux_size + 0x10000, | |
466 | (0x10000000 - size), | |
530a4814 VS |
467 | size, 0x10000, |
468 | GRUB_RELOCATOR_PREFERENCE_NONE); | |
469 | ||
470 | if (err) | |
471 | { | |
472 | grub_file_close (file); | |
473 | return err; | |
474 | } | |
475 | initrd_src = get_virtual_current_address (ch); | |
476 | initrd_dest = get_physical_target_address (ch) | 0x80000000; | |
477 | } | |
ea818634 | 478 | |
7d8c9ec6 | 479 | if (grub_file_read (file, initrd_src, size) != size) |
ea818634 | 480 | { |
67951a53 | 481 | grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file"); |
ea818634 | 482 | grub_file_close (file); |
483 | ||
484 | return grub_errno; | |
485 | } | |
486 | ||
dc16af03 VS |
487 | #ifdef GRUB_MACHINE_MIPS_QEMU_MIPS |
488 | { | |
489 | char *tmp; | |
490 | tmp = grub_xasprintf ("%s rd_start=0x%" PRIxGRUB_ADDR | |
491 | " rd_size=0x%" PRIxGRUB_ADDR, params, | |
492 | initrd_dest, size); | |
493 | if (!tmp) | |
494 | { | |
495 | grub_file_close (file); | |
496 | return grub_errno; | |
497 | } | |
498 | grub_free (params); | |
499 | params = tmp; | |
500 | } | |
501 | #else | |
2d49abe9 | 502 | grub_snprintf ((char *) playground + rd_addr_arg_off, |
adb893f2 | 503 | sizeof ("rd_start=0xXXXXXXXXXXXXXXXX"), "rd_start=0x%llx", |
7d8c9ec6 | 504 | (unsigned long long) initrd_dest); |
96c210da VS |
505 | ((grub_uint32_t *) (playground + argv_off))[linux_argc] |
506 | = target_addr + rd_addr_arg_off; | |
507 | linux_argc++; | |
508 | ||
2d49abe9 | 509 | grub_snprintf ((char *) playground + rd_size_arg_off, |
adb893f2 | 510 | sizeof ("rd_size=0xXXXXXXXXXXXXXXXXX"), "rd_size=0x%llx", |
96c210da VS |
511 | (unsigned long long) size); |
512 | ((grub_uint32_t *) (playground + argv_off))[linux_argc] | |
513 | = target_addr + rd_size_arg_off; | |
514 | linux_argc++; | |
dc16af03 | 515 | #endif |
96c210da VS |
516 | |
517 | initrd_loaded = 1; | |
ea818634 | 518 | |
519 | grub_file_close (file); | |
520 | ||
521 | return GRUB_ERR_NONE; | |
522 | } | |
523 | ||
524 | static grub_command_t cmd_linux, cmd_initrd; | |
525 | \f | |
526 | GRUB_MOD_INIT(linux) | |
527 | { | |
528 | cmd_linux = grub_register_command ("linux", grub_cmd_linux, | |
ff989071 | 529 | 0, N_("Load Linux.")); |
ea818634 | 530 | cmd_initrd = grub_register_command ("initrd", grub_cmd_initrd, |
ff989071 | 531 | 0, N_("Load initrd.")); |
ea818634 | 532 | my_mod = mod; |
533 | } | |
534 | ||
535 | GRUB_MOD_FINI(linux) | |
536 | { | |
537 | grub_unregister_command (cmd_linux); | |
538 | grub_unregister_command (cmd_initrd); | |
539 | } |