]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - GRUB2/MOD_SRC/grub-2.04/grub-core/loader/i386/linux.c
d17eeba174a6bf193c840681f3df6f5c764c07b6
[Ventoy.git] / GRUB2 / MOD_SRC / grub-2.04 / grub-core / loader / i386 / linux.c
1 /*
2 * GRUB -- GRand Unified Bootloader
3 * Copyright (C) 2006,2007,2008,2009,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/memory.h>
21 #include <grub/normal.h>
22 #include <grub/file.h>
23 #include <grub/disk.h>
24 #include <grub/err.h>
25 #include <grub/misc.h>
26 #include <grub/types.h>
27 #include <grub/dl.h>
28 #include <grub/mm.h>
29 #include <grub/term.h>
30 #include <grub/cpu/linux.h>
31 #include <grub/video.h>
32 #include <grub/video_fb.h>
33 #include <grub/command.h>
34 #include <grub/i386/relocator.h>
35 #include <grub/i18n.h>
36 #include <grub/lib/cmdline.h>
37 #include <grub/linux.h>
38 #include <grub/machine/kernel.h>
39
40 GRUB_MOD_LICENSE ("GPLv3+");
41
42 #ifdef GRUB_MACHINE_PCBIOS
43 #include <grub/i386/pc/vesa_modes_table.h>
44 #endif
45
46 #ifdef GRUB_MACHINE_EFI
47 #include <grub/efi/efi.h>
48 #define HAS_VGA_TEXT 0
49 #define DEFAULT_VIDEO_MODE "auto"
50 #define ACCEPTS_PURE_TEXT 0
51 #elif defined (GRUB_MACHINE_IEEE1275)
52 #include <grub/ieee1275/ieee1275.h>
53 #define HAS_VGA_TEXT 0
54 #define DEFAULT_VIDEO_MODE "text"
55 #define ACCEPTS_PURE_TEXT 1
56 #else
57 #include <grub/i386/pc/vbe.h>
58 #include <grub/i386/pc/console.h>
59 #define HAS_VGA_TEXT 1
60 #define DEFAULT_VIDEO_MODE "text"
61 #define ACCEPTS_PURE_TEXT 1
62 #endif
63
64 static grub_dl_t my_mod;
65
66 static grub_size_t linux_mem_size;
67 static int loaded;
68 static void *prot_mode_mem;
69 static grub_addr_t prot_mode_target;
70 static void *initrd_mem;
71 static grub_addr_t initrd_mem_target;
72 static grub_size_t prot_init_space;
73 static struct grub_relocator *relocator = NULL;
74 static void *efi_mmap_buf;
75 static grub_size_t maximal_cmdline_size;
76 static struct linux_kernel_params linux_params;
77 static char *linux_cmdline;
78 #ifdef GRUB_MACHINE_EFI
79 static grub_efi_uintn_t efi_mmap_size;
80 #else
81 static const grub_size_t efi_mmap_size = 0;
82 #endif
83
84 #define LINUX_MAX_ARGC 1024
85 static int ventoy_debug = 0;
86 static int ventoy_initrd_called = 0;
87 static int ventoy_linux_argc = 0;
88 static char **ventoy_linux_args = NULL;
89 static int ventoy_extra_initrd_num = 0;
90 static char *ventoy_extra_initrd_list[256];
91
92 static grub_err_t
93 grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), int argc, char *argv[]);
94
95 /* FIXME */
96 #if 0
97 struct idt_descriptor
98 {
99 grub_uint16_t limit;
100 void *base;
101 } GRUB_PACKED;
102
103 static struct idt_descriptor idt_desc =
104 {
105 0,
106 0
107 };
108 #endif
109
110 static inline grub_size_t
111 page_align (grub_size_t size)
112 {
113 return (size + (1 << 12) - 1) & (~((1 << 12) - 1));
114 }
115
116 /* Helper for find_mmap_size. */
117 static int
118 count_hook (grub_uint64_t addr __attribute__ ((unused)),
119 grub_uint64_t size __attribute__ ((unused)),
120 grub_memory_type_t type __attribute__ ((unused)), void *data)
121 {
122 grub_size_t *count = data;
123
124 (*count)++;
125 return 0;
126 }
127
128 /* Find the optimal number of pages for the memory map. */
129 static grub_size_t
130 find_mmap_size (void)
131 {
132 grub_size_t count = 0, mmap_size;
133
134 grub_mmap_iterate (count_hook, &count);
135
136 mmap_size = count * sizeof (struct grub_e820_mmap);
137
138 /* Increase the size a bit for safety, because GRUB allocates more on
139 later. */
140 mmap_size += (1 << 12);
141
142 return page_align (mmap_size);
143 }
144
145 static void
146 free_pages (void)
147 {
148 grub_relocator_unload (relocator);
149 relocator = NULL;
150 prot_mode_mem = initrd_mem = 0;
151 prot_mode_target = initrd_mem_target = 0;
152 }
153
154 /* Allocate pages for the real mode code and the protected mode code
155 for linux as well as a memory map buffer. */
156 static grub_err_t
157 allocate_pages (grub_size_t prot_size, grub_size_t *align,
158 grub_size_t min_align, int relocatable,
159 grub_uint64_t preferred_address)
160 {
161 grub_err_t err;
162
163 if (prot_size == 0)
164 prot_size = 1;
165
166 prot_size = page_align (prot_size);
167
168 /* Initialize the memory pointers with NULL for convenience. */
169 free_pages ();
170
171 relocator = grub_relocator_new ();
172 if (!relocator)
173 {
174 err = grub_errno;
175 goto fail;
176 }
177
178 /* FIXME: Should request low memory from the heap when this feature is
179 implemented. */
180
181 {
182 grub_relocator_chunk_t ch;
183 if (relocatable)
184 {
185 err = grub_relocator_alloc_chunk_align (relocator, &ch,
186 preferred_address,
187 preferred_address,
188 prot_size, 1,
189 GRUB_RELOCATOR_PREFERENCE_LOW,
190 1);
191 for (; err && *align + 1 > min_align; (*align)--)
192 {
193 grub_errno = GRUB_ERR_NONE;
194 err = grub_relocator_alloc_chunk_align (relocator, &ch,
195 0x1000000,
196 0xffffffff & ~prot_size,
197 prot_size, 1 << *align,
198 GRUB_RELOCATOR_PREFERENCE_LOW,
199 1);
200 }
201 if (err)
202 goto fail;
203 }
204 else
205 err = grub_relocator_alloc_chunk_addr (relocator, &ch,
206 preferred_address,
207 prot_size);
208 if (err)
209 goto fail;
210 prot_mode_mem = get_virtual_current_address (ch);
211 prot_mode_target = get_physical_target_address (ch);
212 }
213
214 grub_dprintf ("linux", "prot_mode_mem = %p, prot_mode_target = %lx, prot_size = %x\n",
215 prot_mode_mem, (unsigned long) prot_mode_target,
216 (unsigned) prot_size);
217 return GRUB_ERR_NONE;
218
219 fail:
220 free_pages ();
221 return err;
222 }
223
224 static grub_err_t
225 grub_e820_add_region (struct grub_e820_mmap *e820_map, int *e820_num,
226 grub_uint64_t start, grub_uint64_t size,
227 grub_uint32_t type)
228 {
229 int n = *e820_num;
230
231 if ((n > 0) && (e820_map[n - 1].addr + e820_map[n - 1].size == start) &&
232 (e820_map[n - 1].type == type))
233 e820_map[n - 1].size += size;
234 else
235 {
236 e820_map[n].addr = start;
237 e820_map[n].size = size;
238 e820_map[n].type = type;
239 (*e820_num)++;
240 }
241 return GRUB_ERR_NONE;
242 }
243
244 static grub_err_t
245 grub_linux_setup_video (struct linux_kernel_params *params)
246 {
247 struct grub_video_mode_info mode_info;
248 void *framebuffer;
249 grub_err_t err;
250 grub_video_driver_id_t driver_id;
251 const char *gfxlfbvar = grub_env_get ("gfxpayloadforcelfb");
252
253 driver_id = grub_video_get_driver_id ();
254
255 if (driver_id == GRUB_VIDEO_DRIVER_NONE)
256 return 1;
257
258 err = grub_video_get_info_and_fini (&mode_info, &framebuffer);
259
260 if (err)
261 {
262 grub_errno = GRUB_ERR_NONE;
263 return 1;
264 }
265
266 params->lfb_width = mode_info.width;
267 params->lfb_height = mode_info.height;
268 params->lfb_depth = mode_info.bpp;
269 params->lfb_line_len = mode_info.pitch;
270
271 params->lfb_base = (grub_size_t) framebuffer;
272
273 #if defined (GRUB_MACHINE_EFI) && defined (__x86_64__)
274 params->ext_lfb_base = (grub_size_t) (((grub_uint64_t)(grub_size_t) framebuffer) >> 32);
275 params->capabilities |= VIDEO_CAPABILITY_64BIT_BASE;
276 #endif
277
278 params->lfb_size = ALIGN_UP (params->lfb_line_len * params->lfb_height, 65536);
279
280 params->red_mask_size = mode_info.red_mask_size;
281 params->red_field_pos = mode_info.red_field_pos;
282 params->green_mask_size = mode_info.green_mask_size;
283 params->green_field_pos = mode_info.green_field_pos;
284 params->blue_mask_size = mode_info.blue_mask_size;
285 params->blue_field_pos = mode_info.blue_field_pos;
286 params->reserved_mask_size = mode_info.reserved_mask_size;
287 params->reserved_field_pos = mode_info.reserved_field_pos;
288
289 if (gfxlfbvar && (gfxlfbvar[0] == '1' || gfxlfbvar[0] == 'y'))
290 params->have_vga = GRUB_VIDEO_LINUX_TYPE_SIMPLE;
291 else
292 {
293 switch (driver_id)
294 {
295 case GRUB_VIDEO_DRIVER_VBE:
296 params->lfb_size >>= 16;
297 params->have_vga = GRUB_VIDEO_LINUX_TYPE_VESA;
298 break;
299
300 case GRUB_VIDEO_DRIVER_EFI_UGA:
301 case GRUB_VIDEO_DRIVER_EFI_GOP:
302 params->have_vga = GRUB_VIDEO_LINUX_TYPE_EFIFB;
303 break;
304
305 /* FIXME: check if better id is available. */
306 case GRUB_VIDEO_DRIVER_SM712:
307 case GRUB_VIDEO_DRIVER_SIS315PRO:
308 case GRUB_VIDEO_DRIVER_VGA:
309 case GRUB_VIDEO_DRIVER_CIRRUS:
310 case GRUB_VIDEO_DRIVER_BOCHS:
311 case GRUB_VIDEO_DRIVER_RADEON_FULOONG2E:
312 case GRUB_VIDEO_DRIVER_RADEON_YEELOONG3A:
313 case GRUB_VIDEO_DRIVER_IEEE1275:
314 case GRUB_VIDEO_DRIVER_COREBOOT:
315 /* Make gcc happy. */
316 case GRUB_VIDEO_DRIVER_XEN:
317 case GRUB_VIDEO_DRIVER_SDL:
318 case GRUB_VIDEO_DRIVER_NONE:
319 case GRUB_VIDEO_ADAPTER_CAPTURE:
320 params->have_vga = GRUB_VIDEO_LINUX_TYPE_SIMPLE;
321 break;
322 }
323 }
324
325 #ifdef GRUB_MACHINE_PCBIOS
326 /* VESA packed modes may come with zeroed mask sizes, which need
327 to be set here according to DAC Palette width. If we don't,
328 this results in Linux displaying a black screen. */
329 if (driver_id == GRUB_VIDEO_DRIVER_VBE && mode_info.bpp <= 8)
330 {
331 struct grub_vbe_info_block controller_info;
332 int status;
333 int width = 8;
334
335 status = grub_vbe_bios_get_controller_info (&controller_info);
336
337 if (status == GRUB_VBE_STATUS_OK &&
338 (controller_info.capabilities & GRUB_VBE_CAPABILITY_DACWIDTH))
339 status = grub_vbe_bios_set_dac_palette_width (&width);
340
341 if (status != GRUB_VBE_STATUS_OK)
342 /* 6 is default after mode reset. */
343 width = 6;
344
345 params->red_mask_size = params->green_mask_size
346 = params->blue_mask_size = width;
347 params->reserved_mask_size = 0;
348 }
349 #endif
350
351 return GRUB_ERR_NONE;
352 }
353
354 /* Context for grub_linux_boot. */
355 struct grub_linux_boot_ctx
356 {
357 grub_addr_t real_mode_target;
358 grub_size_t real_size;
359 struct linux_kernel_params *params;
360 int e820_num;
361 };
362
363 /* Helper for grub_linux_boot. */
364 static int
365 grub_linux_boot_mmap_find (grub_uint64_t addr, grub_uint64_t size,
366 grub_memory_type_t type, void *data)
367 {
368 struct grub_linux_boot_ctx *ctx = data;
369
370 /* We must put real mode code in the traditional space. */
371 if (type != GRUB_MEMORY_AVAILABLE || addr > 0x90000)
372 return 0;
373
374 if (addr + size < 0x10000)
375 return 0;
376
377 if (addr < 0x10000)
378 {
379 size += addr - 0x10000;
380 addr = 0x10000;
381 }
382
383 if (addr + size > 0x90000)
384 size = 0x90000 - addr;
385
386 if (ctx->real_size + efi_mmap_size > size)
387 return 0;
388
389 grub_dprintf ("linux", "addr = %lx, size = %x, need_size = %x\n",
390 (unsigned long) addr,
391 (unsigned) size,
392 (unsigned) (ctx->real_size + efi_mmap_size));
393 ctx->real_mode_target = ((addr + size) - (ctx->real_size + efi_mmap_size));
394 return 1;
395 }
396
397 /* GRUB types conveniently match E820 types. */
398 static int
399 grub_linux_boot_mmap_fill (grub_uint64_t addr, grub_uint64_t size,
400 grub_memory_type_t type, void *data)
401 {
402 struct grub_linux_boot_ctx *ctx = data;
403
404 if (grub_e820_add_region (ctx->params->e820_map, &ctx->e820_num,
405 addr, size, type))
406 return 1;
407
408 return 0;
409 }
410
411 static void ventoy_debug_pause(void)
412 {
413 char key;
414
415 if (0 == ventoy_debug)
416 {
417 return;
418 }
419
420 grub_printf("press Enter to continue ......\n");
421 while (1)
422 {
423 key = grub_getkey();
424 if (key == '\n' || key == '\r')
425 {
426 break;
427 }
428 }
429 }
430
431 static int ventoy_preboot(void)
432 {
433 int i;
434 const char *file;
435 char buf[128];
436
437 if (ventoy_debug)
438 {
439 grub_printf("ventoy_preboot %d %d\n", ventoy_linux_argc, ventoy_initrd_called);
440 ventoy_debug_pause();
441 }
442
443 if (ventoy_linux_argc == 0)
444 {
445 return 0;
446 }
447
448 if (ventoy_initrd_called)
449 {
450 ventoy_initrd_called = 0;
451 return 0;
452 }
453
454 grub_snprintf(buf, sizeof(buf), "mem:%s:size:%s", grub_env_get("ventoy_cpio_addr"), grub_env_get("ventoy_cpio_size"));
455
456 ventoy_extra_initrd_list[ventoy_extra_initrd_num++] = grub_strdup(buf);
457
458 file = grub_env_get("vtoy_img_part_file");
459 if (file)
460 {
461 ventoy_extra_initrd_list[ventoy_extra_initrd_num++] = grub_strdup(file);
462 }
463
464 if (ventoy_debug)
465 {
466 grub_printf("========== initrd list ==========\n");
467 for (i = 0; i < ventoy_extra_initrd_num; i++)
468 {
469 grub_printf("%s\n", ventoy_extra_initrd_list[i]);
470 }
471 grub_printf("=================================\n");
472
473 ventoy_debug_pause();
474 }
475
476 grub_cmd_initrd(NULL, ventoy_extra_initrd_num, ventoy_extra_initrd_list);
477
478 return 0;
479 }
480
481 static int ventoy_boot_opt_filter(char *opt)
482 {
483 if (grub_strcmp(opt, "noinitrd") == 0)
484 {
485 return 1;
486 }
487
488 if (grub_strncmp(opt, "rdinit=", 7) == 0)
489 {
490 if (grub_strcmp(opt, "rdinit=/vtoy/vtoy") != 0)
491 {
492 opt[0] = 'v';
493 opt[1] = 't';
494 }
495 return 0;
496 }
497
498 if (grub_strncmp(opt, "init=", 5) == 0)
499 {
500 opt[0] = 'v';
501 opt[1] = 't';
502 return 0;
503 }
504
505 if (ventoy_debug)
506 {
507 if (grub_strcmp(opt, "quiet") == 0)
508 {
509 return 1;
510 }
511
512 if (grub_strncmp(opt, "loglevel=", 9) == 0)
513 {
514 return 1;
515 }
516
517 if (grub_strcmp(opt, "splash") == 0)
518 {
519 return 1;
520 }
521 }
522
523 return 0;
524 }
525
526 static int ventoy_bootopt_hook(int argc, char *argv[])
527 {
528 int i;
529 int count = 0;
530 const char *env;
531 char c;
532 char *newenv;
533 char *last, *pos;
534
535 //grub_printf("ventoy_bootopt_hook: %d %d\n", argc, ventoy_linux_argc);
536
537 if (ventoy_linux_argc == 0)
538 {
539 return 0;
540 }
541
542 for (i = 0; i < argc; i++)
543 {
544 if (ventoy_boot_opt_filter(argv[i]))
545 {
546 continue;
547 }
548
549 ventoy_linux_args[count++] = grub_strdup(argv[i]);
550 }
551
552 for (i = 0; i < ventoy_linux_argc; i++)
553 {
554 ventoy_linux_args[count] = ventoy_linux_args[i + (LINUX_MAX_ARGC / 2)];
555 ventoy_linux_args[i + (LINUX_MAX_ARGC / 2)] = NULL;
556
557 if (ventoy_linux_args[count][0] == '@')
558 {
559 env = grub_env_get(ventoy_linux_args[count] + 1);
560 if (env)
561 {
562 grub_free(ventoy_linux_args[count]);
563
564 newenv = grub_strdup(env);
565 last = newenv;
566
567 while (*last)
568 {
569 while (*last)
570 {
571 if (*last != ' ' && *last != '\t')
572 {
573 break;
574 }
575 last++;
576 }
577
578 if (*last == 0)
579 {
580 break;
581 }
582
583 for (pos = last; *pos; pos++)
584 {
585 if (*pos == ' ' || *pos == '\t')
586 {
587 c = *pos;
588 *pos = 0;
589 if (0 == ventoy_boot_opt_filter(last))
590 {
591 ventoy_linux_args[count++] = grub_strdup(last);
592 }
593 *pos = c;
594 break;
595 }
596 }
597
598 if (*pos == 0)
599 {
600 if (0 == ventoy_boot_opt_filter(last))
601 {
602 ventoy_linux_args[count++] = grub_strdup(last);
603 }
604 break;
605 }
606
607 last = pos + 1;
608 }
609 }
610 else
611 {
612 count++;
613 }
614 }
615 else
616 {
617 count++;
618 }
619 }
620
621 if (ventoy_debug)
622 {
623 ventoy_linux_args[count++] = grub_strdup("loglevel=7");
624 }
625
626 ventoy_linux_argc = count;
627
628 if (ventoy_debug)
629 {
630 grub_printf("========== bootoption ==========\n");
631 for (i = 0; i < count; i++)
632 {
633 grub_printf("%s ", ventoy_linux_args[i]);
634 }
635 grub_printf("\n================================\n");
636 }
637
638 return 0;
639 }
640
641 static grub_err_t
642 grub_cmd_set_boot_opt (grub_command_t cmd __attribute__ ((unused)),
643 int argc, char *argv[])
644 {
645 int i;
646 const char *vtdebug;
647
648 for (i = 0; i < argc; i++)
649 {
650 ventoy_linux_args[ventoy_linux_argc + (LINUX_MAX_ARGC / 2) ] = grub_strdup(argv[i]);
651 ventoy_linux_argc++;
652 }
653
654 vtdebug = grub_env_get("vtdebug_flag");
655 if (vtdebug && vtdebug[0])
656 {
657 ventoy_debug = 1;
658 }
659
660 if (ventoy_debug) grub_printf("ventoy set boot opt %d\n", ventoy_linux_argc);
661
662 return 0;
663 }
664
665 static grub_err_t
666 grub_cmd_unset_boot_opt (grub_command_t cmd __attribute__ ((unused)),
667 int argc, char *argv[])
668 {
669 int i;
670
671 (void)argc;
672 (void)argv;
673
674 for (i = 0; i < LINUX_MAX_ARGC; i++)
675 {
676 if (ventoy_linux_args[i])
677 {
678 grub_free(ventoy_linux_args[i]);
679 }
680 }
681
682 ventoy_debug = 0;
683 ventoy_linux_argc = 0;
684 ventoy_initrd_called = 0;
685 grub_memset(ventoy_linux_args, 0, sizeof(char *) * LINUX_MAX_ARGC);
686 return 0;
687 }
688
689 static grub_err_t
690 grub_cmd_extra_initrd_append (grub_command_t cmd __attribute__ ((unused)),
691 int argc, char *argv[])
692 {
693 int newclen = 0;
694 char *pos = NULL;
695 char *end = NULL;
696 char buf[256] = {0};
697
698 if (argc != 1)
699 {
700 return 1;
701 }
702
703 for (pos = argv[0]; *pos; pos++)
704 {
705 if (*pos == '/')
706 {
707 end = pos;
708 }
709 }
710
711 if (end)
712 {
713 /* grub2 newc bug workaround */
714 newclen = (int)grub_strlen(end + 1);
715 if ((110 + newclen) % 4 == 0)
716 {
717 grub_snprintf(buf, sizeof(buf), "newc:.%s:%s", end + 1, argv[0]);
718 }
719 else
720 {
721 grub_snprintf(buf, sizeof(buf), "newc:%s:%s", end + 1, argv[0]);
722 }
723
724 if (ventoy_extra_initrd_num < 256)
725 {
726 ventoy_extra_initrd_list[ventoy_extra_initrd_num++] = grub_strdup(buf);
727 }
728 }
729
730 return 0;
731 }
732
733 static grub_err_t
734 grub_cmd_extra_initrd_reset (grub_command_t cmd __attribute__ ((unused)),
735 int argc, char *argv[])
736 {
737 int i;
738
739 (void)argc;
740 (void)argv;
741
742 for (i = 0; i < ventoy_extra_initrd_num; i++)
743 {
744 if (ventoy_extra_initrd_list[i])
745 {
746 grub_free(ventoy_extra_initrd_list[i]);
747 }
748 }
749
750 grub_memset(ventoy_extra_initrd_list, 0, sizeof(ventoy_extra_initrd_list));
751
752 return 0;
753 }
754
755
756 static grub_err_t
757 grub_linux_boot (void)
758 {
759 grub_err_t err = 0;
760 const char *modevar;
761 char *tmp;
762 struct grub_relocator32_state state;
763 void *real_mode_mem;
764 struct grub_linux_boot_ctx ctx = {
765 .real_mode_target = 0
766 };
767 grub_size_t mmap_size;
768 grub_size_t cl_offset;
769
770 ventoy_preboot();
771
772 #ifdef GRUB_MACHINE_IEEE1275
773 {
774 const char *bootpath;
775 grub_ssize_t len;
776
777 bootpath = grub_env_get ("root");
778 if (bootpath)
779 grub_ieee1275_set_property (grub_ieee1275_chosen,
780 "bootpath", bootpath,
781 grub_strlen (bootpath) + 1,
782 &len);
783 linux_params.ofw_signature = GRUB_LINUX_OFW_SIGNATURE;
784 linux_params.ofw_num_items = 1;
785 linux_params.ofw_cif_handler = (grub_uint32_t) grub_ieee1275_entry_fn;
786 linux_params.ofw_idt = 0;
787 }
788 #endif
789
790 modevar = grub_env_get ("gfxpayload");
791
792 /* Now all graphical modes are acceptable.
793 May change in future if we have modes without framebuffer. */
794 if (modevar && *modevar != 0)
795 {
796 tmp = grub_xasprintf ("%s;" DEFAULT_VIDEO_MODE, modevar);
797 if (! tmp)
798 return grub_errno;
799 #if ACCEPTS_PURE_TEXT
800 err = grub_video_set_mode (tmp, 0, 0);
801 #else
802 err = grub_video_set_mode (tmp, GRUB_VIDEO_MODE_TYPE_PURE_TEXT, 0);
803 #endif
804 grub_free (tmp);
805 }
806 else /* We can't go back to text mode from coreboot fb. */
807 #ifdef GRUB_MACHINE_COREBOOT
808 if (grub_video_get_driver_id () == GRUB_VIDEO_DRIVER_COREBOOT)
809 err = GRUB_ERR_NONE;
810 else
811 #endif
812 {
813 #if ACCEPTS_PURE_TEXT
814 err = grub_video_set_mode (DEFAULT_VIDEO_MODE, 0, 0);
815 #else
816 err = grub_video_set_mode (DEFAULT_VIDEO_MODE,
817 GRUB_VIDEO_MODE_TYPE_PURE_TEXT, 0);
818 #endif
819 }
820
821 if (err)
822 {
823 grub_print_error ();
824 grub_puts_ (N_("Booting in blind mode"));
825 grub_errno = GRUB_ERR_NONE;
826 }
827
828 if (grub_linux_setup_video (&linux_params))
829 {
830 #if defined (GRUB_MACHINE_PCBIOS) || defined (GRUB_MACHINE_COREBOOT) || defined (GRUB_MACHINE_QEMU)
831 linux_params.have_vga = GRUB_VIDEO_LINUX_TYPE_TEXT;
832 linux_params.video_mode = 0x3;
833 #else
834 linux_params.have_vga = 0;
835 linux_params.video_mode = 0;
836 linux_params.video_width = 0;
837 linux_params.video_height = 0;
838 #endif
839 }
840
841
842 #ifndef GRUB_MACHINE_IEEE1275
843 if (linux_params.have_vga == GRUB_VIDEO_LINUX_TYPE_TEXT)
844 #endif
845 {
846 grub_term_output_t term;
847 int found = 0;
848 FOR_ACTIVE_TERM_OUTPUTS(term)
849 if (grub_strcmp (term->name, "vga_text") == 0
850 || grub_strcmp (term->name, "console") == 0
851 || grub_strcmp (term->name, "ofconsole") == 0)
852 {
853 struct grub_term_coordinate pos = grub_term_getxy (term);
854 linux_params.video_cursor_x = pos.x;
855 linux_params.video_cursor_y = pos.y;
856 linux_params.video_width = grub_term_width (term);
857 linux_params.video_height = grub_term_height (term);
858 found = 1;
859 break;
860 }
861 if (!found)
862 {
863 linux_params.video_cursor_x = 0;
864 linux_params.video_cursor_y = 0;
865 linux_params.video_width = 80;
866 linux_params.video_height = 25;
867 }
868 }
869
870 #ifdef GRUB_KERNEL_USE_RSDP_ADDR
871 linux_params.acpi_rsdp_addr = grub_le_to_cpu64 (grub_rsdp_addr);
872 #endif
873
874 mmap_size = find_mmap_size ();
875 /* Make sure that each size is aligned to a page boundary. */
876 cl_offset = ALIGN_UP (mmap_size + sizeof (linux_params), 4096);
877 if (cl_offset < ((grub_size_t) linux_params.setup_sects << GRUB_DISK_SECTOR_BITS))
878 cl_offset = ALIGN_UP ((grub_size_t) (linux_params.setup_sects
879 << GRUB_DISK_SECTOR_BITS), 4096);
880 ctx.real_size = ALIGN_UP (cl_offset + maximal_cmdline_size, 4096);
881
882 #ifdef GRUB_MACHINE_EFI
883 efi_mmap_size = grub_efi_find_mmap_size ();
884 if (efi_mmap_size == 0)
885 return grub_errno;
886 #endif
887
888 grub_dprintf ("linux", "real_size = %x, mmap_size = %x\n",
889 (unsigned) ctx.real_size, (unsigned) mmap_size);
890
891 #ifdef GRUB_MACHINE_EFI
892 grub_efi_mmap_iterate (grub_linux_boot_mmap_find, &ctx, 1);
893 if (! ctx.real_mode_target)
894 grub_efi_mmap_iterate (grub_linux_boot_mmap_find, &ctx, 0);
895 #else
896 grub_mmap_iterate (grub_linux_boot_mmap_find, &ctx);
897 #endif
898 grub_dprintf ("linux", "real_mode_target = %lx, real_size = %x, efi_mmap_size = %x\n",
899 (unsigned long) ctx.real_mode_target,
900 (unsigned) ctx.real_size,
901 (unsigned) efi_mmap_size);
902
903 if (! ctx.real_mode_target)
904 return grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate real mode pages");
905
906 {
907 grub_relocator_chunk_t ch;
908 err = grub_relocator_alloc_chunk_addr (relocator, &ch,
909 ctx.real_mode_target,
910 (ctx.real_size + efi_mmap_size));
911 if (err)
912 return err;
913 real_mode_mem = get_virtual_current_address (ch);
914 }
915 efi_mmap_buf = (grub_uint8_t *) real_mode_mem + ctx.real_size;
916
917 grub_dprintf ("linux", "real_mode_mem = %p\n",
918 real_mode_mem);
919
920 ctx.params = real_mode_mem;
921
922 *ctx.params = linux_params;
923 ctx.params->cmd_line_ptr = ctx.real_mode_target + cl_offset;
924 grub_memcpy ((char *) ctx.params + cl_offset, linux_cmdline,
925 maximal_cmdline_size);
926
927 grub_dprintf ("linux", "code32_start = %x\n",
928 (unsigned) ctx.params->code32_start);
929
930 ctx.e820_num = 0;
931 if (grub_mmap_iterate (grub_linux_boot_mmap_fill, &ctx))
932 return grub_errno;
933 ctx.params->mmap_size = ctx.e820_num;
934
935 #ifdef GRUB_MACHINE_EFI
936 {
937 grub_efi_uintn_t efi_desc_size;
938 grub_size_t efi_mmap_target;
939 grub_efi_uint32_t efi_desc_version;
940 err = grub_efi_finish_boot_services (&efi_mmap_size, efi_mmap_buf, NULL,
941 &efi_desc_size, &efi_desc_version);
942 if (err)
943 return err;
944
945 /* Note that no boot services are available from here. */
946 efi_mmap_target = ctx.real_mode_target
947 + ((grub_uint8_t *) efi_mmap_buf - (grub_uint8_t *) real_mode_mem);
948 /* Pass EFI parameters. */
949 if (grub_le_to_cpu16 (ctx.params->version) >= 0x0208)
950 {
951 ctx.params->v0208.efi_mem_desc_size = efi_desc_size;
952 ctx.params->v0208.efi_mem_desc_version = efi_desc_version;
953 ctx.params->v0208.efi_mmap = efi_mmap_target;
954 ctx.params->v0208.efi_mmap_size = efi_mmap_size;
955
956 #ifdef __x86_64__
957 ctx.params->v0208.efi_mmap_hi = (efi_mmap_target >> 32);
958 #endif
959 }
960 else if (grub_le_to_cpu16 (ctx.params->version) >= 0x0206)
961 {
962 ctx.params->v0206.efi_mem_desc_size = efi_desc_size;
963 ctx.params->v0206.efi_mem_desc_version = efi_desc_version;
964 ctx.params->v0206.efi_mmap = efi_mmap_target;
965 ctx.params->v0206.efi_mmap_size = efi_mmap_size;
966 }
967 else if (grub_le_to_cpu16 (ctx.params->version) >= 0x0204)
968 {
969 ctx.params->v0204.efi_mem_desc_size = efi_desc_size;
970 ctx.params->v0204.efi_mem_desc_version = efi_desc_version;
971 ctx.params->v0204.efi_mmap = efi_mmap_target;
972 ctx.params->v0204.efi_mmap_size = efi_mmap_size;
973 }
974 }
975 #endif
976
977 /* FIXME. */
978 /* asm volatile ("lidt %0" : : "m" (idt_desc)); */
979 state.ebp = state.edi = state.ebx = 0;
980 state.esi = ctx.real_mode_target;
981 state.esp = ctx.real_mode_target;
982 state.eip = ctx.params->code32_start;
983 return grub_relocator32_boot (relocator, state, 0);
984 }
985
986 static grub_err_t
987 grub_linux_unload (void)
988 {
989 grub_dl_unref (my_mod);
990 loaded = 0;
991 grub_free (linux_cmdline);
992 linux_cmdline = 0;
993 return GRUB_ERR_NONE;
994 }
995
996 static grub_err_t
997 grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
998 int argc, char *argv[])
999 {
1000 grub_file_t file = 0;
1001 struct linux_i386_kernel_header lh;
1002 grub_uint8_t setup_sects;
1003 grub_size_t real_size, prot_size, prot_file_size;
1004 grub_ssize_t len;
1005 int i;
1006 grub_size_t align, min_align;
1007 int relocatable;
1008 grub_uint64_t preferred_address = GRUB_LINUX_BZIMAGE_ADDR;
1009
1010 grub_dl_ref (my_mod);
1011
1012 if (argc == 0)
1013 {
1014 grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
1015 goto fail;
1016 }
1017
1018 file = grub_file_open (argv[0], GRUB_FILE_TYPE_LINUX_KERNEL);
1019 if (! file)
1020 goto fail;
1021
1022 if (ventoy_linux_argc)
1023 {
1024 const char *tip = grub_env_get("ventoy_loading_tip");
1025 if (tip)
1026 {
1027 grub_printf("%s\n", tip);
1028 grub_refresh();
1029 }
1030 }
1031
1032 if (grub_file_read (file, &lh, sizeof (lh)) != sizeof (lh))
1033 {
1034 if (!grub_errno)
1035 grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
1036 argv[0]);
1037 goto fail;
1038 }
1039
1040 if (lh.boot_flag != grub_cpu_to_le16_compile_time (0xaa55))
1041 {
1042 grub_error (GRUB_ERR_BAD_OS, "invalid magic number");
1043 goto fail;
1044 }
1045
1046 if (lh.setup_sects > GRUB_LINUX_MAX_SETUP_SECTS)
1047 {
1048 grub_error (GRUB_ERR_BAD_OS, "too many setup sectors");
1049 goto fail;
1050 }
1051
1052 /* FIXME: 2.03 is not always good enough (Linux 2.4 can be 2.03 and
1053 still not support 32-bit boot. */
1054 if (lh.header != grub_cpu_to_le32_compile_time (GRUB_LINUX_I386_MAGIC_SIGNATURE)
1055 || grub_le_to_cpu16 (lh.version) < 0x0203)
1056 {
1057 grub_error (GRUB_ERR_BAD_OS, "version too old for 32-bit boot"
1058 #ifdef GRUB_MACHINE_PCBIOS
1059 " (try with `linux16')"
1060 #endif
1061 );
1062 goto fail;
1063 }
1064
1065 if (! (lh.loadflags & GRUB_LINUX_FLAG_BIG_KERNEL))
1066 {
1067 grub_error (GRUB_ERR_BAD_OS, "zImage doesn't support 32-bit boot"
1068 #ifdef GRUB_MACHINE_PCBIOS
1069 " (try with `linux16')"
1070 #endif
1071 );
1072 goto fail;
1073 }
1074
1075 if (grub_le_to_cpu16 (lh.version) >= 0x0206)
1076 maximal_cmdline_size = grub_le_to_cpu32 (lh.cmdline_size) + 1;
1077 else
1078 maximal_cmdline_size = 256;
1079
1080 if (maximal_cmdline_size < 128)
1081 maximal_cmdline_size = 128;
1082
1083 setup_sects = lh.setup_sects;
1084
1085 /* If SETUP_SECTS is not set, set it to the default (4). */
1086 if (! setup_sects)
1087 setup_sects = GRUB_LINUX_DEFAULT_SETUP_SECTS;
1088
1089 real_size = setup_sects << GRUB_DISK_SECTOR_BITS;
1090 prot_file_size = grub_file_size (file) - real_size - GRUB_DISK_SECTOR_SIZE;
1091
1092 if (grub_le_to_cpu16 (lh.version) >= 0x205
1093 && lh.kernel_alignment != 0
1094 && ((lh.kernel_alignment - 1) & lh.kernel_alignment) == 0)
1095 {
1096 for (align = 0; align < 32; align++)
1097 if (grub_le_to_cpu32 (lh.kernel_alignment) & (1 << align))
1098 break;
1099 relocatable = grub_le_to_cpu32 (lh.relocatable);
1100 }
1101 else
1102 {
1103 align = 0;
1104 relocatable = 0;
1105 }
1106
1107 if (grub_le_to_cpu16 (lh.version) >= 0x020a)
1108 {
1109 min_align = lh.min_alignment;
1110 prot_size = grub_le_to_cpu32 (lh.init_size);
1111 prot_init_space = page_align (prot_size);
1112 if (relocatable)
1113 preferred_address = grub_le_to_cpu64 (lh.pref_address);
1114 else
1115 preferred_address = GRUB_LINUX_BZIMAGE_ADDR;
1116 }
1117 else
1118 {
1119 min_align = align;
1120 prot_size = prot_file_size;
1121 preferred_address = GRUB_LINUX_BZIMAGE_ADDR;
1122 /* Usually, the compression ratio is about 50%. */
1123 prot_init_space = page_align (prot_size) * 3;
1124 }
1125
1126 if (allocate_pages (prot_size, &align,
1127 min_align, relocatable,
1128 preferred_address))
1129 goto fail;
1130
1131 grub_memset (&linux_params, 0, sizeof (linux_params));
1132 grub_memcpy (&linux_params.setup_sects, &lh.setup_sects, sizeof (lh) - 0x1F1);
1133
1134 linux_params.code32_start = prot_mode_target + lh.code32_start - GRUB_LINUX_BZIMAGE_ADDR;
1135 linux_params.kernel_alignment = (1 << align);
1136 linux_params.ps_mouse = linux_params.padding10 = 0;
1137
1138 /*
1139 * The Linux 32-bit boot protocol defines the setup header end
1140 * to be at 0x202 + the byte value at 0x201.
1141 */
1142 len = 0x202 + *((char *) &linux_params.jump + 1);
1143
1144 /* Verify the struct is big enough so we do not write past the end. */
1145 if (len > (char *) &linux_params.edd_mbr_sig_buffer - (char *) &linux_params) {
1146 grub_error (GRUB_ERR_BAD_OS, "Linux setup header too big");
1147 goto fail;
1148 }
1149
1150 /* We've already read lh so there is no need to read it second time. */
1151 len -= sizeof(lh);
1152
1153 if (grub_file_read (file, (char *) &linux_params + sizeof (lh), len) != len)
1154 {
1155 if (!grub_errno)
1156 grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
1157 argv[0]);
1158 goto fail;
1159 }
1160
1161 linux_params.type_of_loader = GRUB_LINUX_BOOT_LOADER_TYPE;
1162
1163 /* These two are used (instead of cmd_line_ptr) by older versions of Linux,
1164 and otherwise ignored. */
1165 linux_params.cl_magic = GRUB_LINUX_CL_MAGIC;
1166 linux_params.cl_offset = 0x1000;
1167
1168 linux_params.ramdisk_image = 0;
1169 linux_params.ramdisk_size = 0;
1170
1171 linux_params.heap_end_ptr = GRUB_LINUX_HEAP_END_OFFSET;
1172 linux_params.loadflags |= GRUB_LINUX_FLAG_CAN_USE_HEAP;
1173
1174 /* These are not needed to be precise, because Linux uses these values
1175 only to raise an error when the decompression code cannot find good
1176 space. */
1177 linux_params.ext_mem = ((32 * 0x100000) >> 10);
1178 linux_params.alt_mem = ((32 * 0x100000) >> 10);
1179
1180 /* Ignored by Linux. */
1181 linux_params.video_page = 0;
1182
1183 /* Only used when `video_mode == 0x7', otherwise ignored. */
1184 linux_params.video_ega_bx = 0;
1185
1186 linux_params.font_size = 16; /* XXX */
1187
1188 #ifdef GRUB_MACHINE_EFI
1189 #ifdef __x86_64__
1190 if (grub_le_to_cpu16 (linux_params.version) < 0x0208 &&
1191 ((grub_addr_t) grub_efi_system_table >> 32) != 0)
1192 return grub_error(GRUB_ERR_BAD_OS,
1193 "kernel does not support 64-bit addressing");
1194 #endif
1195
1196 if (grub_le_to_cpu16 (linux_params.version) >= 0x0208)
1197 {
1198 linux_params.v0208.efi_signature = GRUB_LINUX_EFI_SIGNATURE;
1199 linux_params.v0208.efi_system_table = (grub_uint32_t) (grub_addr_t) grub_efi_system_table;
1200 #ifdef __x86_64__
1201 linux_params.v0208.efi_system_table_hi = (grub_uint32_t) ((grub_uint64_t) grub_efi_system_table >> 32);
1202 #endif
1203 }
1204 else if (grub_le_to_cpu16 (linux_params.version) >= 0x0206)
1205 {
1206 linux_params.v0206.efi_signature = GRUB_LINUX_EFI_SIGNATURE;
1207 linux_params.v0206.efi_system_table = (grub_uint32_t) (grub_addr_t) grub_efi_system_table;
1208 }
1209 else if (grub_le_to_cpu16 (linux_params.version) >= 0x0204)
1210 {
1211 linux_params.v0204.efi_signature = GRUB_LINUX_EFI_SIGNATURE_0204;
1212 linux_params.v0204.efi_system_table = (grub_uint32_t) (grub_addr_t) grub_efi_system_table;
1213 }
1214 #endif
1215
1216 /* The other parameters are filled when booting. */
1217
1218 grub_file_seek (file, real_size + GRUB_DISK_SECTOR_SIZE);
1219
1220 grub_dprintf ("linux", "bzImage, setup=0x%x, size=0x%x\n",
1221 (unsigned) real_size, (unsigned) prot_size);
1222
1223 /* Look for memory size and video mode specified on the command line. */
1224 linux_mem_size = 0;
1225 for (i = 1; i < argc; i++)
1226 #ifdef GRUB_MACHINE_PCBIOS
1227 if (grub_memcmp (argv[i], "vga=", 4) == 0)
1228 {
1229 /* Video mode selection support. */
1230 char *val = argv[i] + 4;
1231 unsigned vid_mode = GRUB_LINUX_VID_MODE_NORMAL;
1232 struct grub_vesa_mode_table_entry *linux_mode;
1233 grub_err_t err;
1234 char *buf;
1235
1236 grub_dl_load ("vbe");
1237
1238 if (grub_strcmp (val, "normal") == 0)
1239 vid_mode = GRUB_LINUX_VID_MODE_NORMAL;
1240 else if (grub_strcmp (val, "ext") == 0)
1241 vid_mode = GRUB_LINUX_VID_MODE_EXTENDED;
1242 else if (grub_strcmp (val, "ask") == 0)
1243 {
1244 grub_puts_ (N_("Legacy `ask' parameter no longer supported."));
1245
1246 /* We usually would never do this in a loader, but "vga=ask" means user
1247 requested interaction, so it can't hurt to request keyboard input. */
1248 grub_wait_after_message ();
1249
1250 goto fail;
1251 }
1252 else
1253 vid_mode = (grub_uint16_t) grub_strtoul (val, 0, 0);
1254
1255 switch (vid_mode)
1256 {
1257 case 0:
1258 case GRUB_LINUX_VID_MODE_NORMAL:
1259 grub_env_set ("gfxpayload", "text");
1260 grub_printf_ (N_("%s is deprecated. "
1261 "Use set gfxpayload=%s before "
1262 "linux command instead.\n"),
1263 argv[i], "text");
1264 break;
1265
1266 case 1:
1267 case GRUB_LINUX_VID_MODE_EXTENDED:
1268 /* FIXME: support 80x50 text. */
1269 grub_env_set ("gfxpayload", "text");
1270 grub_printf_ (N_("%s is deprecated. "
1271 "Use set gfxpayload=%s before "
1272 "linux command instead.\n"),
1273 argv[i], "text");
1274 break;
1275 default:
1276 /* Ignore invalid values. */
1277 if (vid_mode < GRUB_VESA_MODE_TABLE_START ||
1278 vid_mode > GRUB_VESA_MODE_TABLE_END)
1279 {
1280 grub_env_set ("gfxpayload", "text");
1281 /* TRANSLATORS: "x" has to be entered in, like an identifier,
1282 so please don't use better Unicode codepoints. */
1283 grub_printf_ (N_("%s is deprecated. VGA mode %d isn't recognized. "
1284 "Use set gfxpayload=WIDTHxHEIGHT[xDEPTH] "
1285 "before linux command instead.\n"),
1286 argv[i], vid_mode);
1287 break;
1288 }
1289
1290 linux_mode = &grub_vesa_mode_table[vid_mode
1291 - GRUB_VESA_MODE_TABLE_START];
1292
1293 buf = grub_xasprintf ("%ux%ux%u,%ux%u",
1294 linux_mode->width, linux_mode->height,
1295 linux_mode->depth,
1296 linux_mode->width, linux_mode->height);
1297 if (! buf)
1298 goto fail;
1299
1300 grub_printf_ (N_("%s is deprecated. "
1301 "Use set gfxpayload=%s before "
1302 "linux command instead.\n"),
1303 argv[i], buf);
1304 err = grub_env_set ("gfxpayload", buf);
1305 grub_free (buf);
1306 if (err)
1307 goto fail;
1308 }
1309 }
1310 else
1311 #endif /* GRUB_MACHINE_PCBIOS */
1312 if (grub_memcmp (argv[i], "mem=", 4) == 0)
1313 {
1314 char *val = argv[i] + 4;
1315
1316 linux_mem_size = grub_strtoul (val, &val, 0);
1317
1318 if (grub_errno)
1319 {
1320 grub_errno = GRUB_ERR_NONE;
1321 linux_mem_size = 0;
1322 }
1323 else
1324 {
1325 int shift = 0;
1326
1327 switch (grub_tolower (val[0]))
1328 {
1329 case 'g':
1330 shift += 10;
1331 /* FALLTHROUGH */
1332 case 'm':
1333 shift += 10;
1334 /* FALLTHROUGH */
1335 case 'k':
1336 shift += 10;
1337 /* FALLTHROUGH */
1338 default:
1339 break;
1340 }
1341
1342 /* Check an overflow. */
1343 if (linux_mem_size > (~0UL >> shift))
1344 linux_mem_size = 0;
1345 else
1346 linux_mem_size <<= shift;
1347 }
1348 }
1349 else if (grub_memcmp (argv[i], "quiet", sizeof ("quiet") - 1) == 0)
1350 {
1351 linux_params.loadflags |= GRUB_LINUX_FLAG_QUIET;
1352 }
1353
1354 /* Create kernel command line. */
1355 linux_cmdline = grub_zalloc (maximal_cmdline_size + 1);
1356 if (!linux_cmdline)
1357 goto fail;
1358 grub_memcpy (linux_cmdline, LINUX_IMAGE, sizeof (LINUX_IMAGE));
1359 {
1360 grub_err_t err;
1361
1362 if (ventoy_linux_argc)
1363 {
1364 ventoy_bootopt_hook(argc, argv);
1365 err = grub_create_loader_cmdline (ventoy_linux_argc, ventoy_linux_args,
1366 linux_cmdline
1367 + sizeof (LINUX_IMAGE) - 1,
1368 maximal_cmdline_size
1369 - (sizeof (LINUX_IMAGE) - 1),
1370 GRUB_VERIFY_KERNEL_CMDLINE);
1371 }
1372 else
1373 {
1374 err = grub_create_loader_cmdline (argc, argv,
1375 linux_cmdline
1376 + sizeof (LINUX_IMAGE) - 1,
1377 maximal_cmdline_size
1378 - (sizeof (LINUX_IMAGE) - 1),
1379 GRUB_VERIFY_KERNEL_CMDLINE);
1380 }
1381
1382 if (err)
1383 goto fail;
1384 }
1385
1386 len = prot_file_size;
1387 if (grub_file_read (file, prot_mode_mem, len) != len && !grub_errno)
1388 grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
1389 argv[0]);
1390
1391 if (grub_errno == GRUB_ERR_NONE)
1392 {
1393 grub_loader_set (grub_linux_boot, grub_linux_unload,
1394 0 /* set noreturn=0 in order to avoid grub_console_fini() */);
1395 loaded = 1;
1396 }
1397
1398 fail:
1399
1400 if (file)
1401 grub_file_close (file);
1402
1403 if (grub_errno != GRUB_ERR_NONE)
1404 {
1405 grub_dl_unref (my_mod);
1406 loaded = 0;
1407 }
1408
1409 return grub_errno;
1410 }
1411
1412 static grub_err_t
1413 grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
1414 int argc, char *argv[])
1415 {
1416 grub_size_t size = 0, aligned_size = 0;
1417 grub_addr_t addr_min, addr_max;
1418 grub_addr_t addr;
1419 grub_err_t err;
1420 struct grub_linux_initrd_context initrd_ctx = { 0, 0, 0 };
1421
1422 if (argc == 0)
1423 {
1424 grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
1425 goto fail;
1426 }
1427
1428 if (! loaded)
1429 {
1430 grub_error (GRUB_ERR_BAD_ARGUMENT, N_("you need to load the kernel first"));
1431 goto fail;
1432 }
1433
1434 if (grub_initrd_init (argc, argv, &initrd_ctx))
1435 goto fail;
1436
1437 size = grub_get_initrd_size (&initrd_ctx);
1438 aligned_size = ALIGN_UP (size, 4096);
1439
1440 /* Get the highest address available for the initrd. */
1441 if (grub_le_to_cpu16 (linux_params.version) >= 0x0203)
1442 {
1443 addr_max = grub_cpu_to_le32 (linux_params.initrd_addr_max);
1444
1445 /* XXX in reality, Linux specifies a bogus value, so
1446 it is necessary to make sure that ADDR_MAX does not exceed
1447 0x3fffffff. */
1448 if (addr_max > GRUB_LINUX_INITRD_MAX_ADDRESS)
1449 addr_max = GRUB_LINUX_INITRD_MAX_ADDRESS;
1450 }
1451 else
1452 addr_max = GRUB_LINUX_INITRD_MAX_ADDRESS;
1453
1454 if (linux_mem_size != 0 && linux_mem_size < addr_max)
1455 addr_max = linux_mem_size;
1456
1457 /* Linux 2.3.xx has a bug in the memory range check, so avoid
1458 the last page.
1459 Linux 2.2.xx has a bug in the memory range check, which is
1460 worse than that of Linux 2.3.xx, so avoid the last 64kb. */
1461 addr_max -= 0x10000;
1462
1463 addr_min = (grub_addr_t) prot_mode_target + prot_init_space;
1464
1465 /* Put the initrd as high as possible, 4KiB aligned. */
1466 addr = (addr_max - aligned_size) & ~0xFFF;
1467
1468 if (addr < addr_min)
1469 {
1470 grub_error (GRUB_ERR_OUT_OF_RANGE, "the initrd is too big");
1471 goto fail;
1472 }
1473
1474 {
1475 grub_relocator_chunk_t ch;
1476 err = grub_relocator_alloc_chunk_align (relocator, &ch,
1477 addr_min, addr, aligned_size,
1478 0x1000,
1479 GRUB_RELOCATOR_PREFERENCE_HIGH,
1480 1);
1481 if (err)
1482 return err;
1483 initrd_mem = get_virtual_current_address (ch);
1484 initrd_mem_target = get_physical_target_address (ch);
1485 }
1486
1487 if (grub_initrd_load (&initrd_ctx, argv, initrd_mem))
1488 goto fail;
1489
1490 grub_dprintf ("linux", "Initrd, addr=0x%x, size=0x%x\n",
1491 (unsigned) addr, (unsigned) size);
1492
1493 linux_params.ramdisk_image = initrd_mem_target;
1494 linux_params.ramdisk_size = size;
1495 linux_params.root_dev = 0x0100; /* XXX */
1496
1497 fail:
1498 grub_initrd_close (&initrd_ctx);
1499
1500 return grub_errno;
1501 }
1502
1503 static grub_err_t
1504 ventoy_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
1505 int argc, char *argv[])
1506 {
1507 int i;
1508 const char *file;
1509 char buf[64];
1510
1511 if (ventoy_debug) grub_printf("ventoy_cmd_initrd %d\n", ventoy_linux_argc);
1512
1513 if (ventoy_linux_argc == 0)
1514 {
1515 return grub_cmd_initrd(cmd, argc, argv);
1516 }
1517
1518 grub_snprintf(buf, sizeof(buf), "mem:%s:size:%s", grub_env_get("ventoy_cpio_addr"), grub_env_get("ventoy_cpio_size"));
1519
1520 if (ventoy_debug) grub_printf("membuf=%s\n", buf);
1521
1522 ventoy_extra_initrd_list[ventoy_extra_initrd_num++] = grub_strdup(buf);
1523
1524 file = grub_env_get("vtoy_img_part_file");
1525 if (file)
1526 {
1527 ventoy_extra_initrd_list[ventoy_extra_initrd_num++] = grub_strdup(file);
1528 }
1529
1530 for (i = 0; i < argc; i++)
1531 {
1532 ventoy_extra_initrd_list[ventoy_extra_initrd_num++] = grub_strdup(argv[i]);
1533 }
1534
1535 ventoy_initrd_called = 1;
1536
1537 if (ventoy_debug)
1538 {
1539 grub_printf("========== initrd list ==========\n");
1540 for (i = 0; i < ventoy_extra_initrd_num; i++)
1541 {
1542 grub_printf("%s\n", ventoy_extra_initrd_list[i]);
1543 }
1544 grub_printf("=================================\n");
1545 }
1546
1547 return grub_cmd_initrd(cmd, ventoy_extra_initrd_num, ventoy_extra_initrd_list);
1548 }
1549
1550
1551 static grub_command_t cmd_linux, cmd_initrd, cmd_linuxefi, cmd_initrdefi;
1552 static grub_command_t cmd_set_bootopt, cmd_unset_bootopt, cmd_extra_initrd_append, cmd_extra_initrd_reset;
1553
1554 GRUB_MOD_INIT(linux)
1555 {
1556 cmd_linux = grub_register_command ("linux", grub_cmd_linux,
1557 0, N_("Load Linux."));
1558 cmd_initrd = grub_register_command ("initrd", ventoy_cmd_initrd,
1559 0, N_("Load initrd."));
1560
1561 cmd_linuxefi = grub_register_command ("linuxefi", grub_cmd_linux,
1562 0, N_("Load Linux."));
1563 cmd_initrdefi = grub_register_command ("initrdefi", ventoy_cmd_initrd,
1564 0, N_("Load initrd."));
1565 cmd_set_bootopt = grub_register_command ("vt_set_boot_opt", grub_cmd_set_boot_opt, 0, N_("set ext boot opt"));
1566 cmd_unset_bootopt = grub_register_command ("vt_unset_boot_opt", grub_cmd_unset_boot_opt, 0, N_("unset ext boot opt"));
1567
1568 cmd_extra_initrd_append = grub_register_command ("vt_img_extra_initrd_append", grub_cmd_extra_initrd_append, 0, N_(""));
1569 cmd_extra_initrd_reset = grub_register_command ("vt_img_extra_initrd_reset", grub_cmd_extra_initrd_reset, 0, N_(""));
1570
1571 ventoy_linux_args = grub_zalloc(sizeof(char *) * LINUX_MAX_ARGC);
1572
1573 my_mod = mod;
1574 }
1575
1576 GRUB_MOD_FINI(linux)
1577 {
1578 grub_unregister_command (cmd_linux);
1579 grub_unregister_command (cmd_initrd);
1580 }