You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Ventoy/GRUB2/MOD_SRC/grub-2.04/grub-core/loader/mips64/linux.c

1024 lines
27 KiB
C

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/* linux.c - boot Linux */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2003,2004,2005,2007,2009,2010,2017 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#include <grub/efi/api.h>
#include <grub/efi/efi.h>
#include <grub/elf.h>
#include <grub/elfload.h>
#include <grub/loader.h>
#include <grub/dl.h>
#include <grub/mm.h>
#include <grub/misc.h>
#include <grub/command.h>
#include <grub/cpu/relocator.h>
#include <grub/machine/loongson.h>
#include <grub/memory.h>
#include <grub/i18n.h>
#include <grub/lib/cmdline.h>
#include <grub/linux.h>
#include <grub/term.h>
#include <grub/env.h>
GRUB_MOD_LICENSE ("GPLv3+");
#define _ull unsigned long long
#pragma GCC diagnostic ignored "-Wcast-align"
typedef unsigned long size_t;
static grub_dl_t my_mod;
static int loaded;
static grub_uint32_t tmp_index = 0;
static grub_size_t linux_size;
static struct grub_relocator *relocator;
static grub_addr_t target_addr, entry_addr;
static int linux_argc;
static grub_uint8_t *linux_args_addr;
static grub_off_t rd_addr_arg_off, rd_size_arg_off;
static int initrd_loaded = 0;
static grub_uint32_t j = 0;
static grub_uint32_t t = 0;
grub_uint64_t tempMemsize = 0;
grub_uint32_t free_index = 0;
grub_uint32_t reserve_index = 0;
grub_uint32_t acpi_table_index = 0;
grub_uint32_t acpi_nvs_index = 0;
#define LINUX_MAX_ARGC 1024
static int ventoy_debug = 0;
static int ventoy_initrd_called = 0;
static int ventoy_linux_argc = 0;
static char **ventoy_linux_args = NULL;
static int ventoy_extra_initrd_num = 0;
static char *ventoy_extra_initrd_list[256];
static grub_err_t
grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
int argc, char *argv[]);
static inline grub_size_t
page_align (grub_size_t size)
{
return (size + (1 << 12) - 1) & (~((1 << 12) - 1));
}
/* Find the optimal number of pages for the memory map. Is it better to
move this code to efi/mm.c? */
static grub_efi_uintn_t
find_mmap_size (void)
{
static grub_efi_uintn_t mmap_size = 0;
if (mmap_size != 0)
return mmap_size;
mmap_size = (1 << 12);
while (1)
{
int ret;
grub_efi_memory_descriptor_t *mmap;
grub_efi_uintn_t desc_size;
mmap = grub_malloc (mmap_size);
if (! mmap)
return 0;
ret = grub_efi_get_memory_map (&mmap_size, mmap, 0, &desc_size, 0);
grub_free (mmap);
if (ret < 0)
{
grub_error (GRUB_ERR_IO, "cannot get memory map");
return 0;
}
else if (ret > 0)
break;
mmap_size += (1 << 12);
}
/* Increase the size a bit for safety, because GRUB allocates more on
later, and EFI itself may allocate more. */
mmap_size += (1 << 12);
return page_align (mmap_size);
}
static void ventoy_debug_pause(void)
{
char key;
if (0 == ventoy_debug)
{
return;
}
grub_printf("press Enter to continue ......\n");
while (1)
{
key = grub_getkey();
if (key == '\n' || key == '\r')
{
break;
}
}
}
static int ventoy_preboot(void)
{
int i;
const char *file;
char buf[128];
if (ventoy_debug)
{
grub_printf("ventoy_preboot %d %d\n", ventoy_linux_argc, ventoy_initrd_called);
ventoy_debug_pause();
}
if (ventoy_linux_argc == 0)
{
return 0;
}
if (ventoy_initrd_called)
{
ventoy_initrd_called = 0;
return 0;
}
grub_snprintf(buf, sizeof(buf), "mem:%s:size:%s", grub_env_get("ventoy_cpio_addr"), grub_env_get("ventoy_cpio_size"));
ventoy_extra_initrd_list[ventoy_extra_initrd_num++] = grub_strdup(buf);
file = grub_env_get("vtoy_img_part_file");
if (file)
{
ventoy_extra_initrd_list[ventoy_extra_initrd_num++] = grub_strdup(file);
}
if (ventoy_debug)
{
grub_printf("========== initrd list ==========\n");
for (i = 0; i < ventoy_extra_initrd_num; i++)
{
grub_printf("%s\n", ventoy_extra_initrd_list[i]);
}
grub_printf("=================================\n");
ventoy_debug_pause();
}
grub_cmd_initrd(NULL, ventoy_extra_initrd_num, ventoy_extra_initrd_list);
return 0;
}
static int ventoy_boot_opt_filter(char *opt)
{
if (grub_strcmp(opt, "noinitrd") == 0)
{
return 1;
}
if (grub_strcmp(opt, "vga=current") == 0)
{
return 1;
}
if (grub_strncmp(opt, "rdinit=", 7) == 0)
{
if (grub_strcmp(opt, "rdinit=/vtoy/vtoy") != 0)
{
opt[0] = 'v';
opt[1] = 't';
}
return 0;
}
if (grub_strncmp(opt, "init=", 5) == 0)
{
opt[0] = 'v';
opt[1] = 't';
return 0;
}
if (ventoy_debug)
{
if (grub_strcmp(opt, "quiet") == 0)
{
return 1;
}
if (grub_strncmp(opt, "loglevel=", 9) == 0)
{
return 1;
}
if (grub_strcmp(opt, "splash") == 0)
{
return 1;
}
}
return 0;
}
static int ventoy_bootopt_hook(int argc, char *argv[])
{
int i;
int count = 0;
const char *env;
char c;
char *newenv;
char *last, *pos;
//grub_printf("ventoy_bootopt_hook: %d %d\n", argc, ventoy_linux_argc);
if (ventoy_linux_argc == 0)
{
return 0;
}
/* the 1st parameter is BOOT_IMAGE=xxxx */
if (argc > 0 && 0 == ventoy_boot_opt_filter(argv[0]))
{
ventoy_linux_args[count++] = grub_strdup(argv[0]);
}
for (i = 0; i < ventoy_linux_argc; i++)
{
ventoy_linux_args[count] = ventoy_linux_args[i + (LINUX_MAX_ARGC / 2)];
ventoy_linux_args[i + (LINUX_MAX_ARGC / 2)] = NULL;
if (ventoy_linux_args[count][0] == '@')
{
env = grub_env_get(ventoy_linux_args[count] + 1);
if (env)
{
grub_free(ventoy_linux_args[count]);
newenv = grub_strdup(env);
last = newenv;
while (*last)
{
while (*last)
{
if (*last != ' ' && *last != '\t')
{
break;
}
last++;
}
if (*last == 0)
{
break;
}
for (pos = last; *pos; pos++)
{
if (*pos == ' ' || *pos == '\t')
{
c = *pos;
*pos = 0;
if (0 == ventoy_boot_opt_filter(last))
{
ventoy_linux_args[count++] = grub_strdup(last);
}
*pos = c;
break;
}
}
if (*pos == 0)
{
if (0 == ventoy_boot_opt_filter(last))
{
ventoy_linux_args[count++] = grub_strdup(last);
}
break;
}
last = pos + 1;
}
}
else
{
count++;
}
}
else
{
count++;
}
}
/* We have processed the 1st parameter before, so start from 1 */
for (i = 1; i < argc; i++)
{
if (ventoy_boot_opt_filter(argv[i]))
{
continue;
}
ventoy_linux_args[count++] = grub_strdup(argv[i]);
}
if (ventoy_debug)
{
ventoy_linux_args[count++] = grub_strdup("loglevel=7");
}
ventoy_linux_argc = count;
if (ventoy_debug)
{
grub_printf("========== bootoption ==========\n");
for (i = 0; i < count; i++)
{
grub_printf("%s ", ventoy_linux_args[i]);
}
grub_printf("\n================================\n");
}
return 0;
}
static grub_err_t
grub_cmd_set_boot_opt (grub_command_t cmd __attribute__ ((unused)),
int argc, char *argv[])
{
int i;
const char *vtdebug;
for (i = 0; i < argc; i++)
{
ventoy_linux_args[ventoy_linux_argc + (LINUX_MAX_ARGC / 2) ] = grub_strdup(argv[i]);
ventoy_linux_argc++;
}
vtdebug = grub_env_get("vtdebug_flag");
if (vtdebug && vtdebug[0])
{
ventoy_debug = 1;
}
if (ventoy_debug) grub_printf("ventoy set boot opt %d\n", ventoy_linux_argc);
return 0;
}
static grub_err_t
grub_cmd_unset_boot_opt (grub_command_t cmd __attribute__ ((unused)),
int argc, char *argv[])
{
int i;
(void)argc;
(void)argv;
for (i = 0; i < LINUX_MAX_ARGC; i++)
{
if (ventoy_linux_args[i])
{
grub_free(ventoy_linux_args[i]);
}
}
ventoy_debug = 0;
ventoy_linux_argc = 0;
ventoy_initrd_called = 0;
grub_memset(ventoy_linux_args, 0, sizeof(char *) * LINUX_MAX_ARGC);
return 0;
}
static grub_err_t
grub_cmd_extra_initrd_append (grub_command_t cmd __attribute__ ((unused)),
int argc, char *argv[])
{
int newclen = 0;
char *pos = NULL;
char *end = NULL;
char buf[256] = {0};
if (argc != 1)
{
return 1;
}
for (pos = argv[0]; *pos; pos++)
{
if (*pos == '/')
{
end = pos;
}
}
if (end)
{
/* grub2 newc bug workaround */
newclen = (int)grub_strlen(end + 1);
if ((110 + newclen) % 4 == 0)
{
grub_snprintf(buf, sizeof(buf), "newc:.%s:%s", end + 1, argv[0]);
}
else
{
grub_snprintf(buf, sizeof(buf), "newc:%s:%s", end + 1, argv[0]);
}
if (ventoy_extra_initrd_num < 256)
{
ventoy_extra_initrd_list[ventoy_extra_initrd_num++] = grub_strdup(buf);
}
}
return 0;
}
static grub_err_t
grub_cmd_extra_initrd_reset (grub_command_t cmd __attribute__ ((unused)),
int argc, char *argv[])
{
int i;
(void)argc;
(void)argv;
for (i = 0; i < ventoy_extra_initrd_num; i++)
{
if (ventoy_extra_initrd_list[i])
{
grub_free(ventoy_extra_initrd_list[i]);
}
}
grub_memset(ventoy_extra_initrd_list, 0, sizeof(ventoy_extra_initrd_list));
return 0;
}
static grub_err_t
grub_linux_boot (void)
{
struct grub_relocator64_state state;
grub_int8_t checksum = 0;
grub_efi_memory_descriptor_t * lsdesc = NULL;
ventoy_preboot();
grub_memset (&state, 0, sizeof (state));
/* Boot the kernel. */
state.gpr[1] = entry_addr;
grub_dprintf("loongson", "entry_addr is 0x%llx\n", (_ull)state.gpr[1]);
state.gpr[4] = linux_argc;
grub_dprintf("loongson", "linux_argc is %lld\n", (_ull)state.gpr[4]);
state.gpr[5] = (grub_addr_t) linux_args_addr;
grub_dprintf("loongson", "args_addr is 0x%llx\n", (_ull)state.gpr[5]);
if(grub_efi_is_loongson ())
{
grub_efi_uintn_t mmap_size;
grub_efi_uintn_t desc_size;
grub_efi_memory_descriptor_t *mmap_buf;
grub_err_t err;
struct bootparamsinterface * boot_params;
void * tmp_boot_params = NULL;
grub_efi_uint8_t new_interface_flag = 0;
mem_map * new_interface_mem = NULL;
char *p = NULL;
struct memmap reserve_mem[GRUB_EFI_LOONGSON_MMAP_MAX];
struct memmap free_mem[GRUB_EFI_LOONGSON_MMAP_MAX];
struct memmap acpi_table_mem[GRUB_EFI_LOONGSON_MMAP_MAX];
struct memmap acpi_nvs_mem[GRUB_EFI_LOONGSON_MMAP_MAX];
grub_memset(reserve_mem, 0, sizeof(struct memmap) * GRUB_EFI_LOONGSON_MMAP_MAX);
grub_memset(free_mem, 0, sizeof(struct memmap) * GRUB_EFI_LOONGSON_MMAP_MAX);
grub_memset(acpi_table_mem, 0, sizeof(struct memmap) * GRUB_EFI_LOONGSON_MMAP_MAX);
grub_memset(acpi_nvs_mem, 0, sizeof(struct memmap) * GRUB_EFI_LOONGSON_MMAP_MAX);
tmp_boot_params = grub_efi_loongson_get_boot_params();
if(tmp_boot_params == NULL)
{
grub_printf("not find param\n");
return -1;
}
boot_params = (struct bootparamsinterface *)tmp_boot_params;
p = (char *)&(boot_params->signature);
if(grub_strncmp(p, "BPI", 3) == 0)
{
/* Check extlist headers */
ext_list * listpointer = NULL;
listpointer = boot_params->extlist;
for( ;listpointer != NULL; listpointer = listpointer->next)
{
char *pl= (char *)&(listpointer->signature);
if(grub_strncmp(pl, "MEM", 3) == 0)
{
new_interface_mem = (mem_map *)listpointer;
}
}
new_interface_flag = 1;
grub_dprintf("loongson", "get new parameter interface\n");
}else{
new_interface_flag = 0;
grub_dprintf("loongson", "get old parameter interface\n");
}
state.gpr[6] = (grub_uint64_t)tmp_boot_params;
grub_dprintf("loongson", "boot_params is 0x%llx\n", (_ull)state.gpr[6]);
mmap_size = find_mmap_size ();
if (! mmap_size)
return grub_errno;
mmap_buf = grub_efi_allocate_any_pages (page_align (mmap_size) >> 12);
if (! mmap_buf)
return grub_error (GRUB_ERR_IO, "cannot allocate memory map");
err = grub_efi_finish_boot_services (&mmap_size, mmap_buf, NULL,
&desc_size, NULL);
//grub_printf("%s-%d\n", __func__, __LINE__);
if (err)
return err;
if(new_interface_flag)
{
if (!mmap_buf || !mmap_size || !desc_size)
return -1;
tmp_index = new_interface_mem -> mapcount;
//grub_printf("%s-%d mapcount %d\n", __func__, __LINE__, tmp_index);
/*
According to UEFI SPEC,mmap_buf is the accurate Memory Map array \
now we can fill platform specific memory structure.
*/
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))
{
/* Recovery */
if((lsdesc->type != GRUB_EFI_ACPI_RECLAIM_MEMORY) && \
(lsdesc->type != GRUB_EFI_ACPI_MEMORY_NVS) && \
(lsdesc->type != GRUB_EFI_RUNTIME_SERVICES_DATA) && \
(lsdesc->type != GRUB_EFI_RUNTIME_SERVICES_CODE) && \
(lsdesc->type != GRUB_EFI_RESERVED_MEMORY_TYPE) && \
(lsdesc->type != GRUB_EFI_PAL_CODE))
{
free_mem[free_index].memtype = GRUB_EFI_LOONGSON_SYSTEM_RAM_LOW;
free_mem[free_index].memstart = (lsdesc->physical_start) & 0xffffffffffff;
free_mem[free_index].memsize = lsdesc->num_pages * 4096;
free_index++;
/*ACPI*/
}else if((lsdesc->type == GRUB_EFI_ACPI_RECLAIM_MEMORY)){
acpi_table_mem[acpi_table_index].memtype = GRUB_EFI_LOONGSON_ACPI_TABLE;
acpi_table_mem[acpi_table_index].memstart = (lsdesc->physical_start) & 0xffffffffffff;
acpi_table_mem[acpi_table_index].memsize = lsdesc->num_pages * 4096;
acpi_table_index++;
}else if((lsdesc->type == GRUB_EFI_ACPI_MEMORY_NVS)){
acpi_nvs_mem[acpi_nvs_index].memtype = GRUB_EFI_LOONGSON_ACPI_NVS;
acpi_nvs_mem[acpi_nvs_index].memstart = (lsdesc->physical_start) & 0xffffffffffff;
acpi_nvs_mem[acpi_nvs_index].memsize = lsdesc->num_pages * 4096;
acpi_nvs_index++;
/* Reserve */
}else{
reserve_mem[reserve_index].memtype = GRUB_EFI_LOONGSON_MEMORY_RESERVED;
reserve_mem[reserve_index].memstart = (lsdesc->physical_start) & 0xffffffffffff;
reserve_mem[reserve_index].memsize = lsdesc->num_pages * 4096;
reserve_index++;
}
}
/* Recovery sort */
for(j = 0; j < free_index;)
{
tempMemsize = free_mem[j].memsize;
for(t = j + 1; t < free_index; t++)
{
if((free_mem[j].memstart + tempMemsize == free_mem[t].memstart) && (free_mem[j].memtype == free_mem[t].memtype))
{
tempMemsize += free_mem[t].memsize;
}else{
break;
}
}
if(free_mem[j].memstart >= 0x10000000) /*HIGH MEM*/
new_interface_mem->map[tmp_index].memtype = GRUB_EFI_LOONGSON_SYSTEM_RAM_HIGH;
else
new_interface_mem->map[tmp_index].memtype = GRUB_EFI_LOONGSON_SYSTEM_RAM_LOW;
new_interface_mem->map[tmp_index].memstart = free_mem[j].memstart;
new_interface_mem->map[tmp_index].memsize = tempMemsize;
grub_dprintf("loongson", "map[%d]:type %x, start 0x%llx, end 0x%llx\n",
tmp_index,
new_interface_mem->map[tmp_index].memtype,
(_ull)new_interface_mem->map[tmp_index].memstart,
(_ull)new_interface_mem->map[tmp_index].memstart+ new_interface_mem->map[tmp_index].memsize
);
j = t;
tmp_index++;
}
/*ACPI Sort*/
tmp_index = grub_efi_loongson_memmap_sort(acpi_table_mem, acpi_table_index, new_interface_mem, tmp_index, GRUB_EFI_LOONGSON_ACPI_TABLE);
tmp_index = grub_efi_loongson_memmap_sort(acpi_nvs_mem, acpi_nvs_index, new_interface_mem, tmp_index, GRUB_EFI_LOONGSON_ACPI_NVS);
/*Reserve Sort*/
tmp_index = grub_efi_loongson_memmap_sort(reserve_mem, reserve_index, new_interface_mem, tmp_index, GRUB_EFI_LOONGSON_MEMORY_RESERVED);
new_interface_mem->mapcount = tmp_index;
new_interface_mem->header.checksum = 0;
//grub_printf("%s-%d mapcount %d\n", __func__, __LINE__, tmp_index);
checksum = grub_efi_loongson_grub_calculatechecksum8((grub_uint8_t *)new_interface_mem, new_interface_mem->header.length);
new_interface_mem->header.checksum = checksum;
}
}
state.jumpreg = 1;
grub_relocator64_boot (relocator, state);
return GRUB_ERR_NONE;
}
static grub_err_t
grub_linux_unload (void)
{
grub_relocator_unload (relocator);
grub_dl_unref (my_mod);
loaded = 0;
return GRUB_ERR_NONE;
}
static grub_err_t
grub_linux_load32 (grub_elf_t elf, const char *filename)
{
Elf32_Addr base;
grub_err_t err;
grub_uint8_t *playground;
/* Linux's entry point incorrectly contains a virtual address. */
entry_addr = elf->ehdr.ehdr32.e_entry;
linux_size = grub_elf32_size (elf, &base, 0);
if (linux_size == 0)
return grub_errno;
target_addr = base;
linux_size = ALIGN_UP (base + linux_size - base, 8);
relocator = grub_relocator_new ();
if (!relocator)
return grub_errno;
{
grub_relocator_chunk_t ch;
err = grub_relocator_alloc_chunk_addr (relocator, &ch,
grub_vtop ((void *) target_addr),
linux_size);
if (err)
return err;
playground = get_virtual_current_address (ch);
}
/* Now load the segments into the area we claimed. */
return grub_elf32_load (elf, filename, playground - base, GRUB_ELF_LOAD_FLAGS_NONE, 0, 0);
}
static grub_err_t
grub_linux_load64 (grub_elf_t elf, const char *filename)
{
Elf64_Addr base;
grub_err_t err;
grub_uint8_t *playground;
/* Linux's entry point incorrectly contains a virtual address. */
entry_addr = elf->ehdr.ehdr64.e_entry;
grub_dprintf("loongson", "entry address = 0x%llx\n", (_ull)entry_addr);
linux_size = grub_elf64_size (elf, &base, 0);
grub_dprintf("loongson", "base = 0x%llx\n", (_ull)base);
if (linux_size == 0)
return grub_errno;
target_addr = base;
linux_size = ALIGN_UP (base + linux_size - base, 8);
relocator = grub_relocator_new ();
if (!relocator)
return grub_errno;
{
grub_relocator_chunk_t ch;
err = grub_relocator_alloc_chunk_addr (relocator, &ch,
grub_vtop ((void *) target_addr),
linux_size);
if (err)
return err;
playground = get_virtual_current_address (ch);
//playground = 0xffffffff81ee0000; //<2F><><EFBFBD>ں<EFBFBD>ֱ<EFBFBD><D6B1>load<61><64>elfͷָ<CDB7><D6B8><EFBFBD>ڴ棬<DAB4><E6A3AC><EFBFBD><EFBFBD>grub<75><62><EFBFBD><EFBFBD><EFBFBD>Ŀռ<C4BF>
//playground = 0xffffffff80200000;
}
grub_printf("playground:0x%llx\n", (_ull)playground);
/* Now load the segments into the area we claimed. */
return grub_elf64_load (elf, filename, playground - base, GRUB_ELF_LOAD_FLAGS_NONE, 0, 0);
}
static grub_err_t
grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
int argc, char *argv[])
{
grub_elf_t elf = 0;
int size;
int i;
grub_uint32_t *linux_argv;
char *linux_args;
grub_err_t err;
if (argc == 0)
return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
if (ventoy_linux_argc)
{
ventoy_bootopt_hook(argc, argv);
argc = ventoy_linux_argc;
argv = ventoy_linux_args;
}
elf = grub_elf_open (argv[0], GRUB_FILE_TYPE_LINUX_KERNEL);
if (! elf)
return grub_errno;
if (elf->ehdr.ehdr32.e_type != ET_EXEC)
{
grub_elf_close (elf);
return grub_error (GRUB_ERR_UNKNOWN_OS,
N_("this ELF file is not of the right type"));
}
/* Release the previously used memory. */
grub_loader_unset ();
loaded = 0;
/* For arguments. */
linux_argc = argc;
/* Main arguments. */
size = (linux_argc) * sizeof (grub_uint32_t);
/* Initrd address and size. */
size += 2 * sizeof (grub_uint32_t);
/* NULL terminator. */
size += sizeof (grub_uint32_t);
/* First argument is always "a0". */
size += ALIGN_UP (sizeof ("a0"), 4);
/* Normal arguments. */
for (i = 1; i < argc; i++)
size += ALIGN_UP (grub_strlen (argv[i]) + 1, 4);
/* rd arguments. */
size += ALIGN_UP (sizeof ("rd_start=0xXXXXXXXXXXXXXXXX"), 4);
size += ALIGN_UP (sizeof ("rd_size=0xXXXXXXXXXXXXXXXX"), 4);
size = ALIGN_UP (size, 8);
if (grub_elf_is_elf32 (elf))
err = grub_linux_load32 (elf, argv[0]);
else
if (grub_elf_is_elf64 (elf))
err = grub_linux_load64 (elf, argv[0]);
else
err = grub_error (GRUB_ERR_BAD_OS, N_("invalid arch-dependent ELF magic"));
grub_elf_close (elf);
if (err)
return err;
{
grub_relocator_chunk_t ch;
err = grub_relocator_alloc_chunk_align (relocator, &ch,
0, (0xffffffff - size) + 1,
size, 8,
GRUB_RELOCATOR_PREFERENCE_HIGH, 0);
if (err)
return err;
linux_args_addr = get_virtual_current_address (ch);
}
linux_argv = (grub_uint32_t *) linux_args_addr;
linux_args = (char *) (linux_argv + (linux_argc + 1 + 2));
grub_memcpy (linux_args, "a0", sizeof ("a0"));
*linux_argv = (grub_uint32_t) (grub_addr_t) linux_args;
linux_argv++;
linux_args += ALIGN_UP (sizeof ("a0"), 4);
for (i = 1; i < argc; i++)
{
grub_memcpy (linux_args, argv[i], grub_strlen (argv[i]) + 1);
*linux_argv = (grub_uint32_t) (grub_addr_t) linux_args;
linux_argv++;
linux_args += ALIGN_UP (grub_strlen (argv[i]) + 1, 4);
}
/* Reserve space for rd arguments. */
rd_addr_arg_off = (grub_uint8_t *) linux_args - linux_args_addr;
linux_args += ALIGN_UP (sizeof ("rd_start=0xXXXXXXXXXXXXXXXX"), 4);
*linux_argv = 0;
linux_argv++;
rd_size_arg_off = (grub_uint8_t *) linux_args - linux_args_addr;
linux_args += ALIGN_UP (sizeof ("rd_size=0xXXXXXXXXXXXXXXXX"), 4);
*linux_argv = 0;
linux_argv++;
*linux_argv = 0;
//wake up other cores
{
__asm__(
"dli $8, 0x900000003ff01000\n\t"
"dli $11, 0 \n\t"
"dsll $11, 8 \n\t"
"or $8, $8,$11 \n\t"
"li $9, 0x5a5a \n\t"
"sw $9, 32($8) \n\t"
"nop \n\t"
:
:
);
}
grub_loader_set (grub_linux_boot, grub_linux_unload, 0);
initrd_loaded = 0;
loaded = 1;
grub_dl_ref (my_mod);
return GRUB_ERR_NONE;
}
static grub_err_t
grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
int argc, char *argv[])
{
grub_size_t size = 0;
void *initrd_dest;
grub_err_t err;
struct grub_linux_initrd_context initrd_ctx = { 0, 0, 0 };
if (argc == 0)
return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
if (!loaded)
return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("you need to load the kernel first"));
if (initrd_loaded)
return grub_error (GRUB_ERR_BAD_ARGUMENT, "only one initrd command can be issued.");
if (grub_initrd_init (argc, argv, &initrd_ctx))
goto fail;
size = grub_get_initrd_size (&initrd_ctx);
{
grub_relocator_chunk_t ch;
err = grub_relocator_alloc_chunk_align (relocator, &ch,
0, (0xffffffff - size) + 1,
size, 0x10000,
GRUB_RELOCATOR_PREFERENCE_HIGH, 0);
if (err)
goto fail;
initrd_dest = get_virtual_current_address (ch);
}
if (grub_initrd_load (&initrd_ctx, argv, initrd_dest))
goto fail;
grub_snprintf ((char *) linux_args_addr + rd_addr_arg_off,
sizeof ("rd_start=0xXXXXXXXXXXXXXXXX"), "rd_start=0x%lx",
(grub_uint64_t) initrd_dest);
((grub_uint32_t *) linux_args_addr)[linux_argc]
= (grub_uint32_t) ((grub_addr_t) linux_args_addr + rd_addr_arg_off);
linux_argc++;
grub_snprintf ((char *) linux_args_addr + rd_size_arg_off,
sizeof ("rd_size=0xXXXXXXXXXXXXXXXXX"), "rd_size=0x%lx",
(grub_uint64_t) size);
((grub_uint32_t *) linux_args_addr)[linux_argc]
= (grub_uint32_t) ((grub_addr_t) linux_args_addr + rd_size_arg_off);
linux_argc++;
initrd_loaded = 1;
fail:
grub_initrd_close (&initrd_ctx);
return grub_errno;
}
static grub_err_t
ventoy_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
int argc, char *argv[])
{
int i;
const char *file;
char buf[64];
if (ventoy_debug) grub_printf("ventoy_cmd_initrd %d\n", ventoy_linux_argc);
if (ventoy_linux_argc == 0)
{
return grub_cmd_initrd(cmd, argc, argv);
}
grub_snprintf(buf, sizeof(buf), "mem:%s:size:%s", grub_env_get("ventoy_cpio_addr"), grub_env_get("ventoy_cpio_size"));
if (ventoy_debug) grub_printf("membuf=%s\n", buf);
ventoy_extra_initrd_list[ventoy_extra_initrd_num++] = grub_strdup(buf);
file = grub_env_get("vtoy_img_part_file");
if (file)
{
ventoy_extra_initrd_list[ventoy_extra_initrd_num++] = grub_strdup(file);
}
for (i = 0; i < argc; i++)
{
ventoy_extra_initrd_list[ventoy_extra_initrd_num++] = grub_strdup(argv[i]);
}
ventoy_initrd_called = 1;
if (ventoy_debug)
{
grub_printf("========== initrd list ==========\n");
for (i = 0; i < ventoy_extra_initrd_num; i++)
{
grub_printf("%s\n", ventoy_extra_initrd_list[i]);
}
grub_printf("=================================\n");
}
return grub_cmd_initrd(cmd, ventoy_extra_initrd_num, ventoy_extra_initrd_list);
}
static grub_command_t cmd_linux, cmd_initrd;
static grub_command_t cmd_set_bootopt, cmd_unset_bootopt, cmd_extra_initrd_append, cmd_extra_initrd_reset;
GRUB_MOD_INIT(linux)
{
cmd_linux = grub_register_command ("linux", grub_cmd_linux,
0, N_("Load Linux."));
cmd_initrd = grub_register_command ("initrd", ventoy_cmd_initrd,
0, N_("Load initrd."));
cmd_set_bootopt = grub_register_command ("vt_set_boot_opt", grub_cmd_set_boot_opt, 0, N_("set ext boot opt"));
cmd_unset_bootopt = grub_register_command ("vt_unset_boot_opt", grub_cmd_unset_boot_opt, 0, N_("unset ext boot opt"));
cmd_extra_initrd_append = grub_register_command ("vt_img_extra_initrd_append", grub_cmd_extra_initrd_append, 0, N_(""));
cmd_extra_initrd_reset = grub_register_command ("vt_img_extra_initrd_reset", grub_cmd_extra_initrd_reset, 0, N_(""));
ventoy_linux_args = grub_zalloc(sizeof(char *) * LINUX_MAX_ARGC);
my_mod = mod;
}
GRUB_MOD_FINI(linux)
{
grub_unregister_command (cmd_linux);
grub_unregister_command (cmd_initrd);
}