2 * GRUB -- GRand Unified Bootloader
3 * Copyright (C) 2013 Free Software Foundation, Inc.
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.
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.
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/>.
19 #include <grub/charset.h>
20 #include <grub/command.h>
22 #include <grub/file.h>
24 #include <grub/linux.h>
25 #include <grub/loader.h>
27 #include <grub/types.h>
28 #include <grub/cpu/linux.h>
29 #include <grub/efi/efi.h>
30 #include <grub/efi/fdtload.h>
31 #include <grub/efi/memory.h>
32 #include <grub/efi/pe32.h>
33 #include <grub/i18n.h>
34 #include <grub/lib/cmdline.h>
35 #include <grub/verify.h>
36 #include <grub/term.h>
39 GRUB_MOD_LICENSE ("GPLv3+");
41 static grub_dl_t my_mod
;
44 static void *kernel_addr
;
45 static grub_uint64_t kernel_size
;
47 static char *linux_args
;
48 static grub_uint32_t cmdline_size
;
50 static grub_addr_t initrd_start
;
51 static grub_addr_t initrd_end
;
53 #define LINUX_MAX_ARGC 1024
54 static int ventoy_debug
= 0;
55 static int ventoy_initrd_called
= 0;
56 static int ventoy_linux_argc
= 0;
57 static char **ventoy_linux_args
= NULL
;
58 static int ventoy_extra_initrd_num
= 0;
59 static char *ventoy_extra_initrd_list
[256];
61 grub_cmd_initrd (grub_command_t cmd
__attribute__ ((unused
)),
62 int argc
, char *argv
[]);
65 grub_arch_efi_linux_check_image (struct linux_arch_kernel_header
* lh
)
67 if (lh
->magic
!= GRUB_LINUX_ARMXX_MAGIC_SIGNATURE
)
68 return grub_error(GRUB_ERR_BAD_OS
, "invalid magic number");
70 if ((lh
->code0
& 0xffff) != GRUB_PE32_MAGIC
)
71 return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET
,
72 N_("plain image kernel not supported - rebuild with CONFIG_(U)EFI_STUB enabled"));
74 grub_dprintf ("linux", "UEFI stub kernel:\n");
75 grub_dprintf ("linux", "PE/COFF header @ %08x\n", lh
->hdr_offset
);
81 finalize_params_linux (void)
87 fdt
= grub_fdt_load (GRUB_EFI_LINUX_FDT_EXTRA_SPACE
);
92 node
= grub_fdt_find_subnode (fdt
, 0, "chosen");
94 node
= grub_fdt_add_subnode (fdt
, 0, "chosen");
100 if (initrd_start
&& initrd_end
> initrd_start
)
102 grub_dprintf ("linux", "Initrd @ %p-%p\n",
103 (void *) initrd_start
, (void *) initrd_end
);
105 retval
= grub_fdt_set_prop64 (fdt
, node
, "linux,initrd-start",
109 retval
= grub_fdt_set_prop64 (fdt
, node
, "linux,initrd-end",
115 if (grub_fdt_install() != GRUB_ERR_NONE
)
118 return GRUB_ERR_NONE
;
122 return grub_error(GRUB_ERR_BAD_OS
, "failed to install/update FDT");
126 grub_arch_efi_linux_boot_image (grub_addr_t addr
, grub_size_t size
, char *args
)
128 grub_efi_memory_mapped_device_path_t
*mempath
;
129 grub_efi_handle_t image_handle
;
130 grub_efi_boot_services_t
*b
;
131 grub_efi_status_t status
;
132 grub_efi_loaded_image_t
*loaded_image
;
135 mempath
= grub_malloc (2 * sizeof (grub_efi_memory_mapped_device_path_t
));
139 mempath
[0].header
.type
= GRUB_EFI_HARDWARE_DEVICE_PATH_TYPE
;
140 mempath
[0].header
.subtype
= GRUB_EFI_MEMORY_MAPPED_DEVICE_PATH_SUBTYPE
;
141 mempath
[0].header
.length
= grub_cpu_to_le16_compile_time (sizeof (*mempath
));
142 mempath
[0].memory_type
= GRUB_EFI_LOADER_DATA
;
143 mempath
[0].start_address
= addr
;
144 mempath
[0].end_address
= addr
+ size
;
146 mempath
[1].header
.type
= GRUB_EFI_END_DEVICE_PATH_TYPE
;
147 mempath
[1].header
.subtype
= GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE
;
148 mempath
[1].header
.length
= sizeof (grub_efi_device_path_t
);
150 b
= grub_efi_system_table
->boot_services
;
151 status
= b
->load_image (0, grub_efi_image_handle
,
152 (grub_efi_device_path_t
*) mempath
,
153 (void *) addr
, size
, &image_handle
);
154 if (status
!= GRUB_EFI_SUCCESS
)
155 return grub_error (GRUB_ERR_BAD_OS
, "cannot load image");
157 grub_dprintf ("linux", "linux command line: '%s'\n", args
);
159 /* Convert command line to UCS-2 */
160 loaded_image
= grub_efi_get_loaded_image (image_handle
);
161 loaded_image
->load_options_size
= len
=
162 (grub_strlen (args
) + 1) * sizeof (grub_efi_char16_t
);
163 loaded_image
->load_options
=
164 grub_efi_allocate_any_pages (GRUB_EFI_BYTES_TO_PAGES (loaded_image
->load_options_size
));
165 if (!loaded_image
->load_options
)
168 loaded_image
->load_options_size
=
169 2 * grub_utf8_to_utf16 (loaded_image
->load_options
, len
,
170 (grub_uint8_t
*) args
, len
, NULL
);
172 grub_dprintf ("linux", "starting image %p\n", image_handle
);
173 status
= b
->start_image (image_handle
, 0, NULL
);
175 /* When successful, not reached */
176 b
->unload_image (image_handle
);
177 grub_efi_free_pages ((grub_addr_t
) loaded_image
->load_options
,
178 GRUB_EFI_BYTES_TO_PAGES (loaded_image
->load_options_size
));
184 static void ventoy_debug_pause(void)
188 if (0 == ventoy_debug
)
193 grub_printf("press Enter to continue ......\n");
197 if (key
== '\n' || key
== '\r')
204 static int ventoy_preboot(void)
212 grub_printf("ventoy_preboot %d %d\n", ventoy_linux_argc
, ventoy_initrd_called
);
213 ventoy_debug_pause();
216 if (ventoy_linux_argc
== 0)
221 if (ventoy_initrd_called
)
223 ventoy_initrd_called
= 0;
227 grub_snprintf(buf
, sizeof(buf
), "mem:%s:size:%s", grub_env_get("ventoy_cpio_addr"), grub_env_get("ventoy_cpio_size"));
229 ventoy_extra_initrd_list
[ventoy_extra_initrd_num
++] = grub_strdup(buf
);
231 file
= grub_env_get("vtoy_img_part_file");
234 ventoy_extra_initrd_list
[ventoy_extra_initrd_num
++] = grub_strdup(file
);
239 grub_printf("========== initrd list ==========\n");
240 for (i
= 0; i
< ventoy_extra_initrd_num
; i
++)
242 grub_printf("%s\n", ventoy_extra_initrd_list
[i
]);
244 grub_printf("=================================\n");
246 ventoy_debug_pause();
249 grub_cmd_initrd(NULL
, ventoy_extra_initrd_num
, ventoy_extra_initrd_list
);
254 static int ventoy_boot_opt_filter(char *opt
)
256 if (grub_strcmp(opt
, "noinitrd") == 0)
261 if (grub_strcmp(opt
, "vga=current") == 0)
266 if (grub_strncmp(opt
, "rdinit=", 7) == 0)
268 if (grub_strcmp(opt
, "rdinit=/vtoy/vtoy") != 0)
276 if (grub_strncmp(opt
, "init=", 5) == 0)
285 if (grub_strcmp(opt
, "quiet") == 0)
290 if (grub_strncmp(opt
, "loglevel=", 9) == 0)
295 if (grub_strcmp(opt
, "splash") == 0)
304 static int ventoy_bootopt_hook(int argc
, char *argv
[])
314 //grub_printf("ventoy_bootopt_hook: %d %d\n", argc, ventoy_linux_argc);
316 if (ventoy_linux_argc
== 0)
321 /* To avoid --- parameter, we split two parts */
322 for (TmpIdx
= 0; TmpIdx
< argc
; TmpIdx
++)
324 if (ventoy_boot_opt_filter(argv
[TmpIdx
]))
329 if (grub_strncmp(argv
[TmpIdx
], "--", 2) == 0)
334 ventoy_linux_args
[count
++] = grub_strdup(argv
[TmpIdx
]);
337 for (i
= 0; i
< ventoy_linux_argc
; i
++)
339 ventoy_linux_args
[count
] = ventoy_linux_args
[i
+ (LINUX_MAX_ARGC
/ 2)];
340 ventoy_linux_args
[i
+ (LINUX_MAX_ARGC
/ 2)] = NULL
;
342 if (ventoy_linux_args
[count
][0] == '@')
344 env
= grub_env_get(ventoy_linux_args
[count
] + 1);
347 grub_free(ventoy_linux_args
[count
]);
349 newenv
= grub_strdup(env
);
356 if (*last
!= ' ' && *last
!= '\t')
368 for (pos
= last
; *pos
; pos
++)
370 if (*pos
== ' ' || *pos
== '\t')
374 if (0 == ventoy_boot_opt_filter(last
))
376 ventoy_linux_args
[count
++] = grub_strdup(last
);
385 if (0 == ventoy_boot_opt_filter(last
))
387 ventoy_linux_args
[count
++] = grub_strdup(last
);
406 while (TmpIdx
< argc
)
408 if (ventoy_boot_opt_filter(argv
[TmpIdx
]))
413 ventoy_linux_args
[count
++] = grub_strdup(argv
[TmpIdx
]);
419 ventoy_linux_args
[count
++] = grub_strdup("loglevel=7");
422 ventoy_linux_argc
= count
;
426 grub_printf("========== bootoption ==========\n");
427 for (i
= 0; i
< count
; i
++)
429 grub_printf("%s ", ventoy_linux_args
[i
]);
431 grub_printf("\n================================\n");
438 grub_cmd_set_boot_opt (grub_command_t cmd
__attribute__ ((unused
)),
439 int argc
, char *argv
[])
444 for (i
= 0; i
< argc
; i
++)
446 ventoy_linux_args
[ventoy_linux_argc
+ (LINUX_MAX_ARGC
/ 2) ] = grub_strdup(argv
[i
]);
450 vtdebug
= grub_env_get("vtdebug_flag");
451 if (vtdebug
&& vtdebug
[0])
456 if (ventoy_debug
) grub_printf("ventoy set boot opt %d\n", ventoy_linux_argc
);
462 grub_cmd_unset_boot_opt (grub_command_t cmd
__attribute__ ((unused
)),
463 int argc
, char *argv
[])
470 for (i
= 0; i
< LINUX_MAX_ARGC
; i
++)
472 if (ventoy_linux_args
[i
])
474 grub_free(ventoy_linux_args
[i
]);
479 ventoy_linux_argc
= 0;
480 ventoy_initrd_called
= 0;
481 grub_memset(ventoy_linux_args
, 0, sizeof(char *) * LINUX_MAX_ARGC
);
486 grub_cmd_extra_initrd_append (grub_command_t cmd
__attribute__ ((unused
)),
487 int argc
, char *argv
[])
499 for (pos
= argv
[0]; *pos
; pos
++)
509 /* grub2 newc bug workaround */
510 newclen
= (int)grub_strlen(end
+ 1);
511 if ((110 + newclen
) % 4 == 0)
513 grub_snprintf(buf
, sizeof(buf
), "newc:.%s:%s", end
+ 1, argv
[0]);
517 grub_snprintf(buf
, sizeof(buf
), "newc:%s:%s", end
+ 1, argv
[0]);
520 if (ventoy_extra_initrd_num
< 256)
522 ventoy_extra_initrd_list
[ventoy_extra_initrd_num
++] = grub_strdup(buf
);
530 grub_cmd_extra_initrd_reset (grub_command_t cmd
__attribute__ ((unused
)),
531 int argc
, char *argv
[])
538 for (i
= 0; i
< ventoy_extra_initrd_num
; i
++)
540 if (ventoy_extra_initrd_list
[i
])
542 grub_free(ventoy_extra_initrd_list
[i
]);
546 grub_memset(ventoy_extra_initrd_list
, 0, sizeof(ventoy_extra_initrd_list
));
553 grub_linux_boot (void)
557 if (finalize_params_linux () != GRUB_ERR_NONE
)
560 return (grub_arch_efi_linux_boot_image((grub_addr_t
)kernel_addr
,
561 kernel_size
, linux_args
));
565 grub_linux_unload (void)
567 grub_dl_unref (my_mod
);
570 grub_efi_free_pages ((grub_efi_physical_address_t
) initrd_start
,
571 GRUB_EFI_BYTES_TO_PAGES (initrd_end
- initrd_start
));
572 initrd_start
= initrd_end
= 0;
573 grub_free (linux_args
);
575 grub_efi_free_pages ((grub_addr_t
) kernel_addr
,
576 GRUB_EFI_BYTES_TO_PAGES (kernel_size
));
578 return GRUB_ERR_NONE
;
582 * As per linux/Documentation/arm/Booting
583 * ARM initrd needs to be covered by kernel linear mapping,
584 * so place it in the first 512MB of DRAM.
586 * As per linux/Documentation/arm64/booting.txt
587 * ARM64 initrd needs to be contained entirely within a 1GB aligned window
588 * of up to 32GB of size that covers the kernel image as well.
589 * Since the EFI stub loader will attempt to load the kernel near start of
590 * RAM, place the buffer in the first 32GB of RAM.
593 #define INITRD_MAX_ADDRESS_OFFSET (512U * 1024 * 1024)
594 #else /* __aarch64__ */
595 #define INITRD_MAX_ADDRESS_OFFSET (32ULL * 1024 * 1024 * 1024)
599 * This function returns a pointer to a legally allocated initrd buffer,
600 * or NULL if unsuccessful
603 allocate_initrd_mem (int initrd_pages
)
605 grub_addr_t max_addr
;
607 if (grub_efi_get_ram_base (&max_addr
) != GRUB_ERR_NONE
)
610 max_addr
+= INITRD_MAX_ADDRESS_OFFSET
- 1;
612 return grub_efi_allocate_pages_real (max_addr
, initrd_pages
,
613 GRUB_EFI_ALLOCATE_MAX_ADDRESS
,
614 GRUB_EFI_LOADER_DATA
);
618 grub_cmd_initrd (grub_command_t cmd
__attribute__ ((unused
)),
619 int argc
, char *argv
[])
621 struct grub_linux_initrd_context initrd_ctx
= { 0, 0, 0 };
622 int initrd_size
, initrd_pages
;
623 void *initrd_mem
= NULL
;
627 grub_error (GRUB_ERR_BAD_ARGUMENT
, N_("filename expected"));
633 grub_error (GRUB_ERR_BAD_ARGUMENT
,
634 N_("you need to load the kernel first"));
638 if (grub_initrd_init (argc
, argv
, &initrd_ctx
))
641 initrd_size
= grub_get_initrd_size (&initrd_ctx
);
642 grub_dprintf ("linux", "Loading initrd\n");
644 initrd_pages
= (GRUB_EFI_BYTES_TO_PAGES (initrd_size
));
645 initrd_mem
= allocate_initrd_mem (initrd_pages
);
649 grub_error (GRUB_ERR_OUT_OF_MEMORY
, N_("out of memory"));
653 if (grub_initrd_load (&initrd_ctx
, argv
, initrd_mem
))
656 initrd_start
= (grub_addr_t
) initrd_mem
;
657 initrd_end
= initrd_start
+ initrd_size
;
658 grub_dprintf ("linux", "[addr=%p, size=0x%x]\n",
659 (void *) initrd_start
, initrd_size
);
662 grub_initrd_close (&initrd_ctx
);
663 if (initrd_mem
&& !initrd_start
)
664 grub_efi_free_pages ((grub_addr_t
) initrd_mem
, initrd_pages
);
670 grub_cmd_linux (grub_command_t cmd
__attribute__ ((unused
)),
671 int argc
, char *argv
[])
673 grub_file_t file
= 0;
674 struct linux_arch_kernel_header lh
;
677 grub_dl_ref (my_mod
);
681 grub_error (GRUB_ERR_BAD_ARGUMENT
, N_("filename expected"));
685 file
= grub_file_open (argv
[0], GRUB_FILE_TYPE_LINUX_KERNEL
);
689 kernel_size
= grub_file_size (file
);
691 if (grub_file_read (file
, &lh
, sizeof (lh
)) < (long) sizeof (lh
))
694 if (grub_arch_efi_linux_check_image (&lh
) != GRUB_ERR_NONE
)
699 grub_dprintf ("linux", "kernel file size: %lld\n", (long long) kernel_size
);
700 kernel_addr
= grub_efi_allocate_any_pages (GRUB_EFI_BYTES_TO_PAGES (kernel_size
));
701 grub_dprintf ("linux", "kernel numpages: %lld\n",
702 (long long) GRUB_EFI_BYTES_TO_PAGES (kernel_size
));
705 grub_error (GRUB_ERR_OUT_OF_MEMORY
, N_("out of memory"));
709 grub_file_seek (file
, 0);
710 if (grub_file_read (file
, kernel_addr
, kernel_size
)
711 < (grub_int64_t
) kernel_size
)
714 grub_error (GRUB_ERR_BAD_OS
, N_("premature end of file %s"), argv
[0]);
718 grub_dprintf ("linux", "kernel @ %p\n", kernel_addr
);
720 cmdline_size
= grub_loader_cmdline_size (argc
, argv
) + sizeof (LINUX_IMAGE
);
721 linux_args
= grub_malloc (cmdline_size
);
724 grub_error (GRUB_ERR_OUT_OF_MEMORY
, N_("out of memory"));
727 grub_memcpy (linux_args
, LINUX_IMAGE
, sizeof (LINUX_IMAGE
));
729 if (ventoy_linux_argc
)
731 ventoy_bootopt_hook(argc
, argv
);
732 err
= grub_create_loader_cmdline (ventoy_linux_argc
, ventoy_linux_args
,
733 linux_args
+ sizeof (LINUX_IMAGE
) - 1,
735 GRUB_VERIFY_KERNEL_CMDLINE
); }
738 err
= grub_create_loader_cmdline (argc
, argv
,
739 linux_args
+ sizeof (LINUX_IMAGE
) - 1,
741 GRUB_VERIFY_KERNEL_CMDLINE
);
747 if (grub_errno
== GRUB_ERR_NONE
)
749 grub_loader_set (grub_linux_boot
, grub_linux_unload
, 0);
755 grub_file_close (file
);
757 if (grub_errno
!= GRUB_ERR_NONE
)
759 grub_dl_unref (my_mod
);
763 if (linux_args
&& !loaded
)
764 grub_free (linux_args
);
766 if (kernel_addr
&& !loaded
)
767 grub_efi_free_pages ((grub_addr_t
) kernel_addr
,
768 GRUB_EFI_BYTES_TO_PAGES (kernel_size
));
774 ventoy_cmd_initrd (grub_command_t cmd
__attribute__ ((unused
)),
775 int argc
, char *argv
[])
781 if (ventoy_debug
) grub_printf("ventoy_cmd_initrd %d\n", ventoy_linux_argc
);
783 if (ventoy_linux_argc
== 0)
785 return grub_cmd_initrd(cmd
, argc
, argv
);
788 grub_snprintf(buf
, sizeof(buf
), "mem:%s:size:%s", grub_env_get("ventoy_cpio_addr"), grub_env_get("ventoy_cpio_size"));
790 if (ventoy_debug
) grub_printf("membuf=%s\n", buf
);
792 ventoy_extra_initrd_list
[ventoy_extra_initrd_num
++] = grub_strdup(buf
);
794 file
= grub_env_get("vtoy_img_part_file");
797 ventoy_extra_initrd_list
[ventoy_extra_initrd_num
++] = grub_strdup(file
);
800 for (i
= 0; i
< argc
; i
++)
802 ventoy_extra_initrd_list
[ventoy_extra_initrd_num
++] = grub_strdup(argv
[i
]);
805 ventoy_initrd_called
= 1;
809 grub_printf("========== initrd list ==========\n");
810 for (i
= 0; i
< ventoy_extra_initrd_num
; i
++)
812 grub_printf("%s\n", ventoy_extra_initrd_list
[i
]);
814 grub_printf("=================================\n");
817 return grub_cmd_initrd(cmd
, ventoy_extra_initrd_num
, ventoy_extra_initrd_list
);
821 static grub_command_t cmd_linux
, cmd_initrd
, cmd_linuxefi
, cmd_initrdefi
;
822 static grub_command_t cmd_set_bootopt
, cmd_unset_bootopt
, cmd_extra_initrd_append
, cmd_extra_initrd_reset
;
825 GRUB_MOD_INIT (linux
)
827 cmd_linux
= grub_register_command ("linux", grub_cmd_linux
, 0,
829 cmd_initrd
= grub_register_command ("initrd", ventoy_cmd_initrd
, 0,
832 cmd_linuxefi
= grub_register_command ("linuxefi", grub_cmd_linux
,
833 0, N_("Load Linux."));
834 cmd_initrdefi
= grub_register_command ("initrdefi", ventoy_cmd_initrd
,
835 0, N_("Load initrd."));
837 cmd_set_bootopt
= grub_register_command ("vt_set_boot_opt", grub_cmd_set_boot_opt
, 0, N_("set ext boot opt"));
838 cmd_unset_bootopt
= grub_register_command ("vt_unset_boot_opt", grub_cmd_unset_boot_opt
, 0, N_("unset ext boot opt"));
840 cmd_extra_initrd_append
= grub_register_command ("vt_img_extra_initrd_append", grub_cmd_extra_initrd_append
, 0, N_(""));
841 cmd_extra_initrd_reset
= grub_register_command ("vt_img_extra_initrd_reset", grub_cmd_extra_initrd_reset
, 0, N_(""));
843 ventoy_linux_args
= grub_zalloc(sizeof(char *) * LINUX_MAX_ARGC
);
848 GRUB_MOD_FINI (linux
)
850 grub_unregister_command (cmd_linux
);
851 grub_unregister_command (cmd_initrd
);