diff --git a/0276-port-Add-LoongArch-support.patch b/0276-port-Add-LoongArch-support.patch new file mode 100644 index 0000000000000000000000000000000000000000..0dde2762e578dfc9b0b3c3dd42749a8834f4019e --- /dev/null +++ b/0276-port-Add-LoongArch-support.patch @@ -0,0 +1,3571 @@ +From 2bbda7ea6bb3b5d7da6484ddeec7b9e720faa312 Mon Sep 17 00:00:00 2001 +From: mengyingkun +Date: Thu, 12 Jan 2023 14:44:13 +0800 +Subject: [PATCH] port: Add LoongArch support + +This patch adds support for LoongArch. From now on, we can boot up +grub as a UEFI application on LoongArch platform. + +Signed-off-by: yangqiming +Signed-off-by: mengyingkun +--- + Makefile.util.def | 1 + + configure.ac | 24 + + gentpl.py | 9 +- + grub-core/Makefile.am | 6 + + grub-core/Makefile.core.def | 23 + + grub-core/kern/dl.c | 9 +- + grub-core/kern/efi/mm.c | 3 +- + grub-core/kern/loongarch64/cache.S | 26 + + grub-core/kern/loongarch64/dl.c | 163 ++++++ + grub-core/kern/loongarch64/dl_helper.c | 264 +++++++++ + grub-core/kern/loongarch64/efi/init.c | 73 +++ + grub-core/kern/loongarch64/efi/startup.S | 45 ++ + grub-core/kern/loongarch64/init.c | 47 ++ + .../lib/gnulib-patches/fix-loongarch.patch | 26 + + grub-core/lib/loongarch64/relocator.c | 163 ++++++ + grub-core/lib/loongarch64/relocator_asm.S | 51 ++ + grub-core/lib/loongarch64/setjmp.S | 68 +++ + grub-core/lib/setjmp.S | 2 + + grub-core/loader/efi/chainloader.c | 2 + + grub-core/loader/loongarch64/linux-efi.c | 144 +++++ + grub-core/loader/loongarch64/linux-elf.c | 529 ++++++++++++++++++ + grub-core/loader/loongarch64/linux.c | 398 +++++++++++++ + include/grub/efi/api.h | 2 +- + include/grub/efi/efi.h | 6 +- + include/grub/efi/pe32.h | 4 + + include/grub/elf.h | 30 + + include/grub/fdt.h | 4 +- + include/grub/loongarch64/efi/loader.h | 25 + + include/grub/loongarch64/efi/memory.h | 15 + + include/grub/loongarch64/efi/time.h | 0 + include/grub/loongarch64/io.h | 62 ++ + include/grub/loongarch64/linux.h | 144 +++++ + include/grub/loongarch64/loongarch64.h | 30 + + include/grub/loongarch64/memory.h | 59 ++ + include/grub/loongarch64/reloc.h | 113 ++++ + include/grub/loongarch64/relocator.h | 38 ++ + include/grub/loongarch64/setjmp.h | 27 + + include/grub/loongarch64/time.h | 39 ++ + include/grub/loongarch64/types.h | 34 ++ + include/grub/util/install.h | 1 + + util/grub-install-common.c | 1 + + util/grub-install.c | 16 + + util/grub-mkimagexx.c | 99 +++- + util/grub-module-verifier.c | 15 + + util/mkimage.c | 16 + + 45 files changed, 2842 insertions(+), 14 deletions(-) + create mode 100644 grub-core/kern/loongarch64/cache.S + create mode 100644 grub-core/kern/loongarch64/dl.c + create mode 100644 grub-core/kern/loongarch64/dl_helper.c + create mode 100644 grub-core/kern/loongarch64/efi/init.c + create mode 100644 grub-core/kern/loongarch64/efi/startup.S + create mode 100644 grub-core/kern/loongarch64/init.c + create mode 100644 grub-core/lib/gnulib-patches/fix-loongarch.patch + create mode 100644 grub-core/lib/loongarch64/relocator.c + create mode 100644 grub-core/lib/loongarch64/relocator_asm.S + create mode 100644 grub-core/lib/loongarch64/setjmp.S + create mode 100644 grub-core/loader/loongarch64/linux-efi.c + create mode 100644 grub-core/loader/loongarch64/linux-elf.c + create mode 100644 grub-core/loader/loongarch64/linux.c + create mode 100644 include/grub/loongarch64/efi/loader.h + create mode 100644 include/grub/loongarch64/efi/memory.h + create mode 100644 include/grub/loongarch64/efi/time.h + create mode 100644 include/grub/loongarch64/io.h + create mode 100644 include/grub/loongarch64/linux.h + create mode 100644 include/grub/loongarch64/loongarch64.h + create mode 100644 include/grub/loongarch64/memory.h + create mode 100644 include/grub/loongarch64/reloc.h + create mode 100644 include/grub/loongarch64/relocator.h + create mode 100644 include/grub/loongarch64/setjmp.h + create mode 100644 include/grub/loongarch64/time.h + create mode 100644 include/grub/loongarch64/types.h + +diff --git a/Makefile.util.def b/Makefile.util.def +index 3f191aa80950..1a044a9df0a8 100644 +--- a/Makefile.util.def ++++ b/Makefile.util.def +@@ -169,6 +169,7 @@ library = { + common = grub-core/kern/ia64/dl_helper.c; + common = grub-core/kern/arm/dl_helper.c; + common = grub-core/kern/arm64/dl_helper.c; ++ common = grub-core/kern/loongarch64/dl_helper.c; + common = grub-core/lib/minilzo/minilzo.c; + common = grub-core/lib/xzembed/xz_dec_bcj.c; + common = grub-core/lib/xzembed/xz_dec_lzma2.c; +diff --git a/configure.ac b/configure.ac +index d04c94691efe..dea4dfeda376 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -149,6 +149,10 @@ case "$target_cpu" in + riscv64*) + target_cpu=riscv64 + ;; ++ loongarch64) ++ target_cpu=loongarch64 ++ machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_CPU_LOONGARCH64=1" ++ ;; + esac + + # Specify the platform (such as firmware). +@@ -167,6 +171,7 @@ if test "x$with_platform" = x; then + powerpc64-*) platform=ieee1275 ;; + powerpc64le-*) platform=ieee1275 ;; + sparc64-*) platform=ieee1275 ;; ++ loongarch64-*) platform=efi ;; + mipsel-*) platform=loongson ;; + mips-*) platform=arc ;; + ia64-*) platform=efi ;; +@@ -218,6 +223,7 @@ case "$target_cpu"-"$platform" in + mipsel-yeeloong) platform=loongson ;; + mipsel-fuloong) platform=loongson ;; + mipsel-loongson) ;; ++ loongarch64-efi) ;; + arm-uboot) ;; + arm-coreboot) ;; + arm-efi) ;; +@@ -276,6 +282,7 @@ case "$platform" in + pc) machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_MACHINE_PCBIOS=1" ;; + emu) machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_MACHINE_EMU=1" ;; + loongson) machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_MACHINE_MIPS_LOONGSON=1" ;; ++ loongson64) machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_MACHINE_LOONARCH64=1" ;; + qemu_mips) machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_MACHINE_MIPS_QEMU_MIPS=1" ;; + arc) machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_MACHINE_ARC=1" ;; + esac +@@ -890,6 +897,21 @@ if ( test "x$target_cpu" = xi386 || test "x$target_cpu" = xx86_64 ) && test "x$p + TARGET_CFLAGS="$TARGET_CFLAGS -mno-mmx -mno-sse -mno-sse2 -mno-sse3 -mno-3dnow" + fi + ++if test "x$target_cpu" = xloongarch64; then ++ AC_CACHE_CHECK([whether _mno_explicit_relocs works], [grub_cv_cc_mno_explicit_relocs], [ ++ CFLAGS="$TARGET_CFLAGS -mno-explicit-relocs -Werror" ++ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])], ++ [grub_cv_cc_mno_explicit_relocs=yes], ++ [grub_cv_cc_mno_explicit_relocs=no]) ++ ]) ++ if test "x$grub_cv_cc_mno_explicit_relocs" = xyes; then ++ TARGET_CFLAGS="$TARGET_CFLAGS -mno-explicit-relocs -fno-plt" ++ TARGET_CCASFLAGS="$TARGET_CCASFLAGS -mno-explicit-relocs -fno-plt" ++ fi ++ TARGET_CFLAGS="$TARGET_CFLAGS -Wa,-mla-global-with-abs" ++ TARGET_CCASFLAGS="$TARGET_CCASFLAGS -Wa,-mla-global-with-abs" ++fi ++ + # Should grub utils get the host CFLAGS, or the target CFLAGS? + AC_ARG_WITH([utils], + AS_HELP_STRING([--with-utils=host|target|build], +@@ -2166,6 +2188,8 @@ AM_CONDITIONAL([COND_mips_arc], [test "(" x$target_cpu = xmips -o x$target_cpu = + AM_CONDITIONAL([COND_sparc64_ieee1275], [test x$target_cpu = xsparc64 -a x$platform = xieee1275]) + AM_CONDITIONAL([COND_sparc64_emu], [test x$target_cpu = xsparc64 -a x$platform = xemu]) + AM_CONDITIONAL([COND_powerpc_ieee1275], [test x$target_cpu = xpowerpc -a x$platform = xieee1275]) ++AM_CONDITIONAL([COND_loongarch64_efi], [test x$target_cpu = xloongarch64 -a x$platform = xefi]) ++AM_CONDITIONAL([COND_loongarch64], [test x$target_cpu = xloongarch64]) + AM_CONDITIONAL([COND_mips], [test x$target_cpu = xmips -o x$target_cpu = xmipsel]) + AM_CONDITIONAL([COND_mipsel], [test x$target_cpu = xmipsel]) + AM_CONDITIONAL([COND_mipseb], [test x$target_cpu = xmips]) +diff --git a/gentpl.py b/gentpl.py +index 59f62ef95229..f03aff85c2cd 100644 +--- a/gentpl.py ++++ b/gentpl.py +@@ -32,7 +32,8 @@ GRUB_PLATFORMS = [ "emu", "i386_pc", "i386_efi", "i386_qemu", "i386_coreboot", + "mips_loongson", "sparc64_ieee1275", + "powerpc_ieee1275", "mips_arc", "ia64_efi", + "mips_qemu_mips", "arm_uboot", "arm_efi", "arm64_efi", +- "arm_coreboot", "riscv32_efi", "riscv64_efi" ] ++ "arm_coreboot", "riscv32_efi", "riscv64_efi", ++ "loongarch64_efi" ] + + GROUPS = {} + +@@ -49,11 +50,12 @@ GROUPS["arm"] = [ "arm_uboot", "arm_efi", "arm_coreboot" ] + GROUPS["arm64"] = [ "arm64_efi" ] + GROUPS["riscv32"] = [ "riscv32_efi" ] + GROUPS["riscv64"] = [ "riscv64_efi" ] ++GROUPS["loongarch64"] = [ "loongarch64_efi" ] + + # Groups based on firmware + GROUPS["pc"] = [ "i386_pc" ] + GROUPS["efi"] = [ "i386_efi", "x86_64_efi", "ia64_efi", "arm_efi", "arm64_efi", +- "riscv32_efi", "riscv64_efi" ] ++ "riscv32_efi", "riscv64_efi", "loongarch64_efi" ] + GROUPS["ieee1275"] = [ "i386_ieee1275", "sparc64_ieee1275", "powerpc_ieee1275" ] + GROUPS["uboot"] = [ "arm_uboot" ] + GROUPS["xen"] = [ "i386_xen", "x86_64_xen" ] +@@ -80,7 +82,8 @@ 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", "riscv32_efi", "riscv64_efi" ] ++GROUPS["fdt"] = [ "arm64_efi", "arm_uboot", "arm_efi", "riscv32_efi", ++ "riscv64_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 dd49939aaa98..6582f1630d4d 100644 +--- a/grub-core/Makefile.am ++++ b/grub-core/Makefile.am +@@ -240,6 +240,12 @@ KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/memory.h + KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/kernel.h + endif + ++if COND_loongarch64_efi ++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 ++endif ++ + if COND_powerpc_ieee1275 + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/ieee1275/ieee1275.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/terminfo.h +diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def +index 2c1608bca48b..d7c01a8adbd9 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -103,6 +103,9 @@ kernel = { + arm_coreboot_ldflags = '-Wl,-r,-d'; + arm_coreboot_stripflags = '--strip-unneeded -K start -R .note -R .comment -R .note.gnu.gold-version'; + ++ loongarch64_efi_ldflags = '-Wl,-r,-d'; ++ loongarch64_efi_stripflags = '--strip-unneeded -K start -R .note -R .comment -R .note.gnu.gold-version -R .eh_frame'; ++ + i386_pc_startup = kern/i386/pc/startup.S; + i386_efi_startup = kern/i386/efi/startup.S; + x86_64_efi_startup = kern/x86_64/efi/startup.S; +@@ -122,6 +125,7 @@ kernel = { + arm64_efi_startup = kern/arm64/efi/startup.S; + riscv32_efi_startup = kern/riscv/efi/startup.S; + riscv64_efi_startup = kern/riscv/efi/startup.S; ++ loongarch64_efi_startup = kern/loongarch64/efi/startup.S; + + common = kern/buffer.c; + common = kern/command.c; +@@ -270,6 +274,9 @@ kernel = { + riscv64_efi = kern/riscv/efi/init.c; + riscv64_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; +@@ -351,6 +358,12 @@ kernel = { + riscv64 = kern/riscv/cache_flush.S; + riscv64 = kern/riscv/dl.c; + ++ loongarch64 = kern/loongarch64/init.c; ++ loongarch64 = kern/loongarch64/dl.c; ++ loongarch64 = kern/loongarch64/dl_helper.c; ++ loongarch64 = kern/loongarch64/cache.S; ++ loongarch64 = kern/generic/rtc_get_time_ms.c; ++ + fdt = lib/fdt.c; + + emu = disk/host.c; +@@ -873,6 +886,7 @@ module = { + enable = arm_coreboot; + enable = riscv32_efi; + enable = riscv64_efi; ++ enable = loongarch64_efi; + }; + + module = { +@@ -950,6 +964,7 @@ module = { + i386_multiboot = commands/acpihalt.c; + i386_efi = commands/acpihalt.c; + x86_64_efi = commands/acpihalt.c; ++ loongarch64_efi = commands/acpihalt.c; + i386_multiboot = lib/i386/halt.c; + i386_coreboot = lib/i386/halt.c; + i386_qemu = lib/i386/halt.c; +@@ -1731,6 +1746,8 @@ module = { + x86_64_xen = lib/x86_64/xen/relocator.S; + xen = lib/i386/relocator_common_c.c; + x86_64_efi = lib/x86_64/efi/relocator.c; ++ loongarch64 = lib/loongarch64/relocator_asm.S; ++ loongarch64 = lib/loongarch64/relocator.c; + + extra_dist = lib/i386/relocator_common.S; + extra_dist = kern/powerpc/cache_flush.S; +@@ -1740,6 +1757,7 @@ module = { + enable = x86; + enable = i386_xen_pvh; + enable = xen; ++ enable = loongarch64; + }; + + module = { +@@ -1772,6 +1790,7 @@ module = { + extra_dist = lib/arm/setjmp.S; + extra_dist = lib/arm64/setjmp.S; + extra_dist = lib/riscv/setjmp.S; ++ extra_dist = lib/loongarch64/setjmp.S; + }; + + module = { +@@ -1870,6 +1889,9 @@ module = { + arm64 = loader/arm64/linux.c; + riscv32 = loader/riscv/linux.c; + riscv64 = loader/riscv/linux.c; ++ loongarch64 = loader/loongarch64/linux.c; ++ loongarch64 = loader/loongarch64/linux-elf.c; ++ loongarch64 = loader/loongarch64/linux-efi.c; + emu = loader/emu/linux.c; + + common = loader/linux.c; +@@ -1969,6 +1991,7 @@ module = { + enable = riscv32_efi; + enable = riscv64_efi; + enable = mips; ++ enable = loongarch64_efi; + }; + + module = { +diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c +index d5de80186fa1..c60d49772bc3 100644 +--- a/grub-core/kern/dl.c ++++ b/grub-core/kern/dl.c +@@ -278,7 +278,8 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e) + unsigned i; + const Elf_Shdr *s; + grub_size_t tsize = 0, talign = 1, arch_addralign = 1; +-#if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv) ++#if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv) && \ ++ !defined (__loongarch__) + grub_size_t tramp; + grub_size_t got; + grub_err_t err; +@@ -307,7 +308,8 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e) + talign = sh_addralign; + } + +-#if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv) ++#if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv) && \ ++ !defined (__loongarch__) + err = grub_arch_dl_get_tramp_got_size (e, &tramp, &got); + if (err) + return err; +@@ -375,7 +377,8 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e) + mod->segment = seg; + } + } +-#if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv) ++#if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv) && \ ++ !defined (__loongarch__) + ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, GRUB_ARCH_DL_TRAMP_ALIGN); + mod->tramp = ptr; + mod->trampptr = ptr; +diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c +index 2c33758ed750..613a84488e75 100644 +--- a/grub-core/kern/efi/mm.c ++++ b/grub-core/kern/efi/mm.c +@@ -695,7 +695,8 @@ grub_efi_mm_init (void) + 2 * BYTES_TO_PAGES (MEMORY_MAP_SIZE)); + } + +-#if defined (__aarch64__) || defined (__arm__) || defined (__riscv) ++#if defined (__aarch64__) || defined (__arm__) || defined (__riscv) \ ++ || defined (__loongarch__) + grub_err_t + grub_efi_get_ram_base(grub_addr_t *base_addr) + { +diff --git a/grub-core/kern/loongarch64/cache.S b/grub-core/kern/loongarch64/cache.S +new file mode 100644 +index 000000000000..d291c6769c3c +--- /dev/null ++++ b/grub-core/kern/loongarch64/cache.S +@@ -0,0 +1,26 @@ ++/* ++ * 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 ++ ++FUNCTION (grub_arch_sync_caches) ++ jr $ra ++ ++FUNCTION (grub_arch_sync_dma_caches) ++ jr $ra ++ +diff --git a/grub-core/kern/loongarch64/dl.c b/grub-core/kern/loongarch64/dl.c +new file mode 100644 +index 000000000000..5442ec875478 +--- /dev/null ++++ b/grub-core/kern/loongarch64/dl.c +@@ -0,0 +1,163 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2022 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 ++ ++/* Check if EHDR is a valid ELF header. */ ++grub_err_t ++grub_arch_dl_check_header (void *ehdr) ++{ ++ Elf_Ehdr *e = ehdr; ++ ++ /* Check the magic numbers. */ ++ if (e->e_ident[EI_CLASS] != ELFCLASS64 ++ || e->e_ident[EI_DATA] != ELFDATA2LSB || e->e_machine != EM_LOONGARCH) ++ return grub_error (GRUB_ERR_BAD_OS, N_("invalid arch-dependent ELF magic")); ++ ++ return GRUB_ERR_NONE; ++} ++ ++#pragma GCC diagnostic ignored "-Wcast-align" ++ ++/* ++ * Unified function for both REL and RELA. ++ */ ++grub_err_t ++grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, ++ Elf_Shdr *s, grub_dl_segment_t seg) ++{ ++ Elf_Rel *rel, *max; ++ struct grub_loongarch64_stack stack; ++ grub_loongarch64_stack_init (&stack); ++ ++ for (rel = (Elf_Rel *) ((char *) ehdr + s->sh_offset), ++ max = (Elf_Rel *) ((char *) rel + s->sh_size); ++ rel < max; ++ rel = (Elf_Rel *) ((char *) rel + s->sh_entsize)) ++ { ++ Elf_Sym *sym; ++ void *place; ++ grub_uint64_t sym_addr; ++ ++ if (rel->r_offset >= seg->size) ++ return grub_error (GRUB_ERR_BAD_MODULE, ++ "reloc offset is outside the segment"); ++ ++ sym = (Elf_Sym *) ((char*)mod->symtab ++ + mod->symsize * ELF_R_SYM (rel->r_info)); ++ ++ sym_addr = sym->st_value; ++ if (s->sh_type == SHT_RELA) ++ sym_addr += ((Elf_Rela *) rel)->r_addend; ++ ++ place = (void *) ((grub_addr_t)seg->addr + rel->r_offset); ++ ++ switch (ELF_R_TYPE (rel->r_info)) ++ { ++ case R_LARCH_64: ++ { ++ grub_uint64_t *abs_place = place; ++ ++ grub_dprintf ("dl", "reloc_abs64 %p => 0x%016llx, %p\n", ++ place, (unsigned long long) sym_addr, abs_place); ++ ++ *abs_place += (grub_uint64_t) sym_addr; ++ } ++ break; ++ case R_LARCH_MARK_LA: ++ break; ++ case R_LARCH_SOP_PUSH_PCREL: ++ case R_LARCH_SOP_PUSH_PLT_PCREL: ++ grub_loongarch64_sop_push (&stack, sym_addr - (grub_uint64_t)place); ++ break; ++ case R_LARCH_B26: ++ { ++ grub_uint32_t *abs_place = place; ++ grub_ssize_t off = sym_addr - (grub_addr_t) place; ++ ++ grub_loongarch64_b26 (abs_place, off); ++ } ++ break; ++ case R_LARCH_ABS_HI20: ++ { ++ grub_uint32_t *abs_place = place; ++ grub_loongarch64_xxx_hi20 (abs_place, sym_addr); ++ } ++ break; ++ case R_LARCH_ABS64_LO20: ++ { ++ grub_uint32_t *abs_place = place; ++ grub_loongarch64_xxx64_lo20 (abs_place, sym_addr); ++ } ++ break; ++ case R_LARCH_ABS64_HI12: ++ { ++ grub_uint32_t *abs_place = place; ++ grub_loongarch64_xxx64_hi12 (abs_place, sym_addr); ++ } ++ break; ++ case R_LARCH_PCALA_HI20: ++ { ++ grub_uint32_t *abs_place = place; ++ grub_int32_t off = (((sym_addr + 0x800) & ~0xfffULL) - ((grub_addr_t)place & ~0xfffULL)); ++ ++ grub_loongarch64_xxx_hi20 (abs_place, off); ++ } ++ break; ++ case R_LARCH_ABS_LO12: ++ case R_LARCH_PCALA_LO12: ++ { ++ grub_uint32_t *abs_place = place; ++ grub_loongarch64_xxx_lo12 (abs_place, sym_addr); ++ } ++ break; ++ GRUB_LOONGARCH64_RELOCATION (&stack, place, sym_addr) ++ default: ++ { ++ char rel_info[17]; /* log16(2^64) = 16, plus NUL. */ ++ ++ grub_snprintf (rel_info, sizeof (rel_info) - 1, "%" PRIxGRUB_UINT64_T, ++ (grub_uint64_t) ELF_R_TYPE (rel->r_info)); ++ return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, ++ N_("relocation 0x%s is not implemented yet"), rel_info); ++ } ++ break; ++ } ++ } ++ return GRUB_ERR_NONE; ++} ++ ++/* ++ * Tell the loader what our minimum section alignment is. ++ */ ++grub_size_t ++grub_arch_dl_min_alignment (void) ++{ ++#ifdef GRUB_MACHINE_EFI ++ return 4096; ++#else ++ return 1; ++#endif ++} +diff --git a/grub-core/kern/loongarch64/dl_helper.c b/grub-core/kern/loongarch64/dl_helper.c +new file mode 100644 +index 000000000000..68275fea3339 +--- /dev/null ++++ b/grub-core/kern/loongarch64/dl_helper.c +@@ -0,0 +1,264 @@ ++/* dl_helper.c - relocation helper functions for modules and grub-mkimage */ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2022 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 ++ ++static void grub_loongarch64_stack_push (grub_loongarch64_stack_t stack, grub_uint64_t x); ++static grub_uint64_t grub_loongarch64_stack_pop (grub_loongarch64_stack_t stack); ++ ++void ++grub_loongarch64_stack_init (grub_loongarch64_stack_t stack) ++{ ++ stack->top = -1; ++ stack->count = LOONGARCH64_STACK_MAX; ++} ++ ++static void ++grub_loongarch64_stack_push (grub_loongarch64_stack_t stack, grub_uint64_t x) ++{ ++ if (stack->top == stack->count) ++ return; ++ stack->data[++stack->top] = x; ++} ++ ++static grub_uint64_t ++grub_loongarch64_stack_pop (grub_loongarch64_stack_t stack) ++{ ++ if (stack->top == -1) ++ return -1; ++ return stack->data[stack->top--]; ++} ++ ++void ++grub_loongarch64_sop_push (grub_loongarch64_stack_t stack, grub_int64_t offset) ++{ ++ grub_loongarch64_stack_push (stack, offset); ++} ++ ++/* opr2 = pop (), opr1 = pop (), push (opr1 - opr2) */ ++void ++grub_loongarch64_sop_sub (grub_loongarch64_stack_t stack) ++{ ++ grub_uint64_t a, b; ++ b = grub_loongarch64_stack_pop (stack); ++ a = grub_loongarch64_stack_pop (stack); ++ grub_loongarch64_stack_push (stack, a - b); ++} ++ ++/* opr2 = pop (), opr1 = pop (), push (opr1 << opr2) */ ++void ++grub_loongarch64_sop_sl (grub_loongarch64_stack_t stack) ++{ ++ grub_uint64_t a, b; ++ b = grub_loongarch64_stack_pop (stack); ++ a = grub_loongarch64_stack_pop (stack); ++ grub_loongarch64_stack_push (stack, a << b); ++} ++ ++/* opr2 = pop (), opr1 = pop (), push (opr1 >> opr2) */ ++void ++grub_loongarch64_sop_sr (grub_loongarch64_stack_t stack) ++{ ++ grub_uint64_t a, b; ++ b = grub_loongarch64_stack_pop (stack); ++ a = grub_loongarch64_stack_pop (stack); ++ grub_loongarch64_stack_push (stack, a >> b); ++} ++ ++/* opr2 = pop (), opr1 = pop (), push (opr1 + opr2) */ ++void ++grub_loongarch64_sop_add (grub_loongarch64_stack_t stack) ++{ ++ grub_uint64_t a, b; ++ b = grub_loongarch64_stack_pop (stack); ++ a = grub_loongarch64_stack_pop (stack); ++ grub_loongarch64_stack_push (stack, a + b); ++} ++ ++/* opr2 = pop (), opr1 = pop (), push (opr1 & opr2) */ ++void ++grub_loongarch64_sop_and (grub_loongarch64_stack_t stack) ++{ ++ grub_uint64_t a, b; ++ b = grub_loongarch64_stack_pop (stack); ++ a = grub_loongarch64_stack_pop (stack); ++ grub_loongarch64_stack_push (stack, a & b); ++} ++ ++/* opr3 = pop (), opr2 = pop (), opr1 = pop (), push (opr1 ? opr2 : opr3) */ ++void ++grub_loongarch64_sop_if_else (grub_loongarch64_stack_t stack) ++{ ++ grub_uint64_t a, b, c; ++ c = grub_loongarch64_stack_pop (stack); ++ b = grub_loongarch64_stack_pop (stack); ++ a = grub_loongarch64_stack_pop (stack); ++ ++ if (a) { ++ grub_loongarch64_stack_push (stack, b); ++ } else { ++ grub_loongarch64_stack_push (stack, c); ++ } ++} ++ ++/* opr1 = pop (), (*(uint32_t *) PC) [14 ... 10] = opr1 [4 ... 0] */ ++void ++grub_loongarch64_sop_32_s_10_5 (grub_loongarch64_stack_t stack, ++ grub_uint64_t *place) ++{ ++ grub_uint64_t a = grub_loongarch64_stack_pop (stack); ++ *place |= ((a & 0x1f) << 10); ++} ++ ++/* opr1 = pop (), (*(uint32_t *) PC) [21 ... 10] = opr1 [11 ... 0] */ ++void ++grub_loongarch64_sop_32_u_10_12 (grub_loongarch64_stack_t stack, ++ grub_uint64_t *place) ++{ ++ grub_uint64_t a = grub_loongarch64_stack_pop (stack); ++ *place = *place | ((a & 0xfff) << 10); ++} ++ ++/* opr1 = pop (), (*(uint32_t *) PC) [21 ... 10] = opr1 [11 ... 0] */ ++void ++grub_loongarch64_sop_32_s_10_12 (grub_loongarch64_stack_t stack, ++ grub_uint64_t *place) ++{ ++ grub_uint64_t a = grub_loongarch64_stack_pop (stack); ++ *place = (*place) | ((a & 0xfff) << 10); ++} ++ ++/* opr1 = pop (), (*(uint32_t *) PC) [25 ... 10] = opr1 [15 ... 0] */ ++void ++grub_loongarch64_sop_32_s_10_16 (grub_loongarch64_stack_t stack, ++ grub_uint64_t *place) ++{ ++ grub_uint64_t a = grub_loongarch64_stack_pop (stack); ++ *place = (*place) | ((a & 0xffff) << 10); ++} ++ ++/* opr1 = pop (), (*(uint32_t *) PC) [25 ... 10] = opr1 [17 ... 2] */ ++void ++grub_loongarch64_sop_32_s_10_16_s2 (grub_loongarch64_stack_t stack, ++ grub_uint64_t *place) ++{ ++ grub_uint64_t a = grub_loongarch64_stack_pop (stack); ++ *place = (*place) | (((a >> 2) & 0xffff) << 10); ++} ++ ++/* opr1 = pop (), (*(uint32_t *) PC) [24 ... 5] = opr1 [19 ... 0] */ ++void ++grub_loongarch64_sop_32_s_5_20 (grub_loongarch64_stack_t stack, grub_uint64_t *place) ++{ ++ grub_uint64_t a = grub_loongarch64_stack_pop (stack); ++ *place = (*place) | ((a & 0xfffff)<<5); ++} ++ ++/* opr1 = pop (), ++ (*(uint32_t *) PC) [4 ... 0] = opr1 [22 ... 18] ++ (*(uint32_t *) PC) [25 ...10] = opr1 [17 ... 2] ++ */ ++void ++grub_loongarch64_sop_32_s_0_5_10_16_s2 (grub_loongarch64_stack_t stack, ++ grub_uint64_t *place) ++{ ++ grub_uint64_t a = grub_loongarch64_stack_pop (stack); ++ ++ *place =(*place) | (((a >> 2) & 0xffff) << 10); ++ *place =(*place) | ((a >> 18) & 0x1f); ++} ++ ++/* ++ opr1 = pop () ++ (*(uint32_t *) PC) [9 ... 0] = opr1 [27 ... 18], ++ (*(uint32_t *) PC) [25 ... 10] = opr1 [17 ... 2] ++*/ ++void ++grub_loongarch64_sop_32_s_0_10_10_16_s2 (grub_loongarch64_stack_t stack, ++ grub_uint64_t *place) ++{ ++ grub_uint64_t a = grub_loongarch64_stack_pop (stack); ++ *place =(*place) | (((a >> 2) & 0xffff) << 10); ++ *place =(*place) | ((a >> 18) & 0x3ff); ++} ++ ++void grub_loongarch64_b26 (grub_uint32_t *place, grub_int64_t offset) ++{ ++ grub_uint32_t val; ++ const grub_uint32_t insmask = grub_cpu_to_le32_compile_time (0xfc000000); ++ ++ grub_dprintf ("dl", " reloc_xxxx64 %p %c= 0x%llx\n", ++ place, offset > 0 ? '+' : '-', ++ offset < 0 ? (long long) -(unsigned long long) offset : offset); ++ ++ val = ((offset >> 18) & 0x3ff) | (((offset >> 2) & 0xffff) << 10); ++ ++ *place &= insmask; ++ *place |= grub_cpu_to_le32 (val) & ~insmask; ++} ++ ++void grub_loongarch64_xxx_hi20 (grub_uint32_t *place, grub_int64_t offset) ++{ ++ const grub_uint32_t insmask = grub_cpu_to_le32_compile_time (0xfe00001f); ++ grub_uint32_t val; ++ ++ offset >>= 12; ++ val = ((offset & 0xfffff) << 5); ++ ++ *place &= insmask; ++ *place |= grub_cpu_to_le32 (val) & ~insmask; ++} ++ ++void grub_loongarch64_xxx_lo12 (grub_uint32_t *place, grub_int64_t offset) ++{ ++ const grub_uint32_t insmask = grub_cpu_to_le32_compile_time (0xffc003ff); ++ ++ *place &= insmask; ++ *place |= grub_cpu_to_le32 (offset << 10) & ~insmask; ++} ++ ++void grub_loongarch64_xxx64_hi12 (grub_uint32_t *place, grub_int64_t offset) ++{ ++ const grub_uint32_t insmask = grub_cpu_to_le32_compile_time (0xffc003ff); ++ grub_uint32_t val; ++ ++ offset >>= 52; ++ val = ((offset & 0xfff) << 10); ++ ++ *place &= insmask; ++ *place |= grub_cpu_to_le32 (val) & ~insmask; ++} ++ ++void grub_loongarch64_xxx64_lo20 (grub_uint32_t *place, grub_int64_t offset) ++{ ++ const grub_uint32_t insmask = grub_cpu_to_le32_compile_time (0xfe00001f); ++ grub_uint32_t val; ++ ++ offset >>= 32; ++ val = ((offset & 0xfffff) << 5); ++ ++ *place &= insmask; ++ *place |= grub_cpu_to_le32 (val) & ~insmask; ++} +diff --git a/grub-core/kern/loongarch64/efi/init.c b/grub-core/kern/loongarch64/efi/init.c +new file mode 100644 +index 000000000000..7f7c86676029 +--- /dev/null ++++ b/grub-core/kern/loongarch64/efi/init.c +@@ -0,0 +1,73 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2013 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 ++ ++static grub_uint64_t tmr; ++static grub_efi_event_t tmr_evt; ++ ++static grub_uint64_t ++grub_efi_get_time_ms (void) ++{ ++ return tmr; ++} ++ ++static void ++grub_loongson_increment_timer (grub_efi_event_t event __attribute__ ((unused)), ++ void *context __attribute__ ((unused))) ++{ ++ tmr += 10; ++} ++ ++void ++grub_machine_init (void) ++{ ++ grub_efi_boot_services_t *b; ++ ++ grub_efi_init (); ++ ++ b = grub_efi_system_table->boot_services; ++ efi_call_5 (b->create_event, GRUB_EFI_EVT_TIMER | GRUB_EFI_EVT_NOTIFY_SIGNAL, ++ GRUB_EFI_TPL_CALLBACK, grub_loongson_increment_timer, NULL, &tmr_evt); ++ efi_call_3 (b->set_timer, tmr_evt, GRUB_EFI_TIMER_PERIODIC, 100000); ++ ++ grub_install_get_time_ms (grub_efi_get_time_ms); ++} ++ ++void ++grub_machine_fini (int flags) ++{ ++ grub_efi_boot_services_t *b; ++ ++ if (!(flags & GRUB_LOADER_FLAG_NORETURN)) ++ return; ++ ++ b = grub_efi_system_table->boot_services; ++ ++ efi_call_3 (b->set_timer, tmr_evt, GRUB_EFI_TIMER_CANCEL, 0); ++ efi_call_1 (b->close_event, tmr_evt); ++ ++ grub_efi_fini (); ++} +diff --git a/grub-core/kern/loongarch64/efi/startup.S b/grub-core/kern/loongarch64/efi/startup.S +new file mode 100644 +index 000000000000..1ffff0867b6e +--- /dev/null ++++ b/grub-core/kern/loongarch64/efi/startup.S +@@ -0,0 +1,45 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2013 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 ++ ++ .file "startup.S" ++ .text ++ .globl start, _start ++ .align 4 ++ ++FUNCTION(start) ++FUNCTION(_start) ++ /* ++ * EFI_SYSTEM_TABLE and EFI_HANDLE are passed in a1/a0. ++ */ ++ addi.d $sp, $sp, -16 ++ st.d $ra, $sp, 0 ++ ++ la $a2, grub_efi_image_handle ++ st.d $a0, $a2, 0 ++ la $a2, grub_efi_system_table ++ st.d $a1, $a2, 0 ++ ++ bl grub_main ++ ++1: ++ 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 +new file mode 100644 +index 000000000000..b2de9309c153 +--- /dev/null ++++ b/grub-core/kern/loongarch64/init.c +@@ -0,0 +1,47 @@ ++/* ++ * 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/gnulib-patches/fix-loongarch.patch b/grub-core/lib/gnulib-patches/fix-loongarch.patch +new file mode 100644 +index 000000000000..fa0b09ac52fd +--- /dev/null ++++ b/grub-core/lib/gnulib-patches/fix-loongarch.patch +@@ -0,0 +1,26 @@ ++diff --git a/build-aux/config.guess b/build-aux/config.guess ++index 8e2a58b..927581d 100755 ++--- a/build-aux/config.guess +++++ b/build-aux/config.guess ++@@ -990,6 +990,9 @@ EOF ++ k1om:Linux:*:*) ++ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" ++ exit ;; +++ loongarch32:Linux:*:* | loongarch64:Linux:*:* | loongarchx32:Linux:*:*) +++ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" +++ exit ;; ++ m32r*:Linux:*:*) ++ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" ++ exit ;; ++diff --git a/build-aux/config.sub b/build-aux/config.sub ++index 1fc4cde..6303428 100755 ++--- a/build-aux/config.sub +++++ b/build-aux/config.sub ++@@ -1184,6 +1184,7 @@ case $cpu-$vendor in ++ | k1om \ ++ | le32 | le64 \ ++ | lm32 \ +++ | loongarch32 | loongarch64 | loongarchx32 \ ++ | m32c | m32r | m32rle \ ++ | m5200 | m68000 | m680[012346]0 | m68360 | m683?2 | m68k | v70 | w65 \ ++ | m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip \ +diff --git a/grub-core/lib/loongarch64/relocator.c b/grub-core/lib/loongarch64/relocator.c +new file mode 100644 +index 000000000000..faa4553a5232 +--- /dev/null ++++ b/grub-core/lib/loongarch64/relocator.c +@@ -0,0 +1,163 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2022 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 ++ ++extern grub_uint8_t grub_relocator_forward_start; ++extern grub_uint8_t grub_relocator_forward_end; ++extern grub_uint8_t grub_relocator_backward_start; ++extern grub_uint8_t grub_relocator_backward_end; ++ ++#define REGW_SIZEOF (4 * sizeof (grub_uint32_t)) ++#define JUMP_SIZEOF (2 * sizeof (grub_uint32_t)) ++ ++#define RELOCATOR_SRC_SIZEOF(x) (&grub_relocator_##x##_end \ ++ - &grub_relocator_##x##_start) ++#define RELOCATOR_SIZEOF(x) (RELOCATOR_SRC_SIZEOF(x) \ ++ + REGW_SIZEOF * 3) ++grub_size_t grub_relocator_align = sizeof (grub_uint64_t); ++grub_size_t grub_relocator_forward_size; ++grub_size_t grub_relocator_backward_size; ++grub_size_t grub_relocator_jumper_size = JUMP_SIZEOF + REGW_SIZEOF; ++ ++void ++grub_cpu_relocator_init (void) ++{ ++ grub_relocator_forward_size = RELOCATOR_SIZEOF(forward); ++ grub_relocator_backward_size = RELOCATOR_SIZEOF(backward); ++} ++ ++static void ++write_reg (int regn, grub_uint64_t val, void **target) ++{ ++ grub_uint32_t lu12iw=0x14000000; ++ grub_uint32_t ori=0x03800000; ++ grub_uint32_t lu32id=0x16000000; ++ grub_uint32_t lu52id=0x03000000; ++ ++ *(grub_uint32_t *) *target = (lu12iw | (grub_uint32_t)((val & 0xfffff000)>>12<<5) | (grub_uint32_t)regn);; ++ *target = ((grub_uint32_t *) *target) + 1; ++ *(grub_uint32_t *) *target = (ori | (grub_uint32_t)((val & 0xfff)<<10) | (grub_uint32_t)(regn | regn<<5)); ++ *target = ((grub_uint32_t *) *target) + 1; ++ *(grub_uint32_t *) *target = (lu32id | (grub_uint32_t)((val & 0xfffff00000000)>>32<<5) | (grub_uint32_t)regn);; ++ *target = ((grub_uint32_t *) *target) + 1; ++ *(grub_uint32_t *) *target = (lu52id | (grub_uint32_t)((val & 0xfff0000000000000)>>52<<10) | (grub_uint32_t)(regn | regn<<5));; ++ *target = ((grub_uint32_t *) *target) + 1; ++} ++ ++static void ++write_jump (int regn, void **target) ++{ ++ grub_uint32_t jirl=0x4c000000; ++ ++ *(grub_uint32_t *) *target = (jirl | (grub_uint32_t)(regn<<5)); ++ *target = ((grub_uint32_t *) *target) + 1; ++} ++ ++void ++grub_cpu_relocator_jumper (void *rels, grub_addr_t addr) ++{ ++ write_reg (1, addr, &rels); ++ write_jump (1, &rels); ++} ++ ++void ++grub_cpu_relocator_backward (void *ptr0, void *src, void *dest, ++ grub_size_t size) ++{ ++ void *ptr = ptr0; ++ write_reg (8, (grub_uint64_t) src, &ptr); ++ write_reg (9, (grub_uint64_t) dest, &ptr); ++ write_reg (10, (grub_uint64_t) size, &ptr); ++ grub_memcpy (ptr, &grub_relocator_backward_start, ++ RELOCATOR_SRC_SIZEOF (backward)); ++} ++ ++void ++grub_cpu_relocator_forward (void *ptr0, void *src, void *dest, ++ grub_size_t size) ++{ ++ void *ptr = ptr0; ++ write_reg (8, (grub_uint64_t) src, &ptr); ++ write_reg (9, (grub_uint64_t) dest, &ptr); ++ write_reg (10, (grub_uint64_t) size, &ptr); ++ grub_memcpy (ptr, &grub_relocator_forward_start, ++ RELOCATOR_SRC_SIZEOF (forward)); ++} ++ ++grub_err_t ++grub_relocator64_boot (struct grub_relocator *rel, ++ struct grub_relocator64_state state) ++{ ++ grub_relocator_chunk_t ch; ++ void *ptr; ++ grub_err_t err; ++ void *relst; ++ grub_size_t relsize; ++ grub_size_t stateset_size = 31 * REGW_SIZEOF + JUMP_SIZEOF; ++ unsigned i; ++ grub_addr_t vtarget; ++ ++ err = grub_relocator_alloc_chunk_align (rel, &ch, 0, ++ (0xffffffff - stateset_size) ++ + 1, stateset_size, ++ grub_relocator_align, ++ GRUB_RELOCATOR_PREFERENCE_NONE, 0); ++ if (err) ++ return err; ++ ++ ptr = get_virtual_current_address (ch); ++ for (i = 1; i < 32; i++) ++ write_reg (i, state.gpr[i], &ptr); ++ write_jump (state.jumpreg, &ptr); ++ ++ vtarget = (grub_addr_t) grub_map_memory (get_physical_target_address (ch), ++ stateset_size); ++ ++ err = grub_relocator_prepare_relocs (rel, vtarget, &relst, &relsize); ++ if (err) ++ return err; ++ ++ grub_arch_sync_caches ((void *) relst, relsize); ++ ++ asm volatile ( ++ "ibar 0 \n"); ++ ++ grub_uint64_t val; ++ __asm__ __volatile__( ++ "li.w %0, 0x4\n\t" ++ "csrxchg $r0, %0, 0x0\n\t" ++ : "=r"(val) ++ : ++ : ++ ); ++ ++ ((void (*) (void)) relst) (); ++ ++ /* Not reached. */ ++ return GRUB_ERR_NONE; ++} +diff --git a/grub-core/lib/loongarch64/relocator_asm.S b/grub-core/lib/loongarch64/relocator_asm.S +new file mode 100644 +index 000000000000..ffdccc903e5f +--- /dev/null ++++ b/grub-core/lib/loongarch64/relocator_asm.S +@@ -0,0 +1,51 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2022 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 ++ ++ .p2align 4 /* force 16-byte alignment */ ++ ++VARIABLE (grub_relocator_forward_start) ++ ++copycont1: ++ ld.d $r11,$r8,0 ++ st.d $r11,$r9,0 ++ addi.d $r8, $r8, 8 ++ addi.d $r10, $r10, -8 ++ addi.d $r9, $r9, 8 ++ bne $r10, $r0, copycont1 ++ ++VARIABLE (grub_relocator_forward_end) ++ ++VARIABLE (grub_relocator_backward_start) ++ ++ add.d $r9, $r9, $r10 ++ add.d $r8, $r8, $r10 ++ /* Backward movsl is implicitly off-by-one. compensate that. */ ++ addi.d $r9, $r9, -8 ++ addi.d $r8, $r8, -8 ++copycont2: ++ ld.w $r11,$r8,0 ++ st.w $r11,$r9,0 ++ addi.d $r8, $r8, -8 ++ addi.d $r10, $r10, -8 ++ addi.d $r9, $r9, -8 ++ bne $r10, $r0, copycont2 ++ ++VARIABLE (grub_relocator_backward_end) ++ +diff --git a/grub-core/lib/loongarch64/setjmp.S b/grub-core/lib/loongarch64/setjmp.S +new file mode 100644 +index 000000000000..bb0995937ecf +--- /dev/null ++++ b/grub-core/lib/loongarch64/setjmp.S +@@ -0,0 +1,68 @@ ++/* ++ * 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 ++ ++ .file "setjmp.S" ++ ++GRUB_MOD_LICENSE "GPLv3+" ++ ++ .text ++ ++/* ++ * int grub_setjmp (jmp_buf env) ++ */ ++FUNCTION(grub_setjmp) ++ 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 ++ ++/* ++ * void grub_longjmp (jmp_buf env, int val) ++ */ ++FUNCTION(grub_longjmp) ++ 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/lib/setjmp.S b/grub-core/lib/setjmp.S +index aa297ab0af2f..da71fc751871 100644 +--- a/grub-core/lib/setjmp.S ++++ b/grub-core/lib/setjmp.S +@@ -15,6 +15,8 @@ + #include "./arm/setjmp.S" + #elif defined(__aarch64__) + #include "./arm64/setjmp.S" ++#elif defined(__loongarch64) ++#include "./loongarch64/setjmp.S" + #elif defined(__riscv) + #include "./riscv/setjmp.S" + #else +diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c +index 3af6b1229269..985111cf458b 100644 +--- a/grub-core/loader/efi/chainloader.c ++++ b/grub-core/loader/efi/chainloader.c +@@ -334,6 +334,8 @@ static const grub_uint16_t machine_type __attribute__((__unused__)) = + GRUB_PE32_MACHINE_I386; + #elif defined(__ia64__) + GRUB_PE32_MACHINE_IA64; ++#elif defined(__loongarch64) ++ GRUB_PE32_MACHINE_LOONGARCH64; + #elif defined(__riscv) && (__riscv_xlen == 32) + GRUB_PE32_MACHINE_RISCV32; + #elif defined(__riscv) && (__riscv_xlen == 64) +diff --git a/grub-core/loader/loongarch64/linux-efi.c b/grub-core/loader/loongarch64/linux-efi.c +new file mode 100644 +index 000000000000..4dcefd9d9e27 +--- /dev/null ++++ b/grub-core/loader/loongarch64/linux-efi.c +@@ -0,0 +1,144 @@ ++/* ++ * 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 ++ ++#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 000000000000..85585b44f085 +--- /dev/null ++++ b/grub-core/loader/loongarch64/linux-elf.c +@@ -0,0 +1,529 @@ ++/* ++ * 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 ++ ++#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 } \ ++ } ++ ++static struct grub_relocator *relocator; ++ ++void grub_linux_loongarch_elf_relocator_unload (void) ++{ ++ grub_relocator_unload (relocator); ++} ++ ++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", ++ (grub_uint64_t) (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 ("rd_start=0xXXXXXXXXXXXXXXXX"), 4) \ ++ + ALIGN_UP (sizeof ("rd_size=0xXXXXXXXXXXXXXXXX"), 4) \ ++ + ALIGN_UP (sizeof ("initrd=0xXXXXXXXXXXXXXXXX,0xXXXXXXXXXXXXXXXX"), ++ 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 ("rd_start=0xXXXXXXXXXXXXXXXX"), ++ "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 ("rd_start=0xXXXXXXXXXXXXXXXX"), 4); ++ kernel_params->linux_argc++; ++ ++ /* rd_size */ ++ grub_snprintf (linux_args, ++ sizeof ("rd_size=0xXXXXXXXXXXXXXXXX"), ++ "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 ("rd_size=0xXXXXXXXXXXXXXXXX"), 4); ++ kernel_params->linux_argc++; ++ ++ /* initrd */ ++ grub_snprintf (linux_args, ++ sizeof ("initrd=0xXXXXXXXXXXXXXXXX,0xXXXXXXXXXXXXXXXX"), ++ "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 ("initrd=0xXXXXXXXXXXXXXXXX,0xXXXXXXXXXXXXXXXX"), 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_printf("not find param, is fdt boot\n"); ++ if (allocate_fdt_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->fdt; /* a1 = fdt */ ++ state.gpr[6] = 0; /* a2 = flag */ ++ } else { ++ grub_printf("find param, is 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, ++ 0, (0xffffffff - size) + 1, ++ size, align, ++ GRUB_RELOCATOR_PREFERENCE_LOW, 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_printf("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 +new file mode 100644 +index 000000000000..783054be5100 +--- /dev/null ++++ b/grub-core/loader/loongarch64/linux.c +@@ -0,0 +1,398 @@ ++/* ++ * 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 ++ ++GRUB_MOD_LICENSE ("GPLv3+"); ++ ++#define INITRD_MAX_ADDRESS_OFFSET (32ULL * 1024 * 1024 * 1024) ++ ++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 is_bpi_boot; ++static int grub_loongarch_linux_type = GRUB_LOONGARCH_LINUX_BAD; ++ ++static grub_err_t ++grub_linux_boot (void) ++{ ++ ++ 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)); ++ } ++ if (grub_loongarch_linux_type == GRUB_LOONGARCH_LINUX_ELF) { ++ return grub_linux_loongarch_elf_linux_boot_image (&kernel_params); ++ } ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_linux_unload (void) ++{ ++ ++ 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; ++ ++ 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; ++ } ++ ++ 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 (); ++ } ++ ++ grub_dl_unref (my_mod); ++ loaded = 0; ++ grub_loongarch_linux_type = GRUB_LOONGARCH_LINUX_BAD; ++ ++ return GRUB_ERR_NONE; ++} ++ ++grub_err_t ++grub_linux_loongarch_elf_load_kernel (grub_elf_t elf, const char *filename) ++{ ++ Elf64_Addr base; ++ grub_err_t err; ++ grub_uint8_t *playground; ++ grub_uint64_t addr; ++ int flag; ++ ++ /* Linux's entry point incorrectly contains a virtual address. */ ++ kernel_params.kernel_addr = elf->ehdr.ehdr64.e_entry; ++ kernel_params.kernel_size = grub_elf64_size (elf, &base, 0); ++ ++ if (kernel_params.kernel_size == 0) ++ return grub_errno; ++ ++ 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) { ++ flag = GRUB_ELF_LOAD_FLAGS_NONE; ++ } else { ++ flag = GRUB_ELF_LOAD_FLAGS_30BITS; ++ base &= ~ELF64_LOADMASK; ++ kernel_params.kernel_addr &= ~ELF64_LOADMASK; ++ } ++ ++ 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); ++} ++ ++static grub_err_t ++grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), ++ int argc, char *argv[]) ++{ ++ 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; ++ grub_size_t cmdline_size; ++ int i; ++ ++ grub_dl_ref (my_mod); ++ ++ /* Release the previously used memory. */ ++ grub_loader_unset (); ++ ++ if (argc == 0) ++ { ++ grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); ++ goto fail; ++ } ++ ++ file = grub_file_open (argv[0], GRUB_FILE_TYPE_LINUX_KERNEL); ++ if (!file) ++ goto fail; ++ ++ kernel_params.kernel_size = grub_file_size (file); ++ grub_dprintf ("linux", "kernel file size: %" PRIuGRUB_SIZE "\n", ++ kernel_params.kernel_size); ++ ++ if (grub_file_read (file, &lh, sizeof (lh)) < (long) sizeof (lh)) ++ return grub_errno; ++ ++ if (grub_arch_efi_linux_check_image (&lh) == GRUB_ERR_NONE) { ++ grub_loongarch_linux_type = GRUB_LOONGARCH_LINUX_EFI; ++ } ++ ++ if (grub_loongarch_linux_type != GRUB_LOONGARCH_LINUX_EFI) { ++ elf = grub_elf_file (file, argv[0]); ++ if (elf != NULL) ++ { ++ /* 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_LOONGARCH) ++ { ++ 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); ++ } ++ } else { ++ 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); ++ } ++ ++ cmdline_size = 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_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")); ++ goto fail; ++ } ++ ++ grub_memcpy (kernel_params.linux_args, LINUX_IMAGE, sizeof (LINUX_IMAGE)); ++ ++ if (grub_linux_loongarch_elf_get_boot_params (&boot_params) == 1) ++ is_bpi_boot = 1; ++ else ++ is_bpi_boot = 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), ++ cmdline_size, ++ 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) ++ { ++ grub_loader_set (grub_linux_boot, grub_linux_unload, 0); ++ loaded = 1; ++ } ++ ++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 (kernel_params.linux_args && !loaded) ++ grub_free (kernel_params.linux_args); ++ ++ 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; ++} ++ ++/* ++ * 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[]) ++{ ++ struct grub_linux_initrd_context initrd_ctx = { 0, 0, 0 }; ++ grub_size_t initrd_size; ++ void *initrd_mem = NULL; ++ ++ if (argc == 0) ++ { ++ return 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")); ++ 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_bpi_boot == 0) { ++ grub_size_t initrd_pages; ++ initrd_pages = (GRUB_EFI_BYTES_TO_PAGES (initrd_size)); ++ initrd_mem = allocate_initrd_mem (initrd_pages); ++ } else { ++ grub_err_t err; ++ initrd_mem = grub_linux_loongarch_alloc_virtual_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; ++ } ++ ++ if (grub_initrd_load (&initrd_ctx, argv, initrd_mem)) ++ goto 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_bpi_boot == 0) { ++ if (initrd_mem && !kernel_params.ramdisk_addr) ++ grub_efi_free_pages ((grub_addr_t) initrd_mem, ++ GRUB_EFI_BYTES_TO_PAGES (initrd_size)); ++ } ++ return grub_errno; ++} ++ ++static grub_command_t cmd_linux, cmd_initrd; ++ ++GRUB_MOD_INIT(linux) ++{ ++ cmd_linux = grub_register_command ("linux", grub_cmd_linux, ++ N_("FILE [ARGS...]"), N_("Load Linux.")); ++ cmd_initrd = grub_register_command ("initrd", grub_cmd_initrd, ++ N_("FILE"), N_("Load initrd.")); ++ my_mod = mod; ++} ++ ++GRUB_MOD_FINI(linux) ++{ ++ grub_unregister_command (cmd_linux); ++ grub_unregister_command (cmd_initrd); ++} +diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h +index 464842ba3705..66d20742b1fd 100644 +--- a/include/grub/efi/api.h ++++ b/include/grub/efi/api.h +@@ -2129,7 +2129,7 @@ typedef struct grub_efi_memory_attribute_protocol grub_efi_memory_attribute_prot + + #if (GRUB_TARGET_SIZEOF_VOID_P == 4) || defined (__ia64__) \ + || defined (__aarch64__) || defined (__MINGW64__) || defined (__CYGWIN__) \ +- || defined(__riscv) ++ || defined(__riscv) || defined (__loongarch64) + + #define efi_call_0(func) func() + #define efi_call_1(func, a) func(a) +diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h +index 34825c4adc7f..789e0112b14a 100644 +--- a/include/grub/efi/efi.h ++++ b/include/grub/efi/efi.h +@@ -140,13 +140,17 @@ extern void (*EXPORT_VAR(grub_efi_net_config)) (grub_efi_handle_t hnd, + char **device, + char **path); + +-#if defined(__arm__) || defined(__aarch64__) || defined(__riscv) ++#if defined(__arm__) || defined(__aarch64__) || defined(__riscv) || defined(__loongarch__) + void *EXPORT_FUNC(grub_efi_get_firmware_fdt)(void); + grub_err_t EXPORT_FUNC(grub_efi_get_ram_base)(grub_addr_t *); + #include + grub_err_t grub_arch_efi_linux_check_image(struct linux_arch_kernel_header *lh); ++#if defined(__loongarch__) ++grub_err_t grub_arch_efi_linux_boot_image(grub_addr_t addr, grub_size_t size, char *args); ++#else + grub_err_t grub_arch_efi_linux_boot_image(grub_addr_t addr, char *args); + #endif ++#endif + + grub_addr_t grub_efi_section_addr (const char *section); + +diff --git a/include/grub/efi/pe32.h b/include/grub/efi/pe32.h +index 2a5e1ee003ed..f279d1dce0a5 100644 +--- a/include/grub/efi/pe32.h ++++ b/include/grub/efi/pe32.h +@@ -102,6 +102,8 @@ struct grub_pe32_coff_header + #define GRUB_PE32_MACHINE_ARM64 0xAA64 + #define GRUB_PE32_MACHINE_RISCV32 0x5032 + #define GRUB_PE32_MACHINE_RISCV64 0x5064 ++#define GRUB_PE32_MACHINE_LOONGARCH32 0x6232 ++#define GRUB_PE32_MACHINE_LOONGARCH64 0x6264 + + #define GRUB_PE32_RELOCS_STRIPPED 0x0001 + #define GRUB_PE32_EXECUTABLE_IMAGE 0x0002 +@@ -362,6 +364,8 @@ struct grub_pe32_fixup_block + #define GRUB_PE32_REL_BASED_ARM_MOV32T 7 + #define GRUB_PE32_REL_BASED_RISCV_LOW12I 7 + #define GRUB_PE32_REL_BASED_RISCV_LOW12S 8 ++#define GRUB_PE32_REL_BASED_LOONGARCH32_MARK_LA 8 ++#define GRUB_PE32_REL_BASED_LOONGARCH64_MARK_LA 8 + #define GRUB_PE32_REL_BASED_IA64_IMM64 9 + #define GRUB_PE32_REL_BASED_DIR64 10 + #define GRUB_PE32_REL_BASED_HIGH3ADJ 11 +diff --git a/include/grub/elf.h b/include/grub/elf.h +index c478933ee82f..73175bda02ac 100644 +--- a/include/grub/elf.h ++++ b/include/grub/elf.h +@@ -248,6 +248,7 @@ typedef struct + #define EM_NUM 95 + #define EM_AARCH64 183 /* ARM 64-bit architecture */ + #define EM_RISCV 243 /* RISC-V */ ++#define EM_LOONGARCH 258 /* LoongArch */ + + /* If it is necessary to assign new unofficial EM_* values, please + pick large random numbers (0x8523, 0xa7f2, etc.) to minimize the +@@ -2531,6 +2532,35 @@ typedef Elf32_Addr Elf32_Conflict; + #define R_RISCV_SET32 56 + #define R_RISCV_32_PCREL 57 + ++/* LoongArch relocations */ ++#define R_LARCH_NONE 0 ++#define R_LARCH_64 2 ++#define R_LARCH_MARK_LA 20 ++#define R_LARCH_SOP_PUSH_PCREL 22 ++#define R_LARCH_SOP_PUSH_ABSOLUTE 23 ++#define R_LARCH_SOP_PUSH_PLT_PCREL 29 ++#define R_LARCH_SOP_SUB 32 ++#define R_LARCH_SOP_SL 33 ++#define R_LARCH_SOP_SR 34 ++#define R_LARCH_SOP_ADD 35 ++#define R_LARCH_SOP_AND 36 ++#define R_LARCH_SOP_IF_ELSE 37 ++#define R_LARCH_SOP_POP_32_S_10_5 38 ++#define R_LARCH_SOP_POP_32_U_10_12 39 ++#define R_LARCH_SOP_POP_32_S_10_12 40 ++#define R_LARCH_SOP_POP_32_S_10_16 41 ++#define R_LARCH_SOP_POP_32_S_10_16_S2 42 ++#define R_LARCH_SOP_POP_32_S_5_20 43 ++#define R_LARCH_SOP_POP_32_S_0_5_10_16_S2 44 ++#define R_LARCH_SOP_POP_32_S_0_10_10_16_S2 45 ++#define R_LARCH_B26 66 ++#define R_LARCH_ABS_HI20 67 ++#define R_LARCH_ABS_LO12 68 ++#define R_LARCH_ABS64_LO20 69 ++#define R_LARCH_ABS64_HI12 70 ++#define R_LARCH_PCALA_HI20 71 ++#define R_LARCH_PCALA_LO12 72 ++ + #ifdef GRUB_TARGET_WORDSIZE + #if GRUB_TARGET_WORDSIZE == 32 + +diff --git a/include/grub/fdt.h b/include/grub/fdt.h +index 3514aa4a5b64..ba2f9a95c03e 100644 +--- a/include/grub/fdt.h ++++ b/include/grub/fdt.h +@@ -20,7 +20,7 @@ + #define GRUB_FDT_HEADER 1 + + #if !defined(GRUB_MACHINE_EMU) && \ +- (defined(__arm__) || defined(__aarch64__) || defined(__riscv)) ++ (defined(__arm__) || defined(__aarch64__) || defined(__riscv) || defined(__loongarch__)) + + #include + #include +@@ -148,6 +148,6 @@ int EXPORT_FUNC(grub_fdt_set_prop) (void *fdt, unsigned int nodeoffset, const ch + }) + + #endif /* !defined(GRUB_MACHINE_EMU) && \ +- (defined(__arm__) || defined(__aarch64__) || defined(__riscv)) */ ++ (defined(__arm__) || defined(__aarch64__) || defined(__riscv) || defined(__loongarch__)) */ + + #endif /* ! GRUB_FDT_HEADER */ +diff --git a/include/grub/loongarch64/efi/loader.h b/include/grub/loongarch64/efi/loader.h +new file mode 100644 +index 000000000000..71a0159771f6 +--- /dev/null ++++ b/include/grub/loongarch64/efi/loader.h +@@ -0,0 +1,25 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2002,2003,2004,2006,2007,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_LOADER_MACHINE_HEADER ++#define GRUB_LOADER_MACHINE_HEADER 1 ++ ++#include ++#include ++ ++#endif /* ! GRUB_LOADER_MACHINE_HEADER */ +diff --git a/include/grub/loongarch64/efi/memory.h b/include/grub/loongarch64/efi/memory.h +new file mode 100644 +index 000000000000..2d3f36eb4f57 +--- /dev/null ++++ b/include/grub/loongarch64/efi/memory.h +@@ -0,0 +1,15 @@ ++#ifndef GRUB_MEMORY_CPU_HEADER ++#include ++ ++ ++static inline grub_uint64_t grub_efi_max_usable_address(void) ++{ ++ grub_uint64_t addr; ++ asm volatile ("csrrd %0, 0x181" : "=r" (addr)); ++ return addr |= 0xffffffffffUL; ++} ++ ++#define GRUB_EFI_MAX_USABLE_ADDRESS (grub_efi_max_usable_address()) ++#define GRUB_EFI_MAX_ALLOCATION_ADDRESS GRUB_EFI_MAX_USABLE_ADDRESS ++ ++#endif /* ! GRUB_MEMORY_CPU_HEADER */ +diff --git a/include/grub/loongarch64/efi/time.h b/include/grub/loongarch64/efi/time.h +new file mode 100644 +index 000000000000..e69de29bb2d1 +diff --git a/include/grub/loongarch64/io.h b/include/grub/loongarch64/io.h +new file mode 100644 +index 000000000000..5f341037a986 +--- /dev/null ++++ b/include/grub/loongarch64/io.h +@@ -0,0 +1,62 @@ ++/* ++ * 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 . ++ */ ++ ++#ifndef GRUB_IO_H ++#define GRUB_IO_H 1 ++ ++#include ++ ++typedef grub_addr_t grub_port_t; ++ ++static __inline unsigned char ++grub_inb (grub_port_t port) ++{ ++ return *(volatile grub_uint8_t *) port; ++} ++ ++static __inline unsigned short int ++grub_inw (grub_port_t port) ++{ ++ return *(volatile grub_uint16_t *) port; ++} ++ ++static __inline unsigned int ++grub_inl (grub_port_t port) ++{ ++ return *(volatile grub_uint32_t *) port; ++} ++ ++static __inline void ++grub_outb (unsigned char value, grub_port_t port) ++{ ++ *(volatile grub_uint8_t *) port = value; ++} ++ ++static __inline void ++grub_outw (unsigned short int value, grub_port_t port) ++{ ++ *(volatile grub_uint16_t *) port = value; ++} ++ ++static __inline void ++grub_outl (unsigned int value, grub_port_t port) ++{ ++ *(volatile grub_uint32_t *) port = value; ++} ++ ++#endif /* _SYS_IO_H */ +diff --git a/include/grub/loongarch64/linux.h b/include/grub/loongarch64/linux.h +new file mode 100644 +index 000000000000..af1f51dd7676 +--- /dev/null ++++ b/include/grub/loongarch64/linux.h +@@ -0,0 +1,144 @@ ++/* ++ * 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 . ++ */ ++ ++#ifndef GRUB_LOONGARCH64_LINUX_HEADER ++#define GRUB_LOONGARCH64_LINUX_HEADER 1 ++ ++#include ++ ++/* LoongArch linux kernel type */ ++#define GRUB_LOONGARCH_LINUX_BAD 0 ++#define GRUB_LOONGARCH_LINUX_ELF 1 ++#define GRUB_LOONGARCH_LINUX_EFI 2 ++ ++#define GRUB_LOONGSON3_BOOT_MEM_MAP_MAX 128 ++ ++#define GRUB_LINUX_LOONGARCH_MAGIC_SIGNATURE 0x6E6F73676E6F6F4C /* 'Loongson' */ ++#define linux_arch_kernel_header linux_loongarch64_kernel_header ++ ++/* From linux/Documentation/loongarch/booting.txt ++ * ++ * 0-1: MZ ++ * 0x28: LoongArch\0 ++ * 0x3c: PE/COFF头偏移 ++ * 0x20e:内核版本号偏移-512 ++ * riscv的version字段在0x20偏移处,现在LoongArch没有使用,是0 ++ */ ++struct linux_loongarch64_kernel_header ++{ ++ grub_uint32_t code0; /* Executable code */ ++ grub_uint32_t code1; /* Executable code */ ++ grub_uint64_t text_offset; /* Image load offset */ ++ grub_uint64_t res0; /* reserved */ ++ grub_uint64_t res1; /* reserved */ ++ grub_uint64_t res2; /* reserved */ ++ 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; /* 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 ++ ++#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)) ++ ++/* 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_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/loongarch64.h b/include/grub/loongarch64/loongarch64.h +new file mode 100644 +index 000000000000..ea3be3d788de +--- /dev/null ++++ b/include/grub/loongarch64/loongarch64.h +@@ -0,0 +1,30 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 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 . ++ */ ++ ++#ifndef GRUB_REGISTERS_CPU_HEADER ++#define GRUB_REGISTERS_CPU_HEADER 1 ++ ++#ifdef ASM_FILE ++#define GRUB_CPU_REGISTER_WRAP(x) x ++#else ++#define GRUB_CPU_REGISTER_WRAP(x) #x ++#endif ++ ++#define GRUB_CPU_LOONGARCH_COP0_TIMER_COUNT GRUB_CPU_REGISTER_WRAP(9) ++ ++#endif +diff --git a/include/grub/loongarch64/memory.h b/include/grub/loongarch64/memory.h +new file mode 100644 +index 000000000000..cc9faefc1d9d +--- /dev/null ++++ b/include/grub/loongarch64/memory.h +@@ -0,0 +1,59 @@ ++/* ++ * 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_MEMORY_CPU_HEADER ++#define GRUB_MEMORY_CPU_HEADER 1 ++ ++#ifndef ASM_FILE ++#include ++#include ++#include ++#endif ++ ++#ifndef ASM_FILE ++ ++typedef grub_addr_t grub_phys_addr_t; ++ ++static inline grub_phys_addr_t ++grub_vtop (void *a) ++{ ++ if (-1 == ((grub_int64_t) a >> 32)) ++ return ((grub_phys_addr_t) a) & 0x1fffffffUL; ++ return ((grub_phys_addr_t) a) & 0xffffffffffffUL; ++} ++ ++static inline void * ++grub_map_memory (grub_phys_addr_t a, grub_size_t size) ++{ ++ grub_uint64_t addr; ++ asm volatile ("csrrd %0, 0x181" : "=r" (addr)); ++ if (addr & 0x1) ++ return (void *) (a | (addr & 0xffffffffffffff00UL)); ++ else ++ return (void *) a; ++} ++ ++static inline void ++grub_unmap_memory (void *a __attribute__ ((unused)), ++ grub_size_t size __attribute__ ((unused))) ++{ ++} ++ ++#endif ++ ++#endif +diff --git a/include/grub/loongarch64/reloc.h b/include/grub/loongarch64/reloc.h +new file mode 100644 +index 000000000000..2106ba22cd48 +--- /dev/null ++++ b/include/grub/loongarch64/reloc.h +@@ -0,0 +1,113 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2022 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_LOONGARCH64_RELOC_H ++#define GRUB_LOONGARCH64_RELOC_H 1 ++#include ++ ++#define LOONGARCH64_STACK_MAX 16 ++ ++struct grub_loongarch64_stack ++{ ++ grub_uint64_t data[LOONGARCH64_STACK_MAX]; ++ int count; ++ int top; ++}; ++ ++typedef struct grub_loongarch64_stack* grub_loongarch64_stack_t; ++ ++void grub_loongarch64_stack_init (grub_loongarch64_stack_t stack); ++void grub_loongarch64_sop_push (grub_loongarch64_stack_t stack, ++ grub_int64_t offset); ++void grub_loongarch64_sop_sub (grub_loongarch64_stack_t stack); ++void grub_loongarch64_sop_sl (grub_loongarch64_stack_t stack); ++void grub_loongarch64_sop_sr (grub_loongarch64_stack_t stack); ++void grub_loongarch64_sop_add (grub_loongarch64_stack_t stack); ++void grub_loongarch64_sop_and (grub_loongarch64_stack_t stack); ++void grub_loongarch64_sop_if_else (grub_loongarch64_stack_t stack); ++void grub_loongarch64_sop_32_s_10_5 (grub_loongarch64_stack_t stack, ++ grub_uint64_t *place); ++void grub_loongarch64_sop_32_u_10_12 (grub_loongarch64_stack_t stack, ++ grub_uint64_t *place); ++void grub_loongarch64_sop_32_s_10_12 (grub_loongarch64_stack_t stack, ++ grub_uint64_t *place); ++void grub_loongarch64_sop_32_s_10_16 (grub_loongarch64_stack_t stack, ++ grub_uint64_t *place); ++void grub_loongarch64_sop_32_s_10_16_s2 (grub_loongarch64_stack_t stack, ++ grub_uint64_t *place); ++void grub_loongarch64_sop_32_s_5_20 (grub_loongarch64_stack_t stack, ++ grub_uint64_t *place); ++void grub_loongarch64_sop_32_s_0_5_10_16_s2 (grub_loongarch64_stack_t stack, ++ grub_uint64_t *place); ++void grub_loongarch64_sop_32_s_0_10_10_16_s2 (grub_loongarch64_stack_t stack, ++ grub_uint64_t *place); ++ ++void grub_loongarch64_b26 (grub_uint32_t *place, grub_int64_t offset); ++void grub_loongarch64_xxx_hi20 (grub_uint32_t *place, grub_int64_t offset); ++void grub_loongarch64_xxx_lo12 (grub_uint32_t *place, grub_int64_t offset); ++void grub_loongarch64_xxx64_hi12 (grub_uint32_t *place, grub_int64_t offset); ++void grub_loongarch64_xxx64_lo20 (grub_uint32_t *place, grub_int64_t offset); ++ ++#define GRUB_LOONGARCH64_RELOCATION(STACK, PLACE, OFFSET) \ ++ case R_LARCH_SOP_PUSH_ABSOLUTE: \ ++ grub_loongarch64_sop_push (STACK, OFFSET); \ ++ break; \ ++ case R_LARCH_SOP_SUB: \ ++ grub_loongarch64_sop_sub (STACK); \ ++ break; \ ++ case R_LARCH_SOP_SL: \ ++ grub_loongarch64_sop_sl (STACK); \ ++ break; \ ++ case R_LARCH_SOP_SR: \ ++ grub_loongarch64_sop_sr (STACK); \ ++ break; \ ++ case R_LARCH_SOP_ADD: \ ++ grub_loongarch64_sop_add (STACK); \ ++ break; \ ++ case R_LARCH_SOP_AND: \ ++ grub_loongarch64_sop_and (STACK); \ ++ break; \ ++ case R_LARCH_SOP_IF_ELSE: \ ++ grub_loongarch64_sop_if_else (STACK); \ ++ break; \ ++ case R_LARCH_SOP_POP_32_S_10_5: \ ++ grub_loongarch64_sop_32_s_10_5 (STACK, PLACE); \ ++ break; \ ++ case R_LARCH_SOP_POP_32_U_10_12: \ ++ grub_loongarch64_sop_32_u_10_12 (STACK, PLACE); \ ++ break; \ ++ case R_LARCH_SOP_POP_32_S_10_12: \ ++ grub_loongarch64_sop_32_s_10_12 (STACK, PLACE); \ ++ break; \ ++ case R_LARCH_SOP_POP_32_S_10_16: \ ++ grub_loongarch64_sop_32_s_10_16 (STACK, PLACE); \ ++ break; \ ++ case R_LARCH_SOP_POP_32_S_10_16_S2: \ ++ grub_loongarch64_sop_32_s_10_16_s2 (STACK, PLACE); \ ++ break; \ ++ case R_LARCH_SOP_POP_32_S_5_20: \ ++ grub_loongarch64_sop_32_s_5_20 (STACK, PLACE); \ ++ break; \ ++ case R_LARCH_SOP_POP_32_S_0_5_10_16_S2: \ ++ grub_loongarch64_sop_32_s_0_5_10_16_s2 (STACK, PLACE); \ ++ break; \ ++ case R_LARCH_SOP_POP_32_S_0_10_10_16_S2: \ ++ grub_loongarch64_sop_32_s_0_10_10_16_s2 (STACK, PLACE); \ ++ break; ++ ++#endif /* GRUB_LOONGARCH64_RELOC_H */ +diff --git a/include/grub/loongarch64/relocator.h b/include/grub/loongarch64/relocator.h +new file mode 100644 +index 000000000000..cef3aaaf77ba +--- /dev/null ++++ b/include/grub/loongarch64/relocator.h +@@ -0,0 +1,38 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2022 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_RELOCATOR_CPU_HEADER ++#define GRUB_RELOCATOR_CPU_HEADER 1 ++ ++#include ++#include ++#include ++ ++struct grub_relocator64_state ++{ ++ /* gpr[0] is ignored since it's hardwired to 0. */ ++ grub_uint64_t gpr[32]; ++ /* Register holding target $pc. */ ++ int jumpreg; ++}; ++ ++grub_err_t ++grub_relocator64_boot (struct grub_relocator *rel, ++ struct grub_relocator64_state state); ++ ++#endif /* ! GRUB_RELOCATOR_CPU_HEADER */ +diff --git a/include/grub/loongarch64/setjmp.h b/include/grub/loongarch64/setjmp.h +new file mode 100644 +index 000000000000..d9a0776b6a71 +--- /dev/null ++++ b/include/grub/loongarch64/setjmp.h +@@ -0,0 +1,27 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2002,2004,2006,2007,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 . ++ */ ++ ++#ifndef GRUB_SETJMP_CPU_HEADER ++#define GRUB_SETJMP_CPU_HEADER 1 ++ ++typedef grub_uint64_t grub_jmp_buf[12]; ++ ++int grub_setjmp (grub_jmp_buf env) RETURNS_TWICE; ++void grub_longjmp (grub_jmp_buf env, int val) __attribute__ ((noreturn)); ++ ++#endif /* ! GRUB_SETJMP_CPU_HEADER */ +diff --git a/include/grub/loongarch64/time.h b/include/grub/loongarch64/time.h +new file mode 100644 +index 000000000000..c9a7334887e2 +--- /dev/null ++++ b/include/grub/loongarch64/time.h +@@ -0,0 +1,39 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2003,2004,2005,2007,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 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) ++{ ++} ++ ++#endif +diff --git a/include/grub/loongarch64/types.h b/include/grub/loongarch64/types.h +new file mode 100644 +index 000000000000..2dbefbf603c2 +--- /dev/null ++++ b/include/grub/loongarch64/types.h +@@ -0,0 +1,34 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2002,2006,2007,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 . ++ */ ++ ++#ifndef GRUB_TYPES_CPU_HEADER ++#define GRUB_TYPES_CPU_HEADER 1 ++ ++/* The size of void *. */ ++#define GRUB_TARGET_SIZEOF_VOID_P 8 ++ ++/* The size of long. */ ++#define GRUB_TARGET_SIZEOF_LONG 8 ++ ++#ifdef GRUB_CPU_LOONGARCH ++/* loongarch is little-endian. */ ++#undef GRUB_TARGET_WORDS_BIGENDIAN ++ ++#endif /* ! GRUB_TYPES_CPU_HEADER */ ++ ++#endif +diff --git a/include/grub/util/install.h b/include/grub/util/install.h +index 51f3b13ac130..a728afc9b15b 100644 +--- a/include/grub/util/install.h ++++ b/include/grub/util/install.h +@@ -114,6 +114,7 @@ enum grub_install_plat + GRUB_INSTALL_PLATFORM_ARM_COREBOOT, + GRUB_INSTALL_PLATFORM_RISCV32_EFI, + GRUB_INSTALL_PLATFORM_RISCV64_EFI, ++ GRUB_INSTALL_PLATFORM_LOONGARCH64_EFI, + GRUB_INSTALL_PLATFORM_MAX + }; + +diff --git a/util/grub-install-common.c b/util/grub-install-common.c +index 2d9693ffeb7b..19bd44515ebe 100644 +--- a/util/grub-install-common.c ++++ b/util/grub-install-common.c +@@ -932,6 +932,7 @@ static struct + [GRUB_INSTALL_PLATFORM_ARM_COREBOOT] = { "arm", "coreboot" }, + [GRUB_INSTALL_PLATFORM_RISCV32_EFI] = { "riscv32", "efi" }, + [GRUB_INSTALL_PLATFORM_RISCV64_EFI] = { "riscv64", "efi" }, ++ [GRUB_INSTALL_PLATFORM_LOONGARCH64_EFI] = { "loongarch64", "efi" }, + }; + + char * +diff --git a/util/grub-install.c b/util/grub-install.c +index 5babc7af5518..c8f15df5917d 100644 +--- a/util/grub-install.c ++++ b/util/grub-install.c +@@ -332,6 +332,8 @@ get_default_platform (void) + #else + return NULL; + #endif ++#elif defined (__loongarch64) ++ return "loongarch64-efi"; + #else + return NULL; + #endif +@@ -487,6 +489,7 @@ have_bootdev (enum grub_install_plat pl) + case GRUB_INSTALL_PLATFORM_ARM64_EFI: + case GRUB_INSTALL_PLATFORM_RISCV32_EFI: + case GRUB_INSTALL_PLATFORM_RISCV64_EFI: ++ case GRUB_INSTALL_PLATFORM_LOONGARCH64_EFI: + case GRUB_INSTALL_PLATFORM_I386_IEEE1275: + case GRUB_INSTALL_PLATFORM_SPARC64_IEEE1275: + case GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275: +@@ -906,6 +909,7 @@ main (int argc, char *argv[]) + case GRUB_INSTALL_PLATFORM_I386_EFI: + case GRUB_INSTALL_PLATFORM_IA64_EFI: + case GRUB_INSTALL_PLATFORM_X86_64_EFI: ++ case GRUB_INSTALL_PLATFORM_LOONGARCH64_EFI: + is_efi = 1; + grub_util_error (_("this utility cannot be used for EFI platforms" + " because it does not support UEFI Secure Boot")); +@@ -933,6 +937,7 @@ main (int argc, char *argv[]) + case GRUB_INSTALL_PLATFORM_ARM64_EFI: + case GRUB_INSTALL_PLATFORM_RISCV32_EFI: + case GRUB_INSTALL_PLATFORM_RISCV64_EFI: ++ case GRUB_INSTALL_PLATFORM_LOONGARCH64_EFI: + case GRUB_INSTALL_PLATFORM_IA64_EFI: + case GRUB_INSTALL_PLATFORM_I386_IEEE1275: + case GRUB_INSTALL_PLATFORM_SPARC64_IEEE1275: +@@ -980,6 +985,7 @@ main (int argc, char *argv[]) + case GRUB_INSTALL_PLATFORM_ARM64_EFI: + case GRUB_INSTALL_PLATFORM_RISCV32_EFI: + case GRUB_INSTALL_PLATFORM_RISCV64_EFI: ++ case GRUB_INSTALL_PLATFORM_LOONGARCH64_EFI: + case GRUB_INSTALL_PLATFORM_IA64_EFI: + case GRUB_INSTALL_PLATFORM_I386_IEEE1275: + case GRUB_INSTALL_PLATFORM_ARM_UBOOT: +@@ -1133,6 +1139,9 @@ main (int argc, char *argv[]) + case GRUB_INSTALL_PLATFORM_RISCV64_EFI: + efi_file = "BOOTRISCV64.EFI"; + break; ++ case GRUB_INSTALL_PLATFORM_LOONGARCH64_EFI: ++ efi_file = "BOOTLOONGARCH64.EFI"; ++ break; + default: + grub_util_error ("%s", _("You've found a bug")); + break; +@@ -1166,6 +1175,9 @@ main (int argc, char *argv[]) + case GRUB_INSTALL_PLATFORM_RISCV64_EFI: + efi_file = "grubriscv64.efi"; + break; ++ case GRUB_INSTALL_PLATFORM_LOONGARCH64_EFI: ++ efi_file = "grubloongarch64.efi"; ++ break; + default: + efi_file = "grub.efi"; + break; +@@ -1470,6 +1482,7 @@ main (int argc, char *argv[]) + case GRUB_INSTALL_PLATFORM_ARM64_EFI: + case GRUB_INSTALL_PLATFORM_RISCV32_EFI: + case GRUB_INSTALL_PLATFORM_RISCV64_EFI: ++ case GRUB_INSTALL_PLATFORM_LOONGARCH64_EFI: + case GRUB_INSTALL_PLATFORM_IA64_EFI: + g = grub_util_guess_efi_drive (*curdev); + break; +@@ -1614,6 +1627,7 @@ main (int argc, char *argv[]) + case GRUB_INSTALL_PLATFORM_ARM64_EFI: + case GRUB_INSTALL_PLATFORM_RISCV32_EFI: + case GRUB_INSTALL_PLATFORM_RISCV64_EFI: ++ case GRUB_INSTALL_PLATFORM_LOONGARCH64_EFI: + case GRUB_INSTALL_PLATFORM_IA64_EFI: + core_name = "core.efi"; + snprintf (mkimage_target, sizeof (mkimage_target), +@@ -1719,6 +1733,7 @@ main (int argc, char *argv[]) + case GRUB_INSTALL_PLATFORM_ARM64_EFI: + case GRUB_INSTALL_PLATFORM_RISCV32_EFI: + case GRUB_INSTALL_PLATFORM_RISCV64_EFI: ++ case GRUB_INSTALL_PLATFORM_LOONGARCH64_EFI: + case GRUB_INSTALL_PLATFORM_IA64_EFI: + case GRUB_INSTALL_PLATFORM_MIPSEL_QEMU_MIPS: + case GRUB_INSTALL_PLATFORM_MIPS_QEMU_MIPS: +@@ -1973,6 +1988,7 @@ main (int argc, char *argv[]) + case GRUB_INSTALL_PLATFORM_ARM64_EFI: + case GRUB_INSTALL_PLATFORM_RISCV32_EFI: + case GRUB_INSTALL_PLATFORM_RISCV64_EFI: ++ case GRUB_INSTALL_PLATFORM_LOONGARCH64_EFI: + case GRUB_INSTALL_PLATFORM_IA64_EFI: + { + char *dst = grub_util_path_concat (2, efidir, efi_file); +diff --git a/util/grub-mkimagexx.c b/util/grub-mkimagexx.c +index 393119486d3f..cf582a95f043 100644 +--- a/util/grub-mkimagexx.c ++++ b/util/grub-mkimagexx.c +@@ -44,6 +44,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -1160,7 +1161,60 @@ SUFFIX (relocate_addrs) (Elf_Ehdr *e, struct section_metadata *smd, + } + break; + } +-#endif ++ case EM_LOONGARCH: ++ { ++ grub_int64_t pc; ++ grub_uint32_t *t32 = (grub_uint32_t *) target; ++ ++ sym_addr += addend; ++ pc = offset + target_section_addr + image_target->vaddr_offset; ++ ++ switch (ELF_R_TYPE (info)) ++ { ++ case R_LARCH_64: ++ { ++ grub_uint64_t *t64 = (grub_uint64_t *) target; ++ *t64 = grub_host_to_target64 (grub_target_to_host64 (*t64) + sym_addr); ++ } ++ break; ++ case R_LARCH_MARK_LA: ++ break; ++ case R_LARCH_B26: ++ { ++ grub_int64_t off; ++ off = sym_addr - target_section_addr - offset ++ - image_target->vaddr_offset; ++ grub_loongarch64_b26 (t32, off); ++ } ++ break; ++ case R_LARCH_ABS_HI20: ++ grub_loongarch64_xxx_hi20 (t32, sym_addr); ++ break; ++ case R_LARCH_ABS64_LO20: ++ grub_loongarch64_xxx64_lo20 (t32, sym_addr); ++ break; ++ case R_LARCH_ABS64_HI12: ++ grub_loongarch64_xxx64_hi12 (t32, sym_addr); ++ break; ++ case R_LARCH_PCALA_HI20: ++ { ++ grub_int32_t hi20; ++ hi20 = (((sym_addr + 0x800) & ~0xfffULL) - (pc & ~0xfffULL)); ++ grub_loongarch64_xxx_hi20 (t32, hi20); ++ } ++ break; ++ case R_LARCH_ABS_LO12: ++ case R_LARCH_PCALA_LO12: ++ grub_loongarch64_xxx_lo12 (t32, sym_addr); ++ break; ++ default: ++ grub_util_error (_("relocation 0x%x is not implemented yet"), ++ (unsigned int) ELF_R_TYPE (info)); ++ break; ++ } ++ break; ++ } ++#endif /* defined(MKIMAGE_ELF64) */ + #if defined(MKIMAGE_ELF32) + case EM_ARM: + { +@@ -1538,7 +1592,10 @@ add_fixup_entry (struct fixup_block_list **cblock, grub_uint16_t type, + + /* The spec does not mention the requirement of a Page RVA. + Here, align the address with a 4K boundary for safety. */ +- b->page_rva = (addr & ~(0x1000 - 1)); ++#ifdef GRUB_CPU_LOONGARCH64 ++ if (type) ++#endif ++ b->page_rva = (addr & ~(0x1000 - 1)); + b->block_size = sizeof (*b); + } + +@@ -1548,7 +1605,11 @@ add_fixup_entry (struct fixup_block_list **cblock, grub_uint16_t type, + + /* Add a new entry. */ + cur_index = ((b->block_size - sizeof (*b)) >> 1); ++#ifdef GRUB_CPU_LOONGARCH64 ++ entry = GRUB_PE32_FIXUP_ENTRY (type, type ? (addr - b->page_rva) : addr); ++#else + entry = GRUB_PE32_FIXUP_ENTRY (type, addr - b->page_rva); ++#endif + b->entries[cur_index] = grub_host_to_target16 (entry); + b->block_size += 2; + } +@@ -1704,7 +1765,39 @@ translate_relocation_pe (struct translate_context *ctx, + break; + } + break; +- break; ++#if defined(MKIMAGE_ELF64) ++ case EM_LOONGARCH: ++ switch (ELF_R_TYPE (info)) ++ { ++ case R_LARCH_64: ++ ctx->current_address = add_fixup_entry (&ctx->lst, ++ GRUB_PE32_REL_BASED_DIR64, addr, 0, ++ ctx->current_address, image_target); ++ break; ++ case R_LARCH_MARK_LA: ++ ctx->current_address = add_fixup_entry (&ctx->lst, ++ GRUB_PE32_REL_BASED_LOONGARCH64_MARK_LA, ++ addr, 0, ctx->current_address, image_target); ++ break; ++ /* Relative relocations do not require fixup entries. */ ++ case R_LARCH_B26: ++ case R_LARCH_ABS_HI20: ++ case R_LARCH_ABS_LO12: ++ case R_LARCH_ABS64_LO20: ++ case R_LARCH_ABS64_HI12: ++ case R_LARCH_PCALA_HI20: ++ case R_LARCH_PCALA_LO12: ++ grub_util_info (" %s: not adding fixup: 0x%08x : 0x%08x", ++ __FUNCTION__, (unsigned int) addr, ++ (unsigned int) ctx->current_address); ++ break; ++ default: ++ grub_util_error (_("relocation 0x%x is not implemented yet"), ++ (unsigned int) ELF_R_TYPE (info)); ++ break; ++ } ++ break; ++#endif /* defined(MKIMAGE_ELF64) */ + #if defined(MKIMAGE_ELF32) + case EM_ARM: + switch (ELF_R_TYPE (info)) +diff --git a/util/grub-module-verifier.c b/util/grub-module-verifier.c +index 163529ca9c25..071d1c31c91f 100644 +--- a/util/grub-module-verifier.c ++++ b/util/grub-module-verifier.c +@@ -176,6 +176,21 @@ struct grub_module_verifier_arch archs[] = { + -1 + } + }, ++ { "loongarch64", 8, 0, EM_LOONGARCH, GRUB_MODULE_VERIFY_SUPPORTS_REL | GRUB_MODULE_VERIFY_SUPPORTS_RELA, (int[]){ ++ R_LARCH_NONE, ++ R_LARCH_64, ++ R_LARCH_MARK_LA, ++ R_LARCH_B26, ++ R_LARCH_ABS_HI20, ++ R_LARCH_ABS_LO12, ++ R_LARCH_ABS64_LO20, ++ R_LARCH_ABS64_HI12, ++ R_LARCH_PCALA_HI20, ++ R_LARCH_PCALA_LO12, ++ -1 ++ }, (int[]){ ++ -1 ++ } }, + }; + + struct platform_whitelist { +diff --git a/util/mkimage.c b/util/mkimage.c +index 8319e8dfbde4..4e09dfc29f25 100644 +--- a/util/mkimage.c ++++ b/util/mkimage.c +@@ -654,6 +654,22 @@ static const struct grub_install_image_target_desc image_targets[] = + .pe_target = GRUB_PE32_MACHINE_RISCV64, + .elf_target = EM_RISCV, + }, ++ { ++ .dirname = "loongarch64-efi", ++ .names = { "loongarch64-efi", NULL }, ++ .voidp_sizeof = 8, ++ .bigendian = 0, ++ .id = IMAGE_EFI, ++ .flags = PLATFORM_FLAGS_NONE, ++ .total_module_size = TARGET_NO_FIELD, ++ .decompressor_compressed_size = TARGET_NO_FIELD, ++ .decompressor_uncompressed_size = TARGET_NO_FIELD, ++ .decompressor_uncompressed_addr = TARGET_NO_FIELD, ++ .section_align = GRUB_PE32_SECTION_ALIGNMENT, ++ .vaddr_offset = EFI64_HEADER_SIZE, ++ .pe_target = GRUB_PE32_MACHINE_LOONGARCH64, ++ .elf_target = EM_LOONGARCH, ++ }, + }; + + #include +-- +2.33.0 + diff --git a/0277-loongarch-Modify-the-location-where-initrd-is-loaded.patch b/0277-loongarch-Modify-the-location-where-initrd-is-loaded.patch new file mode 100644 index 0000000000000000000000000000000000000000..11513eb147130df94715ee1d50edb0bdadcb1924 --- /dev/null +++ b/0277-loongarch-Modify-the-location-where-initrd-is-loaded.patch @@ -0,0 +1,82 @@ +From 8ed39fc6429ec659afa867e79364e9436a4a8242 Mon Sep 17 00:00:00 2001 +From: mengyingkun +Date: Thu, 2 Feb 2023 20:32:17 +0800 +Subject: [PATCH 2/8] loongarch: Modify the location where initrd is loaded + into memory + +Try to allocate memory from higher than 256MB to +avoid kernel relocation overlaying initrd. If failed, +allocate memory in range 0~256MB, and high address +takes precedence. + +Signed-off-by: mengyingkun +--- + grub-core/loader/loongarch64/linux-elf.c | 21 +++++++++++++++++++++ + grub-core/loader/loongarch64/linux.c | 2 +- + include/grub/loongarch64/linux.h | 5 +++++ + 3 files changed, 27 insertions(+), 1 deletion(-) + +diff --git a/grub-core/loader/loongarch64/linux-elf.c b/grub-core/loader/loongarch64/linux-elf.c +index 85585b44f085..8260e4c26fab 100644 +--- a/grub-core/loader/loongarch64/linux-elf.c ++++ b/grub-core/loader/loongarch64/linux-elf.c +@@ -304,6 +304,27 @@ grub_linux_loongarch_alloc_virtual_mem_align (grub_size_t size, + 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) + { +diff --git a/grub-core/loader/loongarch64/linux.c b/grub-core/loader/loongarch64/linux.c +index 783054be5100..4c0219452a76 100644 +--- a/grub-core/loader/loongarch64/linux.c ++++ b/grub-core/loader/loongarch64/linux.c +@@ -351,7 +351,7 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + initrd_mem = allocate_initrd_mem (initrd_pages); + } else { + grub_err_t err; +- initrd_mem = grub_linux_loongarch_alloc_virtual_mem_align (initrd_size, 0x10000, &err); ++ initrd_mem = grub_linux_loongarch_alloc_initrd_mem_align (initrd_size, 0x10000, &err); + if (err) + goto fail; + } +diff --git a/include/grub/loongarch64/linux.h b/include/grub/loongarch64/linux.h +index af1f51dd7676..f4b198ab7ad0 100644 +--- a/include/grub/loongarch64/linux.h ++++ b/include/grub/loongarch64/linux.h +@@ -129,6 +129,11 @@ 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); + +-- +2.33.0 + diff --git a/0278-loongarch-Add-EFI-frame-buffer-support.patch b/0278-loongarch-Add-EFI-frame-buffer-support.patch new file mode 100644 index 0000000000000000000000000000000000000000..8fee3d629b20a36e250248dc5cb0418bde806d0c --- /dev/null +++ b/0278-loongarch-Add-EFI-frame-buffer-support.patch @@ -0,0 +1,337 @@ +From e496c2969905aa69406b67ed6df063aac2b3c33e Mon Sep 17 00:00:00 2001 +From: mengyingkun +Date: Wed, 8 Feb 2023 09:24:05 +0800 +Subject: [PATCH 3/8] loongarch: Add EFI frame buffer support + +Signed-off-by: yangqiming +Signed-off-by: mengyingkun +--- + grub-core/loader/loongarch64/linux-elf.c | 232 +++++++++++++++++++++++ + include/grub/loongarch64/linux.h | 47 +++++ + 2 files changed, 279 insertions(+) + +diff --git a/grub-core/loader/loongarch64/linux-elf.c b/grub-core/loader/loongarch64/linux-elf.c +index 8260e4c26fab..852e8f4b3ee8 100644 +--- a/grub-core/loader/loongarch64/linux-elf.c ++++ b/grub-core/loader/loongarch64/linux-elf.c +@@ -23,6 +23,7 @@ + #include + #include + #include ++#include + + #define GRUB_ADDRESS_TYPE_SYSRAM 1 + #define GRUB_ADDRESS_TYPE_RESERVED 2 +@@ -34,13 +35,242 @@ + { 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_LARCH_CONSOLE_OUT_DEVICE_GUID \ ++ { 0xd3b36f2c, 0xd551, 0x11d4, \ ++ { 0x9a, 0x46, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d } \ ++ } ++ + static struct grub_relocator *relocator; ++static grub_efi_guid_t screen_info_guid = GRUB_EFI_LARCH_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; ++ ++ status = b->install_configuration_table (&screen_info_guid, si); ++ if (status == GRUB_EFI_SUCCESS) ++ return si; ++ ++ 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_GOP_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_LARCH_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 (&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_fdt_and_exit_boot (struct linux_loongarch64_kernel_params *kernel_params) + { +@@ -242,6 +472,8 @@ grub_linux_loongarch_elf_linux_boot_image (struct linux_loongarch64_kernel_param + struct grub_relocator64_state state; + grub_err_t err; + ++ setup_screen_info (); ++ + /* linux kernel type is ELF */ + grub_memset (&state, 0, sizeof (state)); + +diff --git a/include/grub/loongarch64/linux.h b/include/grub/loongarch64/linux.h +index f4b198ab7ad0..c010982b99b6 100644 +--- a/include/grub/loongarch64/linux.h ++++ b/include/grub/loongarch64/linux.h +@@ -79,6 +79,53 @@ struct linux_loongarch64_kernel_params + sizeof (FDT_ADDR_CELLS_STRING) + \ + sizeof (FDT_SIZE_CELLS_STRING)) + ++/* ++ * 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; +-- +2.33.0 + diff --git a/0279-loongarch-Add-support-for-v4.0-interface.patch b/0279-loongarch-Add-support-for-v4.0-interface.patch new file mode 100644 index 0000000000000000000000000000000000000000..8111a11a14e1dd0a7c173fd5504b78643f7afddc --- /dev/null +++ b/0279-loongarch-Add-support-for-v4.0-interface.patch @@ -0,0 +1,434 @@ +From 7883d8fafd9bbf3e2d7c2c01f0b314c25c6d60ea Mon Sep 17 00:00:00 2001 +From: mengyingkun +Date: Mon, 13 Feb 2023 14:40:16 +0800 +Subject: [PATCH 4/8] loongarch: Add support for v4.0 interface + +This patch adds support for parameter passing converntion +between bootloader and kernel, defined in the document +"loongson devsys firmware kernel interface specification v4.0" + +Signed-off-by: yangqiming +Signed-off-by: mengyingkun +--- + grub-core/lib/loongarch64/relocator.c | 2 +- + grub-core/loader/loongarch64/linux-elf.c | 177 ++++++++++++++++++++--- + grub-core/loader/loongarch64/linux.c | 49 ++----- + include/grub/loongarch64/linux.h | 20 +++ + 4 files changed, 190 insertions(+), 58 deletions(-) + +diff --git a/grub-core/lib/loongarch64/relocator.c b/grub-core/lib/loongarch64/relocator.c +index faa4553a5232..587fc585ab7a 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/loader/loongarch64/linux-elf.c b/grub-core/loader/loongarch64/linux-elf.c +index 852e8f4b3ee8..15f99849c4d1 100644 +--- a/grub-core/loader/loongarch64/linux-elf.c ++++ b/grub-core/loader/loongarch64/linux-elf.c +@@ -25,11 +25,14 @@ + #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 } \ +@@ -45,6 +48,16 @@ + { 0x9a, 0x46, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d } \ + } + ++#define GRUB_EFI_LARCH_BOOT_MEMMAP_GUID \ ++ { 0x800f683f, 0xd08b, 0x423a, \ ++ { 0xa2, 0x93, 0x96, 0x5c, 0x3c, 0x6f, 0xe2, 0xb4 } \ ++ } ++ ++#define GRUB_EFI_LARCH_INITRD_MEDIA_GUID \ ++ { 0x5568e427, 0x68fc, 0x4f3d, \ ++ { 0xac, 0x74, 0xca, 0x55, 0x52, 0x31, 0xcc, 0x68 } \ ++ } ++ + static struct grub_relocator *relocator; + static grub_efi_guid_t screen_info_guid = GRUB_EFI_LARCH_SCREEN_INFO_GUID; + +@@ -271,6 +284,135 @@ free_screen_info: + 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_LARCH_BOOT_MEMMAP_GUID; ++ grub_efi_guid_t initrd_media_guid = GRUB_EFI_LARCH_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) + { +@@ -400,12 +542,11 @@ grub_linux_loongarch_elf_make_argv (struct linux_loongarch64_kernel_params *kern + } + + if (kernel_params->ramdisk_addr && kernel_params->ramdisk_size) +- { +- size += ALIGN_UP (sizeof ("rd_start=0xXXXXXXXXXXXXXXXX"), 4) \ +- + ALIGN_UP (sizeof ("rd_size=0xXXXXXXXXXXXXXXXX"), 4) \ +- + ALIGN_UP (sizeof ("initrd=0xXXXXXXXXXXXXXXXX,0xXXXXXXXXXXXXXXXX"), +- 4); +- } ++ { ++ 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 */ +@@ -427,33 +568,33 @@ grub_linux_loongarch_elf_make_argv (struct linux_loongarch64_kernel_params *kern + { + /* rd_start */ + grub_snprintf (linux_args, +- sizeof ("rd_start=0xXXXXXXXXXXXXXXXX"), ++ 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 ("rd_start=0xXXXXXXXXXXXXXXXX"), 4); ++ linux_args += ALIGN_UP (sizeof (GRUB_RD_START_STRING), 4); + kernel_params->linux_argc++; + + /* rd_size */ + grub_snprintf (linux_args, +- sizeof ("rd_size=0xXXXXXXXXXXXXXXXX"), ++ 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 ("rd_size=0xXXXXXXXXXXXXXXXX"), 4); ++ linux_args += ALIGN_UP (sizeof (GRUB_RD_SIZE_STRING), 4); + kernel_params->linux_argc++; + + /* initrd */ + grub_snprintf (linux_args, +- sizeof ("initrd=0xXXXXXXXXXXXXXXXX,0xXXXXXXXXXXXXXXXX"), ++ 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 ("initrd=0xXXXXXXXXXXXXXXXX,0xXXXXXXXXXXXXXXXX"), 4); ++ linux_args += ALIGN_UP (sizeof (GRUB_INITRD_STRING), 4); + kernel_params->linux_argc++; + } + +@@ -472,8 +613,6 @@ grub_linux_loongarch_elf_linux_boot_image (struct linux_loongarch64_kernel_param + struct grub_relocator64_state state; + grub_err_t err; + +- setup_screen_info (); +- + /* linux kernel type is ELF */ + grub_memset (&state, 0, sizeof (state)); + +@@ -481,14 +620,14 @@ grub_linux_loongarch_elf_linux_boot_image (struct linux_loongarch64_kernel_param + state.gpr[1] = kernel_params->kernel_addr; /* ra */ + if (grub_linux_loongarch_elf_get_boot_params (&boot_params) == 0) + { +- grub_printf("not find param, is fdt boot\n"); +- if (allocate_fdt_and_exit_boot (kernel_params) != GRUB_ERR_NONE) ++ grub_dprintf("loongson", "V4.0 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->fdt; /* a1 = fdt */ +- state.gpr[6] = 0; /* a2 = 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_printf("find param, is bpi boot\n"); ++ 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 */ +diff --git a/grub-core/loader/loongarch64/linux.c b/grub-core/loader/loongarch64/linux.c +index 4c0219452a76..03b7940526ee 100644 +--- a/grub-core/loader/loongarch64/linux.c ++++ b/grub-core/loader/loongarch64/linux.c +@@ -230,7 +230,10 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + grub_dprintf ("linux", "kernel @ %p\n", (void*) kernel_params.kernel_addr); + } + +- cmdline_size = grub_loader_cmdline_size (argc, argv) + sizeof (LINUX_IMAGE); ++ 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) +@@ -250,7 +253,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + { + err = grub_create_loader_cmdline (argc, argv, + (char*) ((grub_addr_t) kernel_params.linux_args + sizeof (LINUX_IMAGE) - 1), +- cmdline_size, ++ kernel_params.ramdisk_args_len, + GRUB_VERIFY_KERNEL_CMDLINE); + if (err) + goto fail; +@@ -299,26 +302,6 @@ fail: + return grub_errno; + } + +-/* +- * 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[]) +@@ -326,6 +309,7 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + 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) + { +@@ -345,16 +329,9 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + initrd_size = grub_get_initrd_size (&initrd_ctx); + grub_dprintf ("linux", "Loading initrd\n"); + +- if (is_bpi_boot == 0) { +- grub_size_t initrd_pages; +- initrd_pages = (GRUB_EFI_BYTES_TO_PAGES (initrd_size)); +- initrd_mem = allocate_initrd_mem (initrd_pages); +- } else { +- grub_err_t err; +- initrd_mem = grub_linux_loongarch_alloc_initrd_mem_align (initrd_size, 0x10000, &err); +- if (err) +- goto fail; +- } ++ initrd_mem = grub_linux_loongarch_alloc_initrd_mem_align (initrd_size, 0x1000, &err); ++ if (err) ++ goto fail; + + if (!initrd_mem) + { +@@ -369,14 +346,10 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + 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); ++ (void *) initrd_mem, initrd_size); + fail: + grub_initrd_close (&initrd_ctx); +- if (is_bpi_boot == 0) { +- if (initrd_mem && !kernel_params.ramdisk_addr) +- grub_efi_free_pages ((grub_addr_t) initrd_mem, +- GRUB_EFI_BYTES_TO_PAGES (initrd_size)); +- } ++ + return grub_errno; + } + +diff --git a/include/grub/loongarch64/linux.h b/include/grub/loongarch64/linux.h +index c010982b99b6..f20a719b1386 100644 +--- a/include/grub/loongarch64/linux.h ++++ b/include/grub/loongarch64/linux.h +@@ -59,6 +59,7 @@ struct linux_loongarch64_kernel_params + 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; +@@ -73,12 +74,31 @@ struct linux_loongarch64_kernel_params + #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: + */ +-- +2.33.0 + diff --git a/0280-loongarch-Add-support-for-new-EFI-screen-info-GUID.patch b/0280-loongarch-Add-support-for-new-EFI-screen-info-GUID.patch new file mode 100644 index 0000000000000000000000000000000000000000..8574c910e80b0ee49423efa9a620e1d86138e7fd --- /dev/null +++ b/0280-loongarch-Add-support-for-new-EFI-screen-info-GUID.patch @@ -0,0 +1,62 @@ +From 70fd160eac36be8cb4441952a9e4cc77750bb05c Mon Sep 17 00:00:00 2001 +From: mengyingkun +Date: Fri, 10 Mar 2023 11:00:51 +0800 +Subject: [PATCH 5/8] loongarch: Add support for new EFI screen info GUID + +Support new screen info GUID defined by upstream kernel, and +keep compatible with old GUID defined by loongson. + +Signed-off-by: mengyingkun +--- + grub-core/loader/loongarch64/linux-elf.c | 16 +++++++++++++++- + 1 file changed, 15 insertions(+), 1 deletion(-) + +diff --git a/grub-core/loader/loongarch64/linux-elf.c b/grub-core/loader/loongarch64/linux-elf.c +index 15f99849c4d1..86a90e76b4c3 100644 +--- a/grub-core/loader/loongarch64/linux-elf.c ++++ b/grub-core/loader/loongarch64/linux-elf.c +@@ -58,8 +58,14 @@ + { 0xac, 0x74, 0xca, 0x55, 0x52, 0x31, 0xcc, 0x68 } \ + } + ++#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 screen_info_guid = GRUB_EFI_LARCH_SCREEN_INFO_GUID; ++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) + { +@@ -161,10 +167,17 @@ alloc_screen_info (void) + if (status != GRUB_EFI_SUCCESS) + return NULL; + ++ 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; +@@ -276,6 +289,7 @@ setup_screen_info (void) + + 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); +-- +2.33.0 + diff --git a/0281-loongarch-Force-initrd-load-address-64KiB-alignment.patch b/0281-loongarch-Force-initrd-load-address-64KiB-alignment.patch new file mode 100644 index 0000000000000000000000000000000000000000..f62901bd6969258d6b2419fdcedd73647a1487c2 --- /dev/null +++ b/0281-loongarch-Force-initrd-load-address-64KiB-alignment.patch @@ -0,0 +1,26 @@ +From d6efeb3425c32d6e24900b281e0c58403c5743a5 Mon Sep 17 00:00:00 2001 +From: mengyingkun +Date: Sat, 18 Mar 2023 09:33:41 +0800 +Subject: [PATCH 6/8] loongarch: Force initrd load address 64KiB alignment + +Signed-off-by: mengyingkun +--- + grub-core/loader/loongarch64/linux.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/grub-core/loader/loongarch64/linux.c b/grub-core/loader/loongarch64/linux.c +index 03b7940526ee..5f1d8453b090 100644 +--- a/grub-core/loader/loongarch64/linux.c ++++ b/grub-core/loader/loongarch64/linux.c +@@ -329,7 +329,7 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + initrd_size = grub_get_initrd_size (&initrd_ctx); + grub_dprintf ("linux", "Loading initrd\n"); + +- initrd_mem = grub_linux_loongarch_alloc_initrd_mem_align (initrd_size, 0x1000, &err); ++ initrd_mem = grub_linux_loongarch_alloc_initrd_mem_align (initrd_size, 0x10000, &err); + if (err) + goto fail; + +-- +2.33.0 + diff --git a/0282-loongarch-Implement-cache-synchronization-operation.patch b/0282-loongarch-Implement-cache-synchronization-operation.patch new file mode 100644 index 0000000000000000000000000000000000000000..c97226844e93bc7fbe90d3f4447d35879d82979f --- /dev/null +++ b/0282-loongarch-Implement-cache-synchronization-operation.patch @@ -0,0 +1,30 @@ +From 7b879fb103bbf09fca504db5b5fd5a52e1c0158a Mon Sep 17 00:00:00 2001 +From: mengyingkun +Date: Wed, 22 Mar 2023 09:29:42 +0800 +Subject: [PATCH 7/8] loongarch: Implement cache synchronization operation + +When the module is loaded, ICACHE and DCACHE need to flush +before calling init function. If the caches are not flushed, +loader will crash unexpectedly. + +Signed-off-by: mengyingkun +--- + grub-core/kern/loongarch64/cache.S | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/grub-core/kern/loongarch64/cache.S b/grub-core/kern/loongarch64/cache.S +index d291c6769c3c..6e32d37a9555 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) +-- +2.33.0 + diff --git a/0283-loongarch-Fix-the-initrd-parameter-passing.patch b/0283-loongarch-Fix-the-initrd-parameter-passing.patch new file mode 100644 index 0000000000000000000000000000000000000000..51291fd01faea822522afca21a6e2785948a7a24 --- /dev/null +++ b/0283-loongarch-Fix-the-initrd-parameter-passing.patch @@ -0,0 +1,276 @@ +From a4d6b98d10de59d9d12923d1a37b71b4703e4277 Mon Sep 17 00:00:00 2001 +From: Yingkun Meng +Date: Mon, 7 Aug 2023 11:47:54 +0800 +Subject: [PATCH 8/8] loongarch: Fix the initrd parameter passing + +When booting with EFI kernel, the kernel can't get +initrd parameter, resulting in the inability to +find the initrd. + +Change-Id: I61c6cee35853cd3ee5ce98a0bce949f6833d85b1 +Signed-off-by: Yingkun Meng +--- + grub-core/loader/loongarch64/linux-efi.c | 44 +--------------- + grub-core/loader/loongarch64/linux-elf.c | 53 +++---------------- + grub-core/loader/loongarch64/linux.c | 66 ++++++++++++++++++++++++ + include/grub/loongarch64/linux.h | 6 +++ + 4 files changed, 80 insertions(+), 89 deletions(-) + +diff --git a/grub-core/loader/loongarch64/linux-efi.c b/grub-core/loader/loongarch64/linux-efi.c +index 4dcefd9d9e27..8e2726163725 100644 +--- a/grub-core/loader/loongarch64/linux-efi.c ++++ b/grub-core/loader/loongarch64/linux-efi.c +@@ -16,11 +16,9 @@ + * along with GRUB. If not, see . + */ + #include +-#include + #include + #include + #include +-#include + #include + + #define GRUB_EFI_PE_MAGIC 0x5A4D +@@ -28,47 +26,7 @@ + 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"); ++ return grub_loongarch_setup_initrd_params(); + } + + grub_err_t +diff --git a/grub-core/loader/loongarch64/linux-elf.c b/grub-core/loader/loongarch64/linux-elf.c +index 86a90e76b4c3..28d3c90ad6e6 100644 +--- a/grub-core/loader/loongarch64/linux-elf.c ++++ b/grub-core/loader/loongarch64/linux-elf.c +@@ -308,54 +308,22 @@ allocate_memmap_and_exit_boot (struct linux_loongarch64_kernel_params *kernel_pa + 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_LARCH_BOOT_MEMMAP_GUID; +- grub_efi_guid_t initrd_media_guid = GRUB_EFI_LARCH_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; ++ err = grub_loongarch_setup_initrd_params(); ++ if (err != GRUB_ERR_NONE) ++ { ++ grub_error(GRUB_ERR_IO, "failed to install initrd media"); ++ return err; + } +- } +-#endif + + tmp.map_size = 0; + status = grub_efi_get_memory_map (&tmp.map_size, NULL, &tmp.map_key, +@@ -371,6 +339,7 @@ allocate_memmap_and_exit_boot (struct linux_loongarch64_kernel_params *kernel_pa + goto uninstall_initrd_table; + } + ++ b = grub_efi_system_table->boot_services; + status = b->install_configuration_table (&boot_memmap_guid, m); + if (status != GRUB_EFI_SUCCESS) { + grub_error (GRUB_ERR_IO, "failed to install boot memmap"); +@@ -414,15 +383,7 @@ free_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))); +- } ++ grub_loongarch_remove_initrd_params(); + + return grub_error(GRUB_ERR_BAD_OS, "failed to V40 boot"); + } +diff --git a/grub-core/loader/loongarch64/linux.c b/grub-core/loader/loongarch64/linux.c +index 5f1d8453b090..0b65249e64d9 100644 +--- a/grub-core/loader/loongarch64/linux.c ++++ b/grub-core/loader/loongarch64/linux.c +@@ -29,6 +29,11 @@ GRUB_MOD_LICENSE ("GPLv3+"); + + #define INITRD_MAX_ADDRESS_OFFSET (32ULL * 1024 * 1024 * 1024) + ++#define GRUB_EFI_LARCH_INITRD_MEDIA_GUID \ ++ { 0x5568e427, 0x68fc, 0x4f3d, \ ++ { 0xac, 0x74, 0xca, 0x55, 0x52, 0x31, 0xcc, 0x68 } \ ++ } ++ + static struct linux_loongarch64_kernel_params kernel_params; + + static grub_addr_t phys_addr; +@@ -36,6 +41,67 @@ static grub_dl_t my_mod; + static int loaded; + static int is_bpi_boot; + static int grub_loongarch_linux_type = GRUB_LOONGARCH_LINUX_BAD; ++struct efi_initrd *initrd_tbl; ++ ++grub_err_t ++grub_loongarch_setup_initrd_params (void) ++{ ++ grub_efi_boot_services_t *b; ++ grub_efi_guid_t initrd_media_guid = GRUB_EFI_LARCH_INITRD_MEDIA_GUID; ++ grub_efi_status_t status; ++ ++ if (!kernel_params.ramdisk_addr || !kernel_params.ramdisk_size) ++ { ++ grub_error (GRUB_ERR_BAD_ARGUMENT, ++ N_("you need to load the initrd first")); ++ return GRUB_ERR_BAD_ARGUMENT; ++ } ++ ++ /* Set initrd info to system table*/ ++ b = grub_efi_system_table->boot_services; ++ initrd_tbl = grub_efi_allocate_any_pages (GRUB_EFI_BYTES_TO_PAGES (sizeof(struct efi_initrd))); ++ if (!initrd_tbl) ++ return grub_error (GRUB_ERR_IO, "cannot allocate tbl memory"); ++ ++ initrd_tbl->base = kernel_params.ramdisk_addr; ++ initrd_tbl->size = kernel_params.ramdisk_size; ++ status = b->install_configuration_table (&initrd_media_guid, initrd_tbl); ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_error (GRUB_ERR_IO, "failed to install initrd media"); ++ goto free_tbl; ++ } ++ ++ return GRUB_ERR_NONE; ++ ++free_tbl: ++ if (initrd_tbl) ++ { ++ grub_efi_free_pages ((grub_addr_t) initrd_tbl, ++ GRUB_EFI_BYTES_TO_PAGES (sizeof(struct efi_initrd))); ++ } ++ ++ return GRUB_ERR_IO; ++} ++ ++void ++grub_loongarch_remove_initrd_params (void) ++{ ++ grub_efi_boot_services_t *b; ++ grub_efi_guid_t initrd_media_guid = GRUB_EFI_LARCH_INITRD_MEDIA_GUID; ++ ++ if (!initrd_tbl) ++ return; ++ ++ b = grub_efi_system_table->boot_services; ++ b->install_configuration_table (&initrd_media_guid, NULL); ++ ++ grub_efi_free_pages ((grub_addr_t) initrd_tbl, ++ GRUB_EFI_BYTES_TO_PAGES (sizeof(struct efi_initrd))); ++ ++ initrd_tbl = NULL; ++} ++ + + static grub_err_t + grub_linux_boot (void) +diff --git a/include/grub/loongarch64/linux.h b/include/grub/loongarch64/linux.h +index f20a719b1386..462ce69cabd4 100644 +--- a/include/grub/loongarch64/linux.h ++++ b/include/grub/loongarch64/linux.h +@@ -179,6 +179,12 @@ struct loongsonlist_mem_map { + } GRUB_PACKED map[GRUB_LOONGSON3_BOOT_MEM_MAP_MAX]; + }GRUB_PACKED; + ++grub_err_t ++grub_loongarch_setup_initrd_params (void); ++ ++void ++grub_loongarch_remove_initrd_params (void); ++ + grub_err_t + finalize_efi_params_linux (struct linux_loongarch64_kernel_params *kernel_params); + +-- +2.33.0 + diff --git a/grub.macros b/grub.macros index ed93ec531a61ef130e76a46d2fc9ea7cb100e027..a960267a18e51fd8aa03f7b13b5ab62c7d380caf 100644 --- a/grub.macros +++ b/grub.macros @@ -99,7 +99,7 @@ %endif -%global efi_only aarch64 %{arm} riscv64 +%global efi_only aarch64 %{arm} riscv64 loongarch64 %global efi_arch x86_64 ia64 %{efi_only} %ifarch %{efi_arch} %global with_efi_arch 1 @@ -117,7 +117,7 @@ %{?with_efi_only:%global without_efi_only 1} ### fixme -%ifarch aarch64 %{arm} riscv64 +%ifarch aarch64 %{arm} riscv64 loongarch64 %global efi_modules " " %else %global efi_modules " backtrace chain tpm usb usbserial_common usbserial_pl2303 usbserial_ftdi usbserial_usbdebug keylayouts at_keyboard connectefi " @@ -192,6 +192,14 @@ )} %endif +%ifarch loongarch64 +%global with_emu_arch 0 +%global efiarch loongarch64 +%global target_cpu_name loongarch64 +%global grub_target_name loongarch64-efi +%global package_arch efi-loongarch64 +%endif + %global _target_platform %{target_cpu_name}-%{_vendor}-%{_target_os}%{?_gnu} %global _alt_target_platform %{alt_target_cpu_name}-%{_vendor}-%{_target_os}%{?_gnu} diff --git a/grub.patches b/grub.patches index 601e2afd9c7a4a4279f3c41ff1a0e9fd4e30055a..56a080148abd74cbc65800074d3098041055a62b 100644 --- a/grub.patches +++ b/grub.patches @@ -273,5 +273,14 @@ Patch0272: 0272-font-Fix-an-integer-underflow-in-blit_comb.patch Patch0273: 0273-font-Harden-grub_font_blit_glyph-and-grub_font_blit_.patch Patch0274: 0274-font-Assign-null_font-to-glyphs-in-ascii_font_glyph.patch Patch0275: 0275-normal-charset-Fix-an-integer-overflow-in-grub_unico.patch +Patch0276: 0276-port-Add-LoongArch-support.patch +Patch0277: 0277-loongarch-Modify-the-location-where-initrd-is-loaded.patch +Patch0278: 0278-loongarch-Add-EFI-frame-buffer-support.patch +Patch0279: 0279-loongarch-Add-support-for-v4.0-interface.patch +Patch0280: 0280-loongarch-Add-support-for-new-EFI-screen-info-GUID.patch +Patch0281: 0281-loongarch-Force-initrd-load-address-64KiB-alignment.patch +Patch0282: 0282-loongarch-Implement-cache-synchronization-operation.patch +Patch0283: 0283-loongarch-Fix-the-initrd-parameter-passing.patch + Patch1000: 1000-change-to-use-fuse3.patch diff --git a/grub2.spec b/grub2.spec index 2af2b0fe6676dda36f4b0620c1a4d137044b3dfd..4a3570ce4794ba8151dbce5c69a95eff2b6c5b5b 100644 --- a/grub2.spec +++ b/grub2.spec @@ -1,4 +1,4 @@ -%define anolis_release 10 +%define anolis_release 12 %global _lto_cflags %{nil} %undefine _hardened_build @@ -230,6 +230,7 @@ set -e %if 0%{with_emu_arch} %{expand:%do_emu_install %%{package_arch}} %endif +rm -f $RPM_BUILD_ROOT%{_infodir}/dir ln -s %{name}-set-password ${RPM_BUILD_ROOT}/%{_sbindir}/%{name}-setpassword echo '.so man8/%{name}-set-password.8' > ${RPM_BUILD_ROOT}/%{_datadir}/man/man8/%{name}-setpassword.8 %ifnarch x86_64 @@ -505,6 +506,12 @@ mv ${EFI_HOME}/grub.cfg.stb ${EFI_HOME}/grub.cfg %endif %changelog +* Wed Aug 09 2023 Yingkun Meng -2.06-12 +- add support for loongarch + +* Wed Aug 09 2023 Yingkun Meng -2.06-11 +- fix file installed but unpackaged error + * Wed Jun 28 2023 happy_orange -2.06-10 - add crashkernel in install