diff --git a/1006-Update-patches-in-sync-with-loongarch64.patch b/1006-Update-patches-in-sync-with-loongarch64.patch new file mode 100644 index 0000000000000000000000000000000000000000..dc39a930181953d92b138bd5fba79bf1160d4c7d --- /dev/null +++ b/1006-Update-patches-in-sync-with-loongarch64.patch @@ -0,0 +1,2815 @@ +From 7118e2827e64c205e3b2241b85648f2948cab3a3 Mon Sep 17 00:00:00 2001 +From: Fedora Ninjas +Date: Sat, 22 Mar 2025 16:49:13 +0800 +Subject: [PATCH] Update patches in sync with loongarch64 + +--- + gentpl.py | 2 +- + grub-core/Makefile.am | 1 - + grub-core/Makefile.core.def | 11 +- + grub-core/kern/loongarch64/cache.S | 2 + + grub-core/kern/loongarch64/efi/init.c | 2 - + grub-core/kern/loongarch64/efi/startup.S | 4 +- + grub-core/kern/loongarch64/init.c | 47 -- + grub-core/lib/loongarch64/efi/loongson.c | 119 --- + grub-core/lib/loongarch64/relocator.c | 2 +- + grub-core/lib/loongarch64/setjmp.S | 80 +- + grub-core/loader/loongarch64/linux-efi.c | 143 ++++ + grub-core/loader/loongarch64/linux-elf.c | 910 +++++++++++++++++++++++ + grub-core/loader/loongarch64/linux.c | 731 +++++------------- + include/grub/efi/api.h | 20 + + include/grub/fdt.h | 2 +- + include/grub/loongarch64/asm.h | 10 - + include/grub/loongarch64/efi/loongson.h | 113 --- + include/grub/loongarch64/efi/memory.h | 7 +- + include/grub/loongarch64/efi/time.h | 0 + include/grub/loongarch64/linux.h | 163 +++- + include/grub/loongarch64/time.h | 12 - + 21 files changed, 1487 insertions(+), 894 deletions(-) + delete mode 100644 grub-core/kern/loongarch64/init.c + delete mode 100644 grub-core/lib/loongarch64/efi/loongson.c + create mode 100644 grub-core/loader/loongarch64/linux-efi.c + create mode 100644 grub-core/loader/loongarch64/linux-elf.c + delete mode 100644 include/grub/loongarch64/asm.h + delete mode 100644 include/grub/loongarch64/efi/loongson.h + delete mode 100644 include/grub/loongarch64/efi/time.h + +diff --git a/gentpl.py b/gentpl.py +index 3afd642..fa7f1ba 100644 +--- a/gentpl.py ++++ b/gentpl.py +@@ -78,7 +78,7 @@ GROUPS["terminfomodule"] = GRUB_PLATFORMS[:]; + for i in GROUPS["terminfoinkernel"]: GROUPS["terminfomodule"].remove(i) + + # Flattened Device Trees (FDT) +-GROUPS["fdt"] = [ "arm64_efi", "arm_uboot", "arm_efi" ] ++GROUPS["fdt"] = [ "arm64_efi", "arm_uboot", "arm_efi", "loongarch64_efi" ] + + # Needs software helpers for division + # Must match GRUB_DIVISION_IN_SOFTWARE in misc.h +diff --git a/grub-core/Makefile.am b/grub-core/Makefile.am +index a976fad..ec771c5 100644 +--- a/grub-core/Makefile.am ++++ b/grub-core/Makefile.am +@@ -227,7 +227,6 @@ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/efi.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/disk.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/acpi.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/fdt.h +-KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/loongson.h + endif + + if COND_powerpc_ieee1275 +diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def +index aded014..b89e58e 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -250,6 +250,9 @@ kernel = { + arm64_efi = kern/arm64/efi/init.c; + arm64_efi = kern/efi/fdt.c; + ++ loongarch64_efi = kern/loongarch64/efi/init.c; ++ loongarch64_efi = kern/efi/fdt.c; ++ + i386_pc = kern/i386/pc/init.c; + i386_pc = kern/i386/pc/mmap.c; + i386_pc = term/i386/pc/console.c; +@@ -300,14 +303,8 @@ kernel = { + extra_dist = video/sis315_init.c; + mips_loongson = commands/keylayouts.c; + +- loongarch64 = kern/loongarch64/init.c; + loongarch64 = kern/loongarch64/dl.c; + loongarch64 = kern/loongarch64/cache.S; +- loongarch64 = kern/generic/rtc_get_time_ms.c; +- loongarch64 = kern/efi/fdt.c; +- loongarch64 = lib/fdt.c; +- loongarch64_efi = kern/loongarch64/efi/init.c; +- loongarch64_efi = lib/loongarch64/efi/loongson.c; + + powerpc_ieee1275 = kern/powerpc/cache.S; + powerpc_ieee1275 = kern/powerpc/dl.c; +@@ -1767,6 +1764,8 @@ module = { + i386_pc = lib/i386/pc/vesa_modes_table.c; + mips = loader/mips/linux.c; + loongarch64 = loader/loongarch64/linux.c; ++ loongarch64 = loader/loongarch64/linux-elf.c; ++ loongarch64 = loader/loongarch64/linux-efi.c; + powerpc_ieee1275 = loader/powerpc/ieee1275/linux.c; + sparc64_ieee1275 = loader/sparc64/ieee1275/linux.c; + ia64_efi = loader/ia64/efi/linux.c; +diff --git a/grub-core/kern/loongarch64/cache.S b/grub-core/kern/loongarch64/cache.S +index d291c67..b268261 100644 +--- a/grub-core/kern/loongarch64/cache.S ++++ b/grub-core/kern/loongarch64/cache.S +@@ -19,6 +19,8 @@ + #include + + FUNCTION (grub_arch_sync_caches) ++ ibar 0 ++ dbar 0 + jr $ra + + FUNCTION (grub_arch_sync_dma_caches) +diff --git a/grub-core/kern/loongarch64/efi/init.c b/grub-core/kern/loongarch64/efi/init.c +index 632c39a..15c41aa 100644 +--- a/grub-core/kern/loongarch64/efi/init.c ++++ b/grub-core/kern/loongarch64/efi/init.c +@@ -1,4 +1,3 @@ +-/* init.c - initialize an arm-based EFI system */ + /* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2013 Free Software Foundation, Inc. +@@ -24,7 +23,6 @@ + #include + #include + #include +-#include + + static grub_uint64_t tmr; + static grub_efi_event_t tmr_evt; +diff --git a/grub-core/kern/loongarch64/efi/startup.S b/grub-core/kern/loongarch64/efi/startup.S +index 1ffff08..00ecd15 100644 +--- a/grub-core/kern/loongarch64/efi/startup.S ++++ b/grub-core/kern/loongarch64/efi/startup.S +@@ -19,8 +19,9 @@ + #include + + .file "startup.S" +- .text + .globl start, _start ++ .text ++ + .align 4 + + FUNCTION(start) +@@ -42,4 +43,3 @@ FUNCTION(_start) + ld.d $ra, $sp, 0 + addi.d $sp, $sp, 16 + jr $ra +- +diff --git a/grub-core/kern/loongarch64/init.c b/grub-core/kern/loongarch64/init.c +deleted file mode 100644 +index b2de930..0000000 +--- a/grub-core/kern/loongarch64/init.c ++++ /dev/null +@@ -1,47 +0,0 @@ +-/* +- * GRUB -- GRand Unified Bootloader +- * Copyright (C) 2009,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 . +- */ +- +-#include +-#include +-#include +-#include +- +-grub_uint32_t grub_arch_cpuclock; +- +-/* FIXME: use interrupt to count high. */ +-grub_uint64_t +-grub_get_rtc (void) +-{ +- static grub_uint32_t high = 0; +- static grub_uint32_t last = 0; +- grub_uint32_t low; +- +- asm volatile ("csrrd %0, " GRUB_CPU_LOONGARCH_COP0_TIMER_COUNT : "=r" (low)); +- if (low < last) +- high++; +- last = low; +- +- return (((grub_uint64_t) high) << 32) | low; +-} +- +-void +-grub_timer_init (grub_uint32_t cpuclock) +-{ +- grub_arch_cpuclock = cpuclock; +- grub_install_get_time_ms (grub_rtc_get_time_ms); +-} +diff --git a/grub-core/lib/loongarch64/efi/loongson.c b/grub-core/lib/loongarch64/efi/loongson.c +deleted file mode 100644 +index eda1e1c..0000000 +--- a/grub-core/lib/loongarch64/efi/loongson.c ++++ /dev/null +@@ -1,119 +0,0 @@ +-/* +- * GRUB -- GRand Unified Bootloader +- * Copyright (C) 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 . +- */ +- +-#include +-#include +-#include +-#include +-#include +-#include +- +-unsigned long +-grub_efi_get_bpi_version (const char *str) +-{ +- unsigned long version = GRUB_EFI_BPI_VER_NONE; +- +- version = grub_strtoul (str + 4, 0, 0); +- +- return version; +-} +- +-void * +-grub_efi_loongson_get_boot_params (void) +-{ +- static void * boot_params = NULL; +- grub_efi_configuration_table_t *tables; +- grub_efi_guid_t loongson_bpi_guid = GRUB_EFI_LOONGSON_BPI_TABLE_GUID; +- unsigned int i; +- +- if (boot_params) +- return boot_params; +- +- /* Look for Loongson boot params interface in UEFI config tables. */ +- tables = grub_efi_system_table->configuration_table; +- +- for (i = 0; i < grub_efi_system_table->num_table_entries; i++) +- if (grub_memcmp (&tables[i].vendor_guid, &loongson_bpi_guid, sizeof (loongson_bpi_guid)) == 0) +- { +- boot_params= tables[i].vendor_table; +- grub_dprintf ("loongson", "found registered BPI @ %p\n", boot_params); +- break; +- } +- return boot_params; +-} +- +-grub_uint8_t +-grub_efi_loongson_calculatesum8 (const grub_uint8_t *buffer, grub_efi_uintn_t length) +-{ +- grub_uint8_t sum; +- grub_efi_uintn_t count; +- +- for (sum = 0, count = 0; count < length; count++) +- { +- sum = (grub_uint8_t) (sum + *(buffer + count)); +- } +- return sum; +-} +- +-grub_uint8_t +-grub_efi_loongson_grub_calculatechecksum8 (const grub_uint8_t *buffer, grub_efi_uintn_t length) +-{ +- grub_uint8_t checksum; +- +- checksum = grub_efi_loongson_calculatesum8(buffer, length); +- +- return (grub_uint8_t) (0x100 - checksum); +-} +- +- +-grub_uint32_t +-grub_efi_loongson_memmap_v1_sort(struct memmap_v1 array[], grub_uint32_t length, +- mem_map_v1 * bpmem, grub_uint32_t index, grub_uint32_t memtype) +-{ +- grub_uint64_t tempmemsize = 0; +- grub_uint32_t j = 0; +- grub_uint32_t t = 0; +- +- for(j = 0; j < length;) +- { +- tempmemsize = array[j].memsize; +- for(t = j + 1; t < length; t++) +- { +- if(array[j].memstart + tempmemsize == array[t].memstart) +- { +- tempmemsize += array[t].memsize; +- } +- else +- { +- break; +- } +- } +- bpmem->map[index].memtype = memtype; +- bpmem->map[index].memstart = array[j].memstart; +- bpmem->map[index].memsize = tempmemsize; +- grub_dprintf("loongson", "v1 map[%d]:type %x, start 0x%lx, end 0x%lx\n", +- index, +- bpmem->map[index].memtype, +- bpmem->map[index].memstart, +- bpmem->map[index].memstart+ bpmem->map[index].memsize +- ); +- j = t; +- index++; +- } +- return index; +-} +diff --git a/grub-core/lib/loongarch64/relocator.c b/grub-core/lib/loongarch64/relocator.c +index 4b253ca..7217b68 100644 +--- a/grub-core/lib/loongarch64/relocator.c ++++ b/grub-core/lib/loongarch64/relocator.c +@@ -122,7 +122,7 @@ grub_relocator64_boot (struct grub_relocator *rel, + unsigned i; + grub_addr_t vtarget; + +- err = grub_relocator_alloc_chunk_align (rel, &ch, 0, ++ err = grub_relocator_alloc_chunk_align (rel, &ch, 0x3000000, + (0xffffffff - stateset_size) + + 1, stateset_size, + grub_relocator_align, +diff --git a/grub-core/lib/loongarch64/setjmp.S b/grub-core/lib/loongarch64/setjmp.S +index 47db814..bb09959 100644 +--- a/grub-core/lib/loongarch64/setjmp.S ++++ b/grub-core/lib/loongarch64/setjmp.S +@@ -1,6 +1,6 @@ + /* + * GRUB -- GRand Unified Bootloader +- * Copyright (C) 2003,2007,2009 Free Software Foundation, Inc. ++ * Copyright (C) 2021 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 +@@ -16,9 +16,7 @@ + * along with GRUB. If not, see . + */ + +-#include + #include +-#include + + .file "setjmp.S" + +@@ -27,48 +25,44 @@ GRUB_MOD_LICENSE "GPLv3+" + .text + + /* +- * int grub_setjmp (grub_jmp_buf env) ++ * int grub_setjmp (jmp_buf env) + */ + FUNCTION(grub_setjmp) +- GRUB_ASM_REG_S $s0, $a0,0 +- GRUB_ASM_REG_S $s1, $a0,8 +- GRUB_ASM_REG_S $s2, $a0,16 +- GRUB_ASM_REG_S $s3, $a0,24 +- GRUB_ASM_REG_S $s4, $a0,32 +- GRUB_ASM_REG_S $s5, $a0,40 +- GRUB_ASM_REG_S $s6, $a0,48 +- GRUB_ASM_REG_S $s7, $a0,56 +- GRUB_ASM_REG_S $s8, $a0,64 +- GRUB_ASM_REG_S $fp, $a0,72 +- GRUB_ASM_REG_S $sp, $a0,80 +- GRUB_ASM_REG_S $ra, $a0,88 +- move $v0, $zero +- move $v1, $zero +- jr $ra +- nop ++ st.d $s0, $a0, 0x0 ++ st.d $s1, $a0, 0x8 ++ st.d $s2, $a0, 0x10 ++ st.d $s3, $a0, 0x18 ++ st.d $s4, $a0, 0x20 ++ st.d $s5, $a0, 0x28 ++ st.d $s6, $a0, 0x30 ++ st.d $s7, $a0, 0x38 ++ st.d $s8, $a0, 0x40 ++ st.d $fp, $a0, 0x48 ++ st.d $sp, $a0, 0x50 ++ st.d $ra, $a0, 0x58 ++ ++ move $a0, $zero ++ jr $ra ++ + /* +- * int grub_longjmp (grub_jmp_buf env, int val) ++ * void grub_longjmp (jmp_buf env, int val) + */ + FUNCTION(grub_longjmp) +- GRUB_ASM_REG_L $s0, $a0,0 +- GRUB_ASM_REG_L $s1, $a0,8 +- GRUB_ASM_REG_L $s2, $a0,16 +- GRUB_ASM_REG_L $s3, $a0,24 +- GRUB_ASM_REG_L $s4, $a0,32 +- GRUB_ASM_REG_L $s5, $a0,40 +- GRUB_ASM_REG_L $s6, $a0,48 +- GRUB_ASM_REG_L $s7, $a0,56 +- GRUB_ASM_REG_L $s8, $a0,64 +- GRUB_ASM_REG_L $fp, $a0,72 +- GRUB_ASM_REG_L $sp, $a0,80 +- GRUB_ASM_REG_L $ra, $a0,88 +- addi.w $v0, $zero, 1 +- /* +- * replace: movn $v0, $a1, $a1 +- */ +- bnez $a1, .ZW0 +- addi.d $v0, $a1, 0 +-.ZW0: +- addi.d $v1,$zero,0 +- jr $ra +- nop ++ ld.d $s0, $a0, 0x0 ++ ld.d $s1, $a0, 0x8 ++ ld.d $s2, $a0, 0x10 ++ ld.d $s3, $a0, 0x18 ++ ld.d $s4, $a0, 0x20 ++ ld.d $s5, $a0, 0x28 ++ ld.d $s6, $a0, 0x30 ++ ld.d $s7, $a0, 0x38 ++ ld.d $s8, $a0, 0x40 ++ ld.d $fp, $a0, 0x48 ++ ld.d $sp, $a0, 0x50 ++ ld.d $ra, $a0, 0x58 ++ ++ li.w $a0, 1 ++ beqz $a1, .L0 ++ move $a0, $a1 ++.L0: ++ jr $ra +diff --git a/grub-core/loader/loongarch64/linux-efi.c b/grub-core/loader/loongarch64/linux-efi.c +new file mode 100644 +index 0000000..6f5ff15 +--- /dev/null ++++ b/grub-core/loader/loongarch64/linux-efi.c +@@ -0,0 +1,143 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2021 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 . ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define GRUB_EFI_PE_MAGIC 0x5A4D ++ ++grub_err_t ++finalize_efi_params_linux (struct linux_loongarch64_kernel_params *kernel_params) ++{ ++ int node, retval; ++ ++ void *fdt; ++ ++ fdt = grub_fdt_load (GRUB_EFI_LINUX_FDT_EXTRA_SPACE); ++ ++ if (!fdt) ++ goto failure; ++ ++ node = grub_fdt_find_subnode (fdt, 0, "chosen"); ++ if (node < 0) ++ node = grub_fdt_add_subnode (fdt, 0, "chosen"); ++ ++ if (node < 1) ++ goto failure; ++ ++ /* Set initrd info */ ++ if (kernel_params->ramdisk_addr && kernel_params->ramdisk_size) ++ { ++ grub_dprintf ("linux", "Initrd @ %p-%p\n", ++ (void *) kernel_params->ramdisk_addr, ++ (void *) (kernel_params->ramdisk_addr + kernel_params->ramdisk_size)); ++ ++ retval = grub_fdt_set_prop64 (fdt, node, "linux,initrd-start", ++ kernel_params->ramdisk_addr); ++ if (retval) ++ goto failure; ++ retval = grub_fdt_set_prop64 (fdt, node, "linux,initrd-end", ++ kernel_params->ramdisk_addr + kernel_params->ramdisk_size); ++ if (retval) ++ goto failure; ++ } ++ ++ if (grub_fdt_install() != GRUB_ERR_NONE) ++ goto failure; ++ ++ return GRUB_ERR_NONE; ++ ++failure: ++ grub_fdt_unload(); ++ return grub_error(GRUB_ERR_BAD_OS, "failed to install/update FDT"); ++} ++ ++grub_err_t ++grub_arch_efi_linux_check_image (struct linux_arch_kernel_header * lh) ++{ ++ if ((lh->code0 & 0xffff) == GRUB_EFI_PE_MAGIC) ++ return GRUB_ERR_NONE; ++ else ++ return 1; ++ ++ grub_dprintf ("linux", "UEFI stub kernel:\n"); ++ grub_dprintf ("linux", "PE/COFF header @ %08x\n", lh->hdr_offset); ++ ++ return GRUB_ERR_NONE; ++} ++ ++grub_err_t ++grub_arch_efi_linux_boot_image (grub_addr_t addr, grub_size_t size, char *args) ++{ ++ grub_efi_memory_mapped_device_path_t *mempath; ++ grub_efi_handle_t image_handle; ++ grub_efi_boot_services_t *b; ++ grub_efi_status_t status; ++ grub_efi_loaded_image_t *loaded_image; ++ int len; ++ ++ mempath = grub_malloc (2 * sizeof (grub_efi_memory_mapped_device_path_t)); ++ if (!mempath) ++ return grub_errno; ++ ++ mempath[0].header.type = GRUB_EFI_HARDWARE_DEVICE_PATH_TYPE; ++ mempath[0].header.subtype = GRUB_EFI_MEMORY_MAPPED_DEVICE_PATH_SUBTYPE; ++ mempath[0].header.length = grub_cpu_to_le16_compile_time (sizeof (*mempath)); ++ mempath[0].memory_type = GRUB_EFI_LOADER_DATA; ++ mempath[0].start_address = addr; ++ mempath[0].end_address = addr + size; ++ ++ mempath[1].header.type = GRUB_EFI_END_DEVICE_PATH_TYPE; ++ mempath[1].header.subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE; ++ mempath[1].header.length = sizeof (grub_efi_device_path_t); ++ ++ b = grub_efi_system_table->boot_services; ++ status = b->load_image (0, grub_efi_image_handle, ++ (grub_efi_device_path_t *) mempath, ++ (void *) addr, size, &image_handle); ++ if (status != GRUB_EFI_SUCCESS) ++ return grub_error (GRUB_ERR_BAD_OS, "cannot load image"); ++ ++ grub_dprintf ("linux", "linux command line: '%s'\n", args); ++ ++ /* Convert command line to UCS-2 */ ++ loaded_image = grub_efi_get_loaded_image (image_handle); ++ loaded_image->load_options_size = len = ++ (grub_strlen (args) + 1) * sizeof (grub_efi_char16_t); ++ loaded_image->load_options = ++ grub_efi_allocate_any_pages (GRUB_EFI_BYTES_TO_PAGES (loaded_image->load_options_size)); ++ if (!loaded_image->load_options) ++ return grub_errno; ++ ++ loaded_image->load_options_size = ++ 2 * grub_utf8_to_utf16 (loaded_image->load_options, len, ++ (grub_uint8_t *) args, len, NULL); ++ ++ grub_dprintf ("linux", "starting image %p\n", image_handle); ++ status = b->start_image (image_handle, 0, NULL); ++ ++ /* When successful, not reached */ ++ b->unload_image (image_handle); ++ grub_efi_free_pages ((grub_addr_t) loaded_image->load_options, ++ GRUB_EFI_BYTES_TO_PAGES (loaded_image->load_options_size)); ++ ++ return grub_errno; ++} +diff --git a/grub-core/loader/loongarch64/linux-elf.c b/grub-core/loader/loongarch64/linux-elf.c +new file mode 100644 +index 0000000..d54028e +--- /dev/null ++++ b/grub-core/loader/loongarch64/linux-elf.c +@@ -0,0 +1,910 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2021 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 . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define GRUB_EFI_MMAP_NR_SLACK_SLOTS 8 ++ ++#define GRUB_ADDRESS_TYPE_SYSRAM 1 ++#define GRUB_ADDRESS_TYPE_RESERVED 2 ++#define GRUB_ADDRESS_TYPE_ACPI 3 ++#define GRUB_ADDRESS_TYPE_NVS 4 ++#define GRUB_ADDRESS_TYPE_PMEM 5 ++ ++#define GRUB_EFI_LOONGSON_BPI_TABLE_GUID \ ++ { 0x4660f721, 0x2ec5, 0x416a, \ ++ { 0x89, 0x9a, 0x43, 0x18, 0x02, 0x50, 0xa0, 0xc9 } \ ++ } ++ ++#define GRUB_EFI_LARCH_SCREEN_INFO_GUID \ ++ { 0x07fd51a6, 0X9532, 0X926f, \ ++ { 0X51, 0Xdc, 0X6a, 0X63, 0X60, 0X2f, 0X84, 0Xb4 } \ ++ } ++ ++#define GRUB_EFI_SCREEN_INFO_GUID \ ++ { 0xe03fc20a, 0x85dc, 0x406e, \ ++ { 0xb9, 0x0e, 0x4a, 0xb5, 0x02, 0x37, 0x1d, 0x95 } \ ++ } ++ ++static struct grub_relocator *relocator; ++static grub_efi_guid_t compat_screen_info_guid = GRUB_EFI_LARCH_SCREEN_INFO_GUID; ++static grub_efi_guid_t screen_info_guid = GRUB_EFI_SCREEN_INFO_GUID; ++ ++void grub_linux_loongarch_elf_relocator_unload (void) ++{ ++ grub_relocator_unload (relocator); ++} ++ ++static void find_bits(unsigned long mask, grub_efi_uint8_t *pos, grub_efi_uint8_t *size) ++{ ++ grub_efi_uint8_t first, len; ++ ++ first = 0; ++ len = 0; ++ ++ if (mask) { ++ while (!(mask & 0x1)) { ++ mask = mask >> 1; ++ first++; ++ } ++ ++ while (mask & 0x1) { ++ mask = mask >> 1; ++ len++; ++ } ++ } ++ ++ *pos = first; ++ *size = len; ++} ++ ++static void ++setup_pixel_info(struct screen_info *si, grub_efi_uint32_t pixels_per_scan_line, ++ struct grub_efi_gop_pixel_bitmask pixel_info, int pixel_format) ++{ ++ if (pixel_format == GRUB_EFI_GOT_RGBA8) { ++ si->lfb_depth = 32; ++ si->lfb_linelength = pixels_per_scan_line * 4; ++ si->red_size = 8; ++ si->red_pos = 0; ++ si->green_size = 8; ++ si->green_pos = 8; ++ si->blue_size = 8; ++ si->blue_pos = 16; ++ si->rsvd_size = 8; ++ si->rsvd_pos = 24; ++ } else if (pixel_format == GRUB_EFI_GOT_BGRA8) { ++ si->lfb_depth = 32; ++ si->lfb_linelength = pixels_per_scan_line * 4; ++ si->red_size = 8; ++ si->red_pos = 16; ++ si->green_size = 8; ++ si->green_pos = 8; ++ si->blue_size = 8; ++ si->blue_pos = 0; ++ si->rsvd_size = 8; ++ si->rsvd_pos = 24; ++ } else if (pixel_format == GRUB_EFI_GOT_BITMASK) { ++ find_bits(pixel_info.r, &si->red_pos, &si->red_size); ++ find_bits(pixel_info.g, &si->green_pos, ++ &si->green_size); ++ find_bits(pixel_info.b, &si->blue_pos, &si->blue_size); ++ find_bits(pixel_info.a, &si->rsvd_pos, ++ &si->rsvd_size); ++ si->lfb_depth = si->red_size + si->green_size + ++ si->blue_size + si->rsvd_size; ++ si->lfb_linelength = (pixels_per_scan_line * si->lfb_depth) / 8; ++ } else { ++ si->lfb_depth = 4; ++ si->lfb_linelength = si->lfb_width / 2; ++ si->red_size = 0; ++ si->red_pos = 0; ++ si->green_size = 0; ++ si->green_pos = 0; ++ si->blue_size = 0; ++ si->blue_pos = 0; ++ si->rsvd_size = 0; ++ si->rsvd_pos = 0; ++ } ++} ++ ++static struct screen_info *alloc_screen_info(void) ++{ ++ grub_efi_status_t status; ++ grub_efi_boot_services_t *b; ++ struct screen_info *si; ++ ++ b = grub_efi_system_table->boot_services; ++ status = efi_call_3 (b->allocate_pool, GRUB_EFI_RUNTIME_SERVICES_DATA, ++ sizeof(*si), (void**)&si); ++ if (status != GRUB_EFI_SUCCESS) ++ return NULL; ++ ++ grub_memset ((void *)si, 0, sizeof(struct screen_info)); ++ ++ status = b->install_configuration_table (&compat_screen_info_guid, si); ++ if (status != GRUB_EFI_SUCCESS) ++ goto free_mem; ++ ++ status = b->install_configuration_table (&screen_info_guid, si); ++ if (status == GRUB_EFI_SUCCESS) { ++ return si; ++ } ++ ++free_table: ++ b->install_configuration_table (&compat_screen_info_guid, NULL); ++free_mem: ++ efi_call_1 (b->free_pool, si); ++ ++ return NULL; ++} ++ ++static struct screen_info *setup_screen_info(void) ++{ ++ grub_efi_boot_services_t *b; ++ grub_efi_handle_t gop_handle; ++ struct screen_info *si = NULL; ++ struct grub_efi_gop *gop, *first_gop; ++ grub_efi_handle_t *handles; ++ grub_efi_uintn_t num_handles, i; ++ grub_efi_guid_t graphics_output_guid = GRUB_EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID; ++ grub_efi_uint16_t width, height; ++ grub_efi_uint32_t ext_lfb_base, pixels_per_scan_line; ++ grub_efi_uint64_t fb_base; ++ struct grub_efi_gop_pixel_bitmask pixel_info; ++ grub_efi_gop_pixel_format_t pixel_format; ++ ++ si = alloc_screen_info(); ++ if (!si) ++ return NULL; ++ ++ handles = grub_efi_locate_handle (GRUB_EFI_BY_PROTOCOL, ++ &graphics_output_guid, NULL, &num_handles); ++ if (!handles || num_handles == 0) ++ goto free_screen_info; ++ ++ gop = NULL; ++ first_gop = NULL; ++ ++ for (i = 0; i < num_handles; i++) ++ { ++ struct grub_efi_gop_mode *mode; ++ struct grub_efi_gop_mode_info *info = NULL; ++ grub_efi_guid_t conout_proto = GRUB_EFI_CONSOLE_OUT_DEVICE_GUID; ++ void *dummy = NULL; ++ grub_efi_uint8_t conout_found = 0; ++ grub_efi_uint64_t current_fb_base; ++ ++ gop_handle = handles[i]; ++ gop = grub_efi_open_protocol (gop_handle, &graphics_output_guid, ++ GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); ++ ++ dummy = grub_efi_open_protocol (gop_handle, &conout_proto, ++ GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); ++ if (dummy != NULL) ++ conout_found = 1; ++ ++ mode = gop->mode; ++ info = mode->info; ++ current_fb_base = mode->fb_base; ++ ++ if ((!first_gop || conout_found) && ++ info->pixel_format != GRUB_EFI_GOT_BLT_ONLY) { ++ /* ++ * Systems that use the UEFI Console Splitter may ++ * provide multiple GOP devices, not all of which are ++ * backed by real hardware. The workaround is to search ++ * for a GOP implementing the ConOut protocol, and if ++ * one isn't found, to just fall back to the first GOP. ++ */ ++ width = info->width; ++ height = info->height; ++ pixel_format = info->pixel_format; ++ pixel_info = info->pixel_bitmask; ++ pixels_per_scan_line = info->pixels_per_scanline; ++ fb_base = current_fb_base; ++ ++ /* ++ * Once we've found a GOP supporting ConOut, ++ * don't bother looking any further. ++ */ ++ first_gop = gop; ++ if (conout_found) ++ break; ++ } ++ } ++ ++ /* Did we find any GOPs? */ ++ if (!first_gop) ++ goto free_screen_info; ++ ++ /* EFI framebuffer */ ++ si->orig_video_isVGA = GRUB_VIDEO_TYPE_EFI; ++ ++ si->lfb_width = width; ++ si->lfb_height = height; ++ si->lfb_base = fb_base; ++ grub_dprintf ("loongson", "Screen info fb base: 0x%"PRIxGRUB_UINT32_T"\n", si->lfb_base); ++ ++ ext_lfb_base = (grub_uint64_t)fb_base >> 32; ++ if (ext_lfb_base) { ++ si->capabilities |= GRUB_VIDEO_CAPABILITY_64BIT_BASE; ++ si->ext_lfb_base = ext_lfb_base; ++ } ++ si->pages = 1; ++ ++ setup_pixel_info(si, pixels_per_scan_line, pixel_info, pixel_format); ++ ++ si->lfb_size = si->lfb_linelength * si->lfb_height; ++ si->capabilities |= GRUB_VIDEO_CAPABILITY_SKIP_QUIRKS; ++ ++ return si; ++ ++free_screen_info: ++ b = grub_efi_system_table->boot_services; ++ b->install_configuration_table (&compat_screen_info_guid, NULL); ++ b->install_configuration_table (&screen_info_guid, NULL); ++ if (si) ++ efi_call_1 (b->free_pool, si); ++ ++ grub_dprintf ("loongson", "No screen info\n"); ++ return NULL; ++} ++ ++static grub_err_t ++allocate_memmap_and_exit_boot (struct linux_loongarch64_kernel_params *kernel_params) ++{ ++ grub_err_t err; ++ grub_efi_status_t status; ++ grub_efi_uintn_t mmap_size, desc_size, size; ++ grub_efi_uint32_t desc_version; ++ grub_efi_memory_descriptor_t *mmap_buf; ++ grub_efi_boot_services_t *b; ++ struct efi_boot_memmap *m, tmp; ++ struct efi_initrd *tbl = NULL; ++ grub_efi_guid_t boot_memmap_guid = GRUB_EFI_BOOT_MEMMAP_GUID; ++ grub_efi_guid_t initrd_media_guid = GRUB_EFI_INITRD_MEDIA_GUID; ++ ++ setup_screen_info(); ++ ++ b = grub_efi_system_table->boot_services; ++ ++ grub_dprintf ("loongson", "ramdisk_addr:0x%"PRIxGRUB_UINT64_T", \ ++ size:0x%"PRIxGRUB_UINT64_T"\n", ++ kernel_params->ramdisk_addr, ++ kernel_params->ramdisk_size); ++#if 0 ++ char string[64]; ++ ++ /* Set initrd info to cmdline*/ ++ if (kernel_params->ramdisk_addr && kernel_params->ramdisk_size) ++ { ++ grub_printf ( "Initrd @ %p-%p\n", ++ (void *) kernel_params->ramdisk_addr, ++ (void *) (kernel_params->ramdisk_addr + kernel_params->ramdisk_size)); ++ /* initrd */ ++ grub_snprintf (string, ++ sizeof (GRUB_INITRD_STRING), ++ "initrd=0x%lx,0x%lx", ++ ((grub_uint64_t) kernel_params->ramdisk_addr & 0xffffffff), ++ (grub_uint64_t) kernel_params->ramdisk_size); ++ *(char*) ((grub_addr_t) kernel_params->linux_args + kernel_params->ramdisk_args_len - 2) = ' '; ++ grub_memcpy ((char*) ((grub_addr_t) kernel_params->linux_args + kernel_params->ramdisk_args_len - 1), ++ string, sizeof (GRUB_INITRD_STRING)); ++ } ++#else ++ /* Set initrd info to system table*/ ++ if (kernel_params->ramdisk_addr && kernel_params->ramdisk_size) ++ { ++ tbl = grub_efi_allocate_any_pages (GRUB_EFI_BYTES_TO_PAGES (sizeof(struct efi_initrd))); ++ if (!tbl) ++ return grub_error (GRUB_ERR_IO, "cannot allocate tbl memory"); ++ tbl->base = kernel_params->ramdisk_addr; ++ tbl->size = kernel_params->ramdisk_size; ++ ++ status = b->install_configuration_table (&initrd_media_guid, tbl); ++ if (status != GRUB_EFI_SUCCESS) { ++ grub_error (GRUB_ERR_IO, "failed to install initrd media"); ++ goto free_tbl; ++ } ++ } ++#endif ++ ++ tmp.map_size = 0; ++ status = grub_efi_get_memory_map (&tmp.map_size, NULL, &tmp.map_key, ++ &tmp.desc_size, &tmp.desc_ver); ++ if (status != 0) { ++ grub_error (GRUB_ERR_IO, "cannot get memory map"); ++ goto uninstall_initrd_table; ++ } ++ size = tmp.map_size + tmp.desc_size * GRUB_EFI_MMAP_NR_SLACK_SLOTS; ++ m = grub_efi_allocate_any_pages (GRUB_EFI_BYTES_TO_PAGES (sizeof(*m) + size)); ++ if (!m) { ++ grub_error (GRUB_ERR_IO, "cannot allocate m memory"); ++ goto uninstall_initrd_table; ++ } ++ ++ status = b->install_configuration_table (&boot_memmap_guid, m); ++ if (status != GRUB_EFI_SUCCESS) { ++ grub_error (GRUB_ERR_IO, "failed to install boot memmap"); ++ goto free_m; ++ } ++ ++ m->buff_size = m->map_size = size; ++ if (grub_efi_get_memory_map (&m->map_size, m->map, ++ &m->map_key, &m->desc_size, ++ &m->desc_ver) <= 0) ++ { ++ grub_error (GRUB_ERR_IO, "cannot get EFI memory map"); ++ goto uninstall_mem_table; ++ } ++ ++ mmap_size = grub_efi_find_mmap_size (); ++ if (! mmap_size) ++ goto uninstall_mem_table; ++ ++ mmap_buf = grub_efi_allocate_any_pages (GRUB_EFI_BYTES_TO_PAGES (mmap_size)); ++ err = grub_efi_finish_boot_services (&mmap_size, mmap_buf, NULL, ++ &desc_size, &desc_version); ++ if (err) { ++ grub_error (GRUB_ERR_IO, "failed to finish boot services"); ++ goto free_map; ++ } ++ ++ return 0; ++ ++free_map: ++ if (mmap_buf) ++ grub_efi_free_pages ((grub_addr_t) mmap_buf, ++ GRUB_EFI_BYTES_TO_PAGES (mmap_size)); ++ ++uninstall_mem_table: ++ b->install_configuration_table (&boot_memmap_guid, NULL); ++ ++free_m: ++ if (m) ++ grub_efi_free_pages ((grub_addr_t) m, ++ GRUB_EFI_BYTES_TO_PAGES (sizeof(*m) + size)); ++ ++uninstall_initrd_table: ++ if (kernel_params->ramdisk_addr && kernel_params->ramdisk_size) ++ b->install_configuration_table (&initrd_media_guid, NULL); ++ ++free_tbl: ++ if (kernel_params->ramdisk_addr && kernel_params->ramdisk_size) { ++ if (tbl) ++ grub_efi_free_pages ((grub_addr_t) tbl, ++ GRUB_EFI_BYTES_TO_PAGES (sizeof(struct efi_initrd))); ++ } ++ ++ return grub_error(GRUB_ERR_BAD_OS, "failed to V40 boot"); ++} ++ ++static grub_err_t ++allocate_fdt_and_exit_boot (struct linux_loongarch64_kernel_params *kernel_params) ++{ ++ int node, retval; ++ grub_err_t err; ++ unsigned int size; ++ grub_efi_uintn_t mmap_size; ++ grub_efi_uintn_t desc_size; ++ grub_efi_uint32_t desc_version; ++ grub_efi_memory_descriptor_t *mmap_buf; ++ ++ size = GRUB_FDT_EMPTY_TREE_SZ + FDT_ADDR_SIZE_EXTRA + GRUB_EFI_LINUX_FDT_EXTRA_SPACE; ++ ++ kernel_params->fdt = grub_efi_allocate_any_pages (GRUB_EFI_BYTES_TO_PAGES (size)); ++ if (!kernel_params->fdt) ++ return GRUB_ERR_OUT_OF_MEMORY; ++ ++ grub_fdt_create_empty_tree (kernel_params->fdt, size); ++ grub_fdt_set_prop32 (kernel_params->fdt, 0, FDT_ADDR_CELLS_STRING, 2); ++ grub_fdt_set_prop32 (kernel_params->fdt, 0, FDT_SIZE_CELLS_STRING, 2); ++ ++ node = grub_fdt_find_subnode (kernel_params->fdt, 0, "chosen"); ++ if (node < 0) ++ node = grub_fdt_add_subnode (kernel_params->fdt, 0, "chosen"); ++ if (node < 1) ++ goto failure; ++ ++ grub_dprintf ("loongson", "command_line %s, len %ld\n", (char *)kernel_params->linux_args, ++ grub_strlen(kernel_params->linux_args) + 1); ++ if ((kernel_params->linux_args != NULL) && (grub_strlen(kernel_params->linux_args) > 0)) { ++ retval = grub_fdt_set_prop (kernel_params->fdt, node, "bootargs", kernel_params->linux_args, ++ grub_strlen(kernel_params->linux_args) + 1); ++ if (retval) ++ goto failure; ++ } ++ ++ /* Set initrd info */ ++ if (kernel_params->ramdisk_addr && kernel_params->ramdisk_size) ++ { ++ grub_dprintf ("linux", "Initrd @ %p-%p\n", ++ (void *) kernel_params->ramdisk_addr, ++ (void *) (kernel_params->ramdisk_addr + kernel_params->ramdisk_size)); ++ ++ retval = grub_fdt_set_prop64 (kernel_params->fdt, node, "linux,initrd-start", ++ kernel_params->ramdisk_addr); ++ if (retval) ++ goto failure; ++ retval = grub_fdt_set_prop64 (kernel_params->fdt, node, "linux,initrd-end", ++ (kernel_params->ramdisk_addr + kernel_params->ramdisk_size)); ++ if (retval) ++ goto failure; ++ } ++ ++ node = grub_fdt_find_subnode (kernel_params->fdt, 0, "chosen"); ++ retval = grub_fdt_set_prop64 (kernel_params->fdt, node, "linux,uefi-system-table", ++ (grub_uint64_t)grub_efi_system_table); ++ if (retval) ++ goto failure; ++ ++ mmap_size = grub_efi_find_mmap_size (); ++ if (! mmap_size) ++ return grub_errno; ++ mmap_buf = grub_efi_allocate_any_pages (GRUB_EFI_BYTES_TO_PAGES (mmap_size)); ++ 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, &desc_version); ++ if (err) ++ return err; ++ ++ if (!mmap_buf || !mmap_size || !desc_size) ++ return GRUB_ERR_BAD_ARGUMENT; ++ ++ retval = grub_fdt_set_prop64 (kernel_params->fdt, node, "linux,uefi-mmap-start", ++ (grub_uint64_t)mmap_buf); ++ if (retval) ++ goto failure; ++ ++ retval = grub_fdt_set_prop32 (kernel_params->fdt, node, "linux,uefi-mmap-size", ++ mmap_size); ++ if (retval) ++ goto failure; ++ ++ retval = grub_fdt_set_prop32 (kernel_params->fdt, node, "linux,uefi-mmap-desc-size", ++ desc_size); ++ if (retval) ++ goto failure; ++ ++ retval = grub_fdt_set_prop32 (kernel_params->fdt, node, "linux,uefi-mmap-desc-ver", ++ desc_version); ++ if (retval) ++ goto failure; ++ ++ return GRUB_ERR_NONE; ++ ++failure: ++ if (!kernel_params->fdt) { ++ return GRUB_ERR_BAD_OS; ++ } ++ grub_efi_free_pages ((grub_addr_t) kernel_params->fdt, ++ GRUB_EFI_BYTES_TO_PAGES (grub_fdt_get_totalsize (kernel_params->fdt))); ++ kernel_params->fdt = NULL; ++ return grub_error(GRUB_ERR_BAD_OS, "failed to install/update FDT"); ++} ++ ++static void ++grub_linux_loongarch_elf_make_argv (struct linux_loongarch64_kernel_params *kernel_params) ++{ ++ static void* linux_args_addr; ++ int size; ++ grub_uint64_t *linux_argv; ++ char *args, *p, *linux_args; ++ int i, argc; ++ grub_err_t err; ++ ++ argc = kernel_params->linux_argc; ++ args = kernel_params->linux_args; ++ ++ /* new size */ ++ p = args; ++ size = (argc + 3 + 1) * sizeof (grub_uint64_t); /* orig arguments */ ++ for (i = 0; i < argc; i++) ++ { ++ size += ALIGN_UP (grub_strlen (p) + 1, 4); ++ p += grub_strlen (p) + 1; ++ } ++ ++ if (kernel_params->ramdisk_addr && kernel_params->ramdisk_size) ++ { ++ size += ALIGN_UP (sizeof (GRUB_RD_START_STRING), 4) \ ++ + ALIGN_UP (sizeof (GRUB_RD_SIZE_STRING), 4) \ ++ + ALIGN_UP (sizeof (GRUB_INITRD_STRING), 4); ++ } ++ size = ALIGN_UP (size, 8); ++ ++ /* alloc memory */ ++ linux_args_addr = grub_linux_loongarch_alloc_virtual_mem_align (size, 8, &err); ++ ++ linux_argv = linux_args_addr; ++ linux_args = (char *)(linux_argv + (argc + 1 + 3)); ++ p = args; ++ for (i = 0; i < argc; i++) ++ { ++ grub_memcpy (linux_args, p, grub_strlen (p) + 1); ++ *linux_argv = (grub_uint64_t) (grub_addr_t) linux_args; ++ linux_argv++; ++ linux_args += ALIGN_UP (grub_strlen (p) + 1, 4); ++ p += grub_strlen (p) + 1; ++ } ++ ++ if (kernel_params->ramdisk_addr && kernel_params->ramdisk_size) ++ { ++ /* rd_start */ ++ grub_snprintf (linux_args, ++ sizeof (GRUB_RD_START_STRING), ++ "rd_start=0x%lx", ++ (grub_uint64_t) kernel_params->ramdisk_addr); ++ *linux_argv = (grub_uint64_t) (grub_addr_t) linux_args; ++ linux_argv++; ++ linux_args += ALIGN_UP (sizeof (GRUB_RD_START_STRING), 4); ++ kernel_params->linux_argc++; ++ ++ /* rd_size */ ++ grub_snprintf (linux_args, ++ sizeof (GRUB_RD_SIZE_STRING), ++ "rd_size=0x%lx", ++ (grub_uint64_t) kernel_params->ramdisk_size); ++ *linux_argv = (grub_uint64_t) (grub_addr_t) linux_args; ++ linux_argv++; ++ linux_args += ALIGN_UP (sizeof (GRUB_RD_SIZE_STRING), 4); ++ kernel_params->linux_argc++; ++ ++ /* initrd */ ++ grub_snprintf (linux_args, ++ sizeof (GRUB_INITRD_STRING), ++ "initrd=0x%lx,0x%lx", ++ ((grub_uint64_t) kernel_params->ramdisk_addr & 0xffffffff), ++ (grub_uint64_t) kernel_params->ramdisk_size); ++ *linux_argv = (grub_uint64_t) (grub_addr_t) linux_args; ++ linux_argv++; ++ linux_args += ALIGN_UP (sizeof (GRUB_INITRD_STRING), 4); ++ kernel_params->linux_argc++; ++ } ++ ++ /* Reserve space for initrd arguments. */ ++ *linux_argv = 0; ++ ++ grub_free (kernel_params->linux_args); ++ kernel_params->linux_argv = (grub_addr_t) linux_args_addr; ++} ++ ++grub_err_t ++grub_linux_loongarch_elf_linux_boot_image (struct linux_loongarch64_kernel_params ++ *kernel_params) ++{ ++ struct boot_params_interface *boot_params = NULL; ++ struct grub_relocator64_state state; ++ grub_err_t err; ++ ++ /* linux kernel type is ELF */ ++ grub_memset (&state, 0, sizeof (state)); ++ ++ state.jumpreg = 1; ++ state.gpr[1] = kernel_params->kernel_addr; /* ra */ ++ if (grub_linux_loongarch_elf_get_boot_params (&boot_params) == 0) ++ { ++ grub_dprintf ("loongson", "V40 boot\n"); ++ if (allocate_memmap_and_exit_boot(kernel_params) != GRUB_ERR_NONE) ++ return grub_errno; ++ state.gpr[4] = 1 << FLAGS_EFI_SUPPORT_BIT; /* a0 = flag */ ++ state.gpr[5] = (grub_uint64_t)kernel_params->linux_args; /* a1 = cmdline */ ++ state.gpr[6] = (grub_uint64_t)grub_efi_system_table; /* a2 = system_table */ ++ } else { ++ grub_dprintf ("loongson", "BPI boot\n"); ++ grub_linux_loongarch_elf_make_argv (kernel_params); ++ state.gpr[4] = kernel_params->linux_argc; /* a0 = argc */ ++ state.gpr[5] = kernel_params->linux_argv; /* a1 = args */ ++ state.gpr[6] = (grub_uint64_t) boot_params; /* a2 = envp */ ++ err = grub_linux_loongarch_elf_boot_params (boot_params); ++ if (err) ++ return err; ++ } ++ ++ /* Boot the ELF kernel */ ++ grub_relocator64_boot (relocator, state); ++ ++ return GRUB_ERR_NONE; ++} ++ ++void* ++grub_linux_loongarch_alloc_virtual_mem_addr (grub_addr_t addr, ++ grub_size_t size, ++ grub_err_t *err) ++{ ++ relocator = grub_relocator_new (); ++ if (!relocator) ++ return NULL; ++ ++ grub_relocator_chunk_t ch; ++ *err = grub_relocator_alloc_chunk_addr (relocator, &ch, ++ grub_vtop ((void *) addr), ++ size); ++ if (*err) ++ return NULL; ++ return get_virtual_current_address (ch); ++} ++ ++void* ++grub_linux_loongarch_alloc_virtual_mem_align (grub_size_t size, ++ grub_size_t align, ++ grub_err_t *err) ++{ ++ grub_relocator_chunk_t ch; ++ ++ *err = grub_relocator_alloc_chunk_align (relocator, &ch, ++ 0x3000000, (0xffffffff - size) + 1, ++ size, align, ++ GRUB_RELOCATOR_PREFERENCE_LOW, 0); ++ return get_virtual_current_address (ch); ++} ++ ++void* ++grub_linux_loongarch_alloc_initrd_mem_align (grub_size_t size, ++ grub_size_t align, ++ grub_err_t *err) ++{ ++ grub_relocator_chunk_t ch; ++ ++ /* Firstly try to allocate from memory higher than 256MB */ ++ *err = grub_relocator_alloc_chunk_align (relocator, &ch, ++ 0x10000000, (0xffffffff - size) + 1, size, align, ++ GRUB_RELOCATOR_PREFERENCE_LOW, 0); ++ if (*err != GRUB_ERR_NONE) ++ { ++ /* Failed, try to allocate in range 0 ~ 256MB */ ++ *err = grub_relocator_alloc_chunk_align (relocator, &ch, ++ 0, (0xfffffff - size) + 1, size, align, ++ GRUB_RELOCATOR_PREFERENCE_HIGH, 0); ++ } ++ return get_virtual_current_address (ch); ++} ++ ++int ++grub_linux_loongarch_elf_get_boot_params (struct boot_params_interface **boot_params) ++{ ++ grub_efi_configuration_table_t *tables; ++ grub_efi_guid_t bpi_guid = GRUB_EFI_LOONGSON_BPI_TABLE_GUID; ++ unsigned int i; ++ int found = 0; ++ ++ /* Look for Loongson BPI in UEFI config tables. */ ++ tables = grub_efi_system_table->configuration_table; ++ ++ for (i = 0; i < grub_efi_system_table->num_table_entries; i++) ++ if (grub_memcmp (&tables[i].vendor_guid, &bpi_guid, sizeof (bpi_guid)) == 0) ++ { ++ *boot_params = tables[i].vendor_table; ++ char *p = (char*) &((*boot_params)->signature); ++ if (grub_strncmp (p, "BPI", 3) == 0) ++ { ++ found = 1; ++ break; ++ } ++ } ++ return found; ++} ++ ++static grub_uint8_t ++grub_kernel_update_checksum (const grub_uint8_t *buffer, grub_efi_uintn_t length) ++{ ++ grub_uint8_t sum; ++ grub_efi_uintn_t count; ++ ++ for (sum = 0, count = 0; count < length; count++) ++ { ++ sum = (grub_uint8_t) (sum + *(buffer + count)); ++ } ++ ++ return (grub_uint8_t) (0x100 - sum); ++} ++ ++static grub_uint32_t ++grub_efi_loongarch64_memmap_sort (struct memmap array[], ++ grub_uint32_t length, ++ struct loongsonlist_mem_map* bpmem, ++ grub_uint32_t index, ++ grub_uint32_t memtype) ++{ ++ grub_uint64_t tempmemsize = 0; ++ grub_uint32_t j = 0; ++ grub_uint32_t t = 0; ++ ++ for(j = 0; j < length;) ++ { ++ tempmemsize = array[j].mem_size; ++ for(t = j + 1; t < length; t++) ++ { ++ if(array[j].mem_start + tempmemsize == array[t].mem_start) ++ { ++ tempmemsize += array[t].mem_size; ++ } ++ else ++ { ++ break; ++ } ++ } ++ bpmem->map[index].mem_type = memtype; ++ bpmem->map[index].mem_start = array[j].mem_start; ++ bpmem->map[index].mem_size = tempmemsize; ++ grub_dprintf ("loongson", "map[%d]:type %"PRIuGRUB_UINT32_T", start 0x%" ++ PRIxGRUB_UINT64_T", end 0x%"PRIxGRUB_UINT64_T"\n", ++ index, ++ bpmem->map[index].mem_type, ++ bpmem->map[index].mem_start, ++ bpmem->map[index].mem_start+ bpmem->map[index].mem_size ++ ); ++ j = t; ++ index++; ++ } ++ return index; ++} ++ ++grub_err_t ++grub_linux_loongarch_elf_boot_params (struct boot_params_interface *boot_params) ++{ ++ grub_int8_t checksum = 0; ++ grub_err_t err; ++ ++ struct loongsonlist_mem_map *loongson_mem_map = NULL; ++ struct _extention_list_hdr * listpointer = NULL; ++ grub_uint32_t tmp_index = 0; ++ grub_efi_memory_descriptor_t * lsdesc = NULL; ++ ++ 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; ++ ++ grub_efi_uintn_t mmap_size; ++ grub_efi_uintn_t desc_size; ++ grub_efi_memory_descriptor_t *mmap_buf; ++ ++ struct memmap reserve_mem[GRUB_LOONGSON3_BOOT_MEM_MAP_MAX]; ++ struct memmap free_mem[GRUB_LOONGSON3_BOOT_MEM_MAP_MAX]; ++ struct memmap acpi_table_mem[GRUB_LOONGSON3_BOOT_MEM_MAP_MAX]; ++ struct memmap acpi_nvs_mem[GRUB_LOONGSON3_BOOT_MEM_MAP_MAX]; ++ ++ grub_memset (reserve_mem, 0, sizeof(struct memmap) * GRUB_LOONGSON3_BOOT_MEM_MAP_MAX); ++ grub_memset (free_mem, 0, sizeof(struct memmap) * GRUB_LOONGSON3_BOOT_MEM_MAP_MAX); ++ grub_memset (acpi_table_mem, 0, sizeof(struct memmap) * GRUB_LOONGSON3_BOOT_MEM_MAP_MAX); ++ grub_memset (acpi_nvs_mem, 0, sizeof(struct memmap) * GRUB_LOONGSON3_BOOT_MEM_MAP_MAX); ++ ++ /* Check extlist headers */ ++ listpointer = boot_params->extlist; ++ for( ;listpointer != NULL; listpointer = listpointer->next) ++ { ++ char *pl= (char *)&(listpointer->signature); ++ if(grub_strncmp(pl, "MEM", 3) == 0) ++ { ++ loongson_mem_map = (struct loongsonlist_mem_map *)listpointer; ++ break; ++ } ++ } ++ ++ mmap_size = grub_efi_find_mmap_size (); ++ if (! mmap_size) ++ return grub_errno; ++ mmap_buf = grub_efi_allocate_any_pages (GRUB_EFI_BYTES_TO_PAGES (mmap_size)); ++ 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); ++ if (err) ++ return err; ++ ++ if (!mmap_buf || !mmap_size || !desc_size) ++ return -1; ++ ++ /* ++ 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)) ++ { ++ /* System RAM */ ++ 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].mem_type = GRUB_ADDRESS_TYPE_SYSRAM; ++ free_mem[free_index].mem_start = (lsdesc->physical_start) & GRUB_EFI_MAX_PHY_ADDRESS; ++ free_mem[free_index].mem_size = lsdesc->num_pages * GRUB_EFI_PAGE_SIZE; ++ free_index++; ++ ++ /*ACPI*/ ++ }else if((lsdesc->type == GRUB_EFI_ACPI_RECLAIM_MEMORY)){ ++ acpi_table_mem[acpi_table_index].mem_type = GRUB_ADDRESS_TYPE_ACPI; ++ acpi_table_mem[acpi_table_index].mem_start = (lsdesc->physical_start) & GRUB_EFI_MAX_PHY_ADDRESS; ++ acpi_table_mem[acpi_table_index].mem_size = lsdesc->num_pages * GRUB_EFI_PAGE_SIZE; ++ acpi_table_index++; ++ }else if((lsdesc->type == GRUB_EFI_ACPI_MEMORY_NVS)){ ++ acpi_nvs_mem[acpi_nvs_index].mem_type = GRUB_ADDRESS_TYPE_NVS; ++ acpi_nvs_mem[acpi_nvs_index].mem_start = (lsdesc->physical_start) & GRUB_EFI_MAX_PHY_ADDRESS; ++ acpi_nvs_mem[acpi_nvs_index].mem_size = lsdesc->num_pages * GRUB_EFI_PAGE_SIZE; ++ acpi_nvs_index++; ++ ++ /* Reserve */ ++ }else{ ++ reserve_mem[reserve_index].mem_type = GRUB_ADDRESS_TYPE_RESERVED; ++ reserve_mem[reserve_index].mem_start = (lsdesc->physical_start) & GRUB_EFI_MAX_PHY_ADDRESS; ++ reserve_mem[reserve_index].mem_size = lsdesc->num_pages * GRUB_EFI_PAGE_SIZE; ++ reserve_index++; ++ } ++ } ++ ++ tmp_index = loongson_mem_map->map_count; ++ /*System RAM Sort*/ ++ tmp_index = grub_efi_loongarch64_memmap_sort(free_mem, ++ free_index, ++ loongson_mem_map, ++ tmp_index, ++ GRUB_ADDRESS_TYPE_SYSRAM); ++ /*ACPI Sort*/ ++ tmp_index = grub_efi_loongarch64_memmap_sort(acpi_table_mem, ++ acpi_table_index, ++ loongson_mem_map, ++ tmp_index, ++ GRUB_ADDRESS_TYPE_ACPI); ++ tmp_index = grub_efi_loongarch64_memmap_sort(acpi_nvs_mem, ++ acpi_nvs_index, ++ loongson_mem_map, ++ tmp_index, ++ GRUB_ADDRESS_TYPE_NVS); ++ ++ /*Reserve Sort*/ ++ { ++ grub_uint64_t loongarch_addr; ++ asm volatile ("csrrd %0, 0x181" : "=r" (loongarch_addr)); ++ if ((loongarch_addr & 0xff00000000000000) == 0x9000000000000000) ++ tmp_index = grub_efi_loongarch64_memmap_sort(reserve_mem, ++ reserve_index, ++ loongson_mem_map, ++ tmp_index, ++ GRUB_ADDRESS_TYPE_RESERVED); ++ else ++ tmp_index = grub_efi_loongarch64_memmap_sort(reserve_mem, ++ reserve_index, ++ loongson_mem_map, ++ tmp_index, ++ GRUB_ADDRESS_TYPE_RESERVED + 1); ++ } ++ loongson_mem_map->map_count = tmp_index; ++ loongson_mem_map->header.checksum = 0; ++ ++ checksum = grub_kernel_update_checksum ((grub_uint8_t *) loongson_mem_map, ++ loongson_mem_map->header.length); ++ loongson_mem_map->header.checksum = checksum; ++ ++ return grub_errno; ++} +diff --git a/grub-core/loader/loongarch64/linux.c b/grub-core/loader/loongarch64/linux.c +index 7594ca2..8dae4fe 100644 +--- a/grub-core/loader/loongarch64/linux.c ++++ b/grub-core/loader/loongarch64/linux.c +@@ -1,7 +1,6 @@ +-/* linux.c - boot Linux */ + /* + * GRUB -- GRand Unified Bootloader +- * Copyright (C) 2003,2004,2005,2007,2009,2010,2017 Free Software Foundation, Inc. ++ * Copyright (C) 2021 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 +@@ -17,346 +16,76 @@ + * along with GRUB. If not, see . + */ + +-#include +-#include +-#include +-#include + #include +-#include +-#include + #include + #include +-#include +-#include +-#include +-#include + #include + #include + #include +-#include ++#include + #include + + GRUB_MOD_LICENSE ("GPLv3+"); + +-#pragma GCC diagnostic ignored "-Wcast-align" +- +-typedef unsigned long size_t; ++#define INITRD_MAX_ADDRESS_OFFSET (32ULL * 1024 * 1024 * 1024) + +-#define FDT_ADDR_CELLS_STRING "#address-cells" +-#define FDT_SIZE_CELLS_STRING "#size-cells" +-#define FDT_ADDR_SIZE_EXTRA ((2 * grub_fdt_prop_entry_size (sizeof(grub_uint32_t))) + \ +- sizeof (FDT_ADDR_CELLS_STRING) + \ +- sizeof (FDT_SIZE_CELLS_STRING)) ++static struct linux_loongarch64_kernel_params kernel_params; + ++static grub_addr_t phys_addr; + static grub_dl_t my_mod; + static int loaded; +-static int initrd_loaded = 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, initrd_addr_arg_off; +- +-static void *fdt; +-static int is_fdt_boot; +-static grub_addr_t initrd_start, initrd_end; +-static char *fdt_linux_args; ++static int is_bpi_boot; ++static int grub_loongarch_linux_type = GRUB_LOONGARCH_LINUX_BAD; + + static grub_err_t +-allocate_fdt_and_exit_boot (void) ++grub_linux_boot (void) + { +- int node, retval; +- grub_err_t err; +- unsigned int size; +- grub_efi_uintn_t mmap_size; +- grub_efi_uintn_t desc_size; +- grub_efi_uint32_t desc_version; +- grub_efi_memory_descriptor_t *mmap_buf; +- +- size = GRUB_FDT_EMPTY_TREE_SZ + FDT_ADDR_SIZE_EXTRA + GRUB_EFI_LINUX_FDT_EXTRA_SPACE; +- +- fdt = grub_efi_allocate_any_pages (GRUB_EFI_BYTES_TO_PAGES (size)); +- if (!fdt) +- return GRUB_ERR_OUT_OF_MEMORY; +- +- grub_fdt_create_empty_tree (fdt, size); +- grub_fdt_set_prop32 (fdt, 0, FDT_ADDR_CELLS_STRING, 2); +- grub_fdt_set_prop32 (fdt, 0, FDT_SIZE_CELLS_STRING, 2); +- +- node = grub_fdt_find_subnode (fdt, 0, "chosen"); +- if (node < 0) +- node = grub_fdt_add_subnode (fdt, 0, "chosen"); +- if (node < 1) +- goto failure; +- +- grub_dprintf ("loongson", "command_line %s, len %ld\n", +- fdt_linux_args, grub_strlen(fdt_linux_args) + 1); +- if ((fdt_linux_args != NULL) && (grub_strlen(fdt_linux_args) > 0)) { +- retval = grub_fdt_set_prop (fdt, node, "bootargs", fdt_linux_args, +- grub_strlen(fdt_linux_args) + 1); +- if (retval) +- goto failure; +- } + +- /* Set initrd info */ +- if (initrd_start && initrd_end > initrd_start) +- { +- grub_dprintf ("linux", "Initrd @ %p-%p\n", +- (void *) initrd_start, (void *) initrd_end); +- +- retval = grub_fdt_set_prop64 (fdt, node, "linux,initrd-start", +- initrd_start); +- if (retval) +- goto failure; +- retval = grub_fdt_set_prop64 (fdt, node, "linux,initrd-end", +- initrd_end); +- if (retval) +- goto failure; ++ if (grub_loongarch_linux_type == GRUB_LOONGARCH_LINUX_EFI) { ++ if (finalize_efi_params_linux (&kernel_params) != GRUB_ERR_NONE) ++ return grub_errno; ++ return (grub_arch_efi_linux_boot_image((grub_addr_t) kernel_params.kernel_addr, ++ kernel_params.kernel_size, ++ kernel_params.linux_args)); + } +- +- node = grub_fdt_find_subnode (fdt, 0, "chosen"); +- retval = grub_fdt_set_prop64 (fdt, node, "linux,uefi-system-table", +- (grub_uint64_t)grub_efi_system_table); +- if (retval) +- goto failure; +- +- mmap_size = grub_efi_find_mmap_size (); +- if (! mmap_size) +- return grub_errno; +- mmap_buf = grub_efi_allocate_any_pages (GRUB_EFI_BYTES_TO_PAGES (mmap_size)); +- 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, &desc_version); +- if (err) +- return err; +- +- if (!mmap_buf || !mmap_size || !desc_size) +- return GRUB_ERR_BAD_ARGUMENT; +- +- retval = grub_fdt_set_prop64 (fdt, node, "linux,uefi-mmap-start", +- (grub_uint64_t)mmap_buf); +- if (retval) +- goto failure; +- +- retval = grub_fdt_set_prop32 (fdt, node, "linux,uefi-mmap-size", +- mmap_size); +- if (retval) +- goto failure; +- +- retval = grub_fdt_set_prop32 (fdt, node, "linux,uefi-mmap-desc-size", +- desc_size); +- if (retval) +- goto failure; +- +- retval = grub_fdt_set_prop32 (fdt, node, "linux,uefi-mmap-desc-ver", +- desc_version); +- if (retval) +- goto failure; +- +- return GRUB_ERR_NONE; +- +-failure: +- if (!fdt) { +- return GRUB_ERR_BAD_OS; ++ if (grub_loongarch_linux_type == GRUB_LOONGARCH_LINUX_ELF) { ++ return grub_linux_loongarch_elf_linux_boot_image (&kernel_params); + } +- grub_efi_free_pages ((grub_addr_t) fdt, +- GRUB_EFI_BYTES_TO_PAGES (grub_fdt_get_totalsize (fdt))); +- fdt = NULL; +- return grub_error(GRUB_ERR_BAD_OS, "failed to install/update FDT"); +-} +- +-static grub_err_t +-allocate_boot_params_and_exit_boot (void) +-{ +- grub_efi_uintn_t mmap_size; +- grub_efi_uintn_t desc_size; +- grub_efi_uint32_t desc_version; +- grub_efi_memory_descriptor_t *mmap_buf; +- grub_efi_memory_descriptor_t * lsdesc = NULL; +- grub_err_t err; +- struct boot_params_interface * boot_params; +- mem_map_v1 * mem_map_v1_table = NULL; +- unsigned long bpi_version = 0; +- grub_int8_t checksum = 0; +- grub_uint32_t tmp_index = 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; +- +- struct memmap_v1 reserve_mem_v1[GRUB_EFI_LOONGSON_MMAP_MAX]; +- struct memmap_v1 free_mem_v1[GRUB_EFI_LOONGSON_MMAP_MAX]; +- struct memmap_v1 acpi_table_mem_v1[GRUB_EFI_LOONGSON_MMAP_MAX]; +- struct memmap_v1 acpi_nvs_mem_v1[GRUB_EFI_LOONGSON_MMAP_MAX]; +- +- grub_memset(reserve_mem_v1, 0, sizeof(struct memmap_v1) * GRUB_EFI_LOONGSON_MMAP_MAX); +- grub_memset(free_mem_v1, 0, sizeof(struct memmap_v1) * GRUB_EFI_LOONGSON_MMAP_MAX); +- grub_memset(acpi_table_mem_v1, 0, sizeof(struct memmap_v1) * GRUB_EFI_LOONGSON_MMAP_MAX); +- grub_memset(acpi_nvs_mem_v1, 0, sizeof(struct memmap_v1) * GRUB_EFI_LOONGSON_MMAP_MAX); +- +- boot_params = (struct boot_params_interface *)grub_efi_loongson_get_boot_params(); +- +- ext_list * listpointer = NULL; +- /* Check extlist headers */ +- listpointer = boot_params->extlist; +- for( ;listpointer != NULL; listpointer = listpointer->next) +- { +- char *pl= (char *)&(listpointer->signature); +- if(grub_strncmp(pl, "MEM", 3) == 0) +- { +- mem_map_v1_table = (mem_map_v1 *)listpointer; +- break; +- } +- } +- +- mmap_size = grub_efi_find_mmap_size (); +- if (! mmap_size) +- return grub_errno; +- mmap_buf = grub_efi_allocate_any_pages (GRUB_EFI_BYTES_TO_PAGES (mmap_size)); +- 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, &desc_version); +- if (err) +- return err; +- +- if (!mmap_buf || !mmap_size || !desc_size) +- return GRUB_ERR_BAD_ARGUMENT; +- +- char *p = (char *)&(boot_params->signature); +- bpi_version = grub_efi_get_bpi_version(p); +- grub_dprintf("loongson", "get bpi version:%ld\n", bpi_version); +- +- if (bpi_version <= GRUB_EFI_BPI_VER_V2) +- { +- /* +- 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)) +- { +- grub_dprintf("loongson", "type:%d, phy_start:0x%lx, phy_end:0x%lx\n", lsdesc->type, +- lsdesc->physical_start, lsdesc->physical_start + lsdesc->num_pages * GRUB_EFI_PAGE_SIZE); +- +- /* System RAM */ +- 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_v1[free_index].memtype = GRUB_EFI_LOONGSON_SYSTEM_RAM; +- free_mem_v1[free_index].memstart = (lsdesc->physical_start) & GRUB_EFI_MAX_PHY_ADDRESS; +- free_mem_v1[free_index].memsize = lsdesc->num_pages * GRUB_EFI_PAGE_SIZE; +- free_index++; +- +- /*ACPI*/ +- } else if ((lsdesc->type == GRUB_EFI_ACPI_RECLAIM_MEMORY)){ +- acpi_table_mem_v1[acpi_table_index].memtype = GRUB_EFI_LOONGSON_ACPI_TABLE; +- acpi_table_mem_v1[acpi_table_index].memstart = (lsdesc->physical_start) & GRUB_EFI_MAX_PHY_ADDRESS; +- acpi_table_mem_v1[acpi_table_index].memsize = lsdesc->num_pages * GRUB_EFI_PAGE_SIZE; +- acpi_table_index++; +- } else if ((lsdesc->type == GRUB_EFI_ACPI_MEMORY_NVS)){ +- acpi_nvs_mem_v1[acpi_nvs_index].memtype = GRUB_EFI_LOONGSON_ACPI_NVS; +- acpi_nvs_mem_v1[acpi_nvs_index].memstart = (lsdesc->physical_start) & GRUB_EFI_MAX_PHY_ADDRESS; +- acpi_nvs_mem_v1[acpi_nvs_index].memsize = lsdesc->num_pages * GRUB_EFI_PAGE_SIZE; +- acpi_nvs_index++; +- +- /* Reserve */ +- } else { +- reserve_mem_v1[reserve_index].memtype = GRUB_EFI_LOONGSON_MEMORY_RESERVED; +- reserve_mem_v1[reserve_index].memstart = (lsdesc->physical_start) & GRUB_EFI_MAX_PHY_ADDRESS; +- reserve_mem_v1[reserve_index].memsize = lsdesc->num_pages * GRUB_EFI_PAGE_SIZE; +- reserve_index++; +- } +- } +- +- tmp_index = mem_map_v1_table->mapcount; +- /*System RAM Sort*/ +- tmp_index = grub_efi_loongson_memmap_v1_sort(free_mem_v1, free_index, mem_map_v1_table, +- tmp_index, GRUB_EFI_LOONGSON_SYSTEM_RAM); +- /*ACPI Sort*/ +- tmp_index = grub_efi_loongson_memmap_v1_sort(acpi_table_mem_v1, acpi_table_index, +- mem_map_v1_table, tmp_index, GRUB_EFI_LOONGSON_ACPI_TABLE); +- tmp_index = grub_efi_loongson_memmap_v1_sort(acpi_nvs_mem_v1, acpi_nvs_index, +- mem_map_v1_table, tmp_index, GRUB_EFI_LOONGSON_ACPI_NVS); +- /*Reserve Sort*/ +- { +- grub_uint64_t loongarch_addr; +- asm volatile ("csrrd %0, 0x181" : "=r" (loongarch_addr)); +- if ((loongarch_addr & 0xff00000000000000) == 0x9000000000000000) +- tmp_index = grub_efi_loongson_memmap_v1_sort(reserve_mem_v1, reserve_index, +- mem_map_v1_table, tmp_index, +- GRUB_EFI_LOONGSON_MEMORY_RESERVED); +- else +- tmp_index = grub_efi_loongson_memmap_v1_sort(reserve_mem_v1, reserve_index, +- mem_map_v1_table, tmp_index, +- GRUB_EFI_LOONGSON_MEMORY_RESERVED + 1); +- } +- mem_map_v1_table->mapcount = tmp_index; +- mem_map_v1_table->header.checksum = 0; +- +- checksum = grub_efi_loongson_grub_calculatechecksum8((grub_uint8_t *)mem_map_v1_table, +- mem_map_v1_table->header.length); +- mem_map_v1_table->header.checksum = checksum; +- } + + return GRUB_ERR_NONE; + } + + static grub_err_t +-grub_linux_boot (void) ++grub_linux_unload (void) + { +- struct grub_relocator64_state state; +- +- grub_memset (&state, 0, sizeof (state)); +- +- /* Boot the kernel. */ +- state.gpr[1] = entry_addr; +- grub_dprintf("loongson", "entry_addr is 0x%lx\n", state.gpr[1]); + +- if (is_fdt_boot == 1) +- { +- if (allocate_fdt_and_exit_boot () != GRUB_ERR_NONE) +- return grub_errno; ++ if (grub_loongarch_linux_type == GRUB_LOONGARCH_LINUX_EFI) { ++ if (kernel_params.ramdisk_addr) ++ grub_efi_free_pages ((grub_efi_physical_address_t) kernel_params.ramdisk_addr, ++ GRUB_EFI_BYTES_TO_PAGES (kernel_params.ramdisk_size)); ++ kernel_params.ramdisk_size = 0; + +- state.gpr[4] = 1 << FLAGS_EFI_SUPPORT_BIT; +- state.gpr[5] = (grub_uint64_t)fdt; +- state.gpr[6] = 0; +- } else { +- state.gpr[4] = linux_argc; +- state.gpr[5] = (grub_addr_t) linux_args_addr; +- state.gpr[6] = (grub_uint64_t)grub_efi_loongson_get_boot_params(); +- +- if (allocate_boot_params_and_exit_boot () != GRUB_ERR_NONE) +- return grub_errno; ++ if (kernel_params.kernel_addr) ++ grub_efi_free_pages ((grub_addr_t) kernel_params.kernel_addr, ++ GRUB_EFI_BYTES_TO_PAGES (kernel_params.kernel_size)); ++ kernel_params.kernel_addr = 0; + } +- grub_dprintf("loongson", "gpr[4]:%ld, gpr[5]:0x%lx, gpr[6]:0x%lx\n", +- state.gpr[4], state.gpr[5], state.gpr[6]); + +- state.jumpreg = 1; +- grub_relocator64_boot (relocator, state); +- +- return GRUB_ERR_NONE; +-} ++ if (grub_loongarch_linux_type == GRUB_LOONGARCH_LINUX_ELF) { ++ grub_free (kernel_params.linux_args); ++ kernel_params.linux_args = 0; ++ grub_linux_loongarch_elf_relocator_unload (); ++ } + +-static grub_err_t +-grub_linux_unload (void) +-{ +- grub_relocator_unload (relocator); + grub_dl_unref (my_mod); + loaded = 0; ++ grub_loongarch_linux_type = GRUB_LOONGARCH_LINUX_BAD; + + return GRUB_ERR_NONE; + } + +-static grub_err_t +-grub_linux_load64 (grub_elf_t elf, const char *filename) ++grub_err_t ++grub_linux_loongarch_elf_load_kernel (grub_elf_t elf, const char *filename) + { + Elf64_Addr base; + grub_err_t err; +@@ -365,16 +94,14 @@ grub_linux_load64 (grub_elf_t elf, const char *filename) + int flag; + + /* Linux's entry point incorrectly contains a virtual address. */ +- entry_addr = elf->ehdr.ehdr64.e_entry; +- grub_dprintf("loongson", "entry address = 0x%lx\n", entry_addr); ++ kernel_params.kernel_addr = elf->ehdr.ehdr64.e_entry; ++ kernel_params.kernel_size = grub_elf64_size (elf, &base, 0); + +- linux_size = grub_elf64_size (elf, &base, 0); +- grub_dprintf("loongson", "base = 0x%lx\n", base); +- +- if (linux_size == 0) ++ if (kernel_params.kernel_size == 0) + return grub_errno; +- target_addr = base; +- linux_size = ALIGN_UP (base + linux_size - base, 8); ++ ++ phys_addr = base; ++ kernel_params.kernel_size = ALIGN_UP (base + kernel_params.kernel_size - base, 8); + + asm volatile ("csrrd %0, 0x181" : "=r" (addr)); + if (addr & 0x1) { +@@ -382,157 +109,163 @@ grub_linux_load64 (grub_elf_t elf, const char *filename) + } else { + flag = GRUB_ELF_LOAD_FLAGS_30BITS; + base &= ~ELF64_LOADMASK; +- entry_addr &= ~ELF64_LOADMASK; ++ kernel_params.kernel_addr &= ~ELF64_LOADMASK; + } + +- 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 = grub_linux_loongarch_alloc_virtual_mem_addr (phys_addr, ++ kernel_params.kernel_size, ++ &err); ++ if (playground == NULL) ++ return err; + + /* Now load the segments into the area we claimed. */ +- return grub_elf64_load (elf, filename, playground - base, flag, 0, 0); ++ return grub_elf64_load (elf, filename, playground - base, ++ flag, 0, 0); + } + + static grub_err_t + grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + int argc, char *argv[]) + { +- grub_elf_t elf = 0; ++ grub_file_t file = 0; ++ struct linux_arch_kernel_header lh; ++ struct boot_params_interface *boot_params = NULL; ++ grub_elf_t elf = NULL; + grub_err_t err; +- int args_size = 0; ++ grub_size_t cmdline_size; ++ int i; + + grub_dl_ref (my_mod); + +- if (argc == 0) +- { +- return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); +- } +- +- elf = grub_elf_open (argv[0], GRUB_FILE_TYPE_LINUX_KERNEL); +- if (! elf) +- return grub_errno; ++ /* Release the previously used memory. */ ++ grub_loader_unset (); + +- if (elf->ehdr.ehdr64.e_type != ET_EXEC) ++ if (argc == 0) + { +- grub_elf_close (elf); +- return grub_error (GRUB_ERR_UNKNOWN_OS, +- N_("this ELF file is not of the right type")); ++ grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); ++ goto fail; + } + +- /* Release the previously used memory. */ +- grub_loader_unset (); +- loaded = 0; +- +- 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")); ++ file = grub_file_open (argv[0], GRUB_FILE_TYPE_LINUX_KERNEL); ++ if (!file) ++ goto fail; + +- grub_elf_close (elf); ++ kernel_params.kernel_size = grub_file_size (file); ++ grub_dprintf ("linux", "kernel file size: %" PRIuGRUB_SIZE "\n", ++ kernel_params.kernel_size); + +- if (err) +- return err; ++ if (grub_file_read (file, &lh, sizeof (lh)) < (long) sizeof (lh)) ++ return grub_errno; + +- if (grub_efi_loongson_get_boot_params() == NULL) { +- grub_size_t cmdline_size; ++ if (grub_arch_efi_linux_check_image (&lh) == GRUB_ERR_NONE) { ++ grub_loongarch_linux_type = GRUB_LOONGARCH_LINUX_EFI; ++ } + +- is_fdt_boot = 1; +- cmdline_size = grub_loader_cmdline_size (argc, argv) + sizeof (LINUX_IMAGE); +- fdt_linux_args = grub_malloc (cmdline_size); +- if (!fdt_linux_args) ++ if (grub_loongarch_linux_type != GRUB_LOONGARCH_LINUX_EFI) { ++ elf = grub_elf_file (file, argv[0]); ++ if (elf != NULL) + { +- grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")); +- goto fail; ++ /* linux kernel type is ELF */ ++ grub_loongarch_linux_type = GRUB_LOONGARCH_LINUX_ELF; ++ if (elf->ehdr.ehdr64.e_type != ET_EXEC) ++ { ++ grub_error (GRUB_ERR_UNKNOWN_OS, ++ N_("this ELF file is not of the right type")); ++ goto fail; ++ } ++ if (elf->ehdr.ehdr64.e_machine != EM_LOONGARCH64) ++ { ++ grub_error (GRUB_ERR_BAD_OS, "invalid magic number"); ++ goto fail; ++ } ++ ++ if (grub_elf_is_elf64 (elf)) ++ { ++ err = grub_linux_loongarch_elf_load_kernel (elf, argv[0]); ++ if (err) ++ goto fail; ++ } else { ++ grub_error (GRUB_ERR_BAD_OS, N_("invalid arch-dependent ELF magic")); ++ goto fail; ++ } ++ grub_dprintf ("linux", "kernel @ %p\n", (void*) elf->ehdr.ehdr64.e_entry); + } +- grub_memcpy (fdt_linux_args, LINUX_IMAGE, sizeof (LINUX_IMAGE)); +- err = grub_create_loader_cmdline (argc, argv, +- fdt_linux_args + sizeof (LINUX_IMAGE) - 1, +- cmdline_size, +- GRUB_VERIFY_KERNEL_CMDLINE); +- if (err) +- goto fail; +- grub_dprintf("loongson", "fdt linux args:%s\n", +- fdt_linux_args + sizeof (LINUX_IMAGE) - 1); +- + } else { +- int i; +- grub_uint64_t *linux_argv; +- char *linux_args; +- +- is_fdt_boot = 0; +- /* For arguments. */ +- linux_argc = argc; +- /* Main arguments. */ +- args_size = (linux_argc) * sizeof (grub_uint64_t); +- /* Initrd address/size and initrd */ +- args_size += 3 * sizeof (grub_uint64_t); +- /* NULL terminator. */ +- args_size += sizeof (grub_uint64_t); +- /* First argument is always "a0". */ +- args_size += ALIGN_UP (sizeof ("a0"), 4); +- /* Normal arguments. */ +- for (i = 1; i < argc; i++) +- args_size += ALIGN_UP (grub_strlen (argv[i]) + 1, 4); +- +- /* rd arguments. */ +- args_size += ALIGN_UP (sizeof ("rd_start=0xXXXXXXXXXXXXXXXX"), 4); +- args_size += ALIGN_UP (sizeof ("rd_size=0xXXXXXXXXXXXXXXXX"), 4); +- args_size += ALIGN_UP (sizeof ("initrd=0xXXXXXXXXXXXXXXXX,0xXXXXXXXXXXXXXXXX"), 4); +- +- args_size = ALIGN_UP (args_size, 8); +- +- linux_args_addr = grub_efi_allocate_any_pages (GRUB_EFI_BYTES_TO_PAGES (args_size)); +- grub_dprintf ("linux", "linux args numpages: %lld\n", +- (long long) GRUB_EFI_BYTES_TO_PAGES (args_size)); +- if (!linux_args_addr) +- { +- grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")); +- goto fail; ++ if (grub_file_seek (file, 0) == (grub_off_t) -1) ++ goto fail; ++ ++ if (grub_file_read (file, &lh, sizeof (lh)) < (grub_ssize_t) sizeof (lh)) ++ { ++ if (!grub_errno) ++ grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), ++ argv[0]); ++ goto fail; ++ } ++ ++ if (grub_arch_efi_linux_check_image (&lh) != GRUB_ERR_NONE) ++ { ++ goto fail; ++ } ++ /* linux kernel type is EFI */ ++ grub_loongarch_linux_type = GRUB_LOONGARCH_LINUX_EFI; ++ kernel_params.kernel_addr = (grub_addr_t) grub_efi_allocate_any_pages ( ++ GRUB_EFI_BYTES_TO_PAGES (kernel_params.kernel_size)); ++ grub_dprintf ("linux", "kernel numpages: %" PRIuGRUB_SIZE "\n", ++ GRUB_EFI_BYTES_TO_PAGES (kernel_params.kernel_size)); ++ if (!kernel_params.kernel_addr) ++ { ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")); ++ goto fail; ++ } ++ ++ grub_file_seek (file, 0); ++ if (grub_file_read (file, (void*) kernel_params.kernel_addr, kernel_params.kernel_size) ++ < (grub_int64_t) kernel_params.kernel_size) ++ { ++ if (!grub_errno) ++ grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), argv[0]); ++ goto fail; ++ } ++ ++ grub_dprintf ("linux", "kernel @ %p\n", (void*) kernel_params.kernel_addr); + } +- linux_argv = (grub_uint64_t *) linux_args_addr; +- linux_args = (char *) (linux_argv + (linux_argc + 1 + 3)); +- +- grub_memcpy (linux_args, "a0", sizeof ("a0")); +- *linux_argv = (grub_uint64_t) (grub_addr_t) linux_args; +- linux_argv++; +- linux_args += ALIGN_UP (sizeof ("a0"), 4); + +- for (i = 1; i < argc; i++) ++ cmdline_size = grub_loader_cmdline_size (argc, argv) + sizeof (LINUX_IMAGE) ++ + sizeof (GRUB_INITRD_STRING); ++ kernel_params.ramdisk_args_len = grub_loader_cmdline_size (argc, argv) + sizeof (LINUX_IMAGE); ++ kernel_params.linux_argc = argc; ++ kernel_params.linux_args = grub_malloc (cmdline_size); ++ if (!kernel_params.linux_args) + { +- grub_memcpy (linux_args, argv[i], grub_strlen (argv[i]) + 1); +- *linux_argv = (grub_uint64_t) (grub_addr_t) linux_args; +- linux_argv++; +- linux_args += ALIGN_UP (grub_strlen (argv[i]) + 1, 4); ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")); ++ goto fail; + } + +- /* 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++; ++ grub_memcpy (kernel_params.linux_args, LINUX_IMAGE, sizeof (LINUX_IMAGE)); + +- 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++; +- +- /* Reserve space for initrd arguments. */ +- initrd_addr_arg_off = (grub_uint8_t *) linux_args - linux_args_addr; +- linux_args += ALIGN_UP (sizeof ("initrd=0xXXXXXXXXXXXXXXXX,0xXXXXXXXXXXXXXXXX"), 4); +- *linux_argv = 0; +- linux_argv++; ++ if (grub_linux_loongarch_elf_get_boot_params (&boot_params) == 1) ++ is_bpi_boot = 1; ++ else ++ is_bpi_boot = 0; + +- *linux_argv = 0; ++ if (is_bpi_boot == 0) ++ { ++ err = grub_create_loader_cmdline (argc, argv, ++ (char*) ((grub_addr_t) kernel_params.linux_args + sizeof (LINUX_IMAGE) - 1), ++ kernel_params.ramdisk_args_len, ++ GRUB_VERIFY_KERNEL_CMDLINE); ++ if (err) ++ goto fail; ++ } else { ++ /* save args from linux cmdline */ ++ char *p = kernel_params.linux_args; ++ ++ p += sizeof (LINUX_IMAGE) - 1; ++ for (i=0; i < argc; i++) ++ { ++ grub_memcpy (p, argv[i], grub_strlen(argv[i]) + 1); ++ p += grub_strlen(argv[i]) + 1; ++ } + } + + if (grub_errno == GRUB_ERR_NONE) +@@ -541,133 +274,81 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + loaded = 1; + } + +- initrd_loaded = 0; +- + fail: ++ if (elf != NULL) { ++ /* grub_elf_close will call grub_file_close() */ ++ grub_elf_close (elf); ++ } else { ++ if (file) ++ grub_file_close (file); ++ } ++ + if (grub_errno != GRUB_ERR_NONE) + { + grub_dl_unref (my_mod); + loaded = 0; + } + +- if (fdt_linux_args && !loaded) +- grub_free (fdt_linux_args); ++ if (kernel_params.linux_args && !loaded) ++ grub_free (kernel_params.linux_args); + +- if (linux_args_addr && !loaded) +- grub_efi_free_pages ((grub_addr_t) linux_args_addr, +- GRUB_EFI_BYTES_TO_PAGES (args_size)); ++ if (grub_loongarch_linux_type == GRUB_LOONGARCH_LINUX_EFI) { ++ if (kernel_params.kernel_addr && !loaded) ++ grub_efi_free_pages ((grub_addr_t) kernel_params.kernel_addr, ++ GRUB_EFI_BYTES_TO_PAGES (kernel_params.kernel_size)); ++ } + + return grub_errno; + } + +-#define INITRD_MAX_ADDRESS_OFFSET (32ULL * 1024 * 1024 * 1024) +- +-/* +- * This function returns a pointer to a legally allocated initrd buffer, +- * or NULL if unsuccessful +- */ +-static void * +-allocate_initrd_mem (int initrd_pages) +-{ +- grub_addr_t max_addr; +- +- if (grub_efi_get_ram_base (&max_addr) != GRUB_ERR_NONE) +- return NULL; +- +- max_addr += INITRD_MAX_ADDRESS_OFFSET - 1; +- +- return grub_efi_allocate_pages_real (max_addr, initrd_pages, +- GRUB_EFI_ALLOCATE_MAX_ADDRESS, +- GRUB_EFI_LOADER_DATA); +-} +- +- + static grub_err_t + grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + int argc, char *argv[]) + { +- grub_size_t initrd_size, initrd_pages; +- grub_err_t err; +- void *initrd_mem = NULL; + struct grub_linux_initrd_context initrd_ctx = { 0, 0, 0 }; ++ grub_size_t initrd_size; ++ void *initrd_mem = NULL; ++ grub_err_t err; + + if (argc == 0) +- return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); ++ { ++ grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); ++ goto fail; ++ } + + 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."); ++ { ++ grub_error (GRUB_ERR_BAD_ARGUMENT, ++ N_("you need to load the kernel first")); ++ goto fail; ++ } + + if (grub_initrd_init (argc, argv, &initrd_ctx)) + goto fail; + + initrd_size = grub_get_initrd_size (&initrd_ctx); ++ grub_dprintf ("linux", "Loading initrd\n"); + +- if (is_fdt_boot == 1) //fdt +- { +- initrd_pages = (GRUB_EFI_BYTES_TO_PAGES (initrd_size)); +- initrd_mem = allocate_initrd_mem (initrd_pages); +- if (!initrd_mem) ++ initrd_mem = grub_linux_loongarch_alloc_initrd_mem_align (initrd_size, 0x10000, &err); ++ if (err) ++ goto fail; ++ ++ if (!initrd_mem) + { + grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")); + goto fail; + } +- } else { +- grub_relocator_chunk_t ch; +- err = grub_relocator_alloc_chunk_align (relocator, &ch, +- 0, (0xffffffff - initrd_size) + 1, +- initrd_size, 0x10000, +- GRUB_RELOCATOR_PREFERENCE_HIGH, 0); +- +- if (err) +- return err; +- initrd_mem = get_virtual_current_address (ch); +- } + + if (grub_initrd_load (&initrd_ctx, argv, initrd_mem)) + goto fail; + +- initrd_start = (grub_addr_t) initrd_mem; +- initrd_end = initrd_start + initrd_size; +- grub_dprintf ("linux", "[addr=%p, size=0x%lx]\n", +- (void *) initrd_start, initrd_size); +- +- if (is_fdt_boot == 0) //bpi +- { +- grub_snprintf ((char *) linux_args_addr + rd_addr_arg_off, +- sizeof ("rd_start=0xXXXXXXXXXXXXXXXX"), +- "rd_start=0x%lx", +- (grub_uint64_t) initrd_mem); +- ((grub_uint64_t *) linux_args_addr)[linux_argc] +- = (grub_uint64_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) initrd_size); +- ((grub_uint64_t *) linux_args_addr)[linux_argc] +- = (grub_uint64_t) ((grub_addr_t) linux_args_addr + rd_size_arg_off); +- linux_argc++; +- +- grub_snprintf ((char *) linux_args_addr + initrd_addr_arg_off, +- sizeof ("initrd=0xXXXXXXXXXXXXXXXX,0xXXXXXXXXXXXXXXXX"), +- "initrd=0x%lx,0x%lx", +- ((grub_uint64_t) initrd_mem & GRUB_EFI_MAX_PHY_ADDRESS), +- (grub_uint64_t) initrd_size); +- ((grub_uint64_t *) linux_args_addr)[linux_argc] +- = (grub_uint64_t) ((grub_addr_t) linux_args_addr + initrd_addr_arg_off); +- linux_argc++; +- } +- +- initrd_loaded = 1; +- +- fail: ++ /* save ramdisk addr and size */ ++ kernel_params.ramdisk_addr = (grub_addr_t) initrd_mem; ++ kernel_params.ramdisk_size = initrd_size; ++ grub_dprintf ("linux", "ramdisk [addr=%p, size=0x%lx]\n", ++ (void *) initrd_mem, initrd_size); ++fail: + grub_initrd_close (&initrd_ctx); +- if (is_fdt_boot == 1) +- if (initrd_mem && !initrd_start) +- grub_efi_free_pages ((grub_addr_t) initrd_mem, initrd_pages); + + return grub_errno; + } +@@ -677,9 +358,9 @@ static grub_command_t cmd_linux, cmd_initrd; + GRUB_MOD_INIT(linux) + { + cmd_linux = grub_register_command ("linux", grub_cmd_linux, +- 0, N_("Load Linux.")); ++ N_("FILE [ARGS...]"), N_("Load Linux.")); + cmd_initrd = grub_register_command ("initrd", grub_cmd_initrd, +- 0, N_("Load initrd.")); ++ N_("FILE"), N_("Load initrd.")); + my_mod = mod; + } + +diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h +index d5c805d..c34f9d1 100644 +--- a/include/grub/efi/api.h ++++ b/include/grub/efi/api.h +@@ -374,6 +374,26 @@ + { 0xa1, 0x92, 0xbf, 0x1d, 0x57, 0xd0, 0xb1, 0x89 } \ + } + ++#define GRUB_EFI_BOOT_MEMMAP_GUID \ ++ { 0x800f683f, 0xd08b, 0x423a, \ ++ { 0xa2, 0x93, 0x96, 0x5c, 0x3c, 0x6f, 0xe2, 0xb4 } \ ++ } ++ ++#define GRUB_EFI_INITRD_MEDIA_GUID \ ++ { 0x5568e427, 0x68fc, 0x4f3d, \ ++ { 0xac, 0x74, 0xca, 0x55, 0x52, 0x31, 0xcc, 0x68 } \ ++ } ++ ++#define GRUB_EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID \ ++ { 0x9042a9de, 0x23dc, 0x4a38, \ ++ { 0x96, 0xfb, 0x7a, 0xde, 0xd0, 0x80, 0x51, 0x6a } \ ++ } ++ ++#define GRUB_EFI_CONSOLE_OUT_DEVICE_GUID \ ++ { 0xd3b36f2c, 0xd551, 0x11d4, \ ++ { 0x9a, 0x46, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d } \ ++ } ++ + struct grub_efi_sal_system_table + { + grub_uint32_t signature; +diff --git a/include/grub/fdt.h b/include/grub/fdt.h +index a0710ab..2f4f270 100644 +--- a/include/grub/fdt.h ++++ b/include/grub/fdt.h +@@ -146,6 +146,6 @@ int EXPORT_FUNC(grub_fdt_set_prop) (void *fdt, unsigned int nodeoffset, const ch + grub_fdt_set_prop ((fdt), (nodeoffset), "reg", reg_64, 16); \ + }) + +-#endif /* defined(__arm__) || defined(__aarch64__) */ ++#endif /* defined(__arm__) || defined(__aarch64__) || defined(__loongarch__) */ + + #endif /* ! GRUB_FDT_HEADER */ +diff --git a/include/grub/loongarch64/asm.h b/include/grub/loongarch64/asm.h +deleted file mode 100644 +index c3e77e9..0000000 +--- a/include/grub/loongarch64/asm.h ++++ /dev/null +@@ -1,10 +0,0 @@ +-#ifndef GRUB_LOONGARCH64_ASM_HEADER +-#define GRUB_LOONGARCH64_ASM_HEADER 1 +- +-#define GRUB_ASM_T4 $a4 +-#define GRUB_ASM_T5 $a5 +-#define GRUB_ASM_SZREG 8 +-#define GRUB_ASM_REG_S st.d +-#define GRUB_ASM_REG_L ld.d +- +-#endif +diff --git a/include/grub/loongarch64/efi/loongson.h b/include/grub/loongarch64/efi/loongson.h +deleted file mode 100644 +index 7a9ccb4..0000000 +--- a/include/grub/loongarch64/efi/loongson.h ++++ /dev/null +@@ -1,113 +0,0 @@ +-/* +- * GRUB -- GRand Unified Bootloader +- * Copyright (C) 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 . +- */ +- +-#ifndef GRUB_EFI_LOONGSON_HEADER +-#define GRUB_EFI_LOONGSON_HEADER 1 +- +-#include +- +-#include +- +-#define GRUB_EFI_LOONGSON_BPI_TABLE_GUID \ +- { 0x4660f721, 0x2ec5, 0x416a, \ +- { 0x89, 0x9a, 0x43, 0x18, 0x02, 0x50, 0xa0, 0xc9 } \ +- } +- +-#define GRUB_EFI_MAX_PHY_ADDRESS 0xffffffffffffULL +-#define ELF32_LOADMASK (0xf0000000UL) +-#define ELF64_LOADMASK (0xf000000000000000ULL) +-#define FLAGS_EFI_SUPPORT_BIT 0 +-#define GRUB_EFI_LOONGSON_MMAP_MAX 128 +- +-typedef enum +- { +- GRUB_EFI_LOONGSON_SYSTEM_RAM = 1, +- GRUB_EFI_LOONGSON_MEMORY_RESERVED, +- GRUB_EFI_LOONGSON_ACPI_TABLE, +- GRUB_EFI_LOONGSON_ACPI_NVS, +- GRUB_EFI_LOONGSON_MAX_MEMORY_TYPE +- } +-grub_efi_loongson_memory_type; +- +-typedef enum +- { +- GRUB_EFI_BPI_VER_NONE = 0, +- GRUB_EFI_BPI_VER_V1 = 1000, +- GRUB_EFI_BPI_VER_V2 = 1001, +- } +- grub_efi_loongson_bpi_version; +- +-grub_uint8_t +-EXPORT_FUNC(grub_efi_loongson_calculatesum8) (const grub_uint8_t *Buffer, +- grub_efi_uintn_t Length); +- +-grub_uint8_t +-EXPORT_FUNC(grub_efi_loongson_grub_calculatechecksum8) (const grub_uint8_t *Buffer, +- grub_efi_uintn_t Length); +- +-unsigned long +-EXPORT_FUNC(grub_efi_get_bpi_version) (const char *str); +- +-void * +-EXPORT_FUNC(grub_efi_loongson_get_boot_params) (void); +- +-typedef struct _extention_list_hdr { +- grub_uint64_t signature; +- grub_uint32_t length; +- grub_uint8_t revision; +- grub_uint8_t checksum; +- union { +- struct _extention_list_hdr *next; +- grub_uint64_t next_offset; +- }; +-}GRUB_PACKED +-ext_list; +- +-typedef struct boot_params_interface { +- grub_uint64_t signature; //{'B', 'P', 'I', 'x', 'x', 'x', 'x', 'x'} +- grub_efi_system_table_t *systemtable; +- union { +- ext_list *extlist; +- grub_uint64_t extlist_offset; +- }; +- grub_uint64_t flags; +-}GRUB_PACKED +-boot_params_interface; +- +-typedef struct { +- ext_list header; //{MEM} +- grub_uint8_t mapcount; +- struct GRUB_PACKED memmap_v1 { +- grub_uint32_t memtype; +- grub_uint64_t memstart; +- grub_uint64_t memsize; +- } map[GRUB_EFI_LOONGSON_MMAP_MAX]; +-}GRUB_PACKED +-mem_map_v1; +- +-typedef struct { +- ext_list header; //{VBIOS} +- grub_uint64_t vbiosaddr; +-}GRUB_PACKED +-vbios; +- +-grub_uint32_t +-EXPORT_FUNC (grub_efi_loongson_memmap_v1_sort) (struct memmap_v1 array[], +- grub_uint32_t length, mem_map_v1 * mem, +- grub_uint32_t index, grub_uint32_t memtype); +-#endif /* ! GRUB_EFI_LOONGSON_HEADER */ +diff --git a/include/grub/loongarch64/efi/memory.h b/include/grub/loongarch64/efi/memory.h +index 73641a1..16b2e0b 100644 +--- a/include/grub/loongarch64/efi/memory.h ++++ b/include/grub/loongarch64/efi/memory.h +@@ -6,7 +6,12 @@ grub_efi_max_usable_address(void) + { + grub_uint64_t addr; + asm volatile ("csrrd %0, 0x181" : "=r" (addr)); +- return addr |= 0xffffffffffUL; ++ if (addr & 0x1) ++ addr |= 0xfffffffffffUL; ++ else ++ addr = 0xfffffffffffUL; ++ ++ return addr; + } + + #endif /* ! GRUB_MEMORY_CPU_HEADER */ +diff --git a/include/grub/loongarch64/efi/time.h b/include/grub/loongarch64/efi/time.h +deleted file mode 100644 +index e69de29..0000000 +diff --git a/include/grub/loongarch64/linux.h b/include/grub/loongarch64/linux.h +index 3c6cf65..4ac3c57 100644 +--- a/include/grub/loongarch64/linux.h ++++ b/include/grub/loongarch64/linux.h +@@ -28,8 +28,7 @@ + + #define GRUB_LOONGSON3_BOOT_MEM_MAP_MAX 128 + +-#define GRUB_LINUX_LOONGARCH_MAGIC_SIGNATURE 0x4C6F6F6E67417263 /* 'LoongArc' */ +-#define GRUB_LINUX_LOONGARCH_MAGIC_SIGNATURE2 0x68 /* 'h' */ ++#define GRUB_LINUX_LOONGARCH_MAGIC_SIGNATURE 0x6E6F73676E6F6F4C /* 'Loongson' */ + #define linux_arch_kernel_header linux_loongarch64_kernel_header + + /* From linux/Documentation/loongarch/booting.txt +@@ -48,27 +47,171 @@ struct linux_loongarch64_kernel_header + grub_uint64_t res0; /* reserved */ + grub_uint64_t res1; /* reserved */ + grub_uint64_t res2; /* reserved */ +- grub_uint64_t magic; /* Magic number, little endian, "LoongArc" */ +- grub_uint32_t magic1; /* Magic number, little endian, "h" */ ++ grub_uint64_t magic; /* Magic number, little endian, "Loongson" */ + grub_uint64_t res3; /* reserved */ ++ grub_uint32_t res4; /* reserved */ + grub_uint32_t hdr_offset; /* Offset of PE/COFF header */ + }; + + struct linux_loongarch64_kernel_params + { +- grub_addr_t kernel_addr; /* kernel entry address */ +- grub_size_t kernel_size; /* kernel size */ +- grub_addr_t ramdisk_addr; /* initrd load address */ +- grub_size_t ramdisk_size; /* initrd size */ +- int linux_argc; +- grub_addr_t linux_argv; ++ grub_addr_t kernel_addr; /* kernel entry address */ ++ grub_size_t kernel_size; /* kernel size */ ++ grub_addr_t ramdisk_addr; /* initrd load address */ ++ grub_size_t ramdisk_size; /* initrd size */ ++ int ramdisk_args_len; /* position of initrd in linux_args*/ ++ int linux_argc; /* cmdline parameters number*/ ++ grub_addr_t linux_argv; /* cmdline parameters address*/ + void* linux_args; ++ void* fdt; + }; + + #include + #include + ++#define GRUB_EFI_MAX_PHY_ADDRESS 0xffffffffffffULL + #define ELF32_LOADMASK (0xf0000000UL) + #define ELF64_LOADMASK (0xf000000000000000ULL) ++#define FLAGS_EFI_SUPPORT_BIT 0 ++ ++/*initrd info*/ ++#define GRUB_RD_START_STRING "rd_start=0xXXXXXXXXXXXXXXXX" ++#define GRUB_RD_SIZE_STRING "rd_size=0xXXXXXXXXXXXXXXXX" ++#define GRUB_INITRD_STRING "initrd=0xXXXXXXXXXXXXXXXX,0xXXXXXXXXXXXXXXXX" ++ ++#define FDT_ADDR_CELLS_STRING "#address-cells" ++#define FDT_SIZE_CELLS_STRING "#size-cells" ++#define FDT_ADDR_SIZE_EXTRA ((2 * grub_fdt_prop_entry_size (sizeof(grub_uint32_t))) + \ ++ sizeof (FDT_ADDR_CELLS_STRING) + \ ++ sizeof (FDT_SIZE_CELLS_STRING)) ++ ++struct efi_boot_memmap { ++ grub_efi_uintn_t map_size; ++ grub_efi_uintn_t desc_size; ++ grub_efi_uint32_t desc_ver; ++ grub_efi_uintn_t map_key; ++ grub_efi_uintn_t buff_size; ++ grub_efi_memory_descriptor_t map[]; ++}; ++ ++struct efi_initrd { ++ grub_efi_uintn_t base; ++ grub_efi_uintn_t size; ++}; ++ ++/* ++ * These are set up by the setup-routine at boot-time: ++ */ ++struct screen_info { ++ grub_efi_uint8_t orig_x; /* 0x00 */ ++ grub_efi_uint8_t orig_y; /* 0x01 */ ++ grub_efi_uint16_t ext_mem_k; /* 0x02 */ ++ grub_efi_uint16_t orig_video_page; /* 0x04 */ ++ grub_efi_uint8_t orig_video_mode; /* 0x06 */ ++ grub_efi_uint8_t orig_video_cols; /* 0x07 */ ++ grub_efi_uint8_t flags; /* 0x08 */ ++ grub_efi_uint8_t unused2; /* 0x09 */ ++ grub_efi_uint16_t orig_video_ega_bx;/* 0x0a */ ++ grub_efi_uint16_t unused3; /* 0x0c */ ++ grub_efi_uint8_t orig_video_lines; /* 0x0e */ ++ grub_efi_uint8_t orig_video_isVGA; /* 0x0f */ ++ grub_efi_uint16_t orig_video_points;/* 0x10 */ ++ ++ /* VESA graphic mode -- linear frame buffer */ ++ grub_efi_uint16_t lfb_width; /* 0x12 */ ++ grub_efi_uint16_t lfb_height; /* 0x14 */ ++ grub_efi_uint16_t lfb_depth; /* 0x16 */ ++ grub_efi_uint32_t lfb_base; /* 0x18 */ ++ grub_efi_uint32_t lfb_size; /* 0x1c */ ++ grub_efi_uint16_t cl_magic, cl_offset; /* 0x20 */ ++ grub_efi_uint16_t lfb_linelength; /* 0x24 */ ++ grub_efi_uint8_t red_size; /* 0x26 */ ++ grub_efi_uint8_t red_pos; /* 0x27 */ ++ grub_efi_uint8_t green_size; /* 0x28 */ ++ grub_efi_uint8_t green_pos; /* 0x29 */ ++ grub_efi_uint8_t blue_size; /* 0x2a */ ++ grub_efi_uint8_t blue_pos; /* 0x2b */ ++ grub_efi_uint8_t rsvd_size; /* 0x2c */ ++ grub_efi_uint8_t rsvd_pos; /* 0x2d */ ++ grub_efi_uint16_t vesapm_seg; /* 0x2e */ ++ grub_efi_uint16_t vesapm_off; /* 0x30 */ ++ grub_efi_uint16_t pages; /* 0x32 */ ++ grub_efi_uint16_t vesa_attributes; /* 0x34 */ ++ grub_efi_uint32_t capabilities; /* 0x36 */ ++ grub_efi_uint32_t ext_lfb_base; /* 0x3a */ ++ grub_efi_uint8_t _reserved[2]; /* 0x3e */ ++} __attribute__((packed)); ++ ++#define GRUB_VIDEO_TYPE_EFI 0x70 ++#define GRUB_VIDEO_CAPABILITY_SKIP_QUIRKS (1 << 0) ++#define GRUB_VIDEO_CAPABILITY_64BIT_BASE (1 << 1) /* Frame buffer base is 64-bit */ ++ ++ ++/* From arch/loongarch/include/asm/mach-loongson64/boot_param.h */ ++struct _extention_list_hdr { ++ grub_uint64_t signature; ++ grub_uint32_t length; ++ grub_uint8_t revision; ++ grub_uint8_t checksum; ++ union { ++ struct _extention_list_hdr *next; ++ grub_uint64_t next_offset; ++ }; ++ ++} GRUB_PACKED; ++ ++struct boot_params_interface { ++ grub_uint64_t signature; /* {"B", "P", "I", "0", "1", ... } */ ++ grub_efi_system_table_t *systemtable; ++ union { ++ struct _extention_list_hdr *extlist; ++ grub_uint64_t extlist_offset; ++ }; ++ grub_uint64_t flags; ++}GRUB_PACKED; ++ ++struct loongsonlist_mem_map { ++ struct _extention_list_hdr header; /* {"M", "E", "M"} */ ++ grub_uint8_t map_count; ++ struct memmap { ++ grub_uint32_t mem_type; ++ grub_uint64_t mem_start; ++ grub_uint64_t mem_size; ++ } GRUB_PACKED map[GRUB_LOONGSON3_BOOT_MEM_MAP_MAX]; ++}GRUB_PACKED; ++ ++grub_err_t ++finalize_efi_params_linux (struct linux_loongarch64_kernel_params *kernel_params); ++ ++grub_err_t ++grub_linux_loongarch_elf_linux_boot_image (struct linux_loongarch64_kernel_params ++ *kernel_params); ++ ++void* ++grub_linux_loongarch_alloc_virtual_mem_addr (grub_addr_t addr, ++ grub_size_t size, ++ grub_err_t *err); ++ ++void* ++grub_linux_loongarch_alloc_virtual_mem_align (grub_size_t size, ++ grub_size_t align, ++ grub_err_t *err); ++ ++void* ++grub_linux_loongarch_alloc_initrd_mem_align (grub_size_t size, ++ grub_size_t align, ++ grub_err_t *err); ++ ++void ++grub_linux_loongarch_elf_relocator_unload (void); ++ ++int ++grub_linux_loongarch_elf_get_boot_params (struct boot_params_interface **boot_params); ++ ++grub_err_t ++grub_linux_loongarch_elf_boot_params (struct boot_params_interface *boot_params); ++ ++grub_err_t ++grub_linux_loongarch_elf_load_kernel (grub_elf_t elf, const char *filename); + + #endif /* ! GRUB_LOONGARCH64_LINUX_HEADER */ +diff --git a/include/grub/loongarch64/time.h b/include/grub/loongarch64/time.h +index c9a7334..0a10fbd 100644 +--- a/include/grub/loongarch64/time.h ++++ b/include/grub/loongarch64/time.h +@@ -19,18 +19,6 @@ + #ifndef KERNEL_CPU_TIME_HEADER + #define KERNEL_CPU_TIME_HEADER 1 + +-#ifndef GRUB_UTIL +- +-#define GRUB_TICKS_PER_SECOND (grub_arch_cpuclock / 2) +- +-void grub_timer_init (grub_uint32_t cpuclock); +- +-/* Return the real time in ticks. */ +-grub_uint64_t grub_get_rtc (void); +- +-extern grub_uint32_t grub_arch_cpuclock; +-#endif +- + static inline void + grub_cpu_idle(void) + { +-- +2.43.5 + diff --git a/grub.patches b/grub.patches index b33f4191bed1138831fd748671a48a297e80e3a3..6ace98b4f771112233d356788933357a7a6a95a8 100644 --- a/grub.patches +++ b/grub.patches @@ -596,3 +596,4 @@ Patch1002: 1002-Add-LoongArch64-support-and-update-interface-to-v40.patch Patch1003: 1003-cryptodisk-make-the-password-getter-and-additional-a.patch Patch1004: 1004-cryptodisk-add-OS-provided-secret-support.patch Patch1005: 1005-efi-Add-API-for-retrieving-the-EFI-secret-for-crypto.patch +Patch1006: 1006-Update-patches-in-sync-with-loongarch64.patch diff --git a/grub2.spec b/grub2.spec index 0269b4f19451b36bbc3690495d10048e410a5868..f99f0858d516e04432abfd18ada937e52c0e16b6 100644 --- a/grub2.spec +++ b/grub2.spec @@ -1,4 +1,4 @@ -%define anolis_release .0.2 +%define anolis_release .0.3 %undefine _hardened_build %global tarversion 2.02 @@ -536,6 +536,9 @@ fi %endif %changelog +* Sat Mar 22 2025 Xue Liu - 2.02-160.0.3 +- Update for loongarch64 in sync with latest v2.04 + * Thu Jan 02 2025 hanliyang - 2.02-160.0.2 - Support use confidential computing provisioned secrets for disk decryption