]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - GRUB2/MOD_SRC/grub-2.04/grub-core/loader/i386/linux.c
ae06ad1dbdb0892681a21f493fc965ff19a97534
[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 (grub_strncmp(opt, "dm=", 3) == 0)
510 {
511 opt[0] = 'D';
512 opt[1] = 'M';
513 return 0;
514 }
515
516 if (ventoy_debug)
517 {
518 if (grub_strcmp(opt, "quiet") == 0)
519 {
520 return 1;
521 }
522
523 if (grub_strncmp(opt, "loglevel=", 9) == 0)
524 {
525 return 1;
526 }
527
528 if (grub_strcmp(opt, "splash") == 0)
529 {
530 return 1;
531 }
532 }
533
534 return 0;
535 }
536
537 static int ventoy_bootopt_hook(int argc, char *argv[])
538 {
539 int i;
540 int TmpIdx;
541 int count = 0;
542 const char *env;
543 char c;
544 char *newenv;
545 char *last, *pos;
546
547 //grub_printf("ventoy_bootopt_hook: %d %d\n", argc, ventoy_linux_argc);
548
549 if (ventoy_linux_argc == 0)
550 {
551 return 0;
552 }
553
554 /* To avoid --- parameter, we split two parts */
555 for (TmpIdx = 0; TmpIdx < argc; TmpIdx++)
556 {
557 if (ventoy_boot_opt_filter(argv[TmpIdx]))
558 {
559 continue;
560 }
561
562 if (grub_strncmp(argv[TmpIdx], "--", 2) == 0)
563 {
564 break;
565 }
566
567 ventoy_linux_args[count++] = grub_strdup(argv[TmpIdx]);
568 }
569
570 for (i = 0; i < ventoy_linux_argc; i++)
571 {
572 ventoy_linux_args[count] = ventoy_linux_args[i + (LINUX_MAX_ARGC / 2)];
573 ventoy_linux_args[i + (LINUX_MAX_ARGC / 2)] = NULL;
574
575 if (ventoy_linux_args[count][0] == '@')
576 {
577 env = grub_env_get(ventoy_linux_args[count] + 1);
578 if (env)
579 {
580 grub_free(ventoy_linux_args[count]);
581
582 newenv = grub_strdup(env);
583 last = newenv;
584
585 while (*last)
586 {
587 while (*last)
588 {
589 if (*last != ' ' && *last != '\t')
590 {
591 break;
592 }
593 last++;
594 }
595
596 if (*last == 0)
597 {
598 break;
599 }
600
601 for (pos = last; *pos; pos++)
602 {
603 if (*pos == ' ' || *pos == '\t')
604 {
605 c = *pos;
606 *pos = 0;
607 if (0 == ventoy_boot_opt_filter(last))
608 {
609 ventoy_linux_args[count++] = grub_strdup(last);
610 }
611 *pos = c;
612 break;
613 }
614 }
615
616 if (*pos == 0)
617 {
618 if (0 == ventoy_boot_opt_filter(last))
619 {
620 ventoy_linux_args[count++] = grub_strdup(last);
621 }
622 break;
623 }
624
625 last = pos + 1;
626 }
627 }
628 else
629 {
630 count++;
631 }
632 }
633 else
634 {
635 count++;
636 }
637 }
638
639 while (TmpIdx < argc)
640 {
641 if (ventoy_boot_opt_filter(argv[TmpIdx]))
642 {
643 continue;
644 }
645
646 ventoy_linux_args[count++] = grub_strdup(argv[TmpIdx]);
647 TmpIdx++;
648 }
649
650 if (ventoy_debug)
651 {
652 ventoy_linux_args[count++] = grub_strdup("loglevel=7");
653 }
654
655 ventoy_linux_argc = count;
656
657 if (ventoy_debug)
658 {
659 grub_printf("========== bootoption ==========\n");
660 for (i = 0; i < count; i++)
661 {
662 grub_printf("%s ", ventoy_linux_args[i]);
663 }
664 grub_printf("\n================================\n");
665 }
666
667 return 0;
668 }
669
670 static grub_err_t
671 grub_cmd_set_boot_opt (grub_command_t cmd __attribute__ ((unused)),
672 int argc, char *argv[])
673 {
674 int i;
675 const char *vtdebug;
676
677 for (i = 0; i < argc; i++)
678 {
679 ventoy_linux_args[ventoy_linux_argc + (LINUX_MAX_ARGC / 2) ] = grub_strdup(argv[i]);
680 ventoy_linux_argc++;
681 }
682
683 vtdebug = grub_env_get("vtdebug_flag");
684 if (vtdebug && vtdebug[0])
685 {
686 ventoy_debug = 1;
687 }
688
689 if (ventoy_debug) grub_printf("ventoy set boot opt %d\n", ventoy_linux_argc);
690
691 return 0;
692 }
693
694 static grub_err_t
695 grub_cmd_unset_boot_opt (grub_command_t cmd __attribute__ ((unused)),
696 int argc, char *argv[])
697 {
698 int i;
699
700 (void)argc;
701 (void)argv;
702
703 for (i = 0; i < LINUX_MAX_ARGC; i++)
704 {
705 if (ventoy_linux_args[i])
706 {
707 grub_free(ventoy_linux_args[i]);
708 }
709 }
710
711 ventoy_debug = 0;
712 ventoy_linux_argc = 0;
713 ventoy_initrd_called = 0;
714 grub_memset(ventoy_linux_args, 0, sizeof(char *) * LINUX_MAX_ARGC);
715 return 0;
716 }
717
718 static grub_err_t
719 grub_cmd_extra_initrd_append (grub_command_t cmd __attribute__ ((unused)),
720 int argc, char *argv[])
721 {
722 int newclen = 0;
723 char *pos = NULL;
724 char *end = NULL;
725 char buf[256] = {0};
726
727 if (argc != 1)
728 {
729 return 1;
730 }
731
732 for (pos = argv[0]; *pos; pos++)
733 {
734 if (*pos == '/')
735 {
736 end = pos;
737 }
738 }
739
740 if (end)
741 {
742 /* grub2 newc bug workaround */
743 newclen = (int)grub_strlen(end + 1);
744 if ((110 + newclen) % 4 == 0)
745 {
746 grub_snprintf(buf, sizeof(buf), "newc:.%s:%s", end + 1, argv[0]);
747 }
748 else
749 {
750 grub_snprintf(buf, sizeof(buf), "newc:%s:%s", end + 1, argv[0]);
751 }
752
753 if (ventoy_extra_initrd_num < 256)
754 {
755 ventoy_extra_initrd_list[ventoy_extra_initrd_num++] = grub_strdup(buf);
756 }
757 }
758
759 return 0;
760 }
761
762 static grub_err_t
763 grub_cmd_extra_initrd_reset (grub_command_t cmd __attribute__ ((unused)),
764 int argc, char *argv[])
765 {
766 int i;
767
768 (void)argc;
769 (void)argv;
770
771 for (i = 0; i < ventoy_extra_initrd_num; i++)
772 {
773 if (ventoy_extra_initrd_list[i])
774 {
775 grub_free(ventoy_extra_initrd_list[i]);
776 }
777 }
778
779 grub_memset(ventoy_extra_initrd_list, 0, sizeof(ventoy_extra_initrd_list));
780
781 return 0;
782 }
783
784
785 static grub_err_t
786 grub_linux_boot (void)
787 {
788 grub_err_t err = 0;
789 const char *modevar;
790 char *tmp;
791 struct grub_relocator32_state state;
792 void *real_mode_mem;
793 struct grub_linux_boot_ctx ctx = {
794 .real_mode_target = 0
795 };
796 grub_size_t mmap_size;
797 grub_size_t cl_offset;
798
799 ventoy_preboot();
800
801 #ifdef GRUB_MACHINE_IEEE1275
802 {
803 const char *bootpath;
804 grub_ssize_t len;
805
806 bootpath = grub_env_get ("root");
807 if (bootpath)
808 grub_ieee1275_set_property (grub_ieee1275_chosen,
809 "bootpath", bootpath,
810 grub_strlen (bootpath) + 1,
811 &len);
812 linux_params.ofw_signature = GRUB_LINUX_OFW_SIGNATURE;
813 linux_params.ofw_num_items = 1;
814 linux_params.ofw_cif_handler = (grub_uint32_t) grub_ieee1275_entry_fn;
815 linux_params.ofw_idt = 0;
816 }
817 #endif
818
819 modevar = grub_env_get ("gfxpayload");
820
821 /* Now all graphical modes are acceptable.
822 May change in future if we have modes without framebuffer. */
823 if (modevar && *modevar != 0)
824 {
825 tmp = grub_xasprintf ("%s;" DEFAULT_VIDEO_MODE, modevar);
826 if (! tmp)
827 return grub_errno;
828 #if ACCEPTS_PURE_TEXT
829 err = grub_video_set_mode (tmp, 0, 0);
830 #else
831 err = grub_video_set_mode (tmp, GRUB_VIDEO_MODE_TYPE_PURE_TEXT, 0);
832 #endif
833 grub_free (tmp);
834 }
835 else /* We can't go back to text mode from coreboot fb. */
836 #ifdef GRUB_MACHINE_COREBOOT
837 if (grub_video_get_driver_id () == GRUB_VIDEO_DRIVER_COREBOOT)
838 err = GRUB_ERR_NONE;
839 else
840 #endif
841 {
842 #if ACCEPTS_PURE_TEXT
843 err = grub_video_set_mode (DEFAULT_VIDEO_MODE, 0, 0);
844 #else
845 err = grub_video_set_mode (DEFAULT_VIDEO_MODE,
846 GRUB_VIDEO_MODE_TYPE_PURE_TEXT, 0);
847 #endif
848 }
849
850 if (err)
851 {
852 grub_print_error ();
853 grub_puts_ (N_("Booting in blind mode"));
854 grub_errno = GRUB_ERR_NONE;
855 }
856
857 if (grub_linux_setup_video (&linux_params))
858 {
859 #if defined (GRUB_MACHINE_PCBIOS) || defined (GRUB_MACHINE_COREBOOT) || defined (GRUB_MACHINE_QEMU)
860 linux_params.have_vga = GRUB_VIDEO_LINUX_TYPE_TEXT;
861 linux_params.video_mode = 0x3;
862 #else
863 linux_params.have_vga = 0;
864 linux_params.video_mode = 0;
865 linux_params.video_width = 0;
866 linux_params.video_height = 0;
867 #endif
868 }
869
870
871 #ifndef GRUB_MACHINE_IEEE1275
872 if (linux_params.have_vga == GRUB_VIDEO_LINUX_TYPE_TEXT)
873 #endif
874 {
875 grub_term_output_t term;
876 int found = 0;
877 FOR_ACTIVE_TERM_OUTPUTS(term)
878 if (grub_strcmp (term->name, "vga_text") == 0
879 || grub_strcmp (term->name, "console") == 0
880 || grub_strcmp (term->name, "ofconsole") == 0)
881 {
882 struct grub_term_coordinate pos = grub_term_getxy (term);
883 linux_params.video_cursor_x = pos.x;
884 linux_params.video_cursor_y = pos.y;
885 linux_params.video_width = grub_term_width (term);
886 linux_params.video_height = grub_term_height (term);
887 found = 1;
888 break;
889 }
890 if (!found)
891 {
892 linux_params.video_cursor_x = 0;
893 linux_params.video_cursor_y = 0;
894 linux_params.video_width = 80;
895 linux_params.video_height = 25;
896 }
897 }
898
899 #ifdef GRUB_KERNEL_USE_RSDP_ADDR
900 linux_params.acpi_rsdp_addr = grub_le_to_cpu64 (grub_rsdp_addr);
901 #endif
902
903 mmap_size = find_mmap_size ();
904 /* Make sure that each size is aligned to a page boundary. */
905 cl_offset = ALIGN_UP (mmap_size + sizeof (linux_params), 4096);
906 if (cl_offset < ((grub_size_t) linux_params.setup_sects << GRUB_DISK_SECTOR_BITS))
907 cl_offset = ALIGN_UP ((grub_size_t) (linux_params.setup_sects
908 << GRUB_DISK_SECTOR_BITS), 4096);
909 ctx.real_size = ALIGN_UP (cl_offset + maximal_cmdline_size, 4096);
910
911 #ifdef GRUB_MACHINE_EFI
912 efi_mmap_size = grub_efi_find_mmap_size ();
913 if (efi_mmap_size == 0)
914 return grub_errno;
915 #endif
916
917 grub_dprintf ("linux", "real_size = %x, mmap_size = %x\n",
918 (unsigned) ctx.real_size, (unsigned) mmap_size);
919
920 #ifdef GRUB_MACHINE_EFI
921 grub_efi_mmap_iterate (grub_linux_boot_mmap_find, &ctx, 1);
922 if (! ctx.real_mode_target)
923 grub_efi_mmap_iterate (grub_linux_boot_mmap_find, &ctx, 0);
924 #else
925 grub_mmap_iterate (grub_linux_boot_mmap_find, &ctx);
926 #endif
927 grub_dprintf ("linux", "real_mode_target = %lx, real_size = %x, efi_mmap_size = %x\n",
928 (unsigned long) ctx.real_mode_target,
929 (unsigned) ctx.real_size,
930 (unsigned) efi_mmap_size);
931
932 if (! ctx.real_mode_target)
933 return grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate real mode pages");
934
935 {
936 grub_relocator_chunk_t ch;
937 err = grub_relocator_alloc_chunk_addr (relocator, &ch,
938 ctx.real_mode_target,
939 (ctx.real_size + efi_mmap_size));
940 if (err)
941 return err;
942 real_mode_mem = get_virtual_current_address (ch);
943 }
944 efi_mmap_buf = (grub_uint8_t *) real_mode_mem + ctx.real_size;
945
946 grub_dprintf ("linux", "real_mode_mem = %p\n",
947 real_mode_mem);
948
949 ctx.params = real_mode_mem;
950
951 *ctx.params = linux_params;
952 ctx.params->cmd_line_ptr = ctx.real_mode_target + cl_offset;
953 grub_memcpy ((char *) ctx.params + cl_offset, linux_cmdline,
954 maximal_cmdline_size);
955
956 grub_dprintf ("linux", "code32_start = %x\n",
957 (unsigned) ctx.params->code32_start);
958
959 ctx.e820_num = 0;
960 if (grub_mmap_iterate (grub_linux_boot_mmap_fill, &ctx))
961 return grub_errno;
962 ctx.params->mmap_size = ctx.e820_num;
963
964 #ifdef GRUB_MACHINE_EFI
965 {
966 grub_efi_uintn_t efi_desc_size;
967 grub_size_t efi_mmap_target;
968 grub_efi_uint32_t efi_desc_version;
969 err = grub_efi_finish_boot_services (&efi_mmap_size, efi_mmap_buf, NULL,
970 &efi_desc_size, &efi_desc_version);
971 if (err)
972 return err;
973
974 /* Note that no boot services are available from here. */
975 efi_mmap_target = ctx.real_mode_target
976 + ((grub_uint8_t *) efi_mmap_buf - (grub_uint8_t *) real_mode_mem);
977 /* Pass EFI parameters. */
978 if (grub_le_to_cpu16 (ctx.params->version) >= 0x0208)
979 {
980 ctx.params->v0208.efi_mem_desc_size = efi_desc_size;
981 ctx.params->v0208.efi_mem_desc_version = efi_desc_version;
982 ctx.params->v0208.efi_mmap = efi_mmap_target;
983 ctx.params->v0208.efi_mmap_size = efi_mmap_size;
984
985 #ifdef __x86_64__
986 ctx.params->v0208.efi_mmap_hi = (efi_mmap_target >> 32);
987 #endif
988 }
989 else if (grub_le_to_cpu16 (ctx.params->version) >= 0x0206)
990 {
991 ctx.params->v0206.efi_mem_desc_size = efi_desc_size;
992 ctx.params->v0206.efi_mem_desc_version = efi_desc_version;
993 ctx.params->v0206.efi_mmap = efi_mmap_target;
994 ctx.params->v0206.efi_mmap_size = efi_mmap_size;
995 }
996 else if (grub_le_to_cpu16 (ctx.params->version) >= 0x0204)
997 {
998 ctx.params->v0204.efi_mem_desc_size = efi_desc_size;
999 ctx.params->v0204.efi_mem_desc_version = efi_desc_version;
1000 ctx.params->v0204.efi_mmap = efi_mmap_target;
1001 ctx.params->v0204.efi_mmap_size = efi_mmap_size;
1002 }
1003 }
1004 #endif
1005
1006 /* FIXME. */
1007 /* asm volatile ("lidt %0" : : "m" (idt_desc)); */
1008 state.ebp = state.edi = state.ebx = 0;
1009 state.esi = ctx.real_mode_target;
1010 state.esp = ctx.real_mode_target;
1011 state.eip = ctx.params->code32_start;
1012 return grub_relocator32_boot (relocator, state, 0);
1013 }
1014
1015 static grub_err_t
1016 grub_linux_unload (void)
1017 {
1018 grub_dl_unref (my_mod);
1019 loaded = 0;
1020 grub_free (linux_cmdline);
1021 linux_cmdline = 0;
1022 return GRUB_ERR_NONE;
1023 }
1024
1025 static grub_err_t
1026 grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
1027 int argc, char *argv[])
1028 {
1029 grub_file_t file = 0;
1030 struct linux_i386_kernel_header lh;
1031 grub_uint8_t setup_sects;
1032 grub_size_t real_size, prot_size, prot_file_size;
1033 grub_ssize_t len;
1034 int i;
1035 grub_size_t align, min_align;
1036 int relocatable;
1037 grub_uint64_t preferred_address = GRUB_LINUX_BZIMAGE_ADDR;
1038
1039 grub_dl_ref (my_mod);
1040
1041 if (argc == 0)
1042 {
1043 grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
1044 goto fail;
1045 }
1046
1047 file = grub_file_open (argv[0], GRUB_FILE_TYPE_LINUX_KERNEL);
1048 if (! file)
1049 goto fail;
1050
1051 if (ventoy_linux_argc)
1052 {
1053 const char *tip = grub_env_get("ventoy_loading_tip");
1054 if (tip)
1055 {
1056 grub_printf("%s\n", tip);
1057 grub_refresh();
1058 }
1059 }
1060
1061 if (grub_file_read (file, &lh, sizeof (lh)) != sizeof (lh))
1062 {
1063 if (!grub_errno)
1064 grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
1065 argv[0]);
1066 goto fail;
1067 }
1068
1069 if (lh.boot_flag != grub_cpu_to_le16_compile_time (0xaa55))
1070 {
1071 grub_error (GRUB_ERR_BAD_OS, "invalid magic number");
1072 goto fail;
1073 }
1074
1075 if (lh.setup_sects > GRUB_LINUX_MAX_SETUP_SECTS)
1076 {
1077 grub_error (GRUB_ERR_BAD_OS, "too many setup sectors");
1078 goto fail;
1079 }
1080
1081 /* FIXME: 2.03 is not always good enough (Linux 2.4 can be 2.03 and
1082 still not support 32-bit boot. */
1083 if (lh.header != grub_cpu_to_le32_compile_time (GRUB_LINUX_I386_MAGIC_SIGNATURE)
1084 || grub_le_to_cpu16 (lh.version) < 0x0203)
1085 {
1086 grub_error (GRUB_ERR_BAD_OS, "version too old for 32-bit boot"
1087 #ifdef GRUB_MACHINE_PCBIOS
1088 " (try with `linux16')"
1089 #endif
1090 );
1091 goto fail;
1092 }
1093
1094 if (! (lh.loadflags & GRUB_LINUX_FLAG_BIG_KERNEL))
1095 {
1096 grub_error (GRUB_ERR_BAD_OS, "zImage doesn't support 32-bit boot"
1097 #ifdef GRUB_MACHINE_PCBIOS
1098 " (try with `linux16')"
1099 #endif
1100 );
1101 goto fail;
1102 }
1103
1104 if (grub_le_to_cpu16 (lh.version) >= 0x0206)
1105 maximal_cmdline_size = grub_le_to_cpu32 (lh.cmdline_size) + 1;
1106 else
1107 maximal_cmdline_size = 256;
1108
1109 if (maximal_cmdline_size < 128)
1110 maximal_cmdline_size = 128;
1111
1112 setup_sects = lh.setup_sects;
1113
1114 /* If SETUP_SECTS is not set, set it to the default (4). */
1115 if (! setup_sects)
1116 setup_sects = GRUB_LINUX_DEFAULT_SETUP_SECTS;
1117
1118 real_size = setup_sects << GRUB_DISK_SECTOR_BITS;
1119 prot_file_size = grub_file_size (file) - real_size - GRUB_DISK_SECTOR_SIZE;
1120
1121 if (grub_le_to_cpu16 (lh.version) >= 0x205
1122 && lh.kernel_alignment != 0
1123 && ((lh.kernel_alignment - 1) & lh.kernel_alignment) == 0)
1124 {
1125 for (align = 0; align < 32; align++)
1126 if (grub_le_to_cpu32 (lh.kernel_alignment) & (1 << align))
1127 break;
1128 relocatable = grub_le_to_cpu32 (lh.relocatable);
1129 }
1130 else
1131 {
1132 align = 0;
1133 relocatable = 0;
1134 }
1135
1136 if (grub_le_to_cpu16 (lh.version) >= 0x020a)
1137 {
1138 min_align = lh.min_alignment;
1139 prot_size = grub_le_to_cpu32 (lh.init_size);
1140 prot_init_space = page_align (prot_size);
1141 if (relocatable)
1142 preferred_address = grub_le_to_cpu64 (lh.pref_address);
1143 else
1144 preferred_address = GRUB_LINUX_BZIMAGE_ADDR;
1145 }
1146 else
1147 {
1148 min_align = align;
1149 prot_size = prot_file_size;
1150 preferred_address = GRUB_LINUX_BZIMAGE_ADDR;
1151 /* Usually, the compression ratio is about 50%. */
1152 prot_init_space = page_align (prot_size) * 3;
1153 }
1154
1155 if (allocate_pages (prot_size, &align,
1156 min_align, relocatable,
1157 preferred_address))
1158 goto fail;
1159
1160 grub_memset (&linux_params, 0, sizeof (linux_params));
1161 grub_memcpy (&linux_params.setup_sects, &lh.setup_sects, sizeof (lh) - 0x1F1);
1162
1163 linux_params.code32_start = prot_mode_target + lh.code32_start - GRUB_LINUX_BZIMAGE_ADDR;
1164 linux_params.kernel_alignment = (1 << align);
1165 linux_params.ps_mouse = linux_params.padding10 = 0;
1166
1167 /*
1168 * The Linux 32-bit boot protocol defines the setup header end
1169 * to be at 0x202 + the byte value at 0x201.
1170 */
1171 len = 0x202 + *((char *) &linux_params.jump + 1);
1172
1173 /* Verify the struct is big enough so we do not write past the end. */
1174 if (len > (char *) &linux_params.edd_mbr_sig_buffer - (char *) &linux_params) {
1175 grub_error (GRUB_ERR_BAD_OS, "Linux setup header too big");
1176 goto fail;
1177 }
1178
1179 /* We've already read lh so there is no need to read it second time. */
1180 len -= sizeof(lh);
1181
1182 if (grub_file_read (file, (char *) &linux_params + sizeof (lh), len) != len)
1183 {
1184 if (!grub_errno)
1185 grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
1186 argv[0]);
1187 goto fail;
1188 }
1189
1190 linux_params.type_of_loader = GRUB_LINUX_BOOT_LOADER_TYPE;
1191
1192 /* These two are used (instead of cmd_line_ptr) by older versions of Linux,
1193 and otherwise ignored. */
1194 linux_params.cl_magic = GRUB_LINUX_CL_MAGIC;
1195 linux_params.cl_offset = 0x1000;
1196
1197 linux_params.ramdisk_image = 0;
1198 linux_params.ramdisk_size = 0;
1199
1200 linux_params.heap_end_ptr = GRUB_LINUX_HEAP_END_OFFSET;
1201 linux_params.loadflags |= GRUB_LINUX_FLAG_CAN_USE_HEAP;
1202
1203 /* These are not needed to be precise, because Linux uses these values
1204 only to raise an error when the decompression code cannot find good
1205 space. */
1206 linux_params.ext_mem = ((32 * 0x100000) >> 10);
1207 linux_params.alt_mem = ((32 * 0x100000) >> 10);
1208
1209 /* Ignored by Linux. */
1210 linux_params.video_page = 0;
1211
1212 /* Only used when `video_mode == 0x7', otherwise ignored. */
1213 linux_params.video_ega_bx = 0;
1214
1215 linux_params.font_size = 16; /* XXX */
1216
1217 #ifdef GRUB_MACHINE_EFI
1218 #ifdef __x86_64__
1219 if (grub_le_to_cpu16 (linux_params.version) < 0x0208 &&
1220 ((grub_addr_t) grub_efi_system_table >> 32) != 0)
1221 return grub_error(GRUB_ERR_BAD_OS,
1222 "kernel does not support 64-bit addressing");
1223 #endif
1224
1225 if (grub_le_to_cpu16 (linux_params.version) >= 0x0208)
1226 {
1227 linux_params.v0208.efi_signature = GRUB_LINUX_EFI_SIGNATURE;
1228 linux_params.v0208.efi_system_table = (grub_uint32_t) (grub_addr_t) grub_efi_system_table;
1229 #ifdef __x86_64__
1230 linux_params.v0208.efi_system_table_hi = (grub_uint32_t) ((grub_uint64_t) grub_efi_system_table >> 32);
1231 #endif
1232 }
1233 else if (grub_le_to_cpu16 (linux_params.version) >= 0x0206)
1234 {
1235 linux_params.v0206.efi_signature = GRUB_LINUX_EFI_SIGNATURE;
1236 linux_params.v0206.efi_system_table = (grub_uint32_t) (grub_addr_t) grub_efi_system_table;
1237 }
1238 else if (grub_le_to_cpu16 (linux_params.version) >= 0x0204)
1239 {
1240 linux_params.v0204.efi_signature = GRUB_LINUX_EFI_SIGNATURE_0204;
1241 linux_params.v0204.efi_system_table = (grub_uint32_t) (grub_addr_t) grub_efi_system_table;
1242 }
1243 #endif
1244
1245 /* The other parameters are filled when booting. */
1246
1247 grub_file_seek (file, real_size + GRUB_DISK_SECTOR_SIZE);
1248
1249 grub_dprintf ("linux", "bzImage, setup=0x%x, size=0x%x\n",
1250 (unsigned) real_size, (unsigned) prot_size);
1251
1252 /* Look for memory size and video mode specified on the command line. */
1253 linux_mem_size = 0;
1254 for (i = 1; i < argc; i++)
1255 #ifdef GRUB_MACHINE_PCBIOS
1256 if (grub_memcmp (argv[i], "vga=", 4) == 0 && (grub_memcmp (argv[i], "vga=current", 11) != 0))
1257 {
1258 /* Video mode selection support. */
1259 char *val = argv[i] + 4;
1260 unsigned vid_mode = GRUB_LINUX_VID_MODE_NORMAL;
1261 struct grub_vesa_mode_table_entry *linux_mode;
1262 grub_err_t err;
1263 char *buf;
1264
1265 grub_dl_load ("vbe");
1266
1267 if (grub_strcmp (val, "normal") == 0)
1268 vid_mode = GRUB_LINUX_VID_MODE_NORMAL;
1269 else if (grub_strcmp (val, "ext") == 0)
1270 vid_mode = GRUB_LINUX_VID_MODE_EXTENDED;
1271 else if (grub_strcmp (val, "ask") == 0)
1272 {
1273 grub_puts_ (N_("Legacy `ask' parameter no longer supported."));
1274
1275 /* We usually would never do this in a loader, but "vga=ask" means user
1276 requested interaction, so it can't hurt to request keyboard input. */
1277 grub_wait_after_message ();
1278
1279 goto fail;
1280 }
1281 else
1282 vid_mode = (grub_uint16_t) grub_strtoul (val, 0, 0);
1283
1284 switch (vid_mode)
1285 {
1286 case 0:
1287 case GRUB_LINUX_VID_MODE_NORMAL:
1288 grub_env_set ("gfxpayload", "text");
1289 grub_printf_ (N_("%s is deprecated. "
1290 "Use set gfxpayload=%s before "
1291 "linux command instead.\n"),
1292 argv[i], "text");
1293 break;
1294
1295 case 1:
1296 case GRUB_LINUX_VID_MODE_EXTENDED:
1297 /* FIXME: support 80x50 text. */
1298 grub_env_set ("gfxpayload", "text");
1299 grub_printf_ (N_("%s is deprecated. "
1300 "Use set gfxpayload=%s before "
1301 "linux command instead.\n"),
1302 argv[i], "text");
1303 break;
1304 default:
1305 /* Ignore invalid values. */
1306 if (vid_mode < GRUB_VESA_MODE_TABLE_START ||
1307 vid_mode > GRUB_VESA_MODE_TABLE_END)
1308 {
1309 grub_env_set ("gfxpayload", "text");
1310 /* TRANSLATORS: "x" has to be entered in, like an identifier,
1311 so please don't use better Unicode codepoints. */
1312 grub_printf_ (N_("%s is deprecated. VGA mode %d isn't recognized. "
1313 "Use set gfxpayload=WIDTHxHEIGHT[xDEPTH] "
1314 "before linux command instead.\n"),
1315 argv[i], vid_mode);
1316 break;
1317 }
1318
1319 linux_mode = &grub_vesa_mode_table[vid_mode
1320 - GRUB_VESA_MODE_TABLE_START];
1321
1322 buf = grub_xasprintf ("%ux%ux%u,%ux%u",
1323 linux_mode->width, linux_mode->height,
1324 linux_mode->depth,
1325 linux_mode->width, linux_mode->height);
1326 if (! buf)
1327 goto fail;
1328
1329 grub_printf_ (N_("%s is deprecated. "
1330 "Use set gfxpayload=%s before "
1331 "linux command instead.\n"),
1332 argv[i], buf);
1333 err = grub_env_set ("gfxpayload", buf);
1334 grub_free (buf);
1335 if (err)
1336 goto fail;
1337 }
1338 }
1339 else
1340 #endif /* GRUB_MACHINE_PCBIOS */
1341 if (grub_memcmp (argv[i], "mem=", 4) == 0)
1342 {
1343 char *val = argv[i] + 4;
1344
1345 linux_mem_size = grub_strtoul (val, &val, 0);
1346
1347 if (grub_errno)
1348 {
1349 grub_errno = GRUB_ERR_NONE;
1350 linux_mem_size = 0;
1351 }
1352 else
1353 {
1354 int shift = 0;
1355
1356 switch (grub_tolower (val[0]))
1357 {
1358 case 'g':
1359 shift += 10;
1360 /* FALLTHROUGH */
1361 case 'm':
1362 shift += 10;
1363 /* FALLTHROUGH */
1364 case 'k':
1365 shift += 10;
1366 /* FALLTHROUGH */
1367 default:
1368 break;
1369 }
1370
1371 /* Check an overflow. */
1372 if (linux_mem_size > (~0UL >> shift))
1373 linux_mem_size = 0;
1374 else
1375 linux_mem_size <<= shift;
1376 }
1377 }
1378 else if (grub_memcmp (argv[i], "quiet", sizeof ("quiet") - 1) == 0)
1379 {
1380 linux_params.loadflags |= GRUB_LINUX_FLAG_QUIET;
1381 }
1382
1383 /* Create kernel command line. */
1384 linux_cmdline = grub_zalloc (maximal_cmdline_size + 1);
1385 if (!linux_cmdline)
1386 goto fail;
1387 grub_memcpy (linux_cmdline, LINUX_IMAGE, sizeof (LINUX_IMAGE));
1388 {
1389 grub_err_t err;
1390
1391 if (ventoy_linux_argc)
1392 {
1393 ventoy_bootopt_hook(argc, argv);
1394 err = grub_create_loader_cmdline (ventoy_linux_argc, ventoy_linux_args,
1395 linux_cmdline
1396 + sizeof (LINUX_IMAGE) - 1,
1397 maximal_cmdline_size
1398 - (sizeof (LINUX_IMAGE) - 1),
1399 GRUB_VERIFY_KERNEL_CMDLINE);
1400 }
1401 else
1402 {
1403 err = grub_create_loader_cmdline (argc, argv,
1404 linux_cmdline
1405 + sizeof (LINUX_IMAGE) - 1,
1406 maximal_cmdline_size
1407 - (sizeof (LINUX_IMAGE) - 1),
1408 GRUB_VERIFY_KERNEL_CMDLINE);
1409 }
1410
1411 if (err)
1412 goto fail;
1413 }
1414
1415 len = prot_file_size;
1416 if (grub_file_read (file, prot_mode_mem, len) != len && !grub_errno)
1417 grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
1418 argv[0]);
1419
1420 if (grub_errno == GRUB_ERR_NONE)
1421 {
1422 grub_loader_set (grub_linux_boot, grub_linux_unload,
1423 0 /* set noreturn=0 in order to avoid grub_console_fini() */);
1424 loaded = 1;
1425 }
1426
1427 fail:
1428
1429 if (file)
1430 grub_file_close (file);
1431
1432 if (grub_errno != GRUB_ERR_NONE)
1433 {
1434 grub_dl_unref (my_mod);
1435 loaded = 0;
1436 }
1437
1438 return grub_errno;
1439 }
1440
1441 static grub_err_t
1442 grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
1443 int argc, char *argv[])
1444 {
1445 grub_size_t size = 0, aligned_size = 0;
1446 grub_addr_t addr_min, addr_max;
1447 grub_addr_t addr;
1448 grub_err_t err;
1449 struct grub_linux_initrd_context initrd_ctx = { 0, 0, 0 };
1450
1451 if (argc == 0)
1452 {
1453 grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
1454 goto fail;
1455 }
1456
1457 if (! loaded)
1458 {
1459 grub_error (GRUB_ERR_BAD_ARGUMENT, N_("you need to load the kernel first"));
1460 goto fail;
1461 }
1462
1463 if (grub_initrd_init (argc, argv, &initrd_ctx))
1464 goto fail;
1465
1466 size = grub_get_initrd_size (&initrd_ctx);
1467 aligned_size = ALIGN_UP (size, 4096);
1468
1469 /* Get the highest address available for the initrd. */
1470 if (grub_le_to_cpu16 (linux_params.version) >= 0x0203)
1471 {
1472 addr_max = grub_cpu_to_le32 (linux_params.initrd_addr_max);
1473
1474 /* XXX in reality, Linux specifies a bogus value, so
1475 it is necessary to make sure that ADDR_MAX does not exceed
1476 0x3fffffff. */
1477 if (addr_max > GRUB_LINUX_INITRD_MAX_ADDRESS)
1478 addr_max = GRUB_LINUX_INITRD_MAX_ADDRESS;
1479 }
1480 else
1481 addr_max = GRUB_LINUX_INITRD_MAX_ADDRESS;
1482
1483 if (linux_mem_size != 0 && linux_mem_size < addr_max)
1484 addr_max = linux_mem_size;
1485
1486 /* Linux 2.3.xx has a bug in the memory range check, so avoid
1487 the last page.
1488 Linux 2.2.xx has a bug in the memory range check, which is
1489 worse than that of Linux 2.3.xx, so avoid the last 64kb. */
1490 addr_max -= 0x10000;
1491
1492 addr_min = (grub_addr_t) prot_mode_target + prot_init_space;
1493
1494 /* Put the initrd as high as possible, 4KiB aligned. */
1495 addr = (addr_max - aligned_size) & ~0xFFF;
1496
1497 if (addr < addr_min)
1498 {
1499 grub_error (GRUB_ERR_OUT_OF_RANGE, "the initrd is too big");
1500 goto fail;
1501 }
1502
1503 {
1504 grub_relocator_chunk_t ch;
1505 err = grub_relocator_alloc_chunk_align (relocator, &ch,
1506 addr_min, addr, aligned_size,
1507 0x1000,
1508 GRUB_RELOCATOR_PREFERENCE_HIGH,
1509 1);
1510 if (err)
1511 return err;
1512 initrd_mem = get_virtual_current_address (ch);
1513 initrd_mem_target = get_physical_target_address (ch);
1514 }
1515
1516 if (grub_initrd_load (&initrd_ctx, argv, initrd_mem))
1517 goto fail;
1518
1519 grub_dprintf ("linux", "Initrd, addr=0x%x, size=0x%x\n",
1520 (unsigned) addr, (unsigned) size);
1521
1522 linux_params.ramdisk_image = initrd_mem_target;
1523 linux_params.ramdisk_size = size;
1524 linux_params.root_dev = 0x0100; /* XXX */
1525
1526 fail:
1527 grub_initrd_close (&initrd_ctx);
1528
1529 return grub_errno;
1530 }
1531
1532 static grub_err_t
1533 ventoy_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
1534 int argc, char *argv[])
1535 {
1536 int i;
1537 const char *file;
1538 char buf[64];
1539
1540 if (ventoy_debug) grub_printf("ventoy_cmd_initrd %d\n", ventoy_linux_argc);
1541
1542 if (ventoy_linux_argc == 0)
1543 {
1544 return grub_cmd_initrd(cmd, argc, argv);
1545 }
1546
1547 grub_snprintf(buf, sizeof(buf), "mem:%s:size:%s", grub_env_get("ventoy_cpio_addr"), grub_env_get("ventoy_cpio_size"));
1548
1549 if (ventoy_debug) grub_printf("membuf=%s\n", buf);
1550
1551 ventoy_extra_initrd_list[ventoy_extra_initrd_num++] = grub_strdup(buf);
1552
1553 file = grub_env_get("vtoy_img_part_file");
1554 if (file)
1555 {
1556 ventoy_extra_initrd_list[ventoy_extra_initrd_num++] = grub_strdup(file);
1557 }
1558
1559 for (i = 0; i < argc; i++)
1560 {
1561 ventoy_extra_initrd_list[ventoy_extra_initrd_num++] = grub_strdup(argv[i]);
1562 }
1563
1564 ventoy_initrd_called = 1;
1565
1566 if (ventoy_debug)
1567 {
1568 grub_printf("========== initrd list ==========\n");
1569 for (i = 0; i < ventoy_extra_initrd_num; i++)
1570 {
1571 grub_printf("%s\n", ventoy_extra_initrd_list[i]);
1572 }
1573 grub_printf("=================================\n");
1574 }
1575
1576 return grub_cmd_initrd(cmd, ventoy_extra_initrd_num, ventoy_extra_initrd_list);
1577 }
1578
1579
1580 static grub_command_t cmd_linux, cmd_initrd, cmd_linuxefi, cmd_initrdefi;
1581 static grub_command_t cmd_set_bootopt, cmd_unset_bootopt, cmd_extra_initrd_append, cmd_extra_initrd_reset;
1582
1583 GRUB_MOD_INIT(linux)
1584 {
1585 cmd_linux = grub_register_command ("linux", grub_cmd_linux,
1586 0, N_("Load Linux."));
1587 cmd_initrd = grub_register_command ("initrd", ventoy_cmd_initrd,
1588 0, N_("Load initrd."));
1589
1590 cmd_linuxefi = grub_register_command ("linuxefi", grub_cmd_linux,
1591 0, N_("Load Linux."));
1592 cmd_initrdefi = grub_register_command ("initrdefi", ventoy_cmd_initrd,
1593 0, N_("Load initrd."));
1594 cmd_set_bootopt = grub_register_command ("vt_set_boot_opt", grub_cmd_set_boot_opt, 0, N_("set ext boot opt"));
1595 cmd_unset_bootopt = grub_register_command ("vt_unset_boot_opt", grub_cmd_unset_boot_opt, 0, N_("unset ext boot opt"));
1596
1597 cmd_extra_initrd_append = grub_register_command ("vt_img_extra_initrd_append", grub_cmd_extra_initrd_append, 0, N_(""));
1598 cmd_extra_initrd_reset = grub_register_command ("vt_img_extra_initrd_reset", grub_cmd_extra_initrd_reset, 0, N_(""));
1599
1600 ventoy_linux_args = grub_zalloc(sizeof(char *) * LINUX_MAX_ARGC);
1601
1602 my_mod = mod;
1603 }
1604
1605 GRUB_MOD_FINI(linux)
1606 {
1607 grub_unregister_command (cmd_linux);
1608 grub_unregister_command (cmd_initrd);
1609 }