]> git.proxmox.com Git - grub2.git/blob - grub-core/loader/ia64/efi/linux.c
Clarify and unify messages.
[grub2.git] / grub-core / loader / ia64 / efi / linux.c
1 /*
2 * GRUB -- GRand Unified Bootloader
3 * Copyright (C) 2008,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/file.h>
21 #include <grub/disk.h>
22 #include <grub/err.h>
23 #include <grub/misc.h>
24 #include <grub/types.h>
25 #include <grub/command.h>
26 #include <grub/dl.h>
27 #include <grub/mm.h>
28 #include <grub/cache.h>
29 #include <grub/kernel.h>
30 #include <grub/efi/api.h>
31 #include <grub/efi/efi.h>
32 #include <grub/elf.h>
33 #include <grub/i18n.h>
34
35 GRUB_MOD_LICENSE ("GPLv3+");
36
37 #define ALIGN_MIN (256*1024*1024)
38
39 #define GRUB_ELF_SEARCH 1024
40
41 #define BOOT_PARAM_SIZE 16384
42
43 struct ia64_boot_param
44 {
45 grub_uint64_t command_line; /* physical address of command line. */
46 grub_uint64_t efi_systab; /* physical address of EFI system table */
47 grub_uint64_t efi_memmap; /* physical address of EFI memory map */
48 grub_uint64_t efi_memmap_size; /* size of EFI memory map */
49 grub_uint64_t efi_memdesc_size; /* size of an EFI memory map descriptor */
50 grub_uint32_t efi_memdesc_version; /* memory descriptor version */
51 struct
52 {
53 grub_uint16_t num_cols; /* number of columns on console output dev */
54 grub_uint16_t num_rows; /* number of rows on console output device */
55 grub_uint16_t orig_x; /* cursor's x position */
56 grub_uint16_t orig_y; /* cursor's y position */
57 } console_info;
58 grub_uint64_t fpswa; /* physical address of the fpswa interface */
59 grub_uint64_t initrd_start;
60 grub_uint64_t initrd_size;
61 grub_uint64_t domain_start; /* boot domain address. */
62 grub_uint64_t domain_size; /* how big is the boot domain */
63 grub_uint64_t payloads_chain;
64 grub_uint64_t payloads_nbr;
65 };
66
67 struct ia64_boot_payload
68 {
69 grub_uint64_t start;
70 grub_uint64_t length;
71
72 /* Payload command line */
73 grub_uint64_t cmdline;
74
75 grub_uint64_t next;
76 };
77
78 typedef struct
79 {
80 grub_uint32_t revision;
81 grub_uint32_t reserved;
82 void *fpswa;
83 } fpswa_interface_t;
84 static fpswa_interface_t *fpswa;
85
86 #define NEXT_MEMORY_DESCRIPTOR(desc, size) \
87 ((grub_efi_memory_descriptor_t *) ((char *) (desc) + (size)))
88
89 static grub_dl_t my_mod;
90
91 static int loaded;
92
93 /* Kernel base and size. */
94 static void *kernel_mem;
95 static grub_efi_uintn_t kernel_pages;
96 static grub_uint64_t entry;
97
98 /* Initrd base and size. */
99 static void *initrd_mem;
100 static grub_efi_uintn_t initrd_pages;
101 static grub_efi_uintn_t initrd_size;
102
103 static struct ia64_boot_param *boot_param;
104 static grub_efi_uintn_t boot_param_pages;
105 static struct ia64_boot_payload *last_payload = NULL;
106
107 /* Can linux kernel be relocated ? */
108 #define RELOCATE_OFF 0 /* No. */
109 #define RELOCATE_ON 1 /* Yes. */
110 #define RELOCATE_FORCE 2 /* Always - used to debug. */
111 static int relocate = RELOCATE_OFF;
112
113 static inline grub_size_t
114 page_align (grub_size_t size)
115 {
116 return (size + (1 << 12) - 1) & (~((1 << 12) - 1));
117 }
118
119 static void
120 query_fpswa (void)
121 {
122 grub_efi_handle_t fpswa_image;
123 grub_efi_boot_services_t *bs;
124 grub_efi_status_t status;
125 grub_efi_uintn_t size;
126 static const grub_efi_guid_t fpswa_protocol =
127 { 0xc41b6531, 0x97b9, 0x11d3,
128 {0x9a, 0x29, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d} };
129
130 if (fpswa != NULL)
131 return;
132
133 size = sizeof(grub_efi_handle_t);
134
135 bs = grub_efi_system_table->boot_services;
136 status = bs->locate_handle (GRUB_EFI_BY_PROTOCOL,
137 (void *)&fpswa_protocol,
138 NULL, &size, &fpswa_image);
139 if (status != GRUB_EFI_SUCCESS)
140 {
141 grub_printf (_("Could not locate FPSWA driver\n"));
142 return;
143 }
144 status = bs->handle_protocol (fpswa_image,
145 (void *)&fpswa_protocol, (void *)&fpswa);
146 if (status != GRUB_EFI_SUCCESS)
147 {
148 grub_printf (_("Fpswa protocol not able find the interface\n"));
149 return;
150 }
151 }
152
153 /* Find the optimal number of pages for the memory map. Is it better to
154 move this code to efi/mm.c? */
155 static grub_efi_uintn_t
156 find_mmap_size (void)
157 {
158 static grub_efi_uintn_t mmap_size = 0;
159
160 if (mmap_size != 0)
161 return mmap_size;
162
163 mmap_size = (1 << 12);
164 while (1)
165 {
166 int ret;
167 grub_efi_memory_descriptor_t *mmap;
168 grub_efi_uintn_t desc_size;
169
170 mmap = grub_malloc (mmap_size);
171 if (! mmap)
172 return 0;
173
174 ret = grub_efi_get_memory_map (&mmap_size, mmap, 0, &desc_size, 0);
175 grub_free (mmap);
176
177 if (ret < 0)
178 {
179 grub_error (GRUB_ERR_IO, "cannot get memory map");
180 return 0;
181 }
182 else if (ret > 0)
183 break;
184
185 mmap_size += (1 << 12);
186 }
187
188 /* Increase the size a bit for safety, because GRUB allocates more on
189 later, and EFI itself may allocate more. */
190 mmap_size += (1 << 12);
191
192 return page_align (mmap_size);
193 }
194
195 static void
196 free_pages (void)
197 {
198 if (kernel_mem)
199 {
200 grub_efi_free_pages ((grub_addr_t) kernel_mem, kernel_pages);
201 kernel_mem = 0;
202 }
203
204 if (initrd_mem)
205 {
206 grub_efi_free_pages ((grub_addr_t) initrd_mem, initrd_pages);
207 initrd_mem = 0;
208 }
209
210 if (boot_param)
211 {
212 struct ia64_boot_payload *payload;
213 struct ia64_boot_payload *next_payload;
214
215 /* Free payloads. */
216 payload = (struct ia64_boot_payload *)boot_param->payloads_chain;
217 while (payload != 0)
218 {
219 next_payload = (struct ia64_boot_payload *)payload->next;
220
221 grub_efi_free_pages
222 (payload->start, page_align (payload->length) >> 12);
223 grub_efi_free_pages ((grub_efi_physical_address_t)payload, 1);
224
225 payload = next_payload;
226 }
227
228 /* Free bootparam. */
229 grub_efi_free_pages ((grub_efi_physical_address_t)boot_param,
230 boot_param_pages);
231 boot_param = 0;
232 }
233 }
234
235 static void *
236 allocate_pages (grub_uint64_t align, grub_uint64_t size_pages,
237 grub_uint64_t nobase)
238 {
239 grub_uint64_t size;
240 grub_efi_uintn_t desc_size;
241 grub_efi_memory_descriptor_t *mmap, *mmap_end;
242 grub_efi_uintn_t mmap_size, tmp_mmap_size;
243 grub_efi_memory_descriptor_t *desc;
244 void *mem = NULL;
245
246 size = size_pages << 12;
247
248 mmap_size = find_mmap_size ();
249 if (!mmap_size)
250 return 0;
251
252 /* Read the memory map temporarily, to find free space. */
253 mmap = grub_malloc (mmap_size);
254 if (! mmap)
255 return 0;
256
257 tmp_mmap_size = mmap_size;
258 if (grub_efi_get_memory_map (&tmp_mmap_size, mmap, 0, &desc_size, 0) <= 0)
259 {
260 grub_error (GRUB_ERR_IO, "cannot get memory map");
261 goto fail;
262 }
263
264 mmap_end = NEXT_MEMORY_DESCRIPTOR (mmap, tmp_mmap_size);
265
266 /* First, find free pages for the real mode code
267 and the memory map buffer. */
268 for (desc = mmap;
269 desc < mmap_end;
270 desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size))
271 {
272 grub_uint64_t start, end;
273 grub_uint64_t aligned_start;
274
275 if (desc->type != GRUB_EFI_CONVENTIONAL_MEMORY)
276 continue;
277
278 start = desc->physical_start;
279 end = start + (desc->num_pages << 12);
280 /* Align is a power of 2. */
281 aligned_start = (start + align - 1) & ~(align - 1);
282 if (aligned_start + size > end)
283 continue;
284 if (aligned_start == nobase)
285 aligned_start += align;
286 if (aligned_start + size > end)
287 continue;
288 mem = grub_efi_allocate_pages (aligned_start, size_pages);
289 if (! mem)
290 {
291 grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate memory");
292 goto fail;
293 }
294 break;
295 }
296
297 if (! mem)
298 {
299 grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate memory");
300 goto fail;
301 }
302
303 grub_free (mmap);
304 return mem;
305
306 fail:
307 grub_free (mmap);
308 free_pages ();
309 return 0;
310 }
311
312 static void
313 set_boot_param_console (void)
314 {
315 grub_efi_simple_text_output_interface_t *conout;
316 grub_efi_uintn_t cols, rows;
317
318 conout = grub_efi_system_table->con_out;
319 if (conout->query_mode (conout, conout->mode->mode, &cols, &rows)
320 != GRUB_EFI_SUCCESS)
321 return;
322
323 grub_dprintf ("linux",
324 "Console info: cols=%lu rows=%lu x=%u y=%u\n",
325 cols, rows,
326 conout->mode->cursor_column, conout->mode->cursor_row);
327
328 boot_param->console_info.num_cols = cols;
329 boot_param->console_info.num_rows = rows;
330 boot_param->console_info.orig_x = conout->mode->cursor_column;
331 boot_param->console_info.orig_y = conout->mode->cursor_row;
332 }
333
334 static grub_err_t
335 grub_linux_boot (void)
336 {
337 grub_efi_uintn_t mmap_size;
338 grub_efi_uintn_t map_key;
339 grub_efi_uintn_t desc_size;
340 grub_efi_uint32_t desc_version;
341 grub_efi_memory_descriptor_t *mmap_buf;
342 grub_err_t err;
343
344 /* FPSWA. */
345 query_fpswa ();
346 boot_param->fpswa = (grub_uint64_t)fpswa;
347
348 /* Initrd. */
349 boot_param->initrd_start = (grub_uint64_t)initrd_mem;
350 boot_param->initrd_size = (grub_uint64_t)initrd_size;
351
352 set_boot_param_console ();
353
354 grub_dprintf ("linux", "Jump to %016lx\n", entry);
355
356 /* MDT.
357 Must be done after grub_machine_fini because map_key is used by
358 exit_boot_services. */
359 mmap_size = find_mmap_size ();
360 if (! mmap_size)
361 return grub_errno;
362 mmap_buf = grub_efi_allocate_pages (0, page_align (mmap_size) >> 12);
363 if (! mmap_buf)
364 return grub_error (GRUB_ERR_IO, "cannot allocate memory map");
365 err = grub_efi_finish_boot_services (&mmap_size, mmap_buf, &map_key,
366 &desc_size, &desc_version);
367 if (err)
368 return err;
369
370 boot_param->efi_memmap = (grub_uint64_t)mmap_buf;
371 boot_param->efi_memmap_size = mmap_size;
372 boot_param->efi_memdesc_size = desc_size;
373 boot_param->efi_memdesc_version = desc_version;
374
375 /* See you next boot. */
376 asm volatile ("mov r28=%1; br.sptk.few %0" :: "b"(entry),"r"(boot_param));
377
378 /* Never reach here. */
379 return GRUB_ERR_NONE;
380 }
381
382 static grub_err_t
383 grub_linux_unload (void)
384 {
385 free_pages ();
386 grub_dl_unref (my_mod);
387 loaded = 0;
388 return GRUB_ERR_NONE;
389 }
390
391 static grub_err_t
392 grub_load_elf64 (grub_file_t file, void *buffer, const char *filename)
393 {
394 Elf64_Ehdr *ehdr = (Elf64_Ehdr *) buffer;
395 Elf64_Phdr *phdr;
396 int i;
397 grub_uint64_t low_addr;
398 grub_uint64_t high_addr;
399 grub_uint64_t align;
400 grub_uint64_t reloc_offset;
401
402 if (ehdr->e_ident[EI_CLASS] != ELFCLASS64)
403 return grub_error (GRUB_ERR_UNKNOWN_OS, "invalid ELF class");
404
405 if (ehdr->e_ident[EI_MAG0] != ELFMAG0
406 || ehdr->e_ident[EI_MAG1] != ELFMAG1
407 || ehdr->e_ident[EI_MAG2] != ELFMAG2
408 || ehdr->e_ident[EI_MAG3] != ELFMAG3
409 || ehdr->e_version != EV_CURRENT
410 || ehdr->e_ident[EI_DATA] != ELFDATA2LSB
411 || ehdr->e_machine != EM_IA_64)
412 return grub_error(GRUB_ERR_UNKNOWN_OS, "no valid ELF header found");
413
414 if (ehdr->e_type != ET_EXEC)
415 return grub_error (GRUB_ERR_UNKNOWN_OS, "invalid ELF file type");
416
417 /* FIXME: Should we support program headers at strange locations? */
418 if (ehdr->e_phoff + ehdr->e_phnum * ehdr->e_phentsize > GRUB_ELF_SEARCH)
419 return grub_error (GRUB_ERR_BAD_OS, "program header at a too high offset");
420
421 entry = ehdr->e_entry;
422
423 /* Compute low, high and align addresses. */
424 low_addr = ~0UL;
425 high_addr = 0;
426 align = 0;
427 for (i = 0; i < ehdr->e_phnum; i++)
428 {
429 phdr = (Elf64_Phdr *) ((char *) buffer + ehdr->e_phoff
430 + i * ehdr->e_phentsize);
431 if (phdr->p_type == PT_LOAD)
432 {
433 if (phdr->p_paddr < low_addr)
434 low_addr = phdr->p_paddr;
435 if (phdr->p_paddr + phdr->p_memsz > high_addr)
436 high_addr = phdr->p_paddr + phdr->p_memsz;
437 if (phdr->p_align > align)
438 align = phdr->p_align;
439 }
440 }
441
442 if (align < ALIGN_MIN)
443 align = ALIGN_MIN;
444
445 if (high_addr == 0)
446 return grub_error (GRUB_ERR_BAD_OS, "no program entries");
447
448 kernel_pages = page_align (high_addr - low_addr) >> 12;
449
450 if (relocate != RELOCATE_FORCE)
451 {
452 kernel_mem = grub_efi_allocate_pages (low_addr, kernel_pages);
453 reloc_offset = 0;
454 }
455 /* Try to relocate. */
456 if (! kernel_mem && relocate != RELOCATE_OFF)
457 {
458 kernel_mem = allocate_pages (align, kernel_pages, low_addr);
459 if (kernel_mem)
460 {
461 reloc_offset = (grub_uint64_t)kernel_mem - low_addr;
462 grub_dprintf ("linux", " Relocated at %p (offset=%016lx)\n",
463 kernel_mem, reloc_offset);
464 entry += reloc_offset;
465 }
466 }
467 if (! kernel_mem)
468 return grub_error (GRUB_ERR_OUT_OF_MEMORY,
469 "cannot allocate memory for OS");
470
471 /* Load every loadable segment in memory. */
472 for (i = 0; i < ehdr->e_phnum; i++)
473 {
474 phdr = (Elf64_Phdr *) ((char *) buffer + ehdr->e_phoff
475 + i * ehdr->e_phentsize);
476 if (phdr->p_type == PT_LOAD)
477 {
478 grub_dprintf ("linux", " [paddr=%lx load=%lx memsz=%08lx "
479 "off=%lx flags=%x]\n",
480 phdr->p_paddr, phdr->p_paddr + reloc_offset,
481 phdr->p_memsz, phdr->p_offset, phdr->p_flags);
482
483 if (grub_file_seek (file, phdr->p_offset) == (grub_off_t)-1)
484 return grub_error (GRUB_ERR_BAD_OS,
485 "invalid offset in program header");
486
487 if (grub_file_read (file, (void *) (phdr->p_paddr + reloc_offset),
488 phdr->p_filesz)
489 != (grub_ssize_t) phdr->p_filesz)
490 {
491 if (!grub_errno)
492 grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
493 filename);
494 return grub_errno;
495 }
496
497 if (phdr->p_filesz < phdr->p_memsz)
498 grub_memset
499 ((char *)(phdr->p_paddr + reloc_offset + phdr->p_filesz),
500 0, phdr->p_memsz - phdr->p_filesz);
501
502 /* Sync caches if necessary. */
503 if (phdr->p_flags & PF_X)
504 grub_arch_sync_caches
505 ((void *)(phdr->p_paddr + reloc_offset), phdr->p_memsz);
506 }
507 }
508 loaded = 1;
509 return 0;
510 }
511
512 static grub_err_t
513 grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
514 int argc, char *argv[])
515 {
516 grub_file_t file = 0;
517 char buffer[GRUB_ELF_SEARCH];
518 char *cmdline, *p;
519 grub_ssize_t len;
520 int i;
521
522 grub_dl_ref (my_mod);
523
524 grub_loader_unset ();
525
526 if (argc == 0)
527 {
528 grub_error (GRUB_ERR_BAD_ARGUMENT, "No kernel specified");
529 goto fail;
530 }
531
532 file = grub_file_open (argv[0]);
533 if (! file)
534 goto fail;
535
536 len = grub_file_read (file, buffer, sizeof (buffer));
537 if (len < (grub_ssize_t) sizeof (Elf64_Ehdr))
538 {
539 grub_error (GRUB_ERR_BAD_OS, "File too small");
540 goto fail;
541 }
542
543 grub_dprintf ("linux", "Loading linux: %s\n", argv[0]);
544
545 if (grub_load_elf64 (file, buffer, argv[0]))
546 goto fail;
547
548 len = sizeof("BOOT_IMAGE=") + 8;
549 for (i = 0; i < argc; i++)
550 len += grub_strlen (argv[i]) + 1;
551 len += sizeof (struct ia64_boot_param) + 256; /* Room for extensions. */
552 boot_param_pages = page_align (len) >> 12;
553 boot_param = grub_efi_allocate_pages (0, boot_param_pages);
554 if (boot_param == 0)
555 {
556 grub_error (GRUB_ERR_OUT_OF_MEMORY,
557 "cannot allocate memory for bootparams");
558 goto fail;
559 }
560
561 grub_memset (boot_param, 0, len);
562 cmdline = ((char *)(boot_param + 1)) + 256;
563
564 /* Build cmdline. */
565 p = grub_stpcpy (cmdline, "BOOT_IMAGE");
566 for (i = 0; i < argc; i++)
567 {
568 *p++ = ' ';
569 p = grub_stpcpy (p, argv[i]);
570 }
571 cmdline[10] = '=';
572
573 boot_param->command_line = (grub_uint64_t) cmdline;
574 boot_param->efi_systab = (grub_uint64_t) grub_efi_system_table;
575
576 grub_errno = GRUB_ERR_NONE;
577
578 grub_loader_set (grub_linux_boot, grub_linux_unload, 0);
579
580 fail:
581 if (file)
582 grub_file_close (file);
583
584 if (grub_errno != GRUB_ERR_NONE)
585 {
586 grub_efi_free_pages ((grub_efi_physical_address_t) boot_param,
587 boot_param_pages);
588 grub_dl_unref (my_mod);
589 }
590 return grub_errno;
591 }
592
593 static grub_err_t
594 grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
595 int argc, char *argv[])
596 {
597 grub_file_t *files = 0;
598 int i;
599 int nfiles = 0;
600 grub_uint8_t *ptr;
601
602 if (argc == 0)
603 {
604 grub_error (GRUB_ERR_BAD_ARGUMENT, "No filename specified");
605 goto fail;
606 }
607
608 if (! loaded)
609 {
610 grub_error (GRUB_ERR_BAD_ARGUMENT, "You need to load the kernel first.");
611 goto fail;
612 }
613
614 files = grub_zalloc (argc * sizeof (files[0]));
615 if (!files)
616 goto fail;
617
618 initrd_size = 0;
619 grub_dprintf ("linux", "Loading initrd\n");
620 for (i = 0; i < argc; i++)
621 {
622 grub_file_filter_disable_compression ();
623 files[i] = grub_file_open (argv[i]);
624 if (! files[i])
625 goto fail;
626 nfiles++;
627 initrd_size += grub_file_size (files[i]);
628 grub_dprintf ("linux", "File %d: %s\n", i, argv[i]);
629 }
630
631 initrd_pages = (page_align (initrd_size) >> 12);
632 initrd_mem = grub_efi_allocate_pages (0, initrd_pages);
633 if (! initrd_mem)
634 {
635 grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate pages");
636 goto fail;
637 }
638
639 grub_dprintf ("linux", "[addr=0x%lx, size=0x%lx]\n",
640 (grub_uint64_t) initrd_mem, initrd_size);
641
642 ptr = initrd_mem;
643 for (i = 0; i < nfiles; i++)
644 {
645 grub_ssize_t cursize = grub_file_size (files[i]);
646 if (grub_file_read (files[i], ptr, cursize) != cursize)
647 {
648 if (!grub_errno)
649 grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"),
650 argv[i]);
651 goto fail;
652 }
653 ptr += cursize;
654 }
655 fail:
656 for (i = 0; i < nfiles; i++)
657 grub_file_close (files[i]);
658 grub_free (files);
659 return grub_errno;
660 }
661
662 static grub_err_t
663 grub_cmd_payload (grub_command_t cmd __attribute__ ((unused)),
664 int argc, char *argv[])
665 {
666 grub_file_t file = 0;
667 grub_ssize_t size, len = 0;
668 char *base = 0, *cmdline = 0, *p;
669 struct ia64_boot_payload *payload = NULL;
670 int i;
671
672 if (argc == 0)
673 {
674 grub_error (GRUB_ERR_BAD_ARGUMENT, "No module specified");
675 goto fail;
676 }
677
678 if (!boot_param)
679 {
680 grub_error (GRUB_ERR_BAD_ARGUMENT,
681 "You need to load the kernel first");
682 goto fail;
683 }
684
685 file = grub_file_open (argv[0]);
686 if (! file)
687 goto fail;
688
689 size = grub_file_size (file);
690 base = grub_efi_allocate_pages (0, page_align (size) >> 12);
691 if (! base)
692 goto fail;
693
694 grub_dprintf ("linux", "Payload %s [addr=%lx + %lx]\n",
695 argv[0], (grub_uint64_t)base, size);
696
697 if (grub_file_read (file, base, size) != size)
698 {
699 if (!grub_errno)
700 grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"),
701 argv[0]);
702 goto fail;
703 }
704
705 len = sizeof (struct ia64_boot_payload);
706 for (i = 0; i < argc; i++)
707 len += grub_strlen (argv[i]) + 1;
708
709 if (len > 4096)
710 {
711 grub_error (GRUB_ERR_OUT_OF_RANGE, "payload command line too long");
712 goto fail;
713 }
714 payload = grub_efi_allocate_pages (0, 1);
715 if (! payload)
716 goto fail;
717
718 p = (char *)(payload + 1);
719
720 payload->start = (grub_uint64_t)base;
721 payload->length = size;
722 payload->cmdline = (grub_uint64_t)p;
723 payload->next = 0;
724
725 if (last_payload)
726 last_payload->next = (grub_uint64_t)payload;
727 else
728 {
729 last_payload = payload;
730 boot_param->payloads_chain = (grub_uint64_t)payload;
731 }
732 boot_param->payloads_nbr++;
733
734 /* Copy command line. */
735 for (i = 0; i < argc; i++)
736 {
737 p = grub_stpcpy (p, argv[i]);
738 *(p++) = ' ';
739 }
740
741 /* Remove the space after the last word. */
742 *(--p) = '\0';
743
744
745 fail:
746 if (file)
747 grub_file_close (file);
748
749 if (grub_errno != GRUB_ERR_NONE)
750 {
751 grub_free (base);
752 grub_free (cmdline);
753 }
754 return grub_errno;
755 }
756
757 static grub_err_t
758 grub_cmd_relocate (grub_command_t cmd __attribute__ ((unused)),
759 int argc, char *argv[])
760 {
761 static const char * const vals[] = { "off", "on", "force"};
762 unsigned int i;
763
764 if (argc == 0)
765 {
766 grub_printf (_("relocate is %s\n"), vals[relocate]);
767 return GRUB_ERR_NONE;
768 }
769 else if (argc == 1)
770 {
771 if (kernel_mem != NULL)
772 grub_printf (_("Warning: kernel already loaded!\n"));
773 for (i = 0; i < sizeof (vals)/sizeof(vals[0]); i++)
774 if (grub_strcmp (argv[0], vals[i]) == 0)
775 {
776 relocate = i;
777 return GRUB_ERR_NONE;
778 }
779 return grub_error (GRUB_ERR_BAD_ARGUMENT, "unknown relocate value");
780 }
781 else
782 {
783 return grub_error (GRUB_ERR_BAD_ARGUMENT, "accept 0 or 1 argument");
784 }
785
786 }
787
788
789 static grub_err_t
790 grub_cmd_fpswa (grub_command_t cmd __attribute__ ((unused)),
791 int argc, char *argv[] __attribute__((unused)))
792 {
793 if (argc != 0)
794 return grub_error (GRUB_ERR_BAD_ARGUMENT, "Arguments not expected");
795 query_fpswa ();
796 if (fpswa == NULL)
797 grub_printf (_("No FPSWA loaded\n"));
798 else
799 grub_printf (_("FPSWA revision: %x\n"), fpswa->revision);
800 return GRUB_ERR_NONE;
801 }
802
803 static grub_command_t cmd_linux, cmd_initrd, cmd_payload, cmd_relocate, cmd_fpswa;
804
805 GRUB_MOD_INIT(linux)
806 {
807 cmd_linux = grub_register_command ("linux", grub_cmd_linux,
808 N_("FILE [ARGS...]"), N_("Load Linux."));
809
810 cmd_initrd = grub_register_command ("initrd", grub_cmd_initrd,
811 N_("FILE"), N_("Load initrd."));
812
813 cmd_payload = grub_register_command ("payload", grub_cmd_payload,
814 N_("FILE [ARGS...]"),
815 N_("Load an additional file."));
816
817 cmd_relocate = grub_register_command ("relocate", grub_cmd_relocate,
818 "[on|off|force]",
819 N_("Set relocate feature."));
820
821 cmd_fpswa = grub_register_command ("fpswa", grub_cmd_fpswa,
822 "", N_("Display FPSWA version."));
823
824 my_mod = mod;
825 }
826
827 GRUB_MOD_FINI(linux)
828 {
829 grub_unregister_command (cmd_linux);
830 grub_unregister_command (cmd_initrd);
831 grub_unregister_command (cmd_payload);
832 grub_unregister_command (cmd_relocate);
833 grub_unregister_command (cmd_fpswa);
834 }