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