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