]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - GRUB2/MOD_SRC/grub-2.04/grub-core/loader/mips64/linux.c
85ea20e02ef764ecb891eb2f91678c4822331290
[Ventoy.git] / GRUB2 / MOD_SRC / grub-2.04 / grub-core / loader / mips64 / linux.c
1 /* linux.c - boot Linux */
2 /*
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2003,2004,2005,2007,2009,2010,2017 Free Software Foundation, Inc.
5 *
6 * GRUB is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * GRUB is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <grub/efi/api.h>
21 #include <grub/efi/efi.h>
22 #include <grub/elf.h>
23 #include <grub/elfload.h>
24 #include <grub/loader.h>
25 #include <grub/dl.h>
26 #include <grub/mm.h>
27 #include <grub/misc.h>
28 #include <grub/command.h>
29 #include <grub/cpu/relocator.h>
30 #include <grub/machine/loongson.h>
31 #include <grub/memory.h>
32 #include <grub/i18n.h>
33 #include <grub/lib/cmdline.h>
34 #include <grub/linux.h>
35 #include <grub/term.h>
36 #include <grub/env.h>
37
38
39 GRUB_MOD_LICENSE ("GPLv3+");
40
41 #define _ull unsigned long long
42 #pragma GCC diagnostic ignored "-Wcast-align"
43
44 typedef unsigned long size_t;
45
46 static grub_dl_t my_mod;
47
48 static int loaded;
49
50 static grub_uint32_t tmp_index = 0;
51 static grub_size_t linux_size;
52
53 static struct grub_relocator *relocator;
54 static grub_addr_t target_addr, entry_addr;
55 static int linux_argc;
56 static grub_uint8_t *linux_args_addr;
57 static grub_off_t rd_addr_arg_off, rd_size_arg_off;
58 static int initrd_loaded = 0;
59
60
61 static grub_uint32_t j = 0;
62 static grub_uint32_t t = 0;
63 grub_uint64_t tempMemsize = 0;
64 grub_uint32_t free_index = 0;
65 grub_uint32_t reserve_index = 0;
66 grub_uint32_t acpi_table_index = 0;
67 grub_uint32_t acpi_nvs_index = 0;
68
69 #define LINUX_MAX_ARGC 1024
70 static int ventoy_debug = 0;
71 static int ventoy_initrd_called = 0;
72 static int ventoy_linux_argc = 0;
73 static char **ventoy_linux_args = NULL;
74 static int ventoy_extra_initrd_num = 0;
75 static char *ventoy_extra_initrd_list[256];
76 static grub_err_t
77 grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
78 int argc, char *argv[]);
79
80
81
82 static inline grub_size_t
83 page_align (grub_size_t size)
84 {
85 return (size + (1 << 12) - 1) & (~((1 << 12) - 1));
86 }
87
88 /* Find the optimal number of pages for the memory map. Is it better to
89 move this code to efi/mm.c? */
90 static grub_efi_uintn_t
91 find_mmap_size (void)
92 {
93 static grub_efi_uintn_t mmap_size = 0;
94
95 if (mmap_size != 0)
96 return mmap_size;
97
98 mmap_size = (1 << 12);
99 while (1)
100 {
101 int ret;
102 grub_efi_memory_descriptor_t *mmap;
103 grub_efi_uintn_t desc_size;
104
105 mmap = grub_malloc (mmap_size);
106 if (! mmap)
107 return 0;
108
109 ret = grub_efi_get_memory_map (&mmap_size, mmap, 0, &desc_size, 0);
110 grub_free (mmap);
111
112 if (ret < 0)
113 {
114 grub_error (GRUB_ERR_IO, "cannot get memory map");
115 return 0;
116 }
117 else if (ret > 0)
118 break;
119
120 mmap_size += (1 << 12);
121 }
122
123
124 /* Increase the size a bit for safety, because GRUB allocates more on
125 later, and EFI itself may allocate more. */
126 mmap_size += (1 << 12);
127
128 return page_align (mmap_size);
129 }
130
131
132 static void ventoy_debug_pause(void)
133 {
134 char key;
135
136 if (0 == ventoy_debug)
137 {
138 return;
139 }
140
141 grub_printf("press Enter to continue ......\n");
142 while (1)
143 {
144 key = grub_getkey();
145 if (key == '\n' || key == '\r')
146 {
147 break;
148 }
149 }
150 }
151
152 static int ventoy_preboot(void)
153 {
154 int i;
155 const char *file;
156 char buf[128];
157
158 if (ventoy_debug)
159 {
160 grub_printf("ventoy_preboot %d %d\n", ventoy_linux_argc, ventoy_initrd_called);
161 ventoy_debug_pause();
162 }
163
164 if (ventoy_linux_argc == 0)
165 {
166 return 0;
167 }
168
169 if (ventoy_initrd_called)
170 {
171 ventoy_initrd_called = 0;
172 return 0;
173 }
174
175 grub_snprintf(buf, sizeof(buf), "mem:%s:size:%s", grub_env_get("ventoy_cpio_addr"), grub_env_get("ventoy_cpio_size"));
176
177 ventoy_extra_initrd_list[ventoy_extra_initrd_num++] = grub_strdup(buf);
178
179 file = grub_env_get("vtoy_img_part_file");
180 if (file)
181 {
182 ventoy_extra_initrd_list[ventoy_extra_initrd_num++] = grub_strdup(file);
183 }
184
185 if (ventoy_debug)
186 {
187 grub_printf("========== initrd list ==========\n");
188 for (i = 0; i < ventoy_extra_initrd_num; i++)
189 {
190 grub_printf("%s\n", ventoy_extra_initrd_list[i]);
191 }
192 grub_printf("=================================\n");
193
194 ventoy_debug_pause();
195 }
196
197 grub_cmd_initrd(NULL, ventoy_extra_initrd_num, ventoy_extra_initrd_list);
198
199 return 0;
200 }
201
202 static int ventoy_boot_opt_filter(char *opt)
203 {
204 if (grub_strcmp(opt, "noinitrd") == 0)
205 {
206 return 1;
207 }
208
209 if (grub_strcmp(opt, "vga=current") == 0)
210 {
211 return 1;
212 }
213
214 if (grub_strncmp(opt, "rdinit=", 7) == 0)
215 {
216 if (grub_strcmp(opt, "rdinit=/vtoy/vtoy") != 0)
217 {
218 opt[0] = 'v';
219 opt[1] = 't';
220 }
221 return 0;
222 }
223
224 if (grub_strncmp(opt, "init=", 5) == 0)
225 {
226 opt[0] = 'v';
227 opt[1] = 't';
228 return 0;
229 }
230
231 if (ventoy_debug)
232 {
233 if (grub_strcmp(opt, "quiet") == 0)
234 {
235 return 1;
236 }
237
238 if (grub_strncmp(opt, "loglevel=", 9) == 0)
239 {
240 return 1;
241 }
242
243 if (grub_strcmp(opt, "splash") == 0)
244 {
245 return 1;
246 }
247 }
248
249 return 0;
250 }
251
252 static int ventoy_bootopt_hook(int argc, char *argv[])
253 {
254 int i;
255 int count = 0;
256 const char *env;
257 char c;
258 char *newenv;
259 char *last, *pos;
260
261 //grub_printf("ventoy_bootopt_hook: %d %d\n", argc, ventoy_linux_argc);
262
263 if (ventoy_linux_argc == 0)
264 {
265 return 0;
266 }
267
268 /* the 1st parameter is BOOT_IMAGE=xxxx */
269 if (argc > 0 && 0 == ventoy_boot_opt_filter(argv[0]))
270 {
271 ventoy_linux_args[count++] = grub_strdup(argv[0]);
272 }
273
274 for (i = 0; i < ventoy_linux_argc; i++)
275 {
276 ventoy_linux_args[count] = ventoy_linux_args[i + (LINUX_MAX_ARGC / 2)];
277 ventoy_linux_args[i + (LINUX_MAX_ARGC / 2)] = NULL;
278
279 if (ventoy_linux_args[count][0] == '@')
280 {
281 env = grub_env_get(ventoy_linux_args[count] + 1);
282 if (env)
283 {
284 grub_free(ventoy_linux_args[count]);
285
286 newenv = grub_strdup(env);
287 last = newenv;
288
289 while (*last)
290 {
291 while (*last)
292 {
293 if (*last != ' ' && *last != '\t')
294 {
295 break;
296 }
297 last++;
298 }
299
300 if (*last == 0)
301 {
302 break;
303 }
304
305 for (pos = last; *pos; pos++)
306 {
307 if (*pos == ' ' || *pos == '\t')
308 {
309 c = *pos;
310 *pos = 0;
311 if (0 == ventoy_boot_opt_filter(last))
312 {
313 ventoy_linux_args[count++] = grub_strdup(last);
314 }
315 *pos = c;
316 break;
317 }
318 }
319
320 if (*pos == 0)
321 {
322 if (0 == ventoy_boot_opt_filter(last))
323 {
324 ventoy_linux_args[count++] = grub_strdup(last);
325 }
326 break;
327 }
328
329 last = pos + 1;
330 }
331 }
332 else
333 {
334 count++;
335 }
336 }
337 else
338 {
339 count++;
340 }
341 }
342
343 /* We have processed the 1st parameter before, so start from 1 */
344 for (i = 1; i < argc; i++)
345 {
346 if (ventoy_boot_opt_filter(argv[i]))
347 {
348 continue;
349 }
350
351 ventoy_linux_args[count++] = grub_strdup(argv[i]);
352 }
353
354 if (ventoy_debug)
355 {
356 ventoy_linux_args[count++] = grub_strdup("loglevel=7");
357 }
358
359 ventoy_linux_argc = count;
360
361 if (ventoy_debug)
362 {
363 grub_printf("========== bootoption ==========\n");
364 for (i = 0; i < count; i++)
365 {
366 grub_printf("%s ", ventoy_linux_args[i]);
367 }
368 grub_printf("\n================================\n");
369 }
370
371 return 0;
372 }
373
374 static grub_err_t
375 grub_cmd_set_boot_opt (grub_command_t cmd __attribute__ ((unused)),
376 int argc, char *argv[])
377 {
378 int i;
379 const char *vtdebug;
380
381 for (i = 0; i < argc; i++)
382 {
383 ventoy_linux_args[ventoy_linux_argc + (LINUX_MAX_ARGC / 2) ] = grub_strdup(argv[i]);
384 ventoy_linux_argc++;
385 }
386
387 vtdebug = grub_env_get("vtdebug_flag");
388 if (vtdebug && vtdebug[0])
389 {
390 ventoy_debug = 1;
391 }
392
393 if (ventoy_debug) grub_printf("ventoy set boot opt %d\n", ventoy_linux_argc);
394
395 return 0;
396 }
397
398 static grub_err_t
399 grub_cmd_unset_boot_opt (grub_command_t cmd __attribute__ ((unused)),
400 int argc, char *argv[])
401 {
402 int i;
403
404 (void)argc;
405 (void)argv;
406
407 for (i = 0; i < LINUX_MAX_ARGC; i++)
408 {
409 if (ventoy_linux_args[i])
410 {
411 grub_free(ventoy_linux_args[i]);
412 }
413 }
414
415 ventoy_debug = 0;
416 ventoy_linux_argc = 0;
417 ventoy_initrd_called = 0;
418 grub_memset(ventoy_linux_args, 0, sizeof(char *) * LINUX_MAX_ARGC);
419 return 0;
420 }
421
422 static grub_err_t
423 grub_cmd_extra_initrd_append (grub_command_t cmd __attribute__ ((unused)),
424 int argc, char *argv[])
425 {
426 int newclen = 0;
427 char *pos = NULL;
428 char *end = NULL;
429 char buf[256] = {0};
430
431 if (argc != 1)
432 {
433 return 1;
434 }
435
436 for (pos = argv[0]; *pos; pos++)
437 {
438 if (*pos == '/')
439 {
440 end = pos;
441 }
442 }
443
444 if (end)
445 {
446 /* grub2 newc bug workaround */
447 newclen = (int)grub_strlen(end + 1);
448 if ((110 + newclen) % 4 == 0)
449 {
450 grub_snprintf(buf, sizeof(buf), "newc:.%s:%s", end + 1, argv[0]);
451 }
452 else
453 {
454 grub_snprintf(buf, sizeof(buf), "newc:%s:%s", end + 1, argv[0]);
455 }
456
457 if (ventoy_extra_initrd_num < 256)
458 {
459 ventoy_extra_initrd_list[ventoy_extra_initrd_num++] = grub_strdup(buf);
460 }
461 }
462
463 return 0;
464 }
465
466 static grub_err_t
467 grub_cmd_extra_initrd_reset (grub_command_t cmd __attribute__ ((unused)),
468 int argc, char *argv[])
469 {
470 int i;
471
472 (void)argc;
473 (void)argv;
474
475 for (i = 0; i < ventoy_extra_initrd_num; i++)
476 {
477 if (ventoy_extra_initrd_list[i])
478 {
479 grub_free(ventoy_extra_initrd_list[i]);
480 }
481 }
482
483 grub_memset(ventoy_extra_initrd_list, 0, sizeof(ventoy_extra_initrd_list));
484
485 return 0;
486 }
487
488
489 static grub_err_t
490 grub_linux_boot (void)
491 {
492 struct grub_relocator64_state state;
493 grub_int8_t checksum = 0;
494 grub_efi_memory_descriptor_t * lsdesc = NULL;
495
496 ventoy_preboot();
497
498 grub_memset (&state, 0, sizeof (state));
499
500 /* Boot the kernel. */
501 state.gpr[1] = entry_addr;
502 grub_dprintf("loongson", "entry_addr is 0x%llx\n", (_ull)state.gpr[1]);
503 state.gpr[4] = linux_argc;
504 grub_dprintf("loongson", "linux_argc is %lld\n", (_ull)state.gpr[4]);
505 state.gpr[5] = (grub_addr_t) linux_args_addr;
506 grub_dprintf("loongson", "args_addr is 0x%llx\n", (_ull)state.gpr[5]);
507
508 if(grub_efi_is_loongson ())
509 {
510 grub_efi_uintn_t mmap_size;
511 grub_efi_uintn_t desc_size;
512 grub_efi_memory_descriptor_t *mmap_buf;
513 grub_err_t err;
514 struct bootparamsinterface * boot_params;
515 void * tmp_boot_params = NULL;
516 grub_efi_uint8_t new_interface_flag = 0;
517 mem_map * new_interface_mem = NULL;
518 char *p = NULL;
519
520 struct memmap reserve_mem[GRUB_EFI_LOONGSON_MMAP_MAX];
521 struct memmap free_mem[GRUB_EFI_LOONGSON_MMAP_MAX];
522 struct memmap acpi_table_mem[GRUB_EFI_LOONGSON_MMAP_MAX];
523 struct memmap acpi_nvs_mem[GRUB_EFI_LOONGSON_MMAP_MAX];
524
525 grub_memset(reserve_mem, 0, sizeof(struct memmap) * GRUB_EFI_LOONGSON_MMAP_MAX);
526 grub_memset(free_mem, 0, sizeof(struct memmap) * GRUB_EFI_LOONGSON_MMAP_MAX);
527 grub_memset(acpi_table_mem, 0, sizeof(struct memmap) * GRUB_EFI_LOONGSON_MMAP_MAX);
528 grub_memset(acpi_nvs_mem, 0, sizeof(struct memmap) * GRUB_EFI_LOONGSON_MMAP_MAX);
529
530 tmp_boot_params = grub_efi_loongson_get_boot_params();
531 if(tmp_boot_params == NULL)
532 {
533 grub_printf("not find param\n");
534 return -1;
535 }
536
537 boot_params = (struct bootparamsinterface *)tmp_boot_params;
538 p = (char *)&(boot_params->signature);
539 if(grub_strncmp(p, "BPI", 3) == 0)
540 {
541 /* Check extlist headers */
542 ext_list * listpointer = NULL;
543 listpointer = boot_params->extlist;
544 for( ;listpointer != NULL; listpointer = listpointer->next)
545 {
546 char *pl= (char *)&(listpointer->signature);
547 if(grub_strncmp(pl, "MEM", 3) == 0)
548 {
549 new_interface_mem = (mem_map *)listpointer;
550 }
551 }
552
553 new_interface_flag = 1;
554 grub_dprintf("loongson", "get new parameter interface\n");
555 }else{
556 new_interface_flag = 0;
557 grub_dprintf("loongson", "get old parameter interface\n");
558
559 }
560 state.gpr[6] = (grub_uint64_t)tmp_boot_params;
561 grub_dprintf("loongson", "boot_params is 0x%llx\n", (_ull)state.gpr[6]);
562
563 mmap_size = find_mmap_size ();
564 if (! mmap_size)
565 return grub_errno;
566 mmap_buf = grub_efi_allocate_any_pages (page_align (mmap_size) >> 12);
567 if (! mmap_buf)
568 return grub_error (GRUB_ERR_IO, "cannot allocate memory map");
569 err = grub_efi_finish_boot_services (&mmap_size, mmap_buf, NULL,
570 &desc_size, NULL);
571 //grub_printf("%s-%d\n", __func__, __LINE__);
572 if (err)
573 return err;
574
575 if(new_interface_flag)
576 {
577 if (!mmap_buf || !mmap_size || !desc_size)
578 return -1;
579
580 tmp_index = new_interface_mem -> mapcount;
581 //grub_printf("%s-%d mapcount %d\n", __func__, __LINE__, tmp_index);
582
583 /*
584 According to UEFI SPEC,mmap_buf is the accurate Memory Map array \
585 now we can fill platform specific memory structure.
586 */
587 for(lsdesc = mmap_buf; lsdesc < (grub_efi_memory_descriptor_t *)((char *)mmap_buf + mmap_size); lsdesc = (grub_efi_memory_descriptor_t *)((char *)lsdesc + desc_size))
588 {
589 /* Recovery */
590 if((lsdesc->type != GRUB_EFI_ACPI_RECLAIM_MEMORY) && \
591 (lsdesc->type != GRUB_EFI_ACPI_MEMORY_NVS) && \
592 (lsdesc->type != GRUB_EFI_RUNTIME_SERVICES_DATA) && \
593 (lsdesc->type != GRUB_EFI_RUNTIME_SERVICES_CODE) && \
594 (lsdesc->type != GRUB_EFI_RESERVED_MEMORY_TYPE) && \
595 (lsdesc->type != GRUB_EFI_PAL_CODE))
596 {
597
598 free_mem[free_index].memtype = GRUB_EFI_LOONGSON_SYSTEM_RAM_LOW;
599 free_mem[free_index].memstart = (lsdesc->physical_start) & 0xffffffffffff;
600 free_mem[free_index].memsize = lsdesc->num_pages * 4096;
601 free_index++;
602 /*ACPI*/
603 }else if((lsdesc->type == GRUB_EFI_ACPI_RECLAIM_MEMORY)){
604 acpi_table_mem[acpi_table_index].memtype = GRUB_EFI_LOONGSON_ACPI_TABLE;
605 acpi_table_mem[acpi_table_index].memstart = (lsdesc->physical_start) & 0xffffffffffff;
606 acpi_table_mem[acpi_table_index].memsize = lsdesc->num_pages * 4096;
607 acpi_table_index++;
608
609 }else if((lsdesc->type == GRUB_EFI_ACPI_MEMORY_NVS)){
610 acpi_nvs_mem[acpi_nvs_index].memtype = GRUB_EFI_LOONGSON_ACPI_NVS;
611 acpi_nvs_mem[acpi_nvs_index].memstart = (lsdesc->physical_start) & 0xffffffffffff;
612 acpi_nvs_mem[acpi_nvs_index].memsize = lsdesc->num_pages * 4096;
613 acpi_nvs_index++;
614
615 /* Reserve */
616 }else{
617 reserve_mem[reserve_index].memtype = GRUB_EFI_LOONGSON_MEMORY_RESERVED;
618 reserve_mem[reserve_index].memstart = (lsdesc->physical_start) & 0xffffffffffff;
619 reserve_mem[reserve_index].memsize = lsdesc->num_pages * 4096;
620 reserve_index++;
621 }
622 }
623
624 /* Recovery sort */
625 for(j = 0; j < free_index;)
626 {
627 tempMemsize = free_mem[j].memsize;
628 for(t = j + 1; t < free_index; t++)
629 {
630 if((free_mem[j].memstart + tempMemsize == free_mem[t].memstart) && (free_mem[j].memtype == free_mem[t].memtype))
631 {
632 tempMemsize += free_mem[t].memsize;
633 }else{
634 break;
635 }
636 }
637 if(free_mem[j].memstart >= 0x10000000) /*HIGH MEM*/
638 new_interface_mem->map[tmp_index].memtype = GRUB_EFI_LOONGSON_SYSTEM_RAM_HIGH;
639 else
640 new_interface_mem->map[tmp_index].memtype = GRUB_EFI_LOONGSON_SYSTEM_RAM_LOW;
641 new_interface_mem->map[tmp_index].memstart = free_mem[j].memstart;
642 new_interface_mem->map[tmp_index].memsize = tempMemsize;
643 grub_dprintf("loongson", "map[%d]:type %x, start 0x%llx, end 0x%llx\n",
644 tmp_index,
645 new_interface_mem->map[tmp_index].memtype,
646 (_ull)new_interface_mem->map[tmp_index].memstart,
647 (_ull)new_interface_mem->map[tmp_index].memstart+ new_interface_mem->map[tmp_index].memsize
648 );
649 j = t;
650 tmp_index++;
651 }
652
653 /*ACPI Sort*/
654 tmp_index = grub_efi_loongson_memmap_sort(acpi_table_mem, acpi_table_index, new_interface_mem, tmp_index, GRUB_EFI_LOONGSON_ACPI_TABLE);
655 tmp_index = grub_efi_loongson_memmap_sort(acpi_nvs_mem, acpi_nvs_index, new_interface_mem, tmp_index, GRUB_EFI_LOONGSON_ACPI_NVS);
656 /*Reserve Sort*/
657 tmp_index = grub_efi_loongson_memmap_sort(reserve_mem, reserve_index, new_interface_mem, tmp_index, GRUB_EFI_LOONGSON_MEMORY_RESERVED);
658
659 new_interface_mem->mapcount = tmp_index;
660 new_interface_mem->header.checksum = 0;
661 //grub_printf("%s-%d mapcount %d\n", __func__, __LINE__, tmp_index);
662
663 checksum = grub_efi_loongson_grub_calculatechecksum8((grub_uint8_t *)new_interface_mem, new_interface_mem->header.length);
664 new_interface_mem->header.checksum = checksum;
665 }
666 }
667
668 state.jumpreg = 1;
669 grub_relocator64_boot (relocator, state);
670
671 return GRUB_ERR_NONE;
672 }
673
674 static grub_err_t
675 grub_linux_unload (void)
676 {
677 grub_relocator_unload (relocator);
678 grub_dl_unref (my_mod);
679
680 loaded = 0;
681
682 return GRUB_ERR_NONE;
683 }
684
685 static grub_err_t
686 grub_linux_load32 (grub_elf_t elf, const char *filename)
687 {
688 Elf32_Addr base;
689 grub_err_t err;
690 grub_uint8_t *playground;
691
692 /* Linux's entry point incorrectly contains a virtual address. */
693 entry_addr = elf->ehdr.ehdr32.e_entry;
694
695 linux_size = grub_elf32_size (elf, &base, 0);
696 if (linux_size == 0)
697 return grub_errno;
698 target_addr = base;
699 linux_size = ALIGN_UP (base + linux_size - base, 8);
700
701 relocator = grub_relocator_new ();
702 if (!relocator)
703 return grub_errno;
704
705 {
706 grub_relocator_chunk_t ch;
707 err = grub_relocator_alloc_chunk_addr (relocator, &ch,
708 grub_vtop ((void *) target_addr),
709 linux_size);
710 if (err)
711 return err;
712 playground = get_virtual_current_address (ch);
713 }
714
715 /* Now load the segments into the area we claimed. */
716 return grub_elf32_load (elf, filename, playground - base, GRUB_ELF_LOAD_FLAGS_NONE, 0, 0);
717 }
718
719 static grub_err_t
720 grub_linux_load64 (grub_elf_t elf, const char *filename)
721 {
722 Elf64_Addr base;
723 grub_err_t err;
724 grub_uint8_t *playground;
725
726 /* Linux's entry point incorrectly contains a virtual address. */
727 entry_addr = elf->ehdr.ehdr64.e_entry;
728 grub_dprintf("loongson", "entry address = 0x%llx\n", (_ull)entry_addr);
729
730 linux_size = grub_elf64_size (elf, &base, 0);
731 grub_dprintf("loongson", "base = 0x%llx\n", (_ull)base);
732
733 if (linux_size == 0)
734 return grub_errno;
735 target_addr = base;
736 linux_size = ALIGN_UP (base + linux_size - base, 8);
737
738 relocator = grub_relocator_new ();
739 if (!relocator)
740 return grub_errno;
741
742 {
743 grub_relocator_chunk_t ch;
744 err = grub_relocator_alloc_chunk_addr (relocator, &ch,
745 grub_vtop ((void *) target_addr),
746 linux_size);
747 if (err)
748 return err;
749 playground = get_virtual_current_address (ch);
750 //playground = 0xffffffff81ee0000; //½«ÄÚºËÖ±½Óloadµ½elfÍ·Ö¸¶¨Äڴ棬¶ø·Çgrub·ÖÅäµÄ¿Õ¼ä
751 //playground = 0xffffffff80200000;
752 }
753
754 grub_printf("playground:0x%llx\n", (_ull)playground);
755
756 /* Now load the segments into the area we claimed. */
757 return grub_elf64_load (elf, filename, playground - base, GRUB_ELF_LOAD_FLAGS_NONE, 0, 0);
758 }
759
760 static grub_err_t
761 grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
762 int argc, char *argv[])
763 {
764 grub_elf_t elf = 0;
765 int size;
766 int i;
767 grub_uint32_t *linux_argv;
768 char *linux_args;
769 grub_err_t err;
770
771 if (argc == 0)
772 return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
773
774 if (ventoy_linux_argc)
775 {
776 ventoy_bootopt_hook(argc, argv);
777 argc = ventoy_linux_argc;
778 argv = ventoy_linux_args;
779 }
780
781 elf = grub_elf_open (argv[0], GRUB_FILE_TYPE_LINUX_KERNEL);
782 if (! elf)
783 return grub_errno;
784
785 if (elf->ehdr.ehdr32.e_type != ET_EXEC)
786 {
787 grub_elf_close (elf);
788 return grub_error (GRUB_ERR_UNKNOWN_OS,
789 N_("this ELF file is not of the right type"));
790 }
791
792 /* Release the previously used memory. */
793 grub_loader_unset ();
794 loaded = 0;
795
796 /* For arguments. */
797 linux_argc = argc;
798 /* Main arguments. */
799 size = (linux_argc) * sizeof (grub_uint32_t);
800 /* Initrd address and size. */
801 size += 2 * sizeof (grub_uint32_t);
802 /* NULL terminator. */
803 size += sizeof (grub_uint32_t);
804 /* First argument is always "a0". */
805 size += ALIGN_UP (sizeof ("a0"), 4);
806 /* Normal arguments. */
807 for (i = 1; i < argc; i++)
808 size += ALIGN_UP (grub_strlen (argv[i]) + 1, 4);
809
810 /* rd arguments. */
811 size += ALIGN_UP (sizeof ("rd_start=0xXXXXXXXXXXXXXXXX"), 4);
812 size += ALIGN_UP (sizeof ("rd_size=0xXXXXXXXXXXXXXXXX"), 4);
813
814 size = ALIGN_UP (size, 8);
815
816 if (grub_elf_is_elf32 (elf))
817 err = grub_linux_load32 (elf, argv[0]);
818 else
819 if (grub_elf_is_elf64 (elf))
820 err = grub_linux_load64 (elf, argv[0]);
821 else
822 err = grub_error (GRUB_ERR_BAD_OS, N_("invalid arch-dependent ELF magic"));
823
824 grub_elf_close (elf);
825
826 if (err)
827 return err;
828
829 {
830 grub_relocator_chunk_t ch;
831 err = grub_relocator_alloc_chunk_align (relocator, &ch,
832 0, (0xffffffff - size) + 1,
833 size, 8,
834 GRUB_RELOCATOR_PREFERENCE_HIGH, 0);
835 if (err)
836 return err;
837 linux_args_addr = get_virtual_current_address (ch);
838 }
839
840 linux_argv = (grub_uint32_t *) linux_args_addr;
841 linux_args = (char *) (linux_argv + (linux_argc + 1 + 2));
842
843 grub_memcpy (linux_args, "a0", sizeof ("a0"));
844 *linux_argv = (grub_uint32_t) (grub_addr_t) linux_args;
845 linux_argv++;
846 linux_args += ALIGN_UP (sizeof ("a0"), 4);
847
848 for (i = 1; i < argc; i++)
849 {
850 grub_memcpy (linux_args, argv[i], grub_strlen (argv[i]) + 1);
851 *linux_argv = (grub_uint32_t) (grub_addr_t) linux_args;
852 linux_argv++;
853 linux_args += ALIGN_UP (grub_strlen (argv[i]) + 1, 4);
854 }
855
856 /* Reserve space for rd arguments. */
857 rd_addr_arg_off = (grub_uint8_t *) linux_args - linux_args_addr;
858 linux_args += ALIGN_UP (sizeof ("rd_start=0xXXXXXXXXXXXXXXXX"), 4);
859 *linux_argv = 0;
860 linux_argv++;
861
862 rd_size_arg_off = (grub_uint8_t *) linux_args - linux_args_addr;
863 linux_args += ALIGN_UP (sizeof ("rd_size=0xXXXXXXXXXXXXXXXX"), 4);
864 *linux_argv = 0;
865 linux_argv++;
866
867 *linux_argv = 0;
868
869 //wake up other cores
870 {
871 __asm__(
872 "dli $8, 0x900000003ff01000\n\t"
873 "dli $11, 0 \n\t"
874 "dsll $11, 8 \n\t"
875 "or $8, $8,$11 \n\t"
876 "li $9, 0x5a5a \n\t"
877 "sw $9, 32($8) \n\t"
878 "nop \n\t"
879 :
880 :
881 );
882 }
883 grub_loader_set (grub_linux_boot, grub_linux_unload, 0);
884 initrd_loaded = 0;
885 loaded = 1;
886 grub_dl_ref (my_mod);
887
888 return GRUB_ERR_NONE;
889 }
890
891 static grub_err_t
892 grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
893 int argc, char *argv[])
894 {
895 grub_size_t size = 0;
896 void *initrd_dest;
897 grub_err_t err;
898 struct grub_linux_initrd_context initrd_ctx = { 0, 0, 0 };
899
900 if (argc == 0)
901 return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
902
903 if (!loaded)
904 return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("you need to load the kernel first"));
905
906 if (initrd_loaded)
907 return grub_error (GRUB_ERR_BAD_ARGUMENT, "only one initrd command can be issued.");
908
909 if (grub_initrd_init (argc, argv, &initrd_ctx))
910 goto fail;
911
912 size = grub_get_initrd_size (&initrd_ctx);
913
914 {
915 grub_relocator_chunk_t ch;
916 err = grub_relocator_alloc_chunk_align (relocator, &ch,
917 0, (0xffffffff - size) + 1,
918 size, 0x10000,
919 GRUB_RELOCATOR_PREFERENCE_HIGH, 0);
920
921 if (err)
922 goto fail;
923 initrd_dest = get_virtual_current_address (ch);
924 }
925
926 if (grub_initrd_load (&initrd_ctx, argv, initrd_dest))
927 goto fail;
928
929 grub_snprintf ((char *) linux_args_addr + rd_addr_arg_off,
930 sizeof ("rd_start=0xXXXXXXXXXXXXXXXX"), "rd_start=0x%lx",
931 (grub_uint64_t) initrd_dest);
932 ((grub_uint32_t *) linux_args_addr)[linux_argc]
933 = (grub_uint32_t) ((grub_addr_t) linux_args_addr + rd_addr_arg_off);
934 linux_argc++;
935
936 grub_snprintf ((char *) linux_args_addr + rd_size_arg_off,
937 sizeof ("rd_size=0xXXXXXXXXXXXXXXXXX"), "rd_size=0x%lx",
938 (grub_uint64_t) size);
939 ((grub_uint32_t *) linux_args_addr)[linux_argc]
940 = (grub_uint32_t) ((grub_addr_t) linux_args_addr + rd_size_arg_off);
941 linux_argc++;
942
943 initrd_loaded = 1;
944
945 fail:
946 grub_initrd_close (&initrd_ctx);
947
948 return grub_errno;
949 }
950
951 static grub_err_t
952 ventoy_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
953 int argc, char *argv[])
954 {
955 int i;
956 const char *file;
957 char buf[64];
958
959 if (ventoy_debug) grub_printf("ventoy_cmd_initrd %d\n", ventoy_linux_argc);
960
961 if (ventoy_linux_argc == 0)
962 {
963 return grub_cmd_initrd(cmd, argc, argv);
964 }
965
966 grub_snprintf(buf, sizeof(buf), "mem:%s:size:%s", grub_env_get("ventoy_cpio_addr"), grub_env_get("ventoy_cpio_size"));
967
968 if (ventoy_debug) grub_printf("membuf=%s\n", buf);
969
970 ventoy_extra_initrd_list[ventoy_extra_initrd_num++] = grub_strdup(buf);
971
972 file = grub_env_get("vtoy_img_part_file");
973 if (file)
974 {
975 ventoy_extra_initrd_list[ventoy_extra_initrd_num++] = grub_strdup(file);
976 }
977
978 for (i = 0; i < argc; i++)
979 {
980 ventoy_extra_initrd_list[ventoy_extra_initrd_num++] = grub_strdup(argv[i]);
981 }
982
983 ventoy_initrd_called = 1;
984
985 if (ventoy_debug)
986 {
987 grub_printf("========== initrd list ==========\n");
988 for (i = 0; i < ventoy_extra_initrd_num; i++)
989 {
990 grub_printf("%s\n", ventoy_extra_initrd_list[i]);
991 }
992 grub_printf("=================================\n");
993 }
994
995 return grub_cmd_initrd(cmd, ventoy_extra_initrd_num, ventoy_extra_initrd_list);
996 }
997
998 static grub_command_t cmd_linux, cmd_initrd;
999 static grub_command_t cmd_set_bootopt, cmd_unset_bootopt, cmd_extra_initrd_append, cmd_extra_initrd_reset;
1000
1001 GRUB_MOD_INIT(linux)
1002 {
1003 cmd_linux = grub_register_command ("linux", grub_cmd_linux,
1004 0, N_("Load Linux."));
1005 cmd_initrd = grub_register_command ("initrd", ventoy_cmd_initrd,
1006 0, N_("Load initrd."));
1007
1008 cmd_set_bootopt = grub_register_command ("vt_set_boot_opt", grub_cmd_set_boot_opt, 0, N_("set ext boot opt"));
1009 cmd_unset_bootopt = grub_register_command ("vt_unset_boot_opt", grub_cmd_unset_boot_opt, 0, N_("unset ext boot opt"));
1010
1011 cmd_extra_initrd_append = grub_register_command ("vt_img_extra_initrd_append", grub_cmd_extra_initrd_append, 0, N_(""));
1012 cmd_extra_initrd_reset = grub_register_command ("vt_img_extra_initrd_reset", grub_cmd_extra_initrd_reset, 0, N_(""));
1013
1014 ventoy_linux_args = grub_zalloc(sizeof(char *) * LINUX_MAX_ARGC);
1015
1016 my_mod = mod;
1017 }
1018
1019 GRUB_MOD_FINI(linux)
1020 {
1021 grub_unregister_command (cmd_linux);
1022 grub_unregister_command (cmd_initrd);
1023 }