]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - GRUB2/MOD_SRC/grub-2.04/grub-core/loader/mips64/linux.c
2822187d4029ebca704462a2cb9fdeb9541a474b
[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 TmpIdx;
256 int count = 0;
257 const char *env;
258 char c;
259 char *newenv;
260 char *last, *pos;
261
262 //grub_printf("ventoy_bootopt_hook: %d %d\n", argc, ventoy_linux_argc);
263
264 if (ventoy_linux_argc == 0)
265 {
266 return 0;
267 }
268
269 /* To avoid --- parameter, we split two parts */
270 for (TmpIdx = 0; TmpIdx < argc; TmpIdx++)
271 {
272 if (ventoy_boot_opt_filter(argv[TmpIdx]))
273 {
274 continue;
275 }
276
277 if (grub_strncmp(argv[TmpIdx], "--", 2) == 0)
278 {
279 break;
280 }
281
282 ventoy_linux_args[count++] = grub_strdup(argv[TmpIdx]);
283 }
284
285 for (i = 0; i < ventoy_linux_argc; i++)
286 {
287 ventoy_linux_args[count] = ventoy_linux_args[i + (LINUX_MAX_ARGC / 2)];
288 ventoy_linux_args[i + (LINUX_MAX_ARGC / 2)] = NULL;
289
290 if (ventoy_linux_args[count][0] == '@')
291 {
292 env = grub_env_get(ventoy_linux_args[count] + 1);
293 if (env)
294 {
295 grub_free(ventoy_linux_args[count]);
296
297 newenv = grub_strdup(env);
298 last = newenv;
299
300 while (*last)
301 {
302 while (*last)
303 {
304 if (*last != ' ' && *last != '\t')
305 {
306 break;
307 }
308 last++;
309 }
310
311 if (*last == 0)
312 {
313 break;
314 }
315
316 for (pos = last; *pos; pos++)
317 {
318 if (*pos == ' ' || *pos == '\t')
319 {
320 c = *pos;
321 *pos = 0;
322 if (0 == ventoy_boot_opt_filter(last))
323 {
324 ventoy_linux_args[count++] = grub_strdup(last);
325 }
326 *pos = c;
327 break;
328 }
329 }
330
331 if (*pos == 0)
332 {
333 if (0 == ventoy_boot_opt_filter(last))
334 {
335 ventoy_linux_args[count++] = grub_strdup(last);
336 }
337 break;
338 }
339
340 last = pos + 1;
341 }
342 }
343 else
344 {
345 count++;
346 }
347 }
348 else
349 {
350 count++;
351 }
352 }
353
354 while (TmpIdx < argc)
355 {
356 if (ventoy_boot_opt_filter(argv[TmpIdx]))
357 {
358 continue;
359 }
360
361 ventoy_linux_args[count++] = grub_strdup(argv[TmpIdx]);
362 TmpIdx++;
363 }
364
365 if (ventoy_debug)
366 {
367 ventoy_linux_args[count++] = grub_strdup("loglevel=7");
368 }
369
370 ventoy_linux_argc = count;
371
372 if (ventoy_debug)
373 {
374 grub_printf("========== bootoption ==========\n");
375 for (i = 0; i < count; i++)
376 {
377 grub_printf("%s ", ventoy_linux_args[i]);
378 }
379 grub_printf("\n================================\n");
380 }
381
382 return 0;
383 }
384
385 static grub_err_t
386 grub_cmd_set_boot_opt (grub_command_t cmd __attribute__ ((unused)),
387 int argc, char *argv[])
388 {
389 int i;
390 const char *vtdebug;
391
392 for (i = 0; i < argc; i++)
393 {
394 ventoy_linux_args[ventoy_linux_argc + (LINUX_MAX_ARGC / 2) ] = grub_strdup(argv[i]);
395 ventoy_linux_argc++;
396 }
397
398 vtdebug = grub_env_get("vtdebug_flag");
399 if (vtdebug && vtdebug[0])
400 {
401 ventoy_debug = 1;
402 }
403
404 if (ventoy_debug) grub_printf("ventoy set boot opt %d\n", ventoy_linux_argc);
405
406 return 0;
407 }
408
409 static grub_err_t
410 grub_cmd_unset_boot_opt (grub_command_t cmd __attribute__ ((unused)),
411 int argc, char *argv[])
412 {
413 int i;
414
415 (void)argc;
416 (void)argv;
417
418 for (i = 0; i < LINUX_MAX_ARGC; i++)
419 {
420 if (ventoy_linux_args[i])
421 {
422 grub_free(ventoy_linux_args[i]);
423 }
424 }
425
426 ventoy_debug = 0;
427 ventoy_linux_argc = 0;
428 ventoy_initrd_called = 0;
429 grub_memset(ventoy_linux_args, 0, sizeof(char *) * LINUX_MAX_ARGC);
430 return 0;
431 }
432
433 static grub_err_t
434 grub_cmd_extra_initrd_append (grub_command_t cmd __attribute__ ((unused)),
435 int argc, char *argv[])
436 {
437 int newclen = 0;
438 char *pos = NULL;
439 char *end = NULL;
440 char buf[256] = {0};
441
442 if (argc != 1)
443 {
444 return 1;
445 }
446
447 for (pos = argv[0]; *pos; pos++)
448 {
449 if (*pos == '/')
450 {
451 end = pos;
452 }
453 }
454
455 if (end)
456 {
457 /* grub2 newc bug workaround */
458 newclen = (int)grub_strlen(end + 1);
459 if ((110 + newclen) % 4 == 0)
460 {
461 grub_snprintf(buf, sizeof(buf), "newc:.%s:%s", end + 1, argv[0]);
462 }
463 else
464 {
465 grub_snprintf(buf, sizeof(buf), "newc:%s:%s", end + 1, argv[0]);
466 }
467
468 if (ventoy_extra_initrd_num < 256)
469 {
470 ventoy_extra_initrd_list[ventoy_extra_initrd_num++] = grub_strdup(buf);
471 }
472 }
473
474 return 0;
475 }
476
477 static grub_err_t
478 grub_cmd_extra_initrd_reset (grub_command_t cmd __attribute__ ((unused)),
479 int argc, char *argv[])
480 {
481 int i;
482
483 (void)argc;
484 (void)argv;
485
486 for (i = 0; i < ventoy_extra_initrd_num; i++)
487 {
488 if (ventoy_extra_initrd_list[i])
489 {
490 grub_free(ventoy_extra_initrd_list[i]);
491 }
492 }
493
494 grub_memset(ventoy_extra_initrd_list, 0, sizeof(ventoy_extra_initrd_list));
495
496 return 0;
497 }
498
499
500 static grub_err_t
501 grub_linux_boot (void)
502 {
503 struct grub_relocator64_state state;
504 grub_int8_t checksum = 0;
505 grub_efi_memory_descriptor_t * lsdesc = NULL;
506
507 ventoy_preboot();
508
509 grub_memset (&state, 0, sizeof (state));
510
511 /* Boot the kernel. */
512 state.gpr[1] = entry_addr;
513 grub_dprintf("loongson", "entry_addr is 0x%llx\n", (_ull)state.gpr[1]);
514 state.gpr[4] = linux_argc;
515 grub_dprintf("loongson", "linux_argc is %lld\n", (_ull)state.gpr[4]);
516 state.gpr[5] = (grub_addr_t) linux_args_addr;
517 grub_dprintf("loongson", "args_addr is 0x%llx\n", (_ull)state.gpr[5]);
518
519 if(grub_efi_is_loongson ())
520 {
521 grub_efi_uintn_t mmap_size;
522 grub_efi_uintn_t desc_size;
523 grub_efi_memory_descriptor_t *mmap_buf;
524 grub_err_t err;
525 struct bootparamsinterface * boot_params;
526 void * tmp_boot_params = NULL;
527 grub_efi_uint8_t new_interface_flag = 0;
528 mem_map * new_interface_mem = NULL;
529 char *p = NULL;
530
531 struct memmap reserve_mem[GRUB_EFI_LOONGSON_MMAP_MAX];
532 struct memmap free_mem[GRUB_EFI_LOONGSON_MMAP_MAX];
533 struct memmap acpi_table_mem[GRUB_EFI_LOONGSON_MMAP_MAX];
534 struct memmap acpi_nvs_mem[GRUB_EFI_LOONGSON_MMAP_MAX];
535
536 grub_memset(reserve_mem, 0, sizeof(struct memmap) * GRUB_EFI_LOONGSON_MMAP_MAX);
537 grub_memset(free_mem, 0, sizeof(struct memmap) * GRUB_EFI_LOONGSON_MMAP_MAX);
538 grub_memset(acpi_table_mem, 0, sizeof(struct memmap) * GRUB_EFI_LOONGSON_MMAP_MAX);
539 grub_memset(acpi_nvs_mem, 0, sizeof(struct memmap) * GRUB_EFI_LOONGSON_MMAP_MAX);
540
541 tmp_boot_params = grub_efi_loongson_get_boot_params();
542 if(tmp_boot_params == NULL)
543 {
544 grub_printf("not find param\n");
545 return -1;
546 }
547
548 boot_params = (struct bootparamsinterface *)tmp_boot_params;
549 p = (char *)&(boot_params->signature);
550 if(grub_strncmp(p, "BPI", 3) == 0)
551 {
552 /* Check extlist headers */
553 ext_list * listpointer = NULL;
554 listpointer = boot_params->extlist;
555 for( ;listpointer != NULL; listpointer = listpointer->next)
556 {
557 char *pl= (char *)&(listpointer->signature);
558 if(grub_strncmp(pl, "MEM", 3) == 0)
559 {
560 new_interface_mem = (mem_map *)listpointer;
561 }
562 }
563
564 new_interface_flag = 1;
565 grub_dprintf("loongson", "get new parameter interface\n");
566 }else{
567 new_interface_flag = 0;
568 grub_dprintf("loongson", "get old parameter interface\n");
569
570 }
571 state.gpr[6] = (grub_uint64_t)tmp_boot_params;
572 grub_dprintf("loongson", "boot_params is 0x%llx\n", (_ull)state.gpr[6]);
573
574 mmap_size = find_mmap_size ();
575 if (! mmap_size)
576 return grub_errno;
577 mmap_buf = grub_efi_allocate_any_pages (page_align (mmap_size) >> 12);
578 if (! mmap_buf)
579 return grub_error (GRUB_ERR_IO, "cannot allocate memory map");
580 err = grub_efi_finish_boot_services (&mmap_size, mmap_buf, NULL,
581 &desc_size, NULL);
582 //grub_printf("%s-%d\n", __func__, __LINE__);
583 if (err)
584 return err;
585
586 if(new_interface_flag)
587 {
588 if (!mmap_buf || !mmap_size || !desc_size)
589 return -1;
590
591 tmp_index = new_interface_mem -> mapcount;
592 //grub_printf("%s-%d mapcount %d\n", __func__, __LINE__, tmp_index);
593
594 /*
595 According to UEFI SPEC,mmap_buf is the accurate Memory Map array \
596 now we can fill platform specific memory structure.
597 */
598 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))
599 {
600 /* Recovery */
601 if((lsdesc->type != GRUB_EFI_ACPI_RECLAIM_MEMORY) && \
602 (lsdesc->type != GRUB_EFI_ACPI_MEMORY_NVS) && \
603 (lsdesc->type != GRUB_EFI_RUNTIME_SERVICES_DATA) && \
604 (lsdesc->type != GRUB_EFI_RUNTIME_SERVICES_CODE) && \
605 (lsdesc->type != GRUB_EFI_RESERVED_MEMORY_TYPE) && \
606 (lsdesc->type != GRUB_EFI_PAL_CODE))
607 {
608
609 free_mem[free_index].memtype = GRUB_EFI_LOONGSON_SYSTEM_RAM_LOW;
610 free_mem[free_index].memstart = (lsdesc->physical_start) & 0xffffffffffff;
611 free_mem[free_index].memsize = lsdesc->num_pages * 4096;
612 free_index++;
613 /*ACPI*/
614 }else if((lsdesc->type == GRUB_EFI_ACPI_RECLAIM_MEMORY)){
615 acpi_table_mem[acpi_table_index].memtype = GRUB_EFI_LOONGSON_ACPI_TABLE;
616 acpi_table_mem[acpi_table_index].memstart = (lsdesc->physical_start) & 0xffffffffffff;
617 acpi_table_mem[acpi_table_index].memsize = lsdesc->num_pages * 4096;
618 acpi_table_index++;
619
620 }else if((lsdesc->type == GRUB_EFI_ACPI_MEMORY_NVS)){
621 acpi_nvs_mem[acpi_nvs_index].memtype = GRUB_EFI_LOONGSON_ACPI_NVS;
622 acpi_nvs_mem[acpi_nvs_index].memstart = (lsdesc->physical_start) & 0xffffffffffff;
623 acpi_nvs_mem[acpi_nvs_index].memsize = lsdesc->num_pages * 4096;
624 acpi_nvs_index++;
625
626 /* Reserve */
627 }else{
628 reserve_mem[reserve_index].memtype = GRUB_EFI_LOONGSON_MEMORY_RESERVED;
629 reserve_mem[reserve_index].memstart = (lsdesc->physical_start) & 0xffffffffffff;
630 reserve_mem[reserve_index].memsize = lsdesc->num_pages * 4096;
631 reserve_index++;
632 }
633 }
634
635 /* Recovery sort */
636 for(j = 0; j < free_index;)
637 {
638 tempMemsize = free_mem[j].memsize;
639 for(t = j + 1; t < free_index; t++)
640 {
641 if((free_mem[j].memstart + tempMemsize == free_mem[t].memstart) && (free_mem[j].memtype == free_mem[t].memtype))
642 {
643 tempMemsize += free_mem[t].memsize;
644 }else{
645 break;
646 }
647 }
648 if(free_mem[j].memstart >= 0x10000000) /*HIGH MEM*/
649 new_interface_mem->map[tmp_index].memtype = GRUB_EFI_LOONGSON_SYSTEM_RAM_HIGH;
650 else
651 new_interface_mem->map[tmp_index].memtype = GRUB_EFI_LOONGSON_SYSTEM_RAM_LOW;
652 new_interface_mem->map[tmp_index].memstart = free_mem[j].memstart;
653 new_interface_mem->map[tmp_index].memsize = tempMemsize;
654 grub_dprintf("loongson", "map[%d]:type %x, start 0x%llx, end 0x%llx\n",
655 tmp_index,
656 new_interface_mem->map[tmp_index].memtype,
657 (_ull)new_interface_mem->map[tmp_index].memstart,
658 (_ull)new_interface_mem->map[tmp_index].memstart+ new_interface_mem->map[tmp_index].memsize
659 );
660 j = t;
661 tmp_index++;
662 }
663
664 /*ACPI Sort*/
665 tmp_index = grub_efi_loongson_memmap_sort(acpi_table_mem, acpi_table_index, new_interface_mem, tmp_index, GRUB_EFI_LOONGSON_ACPI_TABLE);
666 tmp_index = grub_efi_loongson_memmap_sort(acpi_nvs_mem, acpi_nvs_index, new_interface_mem, tmp_index, GRUB_EFI_LOONGSON_ACPI_NVS);
667 /*Reserve Sort*/
668 tmp_index = grub_efi_loongson_memmap_sort(reserve_mem, reserve_index, new_interface_mem, tmp_index, GRUB_EFI_LOONGSON_MEMORY_RESERVED);
669
670 new_interface_mem->mapcount = tmp_index;
671 new_interface_mem->header.checksum = 0;
672 //grub_printf("%s-%d mapcount %d\n", __func__, __LINE__, tmp_index);
673
674 checksum = grub_efi_loongson_grub_calculatechecksum8((grub_uint8_t *)new_interface_mem, new_interface_mem->header.length);
675 new_interface_mem->header.checksum = checksum;
676 }
677 }
678
679 state.jumpreg = 1;
680 grub_relocator64_boot (relocator, state);
681
682 return GRUB_ERR_NONE;
683 }
684
685 static grub_err_t
686 grub_linux_unload (void)
687 {
688 grub_relocator_unload (relocator);
689 grub_dl_unref (my_mod);
690
691 loaded = 0;
692
693 return GRUB_ERR_NONE;
694 }
695
696 static grub_err_t
697 grub_linux_load32 (grub_elf_t elf, const char *filename)
698 {
699 Elf32_Addr base;
700 grub_err_t err;
701 grub_uint8_t *playground;
702
703 /* Linux's entry point incorrectly contains a virtual address. */
704 entry_addr = elf->ehdr.ehdr32.e_entry;
705
706 linux_size = grub_elf32_size (elf, &base, 0);
707 if (linux_size == 0)
708 return grub_errno;
709 target_addr = base;
710 linux_size = ALIGN_UP (base + linux_size - base, 8);
711
712 relocator = grub_relocator_new ();
713 if (!relocator)
714 return grub_errno;
715
716 {
717 grub_relocator_chunk_t ch;
718 err = grub_relocator_alloc_chunk_addr (relocator, &ch,
719 grub_vtop ((void *) target_addr),
720 linux_size);
721 if (err)
722 return err;
723 playground = get_virtual_current_address (ch);
724 }
725
726 /* Now load the segments into the area we claimed. */
727 return grub_elf32_load (elf, filename, playground - base, GRUB_ELF_LOAD_FLAGS_NONE, 0, 0);
728 }
729
730 static grub_err_t
731 grub_linux_load64 (grub_elf_t elf, const char *filename)
732 {
733 Elf64_Addr base;
734 grub_err_t err;
735 grub_uint8_t *playground;
736
737 /* Linux's entry point incorrectly contains a virtual address. */
738 entry_addr = elf->ehdr.ehdr64.e_entry;
739 grub_dprintf("loongson", "entry address = 0x%llx\n", (_ull)entry_addr);
740
741 linux_size = grub_elf64_size (elf, &base, 0);
742 grub_dprintf("loongson", "base = 0x%llx\n", (_ull)base);
743
744 if (linux_size == 0)
745 return grub_errno;
746 target_addr = base;
747 linux_size = ALIGN_UP (base + linux_size - base, 8);
748
749 relocator = grub_relocator_new ();
750 if (!relocator)
751 return grub_errno;
752
753 {
754 grub_relocator_chunk_t ch;
755 err = grub_relocator_alloc_chunk_addr (relocator, &ch,
756 grub_vtop ((void *) target_addr),
757 linux_size);
758 if (err)
759 return err;
760 playground = get_virtual_current_address (ch);
761 //playground = 0xffffffff81ee0000; //½«ÄÚºËÖ±½Óloadµ½elfÍ·Ö¸¶¨Äڴ棬¶ø·Çgrub·ÖÅäµÄ¿Õ¼ä
762 //playground = 0xffffffff80200000;
763 }
764
765 grub_printf("playground:0x%llx\n", (_ull)playground);
766
767 /* Now load the segments into the area we claimed. */
768 return grub_elf64_load (elf, filename, playground - base, GRUB_ELF_LOAD_FLAGS_NONE, 0, 0);
769 }
770
771 static grub_err_t
772 grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
773 int argc, char *argv[])
774 {
775 grub_elf_t elf = 0;
776 int size;
777 int i;
778 grub_uint32_t *linux_argv;
779 char *linux_args;
780 grub_err_t err;
781
782 if (argc == 0)
783 return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
784
785 if (ventoy_linux_argc)
786 {
787 ventoy_bootopt_hook(argc, argv);
788 argc = ventoy_linux_argc;
789 argv = ventoy_linux_args;
790 }
791
792 elf = grub_elf_open (argv[0], GRUB_FILE_TYPE_LINUX_KERNEL);
793 if (! elf)
794 return grub_errno;
795
796 if (elf->ehdr.ehdr32.e_type != ET_EXEC)
797 {
798 grub_elf_close (elf);
799 return grub_error (GRUB_ERR_UNKNOWN_OS,
800 N_("this ELF file is not of the right type"));
801 }
802
803 /* Release the previously used memory. */
804 grub_loader_unset ();
805 loaded = 0;
806
807 /* For arguments. */
808 linux_argc = argc;
809 /* Main arguments. */
810 size = (linux_argc) * sizeof (grub_uint32_t);
811 /* Initrd address and size. */
812 size += 2 * sizeof (grub_uint32_t);
813 /* NULL terminator. */
814 size += sizeof (grub_uint32_t);
815 /* First argument is always "a0". */
816 size += ALIGN_UP (sizeof ("a0"), 4);
817 /* Normal arguments. */
818 for (i = 1; i < argc; i++)
819 size += ALIGN_UP (grub_strlen (argv[i]) + 1, 4);
820
821 /* rd arguments. */
822 size += ALIGN_UP (sizeof ("rd_start=0xXXXXXXXXXXXXXXXX"), 4);
823 size += ALIGN_UP (sizeof ("rd_size=0xXXXXXXXXXXXXXXXX"), 4);
824
825 size = ALIGN_UP (size, 8);
826
827 if (grub_elf_is_elf32 (elf))
828 err = grub_linux_load32 (elf, argv[0]);
829 else
830 if (grub_elf_is_elf64 (elf))
831 err = grub_linux_load64 (elf, argv[0]);
832 else
833 err = grub_error (GRUB_ERR_BAD_OS, N_("invalid arch-dependent ELF magic"));
834
835 grub_elf_close (elf);
836
837 if (err)
838 return err;
839
840 {
841 grub_relocator_chunk_t ch;
842 err = grub_relocator_alloc_chunk_align (relocator, &ch,
843 0, (0xffffffff - size) + 1,
844 size, 8,
845 GRUB_RELOCATOR_PREFERENCE_HIGH, 0);
846 if (err)
847 return err;
848 linux_args_addr = get_virtual_current_address (ch);
849 }
850
851 linux_argv = (grub_uint32_t *) linux_args_addr;
852 linux_args = (char *) (linux_argv + (linux_argc + 1 + 2));
853
854 grub_memcpy (linux_args, "a0", sizeof ("a0"));
855 *linux_argv = (grub_uint32_t) (grub_addr_t) linux_args;
856 linux_argv++;
857 linux_args += ALIGN_UP (sizeof ("a0"), 4);
858
859 for (i = 1; i < argc; i++)
860 {
861 grub_memcpy (linux_args, argv[i], grub_strlen (argv[i]) + 1);
862 *linux_argv = (grub_uint32_t) (grub_addr_t) linux_args;
863 linux_argv++;
864 linux_args += ALIGN_UP (grub_strlen (argv[i]) + 1, 4);
865 }
866
867 /* Reserve space for rd arguments. */
868 rd_addr_arg_off = (grub_uint8_t *) linux_args - linux_args_addr;
869 linux_args += ALIGN_UP (sizeof ("rd_start=0xXXXXXXXXXXXXXXXX"), 4);
870 *linux_argv = 0;
871 linux_argv++;
872
873 rd_size_arg_off = (grub_uint8_t *) linux_args - linux_args_addr;
874 linux_args += ALIGN_UP (sizeof ("rd_size=0xXXXXXXXXXXXXXXXX"), 4);
875 *linux_argv = 0;
876 linux_argv++;
877
878 *linux_argv = 0;
879
880 //wake up other cores
881 {
882 __asm__(
883 "dli $8, 0x900000003ff01000\n\t"
884 "dli $11, 0 \n\t"
885 "dsll $11, 8 \n\t"
886 "or $8, $8,$11 \n\t"
887 "li $9, 0x5a5a \n\t"
888 "sw $9, 32($8) \n\t"
889 "nop \n\t"
890 :
891 :
892 );
893 }
894 grub_loader_set (grub_linux_boot, grub_linux_unload, 0);
895 initrd_loaded = 0;
896 loaded = 1;
897 grub_dl_ref (my_mod);
898
899 return GRUB_ERR_NONE;
900 }
901
902 static grub_err_t
903 grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
904 int argc, char *argv[])
905 {
906 grub_size_t size = 0;
907 void *initrd_dest;
908 grub_err_t err;
909 struct grub_linux_initrd_context initrd_ctx = { 0, 0, 0 };
910
911 if (argc == 0)
912 return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
913
914 if (!loaded)
915 return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("you need to load the kernel first"));
916
917 if (initrd_loaded)
918 return grub_error (GRUB_ERR_BAD_ARGUMENT, "only one initrd command can be issued.");
919
920 if (grub_initrd_init (argc, argv, &initrd_ctx))
921 goto fail;
922
923 size = grub_get_initrd_size (&initrd_ctx);
924
925 {
926 grub_relocator_chunk_t ch;
927 err = grub_relocator_alloc_chunk_align (relocator, &ch,
928 0, (0xffffffff - size) + 1,
929 size, 0x10000,
930 GRUB_RELOCATOR_PREFERENCE_HIGH, 0);
931
932 if (err)
933 goto fail;
934 initrd_dest = get_virtual_current_address (ch);
935 }
936
937 if (grub_initrd_load (&initrd_ctx, argv, initrd_dest))
938 goto fail;
939
940 grub_snprintf ((char *) linux_args_addr + rd_addr_arg_off,
941 sizeof ("rd_start=0xXXXXXXXXXXXXXXXX"), "rd_start=0x%lx",
942 (grub_uint64_t) initrd_dest);
943 ((grub_uint32_t *) linux_args_addr)[linux_argc]
944 = (grub_uint32_t) ((grub_addr_t) linux_args_addr + rd_addr_arg_off);
945 linux_argc++;
946
947 grub_snprintf ((char *) linux_args_addr + rd_size_arg_off,
948 sizeof ("rd_size=0xXXXXXXXXXXXXXXXXX"), "rd_size=0x%lx",
949 (grub_uint64_t) size);
950 ((grub_uint32_t *) linux_args_addr)[linux_argc]
951 = (grub_uint32_t) ((grub_addr_t) linux_args_addr + rd_size_arg_off);
952 linux_argc++;
953
954 initrd_loaded = 1;
955
956 fail:
957 grub_initrd_close (&initrd_ctx);
958
959 return grub_errno;
960 }
961
962 static grub_err_t
963 ventoy_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
964 int argc, char *argv[])
965 {
966 int i;
967 const char *file;
968 char buf[64];
969
970 if (ventoy_debug) grub_printf("ventoy_cmd_initrd %d\n", ventoy_linux_argc);
971
972 if (ventoy_linux_argc == 0)
973 {
974 return grub_cmd_initrd(cmd, argc, argv);
975 }
976
977 grub_snprintf(buf, sizeof(buf), "mem:%s:size:%s", grub_env_get("ventoy_cpio_addr"), grub_env_get("ventoy_cpio_size"));
978
979 if (ventoy_debug) grub_printf("membuf=%s\n", buf);
980
981 ventoy_extra_initrd_list[ventoy_extra_initrd_num++] = grub_strdup(buf);
982
983 file = grub_env_get("vtoy_img_part_file");
984 if (file)
985 {
986 ventoy_extra_initrd_list[ventoy_extra_initrd_num++] = grub_strdup(file);
987 }
988
989 for (i = 0; i < argc; i++)
990 {
991 ventoy_extra_initrd_list[ventoy_extra_initrd_num++] = grub_strdup(argv[i]);
992 }
993
994 ventoy_initrd_called = 1;
995
996 if (ventoy_debug)
997 {
998 grub_printf("========== initrd list ==========\n");
999 for (i = 0; i < ventoy_extra_initrd_num; i++)
1000 {
1001 grub_printf("%s\n", ventoy_extra_initrd_list[i]);
1002 }
1003 grub_printf("=================================\n");
1004 }
1005
1006 return grub_cmd_initrd(cmd, ventoy_extra_initrd_num, ventoy_extra_initrd_list);
1007 }
1008
1009 static grub_command_t cmd_linux, cmd_initrd;
1010 static grub_command_t cmd_set_bootopt, cmd_unset_bootopt, cmd_extra_initrd_append, cmd_extra_initrd_reset;
1011
1012 GRUB_MOD_INIT(linux)
1013 {
1014 cmd_linux = grub_register_command ("linux", grub_cmd_linux,
1015 0, N_("Load Linux."));
1016 cmd_initrd = grub_register_command ("initrd", ventoy_cmd_initrd,
1017 0, N_("Load initrd."));
1018
1019 cmd_set_bootopt = grub_register_command ("vt_set_boot_opt", grub_cmd_set_boot_opt, 0, N_("set ext boot opt"));
1020 cmd_unset_bootopt = grub_register_command ("vt_unset_boot_opt", grub_cmd_unset_boot_opt, 0, N_("unset ext boot opt"));
1021
1022 cmd_extra_initrd_append = grub_register_command ("vt_img_extra_initrd_append", grub_cmd_extra_initrd_append, 0, N_(""));
1023 cmd_extra_initrd_reset = grub_register_command ("vt_img_extra_initrd_reset", grub_cmd_extra_initrd_reset, 0, N_(""));
1024
1025 ventoy_linux_args = grub_zalloc(sizeof(char *) * LINUX_MAX_ARGC);
1026
1027 my_mod = mod;
1028 }
1029
1030 GRUB_MOD_FINI(linux)
1031 {
1032 grub_unregister_command (cmd_linux);
1033 grub_unregister_command (cmd_initrd);
1034 }