diff --git a/0251-Add-loongarch64-support.patch b/0251-Add-loongarch64-support.patch new file mode 100644 index 0000000000000000000000000000000000000000..28f5211e83e262bde4a763362e575cd1d6377e27 --- /dev/null +++ b/0251-Add-loongarch64-support.patch @@ -0,0 +1,3845 @@ +From 6d79dc0beecdf0aca34900b19d207f0402f1da39 Mon Sep 17 00:00:00 2001 +From: loongson Buildteam +Date: Thu, 7 Apr 2022 02:20:43 -0400 +Subject: [PATCH] Add loongarch64 support + +Signed-off-by: loongson Buildteam + +diff --git a/conf/Makefile.common b/conf/Makefile.common +index 0647c53..d8cc61d 100644 +--- a/conf/Makefile.common ++++ b/conf/Makefile.common +@@ -20,6 +20,10 @@ endif + if COND_powerpc_ieee1275 + CFLAGS_PLATFORM += -mcpu=powerpc + endif ++if COND_loongarch64 ++ CFLAGS_PLATFORM += -fno-strict-aliasing -march=loongarch64 -mabi=lp64 -fno-plt -Wa,-mla-global-with-pcrel ++ CPPFLAGS_PLATFORM = -fno-strict-aliasing -march=loongarch64 -mabi=lp64 -fno-plt -Wa,-mla-global-with-pcrel ++endif + + # Other options + +diff --git a/configure.ac b/configure.ac +index da735a6..701e011 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -120,6 +120,10 @@ case "$target_cpu" in + i[[3456]]86) target_cpu=i386 ;; + amd64) target_cpu=x86_64 ;; + sparc) target_cpu=sparc64 ;; ++ loongarch64) ++ target_cpu=loongarch64 ++ machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_CPU_LOONGARCH64=1" ++ ;; + mipsel|mips64el) + target_cpu=mipsel + machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_CPU_MIPSEL=1" +@@ -158,6 +162,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 ;; +@@ -209,6 +214,7 @@ case "$target_cpu"-"$platform" in + mipsel-yeeloong) platform=loongson ;; + mipsel-fuloong) platform=loongson ;; + mipsel-loongson) ;; ++ loongarch64-efi) ;; + arm-uboot) ;; + arm-coreboot) ;; + arm-efi) ;; +@@ -267,6 +273,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 +@@ -2133,6 +2140,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 32cf745..60a8b0d 100644 +--- a/gentpl.py ++++ b/gentpl.py +@@ -32,7 +32,7 @@ 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 +49,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" ] +diff --git a/grub-core/Makefile.am b/grub-core/Makefile.am +index dd49939..81566da 100644 +--- a/grub-core/Makefile.am ++++ b/grub-core/Makefile.am +@@ -240,6 +240,13 @@ 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 ++KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/loongson.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 b26774b..666f87a 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; +@@ -114,6 +117,7 @@ kernel = { + i386_coreboot_startup = kern/i386/coreboot/startup.S; + i386_multiboot_startup = kern/i386/coreboot/startup.S; + mips_startup = kern/mips/startup.S; ++ loongarch64_efi_startup = kern/loongarch64/efi/startup.S; + sparc64_ieee1275_startup = kern/sparc64/ieee1275/crt0.S; + powerpc_ieee1275_startup = kern/powerpc/ieee1275/startup.S; + arm_uboot_startup = kern/arm/startup.S; +@@ -320,6 +324,14 @@ kernel = { + extra_dist = video/sis315_init.c; + mips_loongson = commands/keylayouts.c; + ++ loongarch64 = kern/loongarch64/init.c; ++ loongarch64 = kern/loongarch64/dl.c; ++ loongarch64 = kern/loongarch64/cache.S; ++ loongarch64 = kern/generic/rtc_get_time_ms.c; ++ loongarch64_efi = kern/loongarch64/efi/init.c; ++ loongarch64_efi = lib/loongarch64/efi/loongson.c; ++ loongarch64_efi = lib/loongarch64/efi/loongson_asm.S; ++ + powerpc_ieee1275 = kern/powerpc/cache.S; + powerpc_ieee1275 = kern/powerpc/dl.c; + powerpc_ieee1275 = kern/powerpc/compiler-rt.S; +@@ -856,6 +868,7 @@ module = { + enable = sparc64_ieee1275; + enable = powerpc_ieee1275; + enable = mips_arc; ++ enable = loongarch64_efi; + enable = ia64_efi; + enable = arm_efi; + enable = arm64_efi; +@@ -946,6 +959,7 @@ module = { + xen = lib/xen/halt.c; + i386_xen_pvh = lib/xen/halt.c; + efi = lib/efi/halt.c; ++ loongarch64_efi = commands/acpihalt.c; + ieee1275 = lib/ieee1275/halt.c; + emu = lib/emu/halt.c; + uboot = lib/dummy/halt.c; +@@ -961,6 +975,7 @@ module = { + mips_arc = lib/mips/arc/reboot.c; + mips_loongson = lib/mips/loongson/reboot.c; + mips_qemu_mips = lib/mips/qemu_mips/reboot.c; ++ loongarch64_efi = lib/loongson/reboot.c; + xen = lib/xen/reboot.c; + i386_xen_pvh = lib/xen/reboot.c; + uboot = lib/uboot/reboot.c; +@@ -1669,6 +1684,8 @@ module = { + efi = lib/efi/relocator.c; + mips = lib/mips/relocator_asm.S; + mips = lib/mips/relocator.c; ++ loongarch64 = lib/loongarch64/relocator_asm.S; ++ loongarch64 = lib/loongarch64/relocator.c; + powerpc = lib/powerpc/relocator_asm.S; + powerpc = lib/powerpc/relocator.c; + xen = lib/xen/relocator.c; +@@ -1681,6 +1698,7 @@ module = { + extra_dist = kern/powerpc/cache_flush.S; + + enable = mips; ++ enable = loongarch64; + enable = powerpc; + enable = x86; + enable = i386_xen_pvh; +@@ -1806,6 +1824,7 @@ module = { + i386_pc = lib/i386/pc/vesa_modes_table.c; + i386_xen_pvh = lib/i386/pc/vesa_modes_table.c; + mips = loader/mips/linux.c; ++ loongarch64 = loader/loongarch64/linux.c; + powerpc_ieee1275 = loader/powerpc/ieee1275/linux.c; + sparc64_ieee1275 = loader/sparc64/ieee1275/linux.c; + ia64_efi = loader/ia64/efi/linux.c; +@@ -1914,6 +1933,7 @@ module = { + enable = riscv32_efi; + enable = riscv64_efi; + enable = mips; ++ enable = loongarch64_efi; + }; + + module = { +diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c +index f64f79e..94d9552 100644 +--- a/grub-core/kern/efi/mm.c ++++ b/grub-core/kern/efi/mm.c +@@ -157,7 +157,11 @@ grub_efi_allocate_pages_real (grub_efi_physical_address_t address, + grub_efi_physical_address_t ret = address; + + /* Limit the memory access to less than 4GB for 32-bit platforms. */ ++#ifdef GRUB_CPU_LOONGARCH64 ++ if (address > grub_efi_max_usable_address()) ++#else + if (address > GRUB_EFI_MAX_USABLE_ADDRESS) ++#endif + { + grub_error (GRUB_ERR_BAD_ARGUMENT, + N_("invalid memory address (0x%llx > 0x%llx)"), +@@ -180,7 +184,11 @@ grub_efi_allocate_pages_real (grub_efi_physical_address_t address, + { + /* Uggh, the address 0 was allocated... This is too annoying, + so reallocate another one. */ ++#ifdef GRUB_CPU_LOONGARCH64 ++ ret = grub_efi_max_usable_address(); ++#else + ret = address; ++#endif + status = efi_call_4 (b->allocate_pages, alloctype, memtype, pages, &ret); + grub_efi_free_pages (0, pages); + if (status != GRUB_EFI_SUCCESS) +@@ -198,9 +206,15 @@ grub_efi_allocate_pages_real (grub_efi_physical_address_t address, + void * + grub_efi_allocate_any_pages (grub_efi_uintn_t pages) + { ++#ifdef GRUB_CPU_LOONGARCH64 ++ return grub_efi_allocate_pages_real (grub_efi_max_usable_address(), ++ pages, GRUB_EFI_ALLOCATE_MAX_ADDRESS, ++ GRUB_EFI_LOADER_DATA); ++#else + return grub_efi_allocate_pages_real (GRUB_EFI_MAX_USABLE_ADDRESS, + pages, GRUB_EFI_ALLOCATE_MAX_ADDRESS, + GRUB_EFI_LOADER_DATA); ++#endif + } + + void * +@@ -474,7 +488,9 @@ filter_memory_map (grub_efi_memory_descriptor_t *memory_map, + desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size)) + { + if (desc->type == GRUB_EFI_CONVENTIONAL_MEMORY +-#if 1 ++#ifdef GRUB_CPU_LOONGARCH64 ++ && desc->physical_start <= grub_efi_max_usable_address() ++#else + && desc->physical_start <= GRUB_EFI_MAX_ALLOCATION_ADDRESS + #endif + && desc->physical_start + PAGES_TO_BYTES (desc->num_pages) > 0x100000 +@@ -490,7 +506,14 @@ filter_memory_map (grub_efi_memory_descriptor_t *memory_map, + desc->physical_start = 0x100000; + } + +-#if 1 ++#ifdef GRUB_CPU_LOONGARCH64 ++ if (BYTES_TO_PAGES (filtered_desc->physical_start) ++ + filtered_desc->num_pages ++ > BYTES_TO_PAGES_DOWN (grub_efi_max_usable_address())) ++ filtered_desc->num_pages ++ = (BYTES_TO_PAGES_DOWN (grub_efi_max_usable_address()) ++ - BYTES_TO_PAGES (filtered_desc->physical_start)); ++#else + if (BYTES_TO_PAGES (filtered_desc->physical_start) + + filtered_desc->num_pages + > BYTES_TO_PAGES_DOWN (GRUB_EFI_MAX_ALLOCATION_ADDRESS)) +diff --git a/grub-core/kern/elfXX.c b/grub-core/kern/elfXX.c +index 1859d18..8b1dce9 100644 +--- a/grub-core/kern/elfXX.c ++++ b/grub-core/kern/elfXX.c +@@ -134,6 +134,12 @@ grub_elfXX_load (grub_elf_t elf, const char *filename, + load_addr &= 0x3FFFFFFFFFFFFFFFULL; + break; + } ++#ifdef GRUB_CPU_LOONGARCH64 ++ grub_uint64_t addr; ++ asm volatile ("csrrd %0, 0x181" : "=r" (addr)); ++ if ((load_addr >> 48) != (addr >> 48)) ++ return grub_error (GRUB_ERR_BAD_OS, "bad address space"); ++#endif + load_addr += (grub_addr_t) load_offset; + + if (load_addr < load_base) +diff --git a/grub-core/kern/loongarch64/cache.S b/grub-core/kern/loongarch64/cache.S +new file mode 100644 +index 0000000..d291c67 +--- /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 0000000..a6fd387 +--- /dev/null ++++ b/grub-core/kern/loongarch64/dl.c +@@ -0,0 +1,258 @@ ++/* loongarch64/dl.c - arch-dependent part of loadable module support */ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2002,2005,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 . ++ */ ++ ++#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_LOONGARCH64) ++ return grub_error (GRUB_ERR_BAD_OS, N_("invalid arch-dependent ELF magic")); ++ ++ return GRUB_ERR_NONE; ++} ++ ++#pragma GCC diagnostic ignored "-Wcast-align" ++ ++grub_err_t ++grub_arch_dl_get_tramp_got_size (const void *ehdr __attribute__ ((unused)), ++ grub_size_t *tramp, grub_size_t *got) ++{ ++ *tramp = 0; ++ *got = 0; ++ return GRUB_ERR_NONE; ++} ++ ++/* Relocate symbols. */ ++grub_err_t ++grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, ++ Elf_Shdr *s, grub_dl_segment_t seg) ++{ ++ Elf_Ehdr *e = ehdr; ++ Elf_Rel *rel, *max; ++ grub_uint64_t oprs[10240]={0}; ++ int opri=-1; ++ grub_uint32_t la_abs = 0; ++ ++ for (rel = (Elf_Rel *) ((char *) e + s->sh_offset), ++ max = (Elf_Rel *) ((char *) rel + s->sh_size); ++ rel < max; ++ rel = (Elf_Rel *) ((char *) rel + s->sh_entsize)) ++ { ++ grub_uint8_t *addr; ++ Elf_Sym *sym; ++ Elf_Addr r_info; ++ grub_uint64_t sym_value; ++ ++ if (seg->size < rel->r_offset) ++ return grub_error (GRUB_ERR_BAD_MODULE, ++ "reloc offset is out of the segment"); ++ ++ r_info = (grub_uint64_t) (rel->r_info); ++ ++ addr = (grub_uint8_t *) ((char*)seg->addr + rel->r_offset); ++ sym = (Elf_Sym *) ((char*)mod->symtab ++ + mod->symsize * ELF_R_SYM (r_info)); ++ sym_value = sym->st_value; ++ if (s->sh_type == SHT_RELA) ++ { ++ sym_value += ((Elf_Rela *) rel)->r_addend; ++ } ++ switch (ELF_R_TYPE (r_info)) ++ { ++ case R_LARCH_64: ++ { ++ *(grub_uint64_t *)addr=(grub_uint64_t)sym_value; ++ } ++ break; ++ case R_LARCH_MARK_LA: ++ { ++ la_abs=1; ++ } ++ break; ++ case R_LARCH_SOP_PUSH_PCREL: ++ { ++ opri++; ++ oprs[opri]=(grub_uint64_t)(sym_value-(grub_uint64_t)addr); ++ } ++ break; ++ case R_LARCH_SOP_PUSH_ABSOLUTE: ++ { ++ opri++; ++ oprs[opri]=(grub_uint64_t)sym_value; ++ } ++ break; ++ case R_LARCH_SOP_PUSH_PLT_PCREL: ++ { ++ opri++; ++ oprs[opri]=(grub_uint64_t)(sym_value-(grub_uint64_t)addr); ++ } ++ break; ++ case R_LARCH_SOP_SUB: ++ { ++ grub_uint64_t opr2=oprs[opri]; ++ opri--; ++ grub_uint64_t opr1=oprs[opri]; ++ opri--; ++ opri++; ++ oprs[opri]=opr1 - opr2; ++ } ++ break; ++ case R_LARCH_SOP_SL: ++ { ++ grub_uint64_t opr2=oprs[opri]; ++ opri--; ++ grub_uint64_t opr1=oprs[opri]; ++ opri--; ++ opri++; ++ oprs[opri]=opr1 << opr2; ++ } ++ break; ++ case R_LARCH_SOP_SR: ++ { ++ grub_uint64_t opr2=oprs[opri]; ++ opri--; ++ grub_uint64_t opr1=oprs[opri]; ++ opri--; ++ opri++; ++ oprs[opri]=opr1 >> opr2; ++ } ++ break; ++ case R_LARCH_SOP_ADD: ++ { ++ grub_uint64_t opr2=oprs[opri]; ++ opri--; ++ grub_uint64_t opr1=oprs[opri]; ++ opri--; ++ opri++; ++ oprs[opri]=opr1 + opr2; ++ } ++ break; ++ case R_LARCH_SOP_AND: ++ { ++ grub_uint64_t opr2=oprs[opri]; ++ opri--; ++ grub_uint64_t opr1=oprs[opri]; ++ opri--; ++ opri++; ++ oprs[opri]=opr1 & opr2; ++ } ++ break; ++ case R_LARCH_SOP_IF_ELSE: ++ { ++ grub_uint64_t opr3=oprs[opri]; ++ opri--; ++ grub_uint64_t opr2=oprs[opri]; ++ opri--; ++ grub_uint64_t opr1=oprs[opri]; ++ opri--; ++ if(opr1){ ++ opri++; ++ oprs[opri]=opr2; ++ } else { ++ opri++; ++ oprs[opri]=opr3; ++ } ++ } ++ break; ++ case R_LARCH_SOP_POP_32_S_10_5: ++ { ++ grub_uint64_t opr1 = oprs[opri]; ++ opri--; ++ *(grub_uint64_t *)addr=(*(grub_uint64_t *)addr) | ((opr1 & 0x1f) << 10); ++ } ++ break; ++ case R_LARCH_SOP_POP_32_U_10_12: ++ { ++ grub_uint64_t opr1 = oprs[opri]; ++ opri--; ++ *(grub_uint64_t *)addr=(*(grub_uint64_t *)addr) | ((opr1 & 0xfff) << 10); ++ } ++ break; ++ case R_LARCH_SOP_POP_32_S_10_12: ++ { ++ if(la_abs==1) ++ la_abs=0; ++ grub_uint64_t opr1 = oprs[opri]; ++ opri--; ++ *(grub_uint64_t *)addr= (*(grub_uint64_t *)addr) | ((opr1 & 0xfff) << 10); ++ } ++ break; ++ case R_LARCH_SOP_POP_32_S_10_16: ++ { ++ grub_uint64_t opr1 = oprs[opri]; ++ opri--; ++ *(grub_uint64_t *)addr= (*(grub_uint64_t *)addr) | ((opr1 & 0xffff) << 10); ++ } ++ break; ++ case R_LARCH_SOP_POP_32_S_10_16_S2: ++ { ++ grub_uint64_t opr1 = oprs[opri]; ++ opri--; ++ *(grub_uint64_t *)addr= (*(grub_uint64_t *)addr) | (((opr1 >> 2) & 0xffff) << 10); ++ } ++ break; ++ case R_LARCH_SOP_POP_32_S_5_20: ++ { ++ grub_uint64_t opr1 = oprs[opri]; ++ opri--; ++ *(grub_uint64_t *)addr= (*(grub_uint64_t *)addr) | ((opr1 & 0xfffff)<<5) ; ++ } ++ break; ++ case R_LARCH_SOP_POP_32_S_0_5_10_16_S2: ++ { ++ grub_uint64_t opr1 = oprs[opri]; ++ opri--; ++ *(grub_uint64_t *)addr=(*(grub_uint64_t *)addr) | (((opr1 >> 2) & 0xffff) << 10); ++ *(grub_uint64_t *)addr=(*(grub_uint64_t *)addr) | ((opr1 >> 18) & 0x1f); ++ } ++ break; ++ case R_LARCH_SOP_POP_32_S_0_10_10_16_S2: ++ { ++ grub_uint64_t opr1 = oprs[opri]; ++ opri--; ++ *(grub_uint64_t *)addr=(*(grub_uint64_t *)addr) | (((opr1 >> 2) & 0xffff) << 10); ++ *(grub_uint64_t *)addr=(*(grub_uint64_t *)addr) | ((opr1 >> 18) & 0x3ff); ++ } ++ break; ++ default: ++ { ++ return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, ++ N_("relocation 0x%x is not implemented yet"), ++ ELF_R_TYPE (r_info)); ++ } ++ break; ++ } ++ } ++ ++ return GRUB_ERR_NONE; ++} ++ +diff --git a/grub-core/kern/loongarch64/efi/init.c b/grub-core/kern/loongarch64/efi/init.c +new file mode 100644 +index 0000000..b21d4f1 +--- /dev/null ++++ b/grub-core/kern/loongarch64/efi/init.c +@@ -0,0 +1,76 @@ ++/* init.c - initialize an arm-based EFI system */ ++/* ++ * 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 0000000..1ffff08 +--- /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 0000000..b2de930 +--- /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/loongarch64/efi/loongson.c b/grub-core/lib/loongarch64/efi/loongson.c +new file mode 100644 +index 0000000..8b60d82 +--- /dev/null ++++ b/grub-core/lib/loongarch64/efi/loongson.c +@@ -0,0 +1,505 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2017 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define loongson_params (&loongson_boot_params->boot_params.efi.smbios.lp) ++#define loongson_boot_params_size ALIGN_UP (sizeof (*loongson_boot_params), 8) ++#define loongson_reset_code_size (&grub_efi_loongson_reset_end - &grub_efi_loongson_reset_start) ++ ++extern grub_uint8_t grub_efi_loongson_reset_start; ++extern grub_uint8_t grub_efi_loongson_reset_end; ++ ++static struct ++{ ++ grub_efi_loongson_boot_params boot_params; ++ grub_efi_loongson_memory_map memory_map; ++ grub_efi_loongson_cpu_info cpu_info; ++ grub_efi_loongson_system_info system_info; ++ grub_efi_loongson_irq_src_routing_table irq_src_routing_table; ++ grub_efi_loongson_interface_info interface_info; ++ grub_efi_loongson_special_attribute special_attribute; ++ grub_efi_loongson_board_devices board_devices; ++} GRUB_PACKED ++* loongson_boot_params; ++ ++static void ++grub_efi_loongson_init_reset_system (void) ++{ ++ grub_efi_loongson_boot_params *boot_params; ++ grub_uint8_t *reset_code_addr = (grub_uint8_t *) loongson_boot_params + ++ loongson_boot_params_size; ++ ++ boot_params = &loongson_boot_params->boot_params; ++ grub_efi_loongson_reset_system_addr = ++ (grub_uint64_t) grub_efi_system_table->runtime_services->reset_system; ++ grub_memcpy (reset_code_addr, &grub_efi_loongson_reset_start, loongson_reset_code_size); ++ grub_arch_sync_caches (reset_code_addr, loongson_reset_code_size); ++ ++ boot_params->reset_system.reset_cold = (grub_uint64_t) reset_code_addr + ++ ((grub_uint64_t) &grub_efi_loongson_reset_cold - ++ (grub_uint64_t) &grub_efi_loongson_reset_start); ++ boot_params->reset_system.reset_warm = (grub_uint64_t) reset_code_addr + ++ ((grub_uint64_t) &grub_efi_loongson_reset_warm - ++ (grub_uint64_t) &grub_efi_loongson_reset_start); ++ boot_params->reset_system.shutdown = (grub_uint64_t) reset_code_addr + ++ ((grub_uint64_t) &grub_efi_loongson_reset_shutdown - ++ (grub_uint64_t) &grub_efi_loongson_reset_start); ++ boot_params->reset_system.do_suspend = (grub_uint64_t) reset_code_addr + ++ ((grub_uint64_t) &grub_efi_loongson_reset_suspend - ++ (grub_uint64_t) &grub_efi_loongson_reset_start); ++} ++ ++static void ++grub_efi_loongson_init_smbios (grub_efi_loongson_smbios_table *smbios_table) ++{ ++ grub_efi_loongson_smbios_table *dst = &loongson_boot_params->boot_params.efi.smbios; ++ ++ dst->vers = smbios_table->vers; ++ dst->vga_bios = smbios_table->vga_bios; ++} ++ ++static void ++grub_efi_loongson_init_cpu_info (grub_efi_loongson_smbios_table *smbios_table) ++{ ++ grub_efi_loongson_cpu_info *src = (void *) smbios_table->lp.cpu_offset; ++ grub_efi_loongson_cpu_info *dst = &loongson_boot_params->cpu_info; ++ ++ if (!src) ++ return; ++ ++ grub_memcpy (dst, src, sizeof (grub_efi_loongson_cpu_info)); ++ loongson_params->cpu_offset = (grub_uint64_t) dst - (grub_uint64_t) loongson_params; ++} ++ ++static void ++grub_efi_loongson_init_system_info (grub_efi_loongson_smbios_table *smbios_table) ++{ ++ grub_efi_loongson_system_info *src = (void *) smbios_table->lp.system_offset; ++ grub_efi_loongson_system_info *dst = &loongson_boot_params->system_info; ++ ++ if (!src) ++ return; ++ ++ grub_memcpy (dst, src, sizeof (grub_efi_loongson_system_info)); ++ loongson_params->system_offset = (grub_uint64_t) dst - (grub_uint64_t) loongson_params; ++} ++ ++static void ++grub_efi_loongson_init_irq_src_routing_table (grub_efi_loongson_smbios_table *smbios_table) ++{ ++ grub_efi_loongson_irq_src_routing_table *src = (void *) smbios_table->lp.irq_offset; ++ grub_efi_loongson_irq_src_routing_table *dst = &loongson_boot_params->irq_src_routing_table; ++ ++ if (!src) ++ return; ++ ++ grub_memcpy (dst, src, sizeof (grub_efi_loongson_irq_src_routing_table)); ++ loongson_params->irq_offset = (grub_uint64_t) dst - (grub_uint64_t) loongson_params; ++} ++ ++static void ++grub_efi_loongson_init_interface_info (grub_efi_loongson_smbios_table *smbios_table) ++{ ++ grub_efi_loongson_interface_info *src = (void *) smbios_table->lp.interface_offset; ++ grub_efi_loongson_interface_info *dst = &loongson_boot_params->interface_info; ++ ++ if (!src) ++ return; ++ ++ grub_memcpy (dst, src, sizeof (grub_efi_loongson_interface_info)); ++ loongson_params->interface_offset = (grub_uint64_t) dst - (grub_uint64_t) loongson_params; ++} ++ ++static void ++grub_efi_loongson_init_special_attribute (grub_efi_loongson_smbios_table *smbios_table) ++{ ++ grub_efi_loongson_special_attribute *src = (void *) smbios_table->lp.special_offset; ++ grub_efi_loongson_special_attribute *dst = &loongson_boot_params->special_attribute; ++ ++ if (!src) ++ return; ++ ++ grub_memcpy (dst, src, sizeof (grub_efi_loongson_special_attribute)); ++ loongson_params->special_offset = (grub_uint64_t) dst - (grub_uint64_t) loongson_params; ++} ++ ++static void ++grub_efi_loongson_init_board_devices (grub_efi_loongson_smbios_table *smbios_table) ++{ ++ grub_efi_loongson_board_devices *src = (void *) smbios_table->lp.boarddev_table_offset; ++ grub_efi_loongson_board_devices *dst = &loongson_boot_params->board_devices; ++ ++ if (!src) ++ return; ++ ++ grub_memcpy (dst, src, sizeof (grub_efi_loongson_board_devices)); ++ loongson_params->boarddev_table_offset = (grub_uint64_t) dst - (grub_uint64_t) loongson_params; ++} ++ ++#define ADD_MEMORY_DESCRIPTOR(desc, size) \ ++ ((grub_efi_memory_descriptor_t *) ((char *) (desc) + (size))) ++ ++static void ++grub_efi_loongson_init_memory_map (grub_efi_loongson_smbios_table *smbios_table, ++ grub_efi_memory_descriptor_t *mmap_buf, ++ grub_efi_uintn_t mmap_size, ++ grub_efi_uintn_t desc_size) ++{ ++ grub_efi_loongson_memory_map *src = (void *) smbios_table->lp.memory_offset; ++ grub_efi_loongson_memory_map *dst = &loongson_boot_params->memory_map; ++ grub_efi_memory_descriptor_t *mmap_end; ++ grub_efi_memory_descriptor_t *desc; ++ grub_efi_memory_descriptor_t *desc_next; ++ grub_efi_uint32_t mem_types_reserved[] = ++ { ++ 1, // GRUB_EFI_RESERVED_MEMORY_TYPE ++ 0, // GRUB_EFI_LOADER_CODE ++ 0, // GRUB_EFI_LOADER_DATA ++ 0, // GRUB_EFI_BOOT_SERVICES_CODE ++ 0, // GRUB_EFI_BOOT_SERVICES_DATA ++ 1, // GRUB_EFI_RUNTIME_SERVICES_CODE ++ 1, // GRUB_EFI_RUNTIME_SERVICES_DATA ++ 0, // GRUB_EFI_CONVENTIONAL_MEMORY ++ 1, // GRUB_EFI_UNUSABLE_MEMORY ++ 0, // GRUB_EFI_ACPI_RECLAIM_MEMORY ++ 0, // GRUB_EFI_ACPI_MEMORY_NVS ++ 1, // GRUB_EFI_MEMORY_MAPPED_IO ++ 1, // GRUB_EFI_MEMORY_MAPPED_IO_PORT_SPACE ++ 1, // GRUB_EFI_PAL_CODE ++ 1, // GRUB_EFI_PERSISTENT_MEMORY ++ }; ++ grub_uint32_t need_sort = 1; ++ ++ if (!src) ++ return; ++ ++ dst->vers = src->vers; ++ dst->nr_map = 0; ++ dst->mem_freq = src->mem_freq; ++ loongson_params->memory_offset = (grub_uint64_t) dst - (grub_uint64_t) loongson_params; ++ ++ if (!mmap_buf || !mmap_size || !desc_size) ++ return; ++ ++ mmap_end = ADD_MEMORY_DESCRIPTOR (mmap_buf, mmap_size); ++ ++ /* drop reserved */ ++ for (desc = mmap_buf, ++ desc_next = desc; ++ desc < mmap_end; ++ desc = ADD_MEMORY_DESCRIPTOR (desc, desc_size)) ++ { ++ desc->type = mem_types_reserved[desc->type]; ++ if (desc->type) ++ continue; ++ ++ if (desc != desc_next) ++ *desc_next = *desc; ++ desc_next = ADD_MEMORY_DESCRIPTOR (desc_next, desc_size); ++ } ++ mmap_end = desc_next; ++ ++ /* sort: low->high */ ++ while (need_sort) ++ { ++ need_sort = 0; ++ ++ for (desc = mmap_buf, ++ desc_next = ADD_MEMORY_DESCRIPTOR (desc, desc_size); ++ (desc < mmap_end) && (desc_next < mmap_end); ++ desc = desc_next, ++ desc_next = ADD_MEMORY_DESCRIPTOR (desc, desc_size)) ++ { ++ grub_efi_memory_descriptor_t tmp; ++ ++ if (desc->physical_start <= desc_next->physical_start) ++ continue; ++ ++ tmp = *desc; ++ *desc = *desc_next; ++ *desc_next = tmp; ++ need_sort = 1; ++ } ++ } ++ ++ /* combine continuous memory map */ ++ for (desc = mmap_buf, ++ desc_next = ADD_MEMORY_DESCRIPTOR (desc, desc_size); ++ desc_next < mmap_end; ++ desc_next = ADD_MEMORY_DESCRIPTOR (desc_next, desc_size)) ++ { ++ grub_efi_physical_address_t prev_end = desc->physical_start + (desc->num_pages << 12); ++ ++ if (prev_end == desc_next->physical_start) ++ { ++ desc->num_pages += desc_next->num_pages; ++ continue; ++ } ++ ++ desc = ADD_MEMORY_DESCRIPTOR (desc, desc_size); ++ grub_memcpy (desc, desc_next, desc_size); ++ } ++ mmap_end = ADD_MEMORY_DESCRIPTOR (desc, desc_size); ++ ++ /* write to loongson memory map */ ++ for (desc = mmap_buf; ++ desc < mmap_end; ++ desc = ADD_MEMORY_DESCRIPTOR (desc, desc_size)) ++ { ++ grub_efi_physical_address_t physical_start = grub_vtop ((void *) desc->physical_start); ++ grub_efi_physical_address_t physical_end = physical_start + (desc->num_pages << 12); ++ ++ physical_start = ALIGN_UP (physical_start, 0x100000); ++ physical_end = ALIGN_DOWN (physical_end, 0x100000); ++ ++ if (physical_start >= physical_end || (physical_end - physical_start) < 0x100000) ++ continue; ++ ++ dst->map[dst->nr_map].node_id = (desc->physical_start >> 44) & 0xf; ++ dst->map[dst->nr_map].mem_type = GRUB_EFI_LOONGSON_SYSTEM_RAM; ++ dst->map[dst->nr_map].mem_start = physical_start; ++ dst->map[dst->nr_map].mem_size = (physical_end - physical_start) >> 20; ++ ++ grub_dprintf ("loongson", "memory map %03u: 0x%016lx 0x%016lx @ %u\n", ++ dst->nr_map, physical_start, physical_end - physical_start, ++ dst->map[dst->nr_map].node_id); ++ ++ dst->nr_map ++; ++ } ++} ++ ++#define BYTES_TO_PAGES(bytes) (((bytes) + 0xfff) >> 12) ++#define SUB_MEMORY_DESCRIPTOR(desc, size) \ ++ ((grub_efi_memory_descriptor_t *) ((char *) (desc) - (size))) ++ ++void ++grub_efi_loongson_alloc_boot_params (void) ++{ ++ grub_efi_memory_descriptor_t *mmap_buf; ++ grub_efi_memory_descriptor_t *mmap_end; ++ grub_efi_memory_descriptor_t *desc; ++ grub_efi_uintn_t mmap_size; ++ grub_efi_uintn_t desc_size; ++ grub_efi_physical_address_t address; ++ grub_efi_allocate_type_t type; ++ grub_efi_uintn_t pages; ++ grub_efi_status_t status; ++ grub_efi_boot_services_t *b; ++ int mm_status; ++ ++ type = GRUB_EFI_ALLOCATE_ADDRESS; ++ pages = BYTES_TO_PAGES (loongson_boot_params_size + loongson_reset_code_size); ++ ++ mmap_size = (1 << 12); ++ mmap_buf = grub_malloc (mmap_size); ++ if (!mmap_buf) ++ grub_fatal ("out of memory!"); ++ ++ mm_status = grub_efi_get_memory_map (&mmap_size, mmap_buf, 0, &desc_size, 0); ++ if (mm_status == 0) ++ { ++ grub_free (mmap_buf); ++ mmap_size += desc_size * 32; ++ ++ mmap_buf = grub_malloc (mmap_size); ++ if (!mmap_buf) ++ grub_fatal ("out of memory!"); ++ ++ mm_status = grub_efi_get_memory_map (&mmap_size, mmap_buf, 0, &desc_size, 0); ++ } ++ ++ if (mm_status < 0) ++ grub_fatal ("cannot get memory map!"); ++ ++ mmap_end = ADD_MEMORY_DESCRIPTOR (mmap_buf, mmap_size); ++ ++ for (desc = SUB_MEMORY_DESCRIPTOR (mmap_end, desc_size); ++ desc >= mmap_buf; ++ desc = SUB_MEMORY_DESCRIPTOR (desc, desc_size)) ++ { ++ if (desc->type != GRUB_EFI_CONVENTIONAL_MEMORY) ++ continue; ++ if (desc->physical_start >= grub_efi_max_usable_address()) ++ continue; ++ if (desc->num_pages < pages) ++ continue; ++ ++ address = desc->physical_start; ++ break; ++ } ++ ++ grub_free (mmap_buf); ++ ++ b = grub_efi_system_table->boot_services; ++ status = efi_call_4 (b->allocate_pages, type, GRUB_EFI_RUNTIME_SERVICES_DATA, pages, &address); ++ if (status != GRUB_EFI_SUCCESS) ++ grub_fatal ("cannot allocate Loongson boot parameters!"); ++ ++ loongson_boot_params = (void *) ((grub_addr_t) address); ++} ++ ++void ++grub_efi_loongson_free_boot_params (void) ++{ ++ grub_efi_free_pages ((grub_addr_t) loongson_boot_params, ++ BYTES_TO_PAGES (loongson_boot_params_size + loongson_reset_code_size)); ++} ++ ++void * ++grub_efi_loongson_get_smbios_table (void) ++{ ++ static grub_efi_loongson_smbios_table *smbios_table; ++ grub_efi_loongson_boot_params *old_boot_params; ++ struct bootparamsinterface* boot_params; ++ void * tmp_boot_params = NULL; ++ char * p = NULL; ++ if(smbios_table) ++ return smbios_table; ++ ++ tmp_boot_params = grub_efi_loongson_get_boot_params(); ++ if(tmp_boot_params == NULL) ++ { ++ grub_dprintf("loongson", "tmp_boot_params is NULL\n"); ++ return tmp_boot_params; ++ } ++ ++ boot_params = (struct bootparamsinterface *)tmp_boot_params; ++ p = (char *)&(boot_params->signature); ++ if(grub_strncmp(p, "BPI", 3) == 0) ++ { ++ grub_dprintf("loongson", "find new bpi\n"); ++ return boot_params ? boot_params : 0; ++ } ++ else ++ { ++ old_boot_params = (grub_efi_loongson_boot_params *)tmp_boot_params; ++ /* ++ { ++ grub_dprintf("loongson", "smbios addr%llx\n", &old_boot_params->efi.smbios); ++ grub_dprintf("loongson", "smbios vers%d\n", (grub_uint16_t)(&old_boot_params->efi.smbios.vers)); ++ grub_dprintf("loongson", "smbios vga_bios%d\n", &old_boot_params->efi.smbios.vga_bios); ++ grub_dprintf("loongson", "lp memory offset %llx\n", &old_boot_params->efi.smbios.lp.memory_offset); ++ grub_dprintf("loongson", "lp cpu offset %llx\n", &old_boot_params->efi.smbios.lp.cpu_offset); ++ grub_dprintf("loongson", "lp system offset %llx\n", &old_boot_params->efi.smbios.lp.system_offset); ++ grub_dprintf("loongson", "lp irq offset %llx\n", &old_boot_params->efi.smbios.lp.irq_offset); ++ grub_dprintf("loongson", "lp interface offset %llx\n", &old_boot_params->efi.smbios.p.interface_offset); ++ grub_dprintf("loongson", "lp special offset %llx\n", &old_boot_params->efi.smbios.lp.special_offset); ++ grub_dprintf("loongson", "lp boarddev table offset %llx\n", &old_boot_params->efi.smbios.lp.boarddev_table_offset); ++ } ++ */ ++ return old_boot_params ? &old_boot_params->efi.smbios : 0; ++ } ++ ++} ++ ++int ++grub_efi_is_loongson (void) ++{ ++ return grub_efi_loongson_get_smbios_table () ? 1 : 0; ++} ++ ++void * ++grub_efi_loongson_get_boot_params (void) ++{ ++ static void * boot_params = NULL; ++ grub_efi_configuration_table_t *tables; ++ grub_efi_guid_t smbios_guid = GRUB_EFI_LOONGSON_SMBIOS_TABLE_GUID; ++ unsigned int i; ++ ++ if (boot_params) ++ return boot_params; ++ ++ /* Look for Loongson SMBIOS 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, &smbios_guid, sizeof (smbios_guid)) == 0) ++ { ++ boot_params= tables[i].vendor_table; ++ grub_dprintf ("loongson", "found registered SMBIOS @ %p\n", boot_params); ++ break; ++ } ++ return boot_params; ++} ++ ++grub_uint8_t ++grub_efi_loongson_calculatesum8 (const grub_uint8_t *buffer, grub_efi_uintn_t length) ++{ ++ grub_uint8_t sum; ++ grub_efi_uintn_t count; ++ ++ for (sum = 0, count = 0; count < length; count++) ++ { ++ sum = (grub_uint8_t) (sum + *(buffer + count)); ++ } ++ return sum; ++} ++ ++grub_uint8_t ++grub_efi_loongson_grub_calculatechecksum8 (const grub_uint8_t *buffer, grub_efi_uintn_t length) ++{ ++ grub_uint8_t checksum; ++ ++ checksum = grub_efi_loongson_calculatesum8(buffer, length); ++ ++ return (grub_uint8_t) (0x100 - checksum); ++} ++ ++ ++grub_uint32_t ++grub_efi_loongson_memmap_sort(struct memmap array[], grub_uint32_t length, 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].memsize; ++ for(t = j + 1; t < length; t++) ++ { ++ if(array[j].memstart + tempmemsize == array[t].memstart) ++ { ++ tempmemsize += array[t].memsize; ++ } ++ else ++ { ++ break; ++ } ++ } ++ bpmem->map[index].memtype = memtype; ++ bpmem->map[index].memstart = array[j].memstart; ++ bpmem->map[index].memsize = tempmemsize; ++ grub_dprintf("loongson", "map[%d]:type %x, start 0x%llx, end 0x%llx\n", ++ index, ++ bpmem->map[index].memtype, ++ bpmem->map[index].memstart, ++ bpmem->map[index].memstart+ bpmem->map[index].memsize ++ ); ++ j = t; ++ index++; ++ } ++ return index; ++} ++ +diff --git a/grub-core/lib/loongarch64/efi/loongson_asm.S b/grub-core/lib/loongarch64/efi/loongson_asm.S +new file mode 100644 +index 0000000..4a04d34 +--- /dev/null ++++ b/grub-core/lib/loongarch64/efi/loongson_asm.S +@@ -0,0 +1,58 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2017 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#include ++ ++ .file "loongson_asm.S" ++ .text ++ ++ .align 4 ++ ++VARIABLE (grub_efi_loongson_reset_start) ++ ++VARIABLE (grub_efi_loongson_reset_system_addr) ++ .dword 0 ++ ++reset_system: ++ bl 1f ++ move $a1, $zero ++1: ++ ld.d $t8, $ra, -16 ++ move $a2, $zero ++ jr $t8 ++ move $a3, $zero ++ ++FUNCTION(grub_efi_loongson_reset_cold) ++ b reset_system ++ li.w $a0, 0 ++ ++FUNCTION(grub_efi_loongson_reset_warm) ++ b reset_system ++ li.w $a0, 1 ++ ++FUNCTION(grub_efi_loongson_reset_shutdown) ++ b reset_system ++ li.w $a0, 2 ++ ++FUNCTION(grub_efi_loongson_reset_suspend) ++ b reset_system ++ li.w $a0, 3 ++ ++VARIABLE (grub_efi_loongson_reset_end) ++ ++ +diff --git a/grub-core/lib/loongarch64/relocator.c b/grub-core/lib/loongarch64/relocator.c +new file mode 100644 +index 0000000..f6c1b01 +--- /dev/null ++++ b/grub-core/lib/loongarch64/relocator.c +@@ -0,0 +1,163 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2017 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#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 andi=0x4c000000; ++ grub_uint32_t nop=0x03400000; ++ ++ *(grub_uint32_t *) *target = (andi | (grub_uint32_t)(regn<<5)); ++ *target = ((grub_uint32_t *) *target) + 1; ++ *(grub_uint32_t *) *target = nop; ++ *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); ++ ++ 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 0000000..cf1724d +--- /dev/null ++++ b/grub-core/lib/loongarch64/relocator_asm.S +@@ -0,0 +1,51 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2017 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#include ++ ++ .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 0000000..47db814 +--- /dev/null ++++ b/grub-core/lib/loongarch64/setjmp.S +@@ -0,0 +1,74 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2003,2007,2009 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 ++ ++ .file "setjmp.S" ++ ++GRUB_MOD_LICENSE "GPLv3+" ++ ++ .text ++ ++/* ++ * int grub_setjmp (grub_jmp_buf env) ++ */ ++FUNCTION(grub_setjmp) ++ GRUB_ASM_REG_S $s0, $a0,0 ++ GRUB_ASM_REG_S $s1, $a0,8 ++ GRUB_ASM_REG_S $s2, $a0,16 ++ GRUB_ASM_REG_S $s3, $a0,24 ++ GRUB_ASM_REG_S $s4, $a0,32 ++ GRUB_ASM_REG_S $s5, $a0,40 ++ GRUB_ASM_REG_S $s6, $a0,48 ++ GRUB_ASM_REG_S $s7, $a0,56 ++ GRUB_ASM_REG_S $s8, $a0,64 ++ GRUB_ASM_REG_S $fp, $a0,72 ++ GRUB_ASM_REG_S $sp, $a0,80 ++ GRUB_ASM_REG_S $ra, $a0,88 ++ move $v0, $zero ++ move $v1, $zero ++ jr $ra ++ nop ++/* ++ * int grub_longjmp (grub_jmp_buf env, int val) ++ */ ++FUNCTION(grub_longjmp) ++ GRUB_ASM_REG_L $s0, $a0,0 ++ GRUB_ASM_REG_L $s1, $a0,8 ++ GRUB_ASM_REG_L $s2, $a0,16 ++ GRUB_ASM_REG_L $s3, $a0,24 ++ GRUB_ASM_REG_L $s4, $a0,32 ++ GRUB_ASM_REG_L $s5, $a0,40 ++ GRUB_ASM_REG_L $s6, $a0,48 ++ GRUB_ASM_REG_L $s7, $a0,56 ++ GRUB_ASM_REG_L $s8, $a0,64 ++ GRUB_ASM_REG_L $fp, $a0,72 ++ GRUB_ASM_REG_L $sp, $a0,80 ++ GRUB_ASM_REG_L $ra, $a0,88 ++ addi.w $v0, $zero, 1 ++ /* ++ * replace: movn $v0, $a1, $a1 ++ */ ++ bnez $a1, .ZW0 ++ addi.d $v0, $a1, 0 ++.ZW0: ++ addi.d $v1,$zero,0 ++ jr $ra ++ nop +diff --git a/grub-core/lib/loongson/reboot.c b/grub-core/lib/loongson/reboot.c +new file mode 100644 +index 0000000..107787a +--- /dev/null ++++ b/grub-core/lib/loongson/reboot.c +@@ -0,0 +1,33 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2011 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 ++ ++void ++grub_la_reboot (void) ++{ ++ grub_machine_fini (GRUB_LOADER_FLAG_NORETURN); ++ efi_call_4 (grub_efi_system_table->runtime_services->reset_system, ++ GRUB_EFI_RESET_COLD, GRUB_EFI_SUCCESS, 0, NULL); ++ for (;;) ; ++} +diff --git a/grub-core/lib/setjmp.S b/grub-core/lib/setjmp.S +index aa297ab..da71fc7 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 813dc0e..189ca10 100644 +--- a/grub-core/loader/efi/chainloader.c ++++ b/grub-core/loader/efi/chainloader.c +@@ -332,6 +332,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.c b/grub-core/loader/loongarch64/linux.c +new file mode 100644 +index 0000000..c769bb2 +--- /dev/null ++++ b/grub-core/loader/loongarch64/linux.c +@@ -0,0 +1,580 @@ ++/* linux.c - boot Linux */ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2003,2004,2005,2007,2009,2010,2017 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++GRUB_MOD_LICENSE ("GPLv3+"); ++ ++#pragma GCC diagnostic ignored "-Wcast-align" ++ ++typedef unsigned long size_t; ++ ++static grub_dl_t my_mod; ++ ++static int loaded; ++ ++static grub_uint32_t tmp_index = 0; ++static grub_size_t linux_size; ++ ++static struct grub_relocator *relocator; ++static grub_addr_t target_addr, entry_addr; ++static int linux_argc; ++static grub_uint8_t *linux_args_addr; ++static grub_off_t rd_addr_arg_off, rd_size_arg_off; ++static grub_off_t initrd_addr_arg_off; ++static int initrd_loaded = 0; ++ ++ ++static grub_uint32_t j = 0; ++static grub_uint32_t t = 0; ++grub_uint64_t tempMemsize = 0; ++grub_uint32_t free_index = 0; ++grub_uint32_t reserve_index = 0; ++grub_uint32_t acpi_table_index = 0; ++grub_uint32_t acpi_nvs_index = 0; ++ ++static inline grub_size_t ++page_align (grub_size_t size) ++{ ++ return (size + (1 << 12) - 1) & (~((1 << 12) - 1)); ++} ++ ++/* Find the optimal number of pages for the memory map. Is it better to ++ move this code to efi/mm.c? */ ++static grub_efi_uintn_t ++find_mmap_size (void) ++{ ++ static grub_efi_uintn_t mmap_size = 0; ++ ++ if (mmap_size != 0) ++ return mmap_size; ++ ++ mmap_size = (1 << 12); ++ while (1) ++ { ++ int ret; ++ grub_efi_memory_descriptor_t *mmap; ++ grub_efi_uintn_t desc_size; ++ ++ mmap = grub_malloc (mmap_size); ++ if (! mmap) ++ return 0; ++ ++ ret = grub_efi_get_memory_map (&mmap_size, mmap, 0, &desc_size, 0); ++ grub_free (mmap); ++ ++ if (ret < 0) ++ { ++ grub_error (GRUB_ERR_IO, "cannot get memory map"); ++ return 0; ++ } ++ else if (ret > 0) ++ break; ++ ++ mmap_size += (1 << 12); ++ } ++ ++ ++ /* Increase the size a bit for safety, because GRUB allocates more on ++ later, and EFI itself may allocate more. */ ++ mmap_size += (1 << 12); ++ ++ return page_align (mmap_size); ++} ++ ++static grub_err_t ++grub_linux_boot (void) ++{ ++ struct grub_relocator64_state state; ++ grub_int8_t checksum = 0; ++ grub_efi_memory_descriptor_t * lsdesc = NULL; ++ ++ grub_memset (&state, 0, sizeof (state)); ++ ++ /* Boot the kernel. */ ++ state.gpr[1] = entry_addr; ++ grub_dprintf("loongson", "entry_addr is %p\n", state.gpr[1]); ++ state.gpr[4] = linux_argc; ++ grub_dprintf("loongson", "linux_argc is %d\n", state.gpr[4]); ++ state.gpr[5] = (grub_addr_t) linux_args_addr; ++ grub_dprintf("loongson", "args_addr is %p\n", state.gpr[5]); ++ ++ if(grub_efi_is_loongson ()) ++ { ++ grub_efi_uintn_t mmap_size; ++ grub_efi_uintn_t desc_size; ++ grub_efi_memory_descriptor_t *mmap_buf; ++ grub_err_t err; ++ struct bootparamsinterface * boot_params; ++ void * tmp_boot_params = NULL; ++ grub_efi_uint8_t new_interface_flag = 0; ++ mem_map * new_interface_mem = NULL; ++ char *p = NULL; ++ ++ struct memmap reserve_mem[GRUB_EFI_LOONGSON_MMAP_MAX]; ++ struct memmap free_mem[GRUB_EFI_LOONGSON_MMAP_MAX]; ++ struct memmap acpi_table_mem[GRUB_EFI_LOONGSON_MMAP_MAX]; ++ struct memmap acpi_nvs_mem[GRUB_EFI_LOONGSON_MMAP_MAX]; ++ ++ grub_memset(reserve_mem, 0, sizeof(struct memmap) * GRUB_EFI_LOONGSON_MMAP_MAX); ++ grub_memset(free_mem, 0, sizeof(struct memmap) * GRUB_EFI_LOONGSON_MMAP_MAX); ++ grub_memset(acpi_table_mem, 0, sizeof(struct memmap) * GRUB_EFI_LOONGSON_MMAP_MAX); ++ grub_memset(acpi_nvs_mem, 0, sizeof(struct memmap) * GRUB_EFI_LOONGSON_MMAP_MAX); ++ ++ tmp_boot_params = grub_efi_loongson_get_boot_params(); ++ if(tmp_boot_params == NULL) ++ { ++ grub_printf("not find param\n"); ++ return -1; ++ } ++ ++ boot_params = (struct bootparamsinterface *)tmp_boot_params; ++ p = (char *)&(boot_params->signature); ++ if(grub_strncmp(p, "BPI", 3) == 0) ++ { ++ /* Check extlist headers */ ++ ext_list * listpointer = NULL; ++ listpointer = boot_params->extlist; ++ for( ;listpointer != NULL; listpointer = listpointer->next) ++ { ++ char *pl= (char *)&(listpointer->signature); ++ if(grub_strncmp(pl, "MEM", 3) == 0) ++ { ++ new_interface_mem = (mem_map *)listpointer; ++ } ++ } ++ ++ new_interface_flag = 1; ++ grub_dprintf("loongson", "get new parameter interface\n"); ++ }else{ ++ new_interface_flag = 0; ++ grub_dprintf("loongson", "get old parameter interface\n"); ++ } ++ state.gpr[6] = (grub_uint64_t)tmp_boot_params; ++ grub_dprintf("loongson", "boot_params is %p\n", state.gpr[6]); ++ ++ mmap_size = find_mmap_size (); ++ if (! mmap_size) ++ return grub_errno; ++ mmap_buf = grub_efi_allocate_any_pages (page_align (mmap_size) >> 12); ++ if (! mmap_buf) ++ return grub_error (GRUB_ERR_IO, "cannot allocate memory map"); ++ err = grub_efi_finish_boot_services (&mmap_size, mmap_buf, NULL, ++ &desc_size, NULL); ++ if (err) ++ return err; ++ ++ if(new_interface_flag) ++ { ++ if (!mmap_buf || !mmap_size || !desc_size) ++ return -1; ++ tmp_index = new_interface_mem -> mapcount; ++ ++ /* ++ According to UEFI SPEC,mmap_buf is the accurate Memory Map array \ ++ now we can fill platform specific memory structure. ++ */ ++ for(lsdesc = mmap_buf; lsdesc < (grub_efi_memory_descriptor_t *)((char *)mmap_buf + mmap_size); ++ lsdesc = (grub_efi_memory_descriptor_t *)((char *)lsdesc + desc_size)) ++ { ++ /* Recovery */ ++ if((lsdesc->type != GRUB_EFI_ACPI_RECLAIM_MEMORY) && \ ++ (lsdesc->type != GRUB_EFI_ACPI_MEMORY_NVS) && \ ++ (lsdesc->type != GRUB_EFI_RUNTIME_SERVICES_DATA) && \ ++ (lsdesc->type != GRUB_EFI_RUNTIME_SERVICES_CODE) && \ ++ (lsdesc->type != GRUB_EFI_RESERVED_MEMORY_TYPE) && \ ++ (lsdesc->type != GRUB_EFI_PAL_CODE)) ++ { ++ free_mem[free_index].memtype = GRUB_EFI_LOONGSON_SYSTEM_RAM; ++ free_mem[free_index].memstart = (lsdesc->physical_start) & 0xffffffffffff; ++ free_mem[free_index].memsize = lsdesc->num_pages * 4096; ++ free_index++; ++ ++ /*ACPI*/ ++ }else if((lsdesc->type == GRUB_EFI_ACPI_RECLAIM_MEMORY)){ ++ acpi_table_mem[acpi_table_index].memtype = GRUB_EFI_LOONGSON_ACPI_TABLE; ++ acpi_table_mem[acpi_table_index].memstart = (lsdesc->physical_start) & 0xffffffffffff; ++ acpi_table_mem[acpi_table_index].memsize = lsdesc->num_pages * 4096; ++ acpi_table_index++; ++ }else if((lsdesc->type == GRUB_EFI_ACPI_MEMORY_NVS)){ ++ acpi_nvs_mem[acpi_nvs_index].memtype = GRUB_EFI_LOONGSON_ACPI_NVS; ++ acpi_nvs_mem[acpi_nvs_index].memstart = (lsdesc->physical_start) & 0xffffffffffff; ++ acpi_nvs_mem[acpi_nvs_index].memsize = lsdesc->num_pages * 4096; ++ acpi_nvs_index++; ++ ++ /* Reserve */ ++ }else{ ++ reserve_mem[reserve_index].memtype = GRUB_EFI_LOONGSON_MEMORY_RESERVED; ++ reserve_mem[reserve_index].memstart = (lsdesc->physical_start) & 0xffffffffffff; ++ reserve_mem[reserve_index].memsize = lsdesc->num_pages * 4096; ++ reserve_index++; ++ } ++ } ++ ++ /* Recovery sort */ ++ for(j = 0; j < free_index;) ++ { ++ tempMemsize = free_mem[j].memsize; ++ for(t = j + 1; t < free_index; t++) ++ { ++ if((free_mem[j].memstart + tempMemsize == free_mem[t].memstart) && (free_mem[j].memtype == free_mem[t].memtype)) ++ { ++ tempMemsize += free_mem[t].memsize; ++ }else{ ++ break; ++ } ++ } ++ ++ new_interface_mem->map[tmp_index].memtype = GRUB_EFI_LOONGSON_SYSTEM_RAM; ++ new_interface_mem->map[tmp_index].memstart = free_mem[j].memstart; ++ new_interface_mem->map[tmp_index].memsize = tempMemsize; ++ grub_dprintf("loongson", "map[%d]:type %x, start 0x%llx, end 0x%llx\n", ++ tmp_index, ++ new_interface_mem->map[tmp_index].memtype, ++ new_interface_mem->map[tmp_index].memstart, ++ new_interface_mem->map[tmp_index].memstart+ new_interface_mem->map[tmp_index].memsize ++ ); ++ j = t; ++ tmp_index++; ++ } ++ /*ACPI Sort*/ ++ tmp_index = grub_efi_loongson_memmap_sort(acpi_table_mem, acpi_table_index, new_interface_mem, tmp_index, GRUB_EFI_LOONGSON_ACPI_TABLE); ++ tmp_index = grub_efi_loongson_memmap_sort(acpi_nvs_mem, acpi_nvs_index, new_interface_mem, tmp_index, GRUB_EFI_LOONGSON_ACPI_NVS); ++ /*Reserve Sort*/ ++ grub_uint64_t loongarch_addr; ++ asm volatile ("csrrd %0, 0x181" : "=r" (loongarch_addr)); ++ if((loongarch_addr & 0xff00000000000000) == 0x9000000000000000){ ++ tmp_index = grub_efi_loongson_memmap_sort(reserve_mem, reserve_index, new_interface_mem, tmp_index, GRUB_EFI_LOONGSON_MEMORY_RESERVED); ++ }else{ ++ tmp_index = grub_efi_loongson_memmap_sort(reserve_mem, reserve_index, new_interface_mem, tmp_index, GRUB_EFI_LOONGSON_MEMORY_RESERVED + 1); ++ } ++ ++ new_interface_mem->mapcount = tmp_index; ++ new_interface_mem->header.checksum = 0; ++ ++ checksum = grub_efi_loongson_grub_calculatechecksum8(new_interface_mem, new_interface_mem->header.length); ++ new_interface_mem->header.checksum = checksum; ++ } ++ } ++ ++ state.jumpreg = 1; ++ grub_relocator64_boot (relocator, state); ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_linux_unload (void) ++{ ++ grub_relocator_unload (relocator); ++ grub_dl_unref (my_mod); ++ ++ loaded = 0; ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_linux_load32 (grub_elf_t elf, const char *filename) ++{ ++ Elf32_Addr base; ++ grub_err_t err; ++ grub_uint8_t *playground; ++ ++ /* Linux's entry point incorrectly contains a virtual address. */ ++ entry_addr = elf->ehdr.ehdr32.e_entry; ++ ++ linux_size = grub_elf32_size (elf, &base, 0); ++ if (linux_size == 0) ++ return grub_errno; ++ target_addr = base; ++ linux_size = ALIGN_UP (base + linux_size - base, 8); ++ ++ relocator = grub_relocator_new (); ++ if (!relocator) ++ return grub_errno; ++ ++ { ++ grub_relocator_chunk_t ch; ++ err = grub_relocator_alloc_chunk_addr (relocator, &ch, ++ grub_vtop ((void *) target_addr), ++ linux_size); ++ if (err) ++ return err; ++ playground = get_virtual_current_address (ch); ++ } ++ ++ /* Now load the segments into the area we claimed. */ ++ return grub_elf32_load (elf, filename, playground - base, GRUB_ELF_LOAD_FLAGS_NONE, 0, 0); ++} ++ ++static grub_err_t ++grub_linux_load64 (grub_elf_t elf, const char *filename) ++{ ++ Elf64_Addr base; ++ grub_err_t err; ++ grub_uint8_t *playground; ++ ++ /* Linux's entry point incorrectly contains a virtual address. */ ++ entry_addr = elf->ehdr.ehdr64.e_entry; ++ grub_dprintf("loongson", "entry address = %p\n", entry_addr); ++ ++ linux_size = grub_elf64_size (elf, &base, 0); ++ grub_dprintf("loongson", "base = %p\n", base); ++ ++ if (linux_size == 0) ++ return grub_errno; ++ target_addr = base; ++ linux_size = ALIGN_UP (base + linux_size - base, 8); ++ ++ relocator = grub_relocator_new (); ++ // linux_size=0x322fa80; ++ if (!relocator) ++ return grub_errno; ++ ++ { ++ grub_relocator_chunk_t ch; ++ err = grub_relocator_alloc_chunk_addr (relocator, &ch, ++ grub_vtop ((void *) target_addr), ++ linux_size); ++ if (err) ++ return err; ++ playground = get_virtual_current_address (ch); ++ } ++ ++ /* Now load the segments into the area we claimed. */ ++ return grub_elf64_load (elf, filename, playground - base, GRUB_ELF_LOAD_FLAGS_NONE, 0, 0); ++} ++ ++static grub_err_t ++grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), ++ int argc, char *argv[]) ++{ ++ grub_elf_t elf = 0; ++ int size; ++ int i; ++ grub_uint64_t *linux_argv; ++ char *linux_args; ++ grub_err_t err; ++ ++ if (argc == 0) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); ++ ++ elf = grub_elf_open (argv[0],GRUB_FILE_TYPE_LINUX_KERNEL); ++ if (! elf) ++ return grub_errno; ++ ++ if (elf->ehdr.ehdr32.e_type != ET_EXEC) ++ { ++ grub_elf_close (elf); ++ return grub_error (GRUB_ERR_UNKNOWN_OS, ++ N_("this ELF file is not of the right type")); ++ } ++ ++ /* Release the previously used memory. */ ++ grub_loader_unset (); ++ loaded = 0; ++ ++ /* For arguments. */ ++ linux_argc = argc; ++ /* Main arguments. */ ++ size = (linux_argc) * sizeof (grub_uint64_t); ++ /* Initrd address and size. */ ++ size += 3 * sizeof (grub_uint64_t); ++ /* NULL terminator. */ ++ size += sizeof (grub_uint64_t); ++ /* First argument is always "a0". */ ++ size += ALIGN_UP (sizeof ("a0"), 4); ++ /* Normal arguments. */ ++ for (i = 1; i < argc; i++) ++ size += ALIGN_UP (grub_strlen (argv[i]) + 1, 4); ++ ++ /* rd arguments. */ ++ size += ALIGN_UP (sizeof ("rd_start=0xXXXXXXXXXXXXXXXX"), 4); ++ size += ALIGN_UP (sizeof ("rd_size=0xXXXXXXXXXXXXXXXX"), 4); ++ size += ALIGN_UP (sizeof ("initrd=0xXXXXXXXXXXXXXXXX,0xXXXXXXXXXXXXXXXX"), 4); ++ ++ size = ALIGN_UP (size, 8); ++ ++ if (grub_elf_is_elf32 (elf)) ++ err = grub_linux_load32 (elf, argv[0]); ++ else ++ if (grub_elf_is_elf64 (elf)) ++ err = grub_linux_load64 (elf, argv[0]); ++ else ++ err = grub_error (GRUB_ERR_BAD_OS, N_("invalid arch-dependent ELF magic")); ++ ++ grub_elf_close (elf); ++ ++ if (err) ++ return err; ++ ++ { ++ grub_relocator_chunk_t ch; ++ err = grub_relocator_alloc_chunk_align (relocator, &ch, ++ 0, (0xffffffff - size) + 1, ++ size, 8, ++ GRUB_RELOCATOR_PREFERENCE_HIGH, 0); ++ if (err) ++ return err; ++ linux_args_addr = get_virtual_current_address (ch); ++ } ++ ++ linux_argv = (grub_uint64_t *) linux_args_addr; ++ linux_args = (char *) (linux_argv + (linux_argc + 1 + 3)); ++ ++ grub_memcpy (linux_args, "a0", sizeof ("a0")); ++ *linux_argv = (grub_uint64_t) (grub_addr_t) linux_args; ++ linux_argv++; ++ linux_args += ALIGN_UP (sizeof ("a0"), 4); ++ ++ for (i = 1; i < argc; i++) ++ { ++ grub_memcpy (linux_args, argv[i], grub_strlen (argv[i]) + 1); ++ *linux_argv = (grub_uint64_t) (grub_addr_t) linux_args; ++ linux_argv++; ++ linux_args += ALIGN_UP (grub_strlen (argv[i]) + 1, 4); ++ } ++ ++ /* Reserve space for rd arguments. */ ++ rd_addr_arg_off = (grub_uint8_t *) linux_args - linux_args_addr; ++ linux_args += ALIGN_UP (sizeof ("rd_start=0xXXXXXXXXXXXXXXXX"), 4); ++ *linux_argv = 0; ++ linux_argv++; ++ ++ rd_size_arg_off = (grub_uint8_t *) linux_args - linux_args_addr; ++ linux_args += ALIGN_UP (sizeof ("rd_size=0xXXXXXXXXXXXXXXXX"), 4); ++ *linux_argv = 0; ++ linux_argv++; ++ ++ /* Reserve space for initrd arguments. */ ++ initrd_addr_arg_off = (grub_uint8_t *) linux_args - linux_args_addr; ++ linux_args += ALIGN_UP (sizeof ("initrd=0xXXXXXXXXXXXXXXXX,0xXXXXXXXXXXXXXXXX"), 4); ++ *linux_argv = 0; ++ linux_argv++; ++ ++ *linux_argv = 0; ++ ++ grub_loader_set (grub_linux_boot, grub_linux_unload, 0); ++ initrd_loaded = 0; ++ loaded = 1; ++ grub_dl_ref (my_mod); ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), ++ int argc, char *argv[]) ++{ ++ grub_size_t size = 0; ++ void *initrd_dest; ++ grub_err_t err; ++ struct grub_linux_initrd_context initrd_ctx = { 0, 0, 0 }; ++ ++ if (argc == 0) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); ++ ++ if (!loaded) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("you need to load the kernel first")); ++ ++ if (initrd_loaded) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "only one initrd command can be issued."); ++ ++ if (grub_initrd_init (argc, argv, &initrd_ctx)) ++ goto fail; ++ ++ size = grub_get_initrd_size (&initrd_ctx); ++ ++ { ++ grub_relocator_chunk_t ch; ++ err = grub_relocator_alloc_chunk_align (relocator, &ch, ++ 0, (0xffffffff - size) + 1, ++ size, 0x10000, ++ GRUB_RELOCATOR_PREFERENCE_HIGH, 0); ++ ++ if (err) ++ goto fail; ++ initrd_dest = get_virtual_current_address (ch); ++ } ++ ++ if (grub_initrd_load (&initrd_ctx, argv, initrd_dest)) ++ goto fail; ++ ++ grub_snprintf ((char *) linux_args_addr + rd_addr_arg_off, ++ sizeof ("rd_start=0xXXXXXXXXXXXXXXXX"), "rd_start=0x%lx", ++ (grub_uint64_t) initrd_dest); ++ ((grub_uint64_t *) linux_args_addr)[linux_argc] ++ = (grub_uint64_t) ((grub_addr_t) linux_args_addr + rd_addr_arg_off); ++ linux_argc++; ++ ++ grub_snprintf ((char *) linux_args_addr + rd_size_arg_off, ++ sizeof ("rd_size=0xXXXXXXXXXXXXXXXXX"), "rd_size=0x%lx", ++ (grub_uint64_t) size); ++ ((grub_uint64_t *) linux_args_addr)[linux_argc] ++ = (grub_uint64_t) ((grub_addr_t) linux_args_addr + rd_size_arg_off); ++ linux_argc++; ++ ++ ++ grub_snprintf ((char *) linux_args_addr + initrd_addr_arg_off, ++ sizeof ("initrd=0xXXXXXXXXXXXXXXXX,0xXXXXXXXXXXXXXXXX"), "initrd=0x%lx,0x%lx", ++ ((grub_uint64_t) initrd_dest & 0xffffffff), (grub_uint64_t) size); ++ ((grub_uint64_t *) linux_args_addr)[linux_argc] ++ = (grub_uint64_t) ((grub_addr_t) linux_args_addr + initrd_addr_arg_off); ++ linux_argc++; ++ ++ initrd_loaded = 1; ++ ++ fail: ++ grub_initrd_close (&initrd_ctx); ++ ++ return grub_errno; ++} ++ ++static grub_command_t cmd_linux, cmd_initrd; ++ ++GRUB_MOD_INIT(linux) ++{ ++ cmd_linux = grub_register_command ("linux", grub_cmd_linux, ++ 0, N_("Load Linux.")); ++ cmd_initrd = grub_register_command ("initrd", grub_cmd_initrd, ++ 0, 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/dl.h b/include/grub/dl.h +index 2f76e6b..f57867d 100644 +--- a/include/grub/dl.h ++++ b/include/grub/dl.h +@@ -304,7 +304,7 @@ grub_arch_dl_get_tramp_got_size (const void *ehdr, grub_size_t *tramp, + #define GRUB_ARCH_DL_GOT_ALIGN 4 + #endif + +-#if defined (__aarch64__) || defined (__sparc__) || \ ++#if defined (__aarch64__) || defined (__sparc__) || defined (__loongarch64) || \ + (defined(__riscv) && (__riscv_xlen == 64)) + #define GRUB_ARCH_DL_TRAMP_ALIGN 8 + #define GRUB_ARCH_DL_GOT_ALIGN 8 +diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h +index 0e7e926..72d52bd 100644 +--- a/include/grub/efi/api.h ++++ b/include/grub/efi/api.h +@@ -2083,7 +2083,7 @@ typedef struct grub_efi_rng_protocol grub_efi_rng_protocol_t; + + #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/pe32.h b/include/grub/efi/pe32.h +index a43adf2..a843873 100644 +--- a/include/grub/efi/pe32.h ++++ b/include/grub/efi/pe32.h +@@ -79,6 +79,7 @@ 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_LOONGARCH64 0x6264 + + #define GRUB_PE32_RELOCS_STRIPPED 0x0001 + #define GRUB_PE32_EXECUTABLE_IMAGE 0x0002 +@@ -338,6 +339,7 @@ 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_LOONGARCH64 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 c478933..2354350 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_LOONGARCH64 258 /* LoongArch64 architecture */ + + /* If it is necessary to assign new unofficial EM_* values, please + pick large random numbers (0x8523, 0xa7f2, etc.) to minimize the +@@ -1449,6 +1450,60 @@ typedef struct + #define OHWA0_R4KEOP_CHECKED 0x00000001 + #define OHWA1_R4KEOP_CLEAN 0x00000002 + ++/* LOONGARCH64 relocs. */ ++#define R_LARCH_NONE 0 ++#define R_LARCH_32 1 ++#define R_LARCH_64 2 ++#define R_LARCH_RELATIVE 3 ++#define R_LARCH_COPY 4 ++#define R_LARCH_JUMP_SLOT 5 ++#define R_LARCH_TLS_DTPMOD32 6 ++#define R_LARCH_TLS_DTPMOD64 7 ++#define R_LARCH_TLS_DTPREL32 8 ++#define R_LARCH_TLS_DTPREL64 9 ++#define R_LARCH_TLS_TPREL32 10 ++#define R_LARCH_TLS_TPREL64 11 ++#define R_LARCH_IRELATIVE 12 ++#define R_LARCH_MARK_LA 20 ++#define R_LARCH_MARK_PCREL 21 ++#define R_LARCH_SOP_PUSH_PCREL 22 ++#define R_LARCH_SOP_PUSH_ABSOLUTE 23 ++#define R_LARCH_SOP_PUSH_DUP 24 ++#define R_LARCH_SOP_PUSH_GPREL 25 ++#define R_LARCH_SOP_PUSH_TLS_TPREL 26 ++#define R_LARCH_SOP_PUSH_TLS_GOT 27 ++#define R_LARCH_SOP_PUSH_TLS_GD 28 ++#define R_LARCH_SOP_PUSH_PLT_PCREL 29 ++#define R_LARCH_SOP_ASSERT 30 ++#define R_LARCH_SOP_NOT 31 ++#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_SOP_POP_32_U 46 ++#define R_LARCH_ADD8 47 ++#define R_LARCH_ADD16 48 ++#define R_LARCH_ADD24 49 ++#define R_LARCH_ADD32 50 ++#define R_LARCH_ADD64 51 ++#define R_LARCH_SUB8 52 ++#define R_LARCH_SUB16 53 ++#define R_LARCH_SUB24 54 ++#define R_LARCH_SUB32 55 ++#define R_LARCH_SUB64 56 ++#define R_LARCH_GNU_VTINHERIT 57 ++#define R_LARCH_GNU_VTENTRY 58 ++ + /* MIPS relocs. */ + + #define R_MIPS_NONE 0 /* No reloc */ +diff --git a/include/grub/loongarch64/asm.h b/include/grub/loongarch64/asm.h +new file mode 100644 +index 0000000..c3e77e9 +--- /dev/null ++++ b/include/grub/loongarch64/asm.h +@@ -0,0 +1,10 @@ ++#ifndef GRUB_LOONGARCH64_ASM_HEADER ++#define GRUB_LOONGARCH64_ASM_HEADER 1 ++ ++#define GRUB_ASM_T4 $a4 ++#define GRUB_ASM_T5 $a5 ++#define GRUB_ASM_SZREG 8 ++#define GRUB_ASM_REG_S st.d ++#define GRUB_ASM_REG_L ld.d ++ ++#endif +diff --git a/include/grub/loongarch64/efi/boot.h b/include/grub/loongarch64/efi/boot.h +new file mode 100644 +index 0000000..e69de29 +diff --git a/include/grub/loongarch64/efi/loader.h b/include/grub/loongarch64/efi/loader.h +new file mode 100644 +index 0000000..71a0159 +--- /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/loongson.h b/include/grub/loongarch64/efi/loongson.h +new file mode 100644 +index 0000000..fa32ef5 +--- /dev/null ++++ b/include/grub/loongarch64/efi/loongson.h +@@ -0,0 +1,290 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2017 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#ifndef GRUB_EFI_LOONGSON_HEADER ++#define GRUB_EFI_LOONGSON_HEADER 1 ++ ++#include ++ ++#include ++ ++#define GRUB_EFI_LOONGSON_SMBIOS_TABLE_GUID \ ++ { 0x4660f721, 0x2ec5, 0x416a, \ ++ { 0x89, 0x9a, 0x43, 0x18, 0x02, 0x50, 0xa0, 0xc9 } \ ++ } ++ ++#define GRUB_EFI_LOONGSON_MMAP_MAX 128 ++typedef enum ++ { ++ GRUB_EFI_LOONGSON_SYSTEM_RAM = 1, ++ GRUB_EFI_LOONGSON_MEMORY_RESERVED, ++ GRUB_EFI_LOONGSON_ACPI_TABLE, ++ GRUB_EFI_LOONGSON_ACPI_NVS, ++ GRUB_EFI_LOONGSON_MAX_MEMORY_TYPE ++ } ++grub_efi_loongson_memory_type; ++ ++typedef struct ++{ ++ grub_uint16_t vers; /* version */ ++ grub_uint32_t nr_map; /* number of memory_maps */ ++ grub_uint32_t mem_freq; /* memory frequence */ ++ struct mem_map { ++ grub_uint32_t node_id; /* node_id which memory attached to */ ++ grub_uint32_t mem_type; /* system memory, pci memory, pci io, etc. */ ++ grub_uint64_t mem_start; /* memory map start address */ ++ grub_uint32_t mem_size; /* each memory_map size, not the total size */ ++ } map[GRUB_EFI_LOONGSON_MMAP_MAX]; ++} GRUB_PACKED ++grub_efi_loongson_memory_map; ++ ++/* ++ * Capability and feature descriptor structure for LOONGARCH CPU ++ */ ++typedef struct ++{ ++ grub_uint16_t vers; /* version */ ++ grub_uint32_t processor_id; /* PRID, e.g. 6305, 6306 */ ++ grub_uint32_t cputype; /* Loongson_3A/3B, etc. */ ++ grub_uint32_t total_node; /* num of total numa nodes */ ++ grub_uint16_t cpu_startup_core_id; /* Boot core id */ ++ grub_uint16_t reserved_cores_mask; ++ grub_uint32_t cpu_clock_freq; /* cpu_clock */ ++ grub_uint32_t nr_cpus; ++} GRUB_PACKED ++grub_efi_loongson_cpu_info; ++ ++#define GRUB_EFI_LOONGSON_MAX_UARTS 64 ++ ++typedef struct ++{ ++ grub_uint32_t iotype; /* see include/linux/serial_core.h */ ++ grub_uint32_t uartclk; ++ grub_uint32_t int_offset; ++ grub_uint64_t uart_base; ++} GRUB_PACKED ++grub_efi_loongson_uart_device; ++ ++#define GRUB_EFI_LOONGSON_MAX_SENSORS 64 ++ ++typedef struct ++{ ++ char name[32]; /* a formal name */ ++ char label[64]; /* a flexible description */ ++ grub_uint32_t type; /* SENSOR_* */ ++ grub_uint32_t id; /* instance id of a sensor-class */ ++ grub_uint32_t fan_policy; ++ grub_uint32_t fan_percent; /* only for constant speed policy */ ++ grub_uint64_t base_addr; /* base address of device registers */ ++} GRUB_PACKED ++grub_efi_loongson_sensor_device; ++ ++typedef struct ++{ ++ grub_uint16_t vers; /* version */ ++ grub_uint32_t ccnuma_smp; /* 0: no numa; 1: has numa */ ++ grub_uint32_t sing_double_channel; /* 1:single; 2:double */ ++ grub_uint32_t nr_uarts; ++ grub_efi_loongson_uart_device uarts[GRUB_EFI_LOONGSON_MAX_UARTS]; ++ grub_uint32_t nr_sensors; ++ grub_efi_loongson_sensor_device sensors[GRUB_EFI_LOONGSON_MAX_SENSORS]; ++ char has_ec; ++ char ec_name[32]; ++ grub_uint64_t ec_base_addr; ++ char has_tcm; ++ char tcm_name[32]; ++ grub_uint64_t tcm_base_addr; ++ grub_uint64_t workarounds; /* see workarounds.h */ ++} GRUB_PACKED ++grub_efi_loongson_system_info; ++ ++typedef struct ++{ ++ grub_uint16_t vers; ++ grub_uint16_t size; ++ grub_uint16_t rtr_bus; ++ grub_uint16_t rtr_devfn; ++ grub_uint32_t vendor; ++ grub_uint32_t device; ++ grub_uint32_t PIC_type; /* conform use HT or PCI to route to CPU-PIC */ ++ grub_uint64_t ht_int_bit; /* 3A: 1<<24; 3B: 1<<16 */ ++ grub_uint64_t ht_enable; /* irqs used in this PIC */ ++ grub_uint32_t node_id; /* node id: 0x0-0; 0x1-1; 0x10-2; 0x11-3 */ ++ grub_uint64_t pci_mem_start_addr; ++ grub_uint64_t pci_mem_end_addr; ++ grub_uint64_t pci_io_start_addr; ++ grub_uint64_t pci_io_end_addr; ++ grub_uint64_t pci_config_addr; ++ grub_uint32_t dma_mask_bits; ++} GRUB_PACKED ++grub_efi_loongson_irq_src_routing_table; ++ ++typedef struct ++{ ++ grub_uint16_t vers; /* version */ ++ grub_uint16_t size; ++ grub_uint8_t flag; ++ char description[64]; ++} GRUB_PACKED ++grub_efi_loongson_interface_info; ++ ++#define GRUB_EFI_LOONGSON_MAX_RESOURCE_NUMBER 128 ++ ++typedef struct ++{ ++ grub_uint64_t start; /* resource start address */ ++ grub_uint64_t end; /* resource end address */ ++ char name[64]; ++ grub_uint32_t flags; ++} ++grub_efi_loongson_resource; ++ ++/* arch specific additions */ ++typedef struct ++{ ++} ++grub_efi_loongson_archdev_data; ++ ++typedef struct ++{ ++ char name[64]; /* hold the device name */ ++ grub_uint32_t num_resources; /* number of device_resource */ ++ /* for each device's resource */ ++ grub_efi_loongson_resource resource[GRUB_EFI_LOONGSON_MAX_RESOURCE_NUMBER]; ++ /* arch specific additions */ ++ grub_efi_loongson_archdev_data archdata; ++} ++grub_efi_loongson_board_devices; ++ ++typedef struct ++{ ++ grub_uint16_t vers; /* version */ ++ char special_name[64]; /* special_atribute_name */ ++ grub_uint32_t loongson_special_type; /* type of special device */ ++ /* for each device's resource */ ++ grub_efi_loongson_resource resource[GRUB_EFI_LOONGSON_MAX_RESOURCE_NUMBER]; ++} ++grub_efi_loongson_special_attribute; ++ ++typedef struct ++{ ++ grub_uint64_t memory_offset; /* efi_loongson_memory_map struct offset */ ++ grub_uint64_t cpu_offset; /* efi_loongson_cpuinfo struct offset */ ++ grub_uint64_t system_offset; /* efi_loongson_system_info struct offset */ ++ grub_uint64_t irq_offset; /* efi_loongson_irq_src_routing_table struct offset */ ++ grub_uint64_t interface_offset; /* interface_info struct offset */ ++ grub_uint64_t special_offset; /* efi_loongson_special_attribute struct offset */ ++ grub_uint64_t boarddev_table_offset; /* efi_loongson_board_devices offset */ ++} ++grub_efi_loongson_params; ++ ++typedef struct ++{ ++ grub_uint16_t vers; /* version */ ++ grub_uint64_t vga_bios; /* vga_bios address */ ++ grub_efi_loongson_params lp; ++} ++grub_efi_loongson_smbios_table; ++ ++typedef struct ++{ ++ grub_uint64_t reset_cold; ++ grub_uint64_t reset_warm; ++ grub_uint64_t reset_type; ++ grub_uint64_t shutdown; ++ grub_uint64_t do_suspend; /* NULL if not support */ ++} ++grub_efi_loongson_reset_system; ++ ++typedef struct ++{ ++ grub_uint64_t mps; /* MPS table */ ++ grub_uint64_t acpi; /* ACPI table (IA64 ext 0.71) */ ++ grub_uint64_t acpi20; /* ACPI table (ACPI 2.0) */ ++ grub_efi_loongson_smbios_table smbios; /* SM BIOS table */ ++ grub_uint64_t sal_systab; /* SAL system table */ ++ grub_uint64_t boot_info; /* boot info table */ ++} ++grub_efi_loongson; ++ ++typedef struct ++{ ++ grub_efi_loongson efi; ++ grub_efi_loongson_reset_system reset_system; ++} ++grub_efi_loongson_boot_params; ++ ++extern grub_uint64_t grub_efi_loongson_reset_system_addr; ++ ++extern void grub_efi_loongson_reset_cold (void); ++extern void grub_efi_loongson_reset_warm (void); ++extern void grub_efi_loongson_reset_shutdown (void); ++extern void grub_efi_loongson_reset_suspend (void); ++ ++void grub_efi_loongson_alloc_boot_params (void); ++void grub_efi_loongson_free_boot_params (void); ++void * grub_efi_loongson_get_smbios_table (void); ++ ++int EXPORT_FUNC(grub_efi_is_loongson) (void); ++ ++grub_uint8_t ++EXPORT_FUNC(grub_efi_loongson_calculatesum8) (const grub_uint8_t *Buffer, grub_efi_uintn_t Length); ++ ++grub_uint8_t ++EXPORT_FUNC(grub_efi_loongson_grub_calculatechecksum8) (const grub_uint8_t *Buffer, grub_efi_uintn_t Length); ++ ++ ++void * ++EXPORT_FUNC(grub_efi_loongson_get_boot_params) (void); ++ ++typedef struct _extention_list_hdr{ ++ grub_uint64_t signature; ++ grub_uint32_t length; ++ grub_uint8_t revision; ++ grub_uint8_t checksum; ++ struct _extention_list_hdr *next; ++}GRUB_PACKED ++ext_list; ++ ++typedef struct bootparamsinterface { ++ grub_uint64_t signature; //{'B', 'P', 'I', '_', '0', '_', '1'} ++ grub_efi_system_table_t *systemtable; ++ ext_list *extlist; ++}GRUB_PACKED ++bootparamsinterface; ++ ++typedef struct { ++ ext_list header; // {'M', 'E', 'M'} ++ grub_uint8_t mapcount; ++ struct GRUB_PACKED memmap { ++ grub_uint32_t memtype; ++ grub_uint64_t memstart; ++ grub_uint64_t memsize; ++ } map[GRUB_EFI_LOONGSON_MMAP_MAX]; ++}GRUB_PACKED ++mem_map; ++ ++typedef struct { ++ ext_list header; // {VBIOS} ++ grub_uint64_t vbiosaddr; ++}GRUB_PACKED ++vbios; ++ ++grub_uint32_t ++EXPORT_FUNC (grub_efi_loongson_memmap_sort) (struct memmap array[], grub_uint32_t length, mem_map * bpmem, grub_uint32_t index, grub_uint32_t memtype); ++#endif /* ! GRUB_EFI_LOONGSON_HEADER */ +diff --git a/include/grub/loongarch64/efi/memory.h b/include/grub/loongarch64/efi/memory.h +new file mode 100644 +index 0000000..b8556c7 +--- /dev/null ++++ b/include/grub/loongarch64/efi/memory.h +@@ -0,0 +1,14 @@ ++#ifndef GRUB_MEMORY_CPU_HEADER ++#include ++ ++#define GRUB_EFI_MAX_USABLE_ADDRESS 0x9800000fffffffffUL ++#define GRUB_EFI_MAX_ALLOCATION_ADDRESS GRUB_EFI_MAX_USABLE_ADDRESS ++ ++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; ++} ++ ++#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 0000000..e69de29 +diff --git a/include/grub/loongarch64/io.h b/include/grub/loongarch64/io.h +new file mode 100644 +index 0000000..5f34103 +--- /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/kernel.h b/include/grub/loongarch64/kernel.h +new file mode 100644 +index 0000000..909d539 +--- /dev/null ++++ b/include/grub/loongarch64/kernel.h +@@ -0,0 +1,24 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2005,2006,2007,2008,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_KERNEL_CPU_HEADER ++#define GRUB_KERNEL_CPU_HEADER 1 ++ ++#include ++ ++#endif /* ! GRUB_KERNEL_MACHINE_HEADER */ +diff --git a/include/grub/loongarch64/linux.h b/include/grub/loongarch64/linux.h +new file mode 100644 +index 0000000..cbf8775 +--- /dev/null ++++ b/include/grub/loongarch64/linux.h +@@ -0,0 +1,22 @@ ++/* ++ * 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 . ++ */ ++ ++#ifndef GRUB_LOONGARCH64_LINUX_HEADER ++#define GRUB_LOONGARCH64_LINUX_HEADER 1 ++ ++#endif /* ! GRUB_LOONGARCH64_LINUX_HEADER */ +diff --git a/include/grub/loongarch64/loongarch64.h b/include/grub/loongarch64/loongarch64.h +new file mode 100644 +index 0000000..ea3be3d +--- /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 0000000..03398b3 +--- /dev/null ++++ b/include/grub/loongarch64/memory.h +@@ -0,0 +1,57 @@ ++/* ++ * 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)); ++ return (void *) (a | (addr & 0xffffffffffffff00UL)); ++} ++ ++static inline void ++grub_unmap_memory (void *a __attribute__ ((unused)), ++ grub_size_t size __attribute__ ((unused))) ++{ ++} ++ ++#endif ++ ++#endif +diff --git a/include/grub/loongarch64/relocator.h b/include/grub/loongarch64/relocator.h +new file mode 100644 +index 0000000..8815314 +--- /dev/null ++++ b/include/grub/loongarch64/relocator.h +@@ -0,0 +1,38 @@ ++/* ++ * 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_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 0000000..d9a0776 +--- /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 0000000..c9a7334 +--- /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 0000000..5dc7f21 +--- /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 2631b10..81f1387 100644 +--- a/include/grub/util/install.h ++++ b/include/grub/util/install.h +@@ -105,6 +105,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 0295d40..23850ea 100644 +--- a/util/grub-install-common.c ++++ b/util/grub-install-common.c +@@ -737,6 +737,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 d4fd549..ce153c8 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: +@@ -917,6 +920,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: +@@ -964,6 +968,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: +@@ -1019,6 +1024,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: + is_efi = 1; + break; +@@ -1138,6 +1144,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; +@@ -1171,6 +1180,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; +@@ -1475,6 +1487,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; +@@ -1619,6 +1632,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), +@@ -1724,6 +1738,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: +@@ -1965,6 +1980,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 00f49cc..9e51820 100644 +--- a/util/grub-mkimagexx.c ++++ b/util/grub-mkimagexx.c +@@ -784,6 +784,9 @@ SUFFIX (relocate_addrs) (Elf_Ehdr *e, struct section_metadata *smd, + struct grub_ia64_trampoline *tr = (void *) (pe_target + tramp_off); + grub_uint64_t *gpptr = (void *) (pe_target + got_off); + unsigned unmatched_adr_got_page = 0; ++ grub_uint64_t oprs[10240]= {0}; ++ int opri = -1; ++ grub_uint32_t la_abs = 0; + #define MASK19 ((1 << 19) - 1) + #else + grub_uint32_t *tr = (void *) (pe_target + tramp_off); +@@ -1123,6 +1126,173 @@ SUFFIX (relocate_addrs) (Elf_Ehdr *e, struct section_metadata *smd, + } + break; + } ++ case EM_LOONGARCH64: ++ { ++ sym_addr += addend; ++ switch (ELF_R_TYPE (info)) ++ { ++ case R_LARCH_64: ++ { ++ *target=(grub_uint64_t)sym_addr; ++ } ++ break; ++ case R_LARCH_MARK_LA: ++ { ++ la_abs=1; ++ } ++ break; ++ case R_LARCH_SOP_PUSH_PCREL: ++ { ++ opri++; ++ oprs[opri]=(grub_uint64_t)(sym_addr-(target_section_addr+offset+image_target->vaddr_offset)); ++ } ++ break; ++ case R_LARCH_SOP_PUSH_ABSOLUTE: ++ { ++ opri++; ++ oprs[opri]=(grub_uint64_t)sym_addr; ++ } ++ break; ++ case R_LARCH_SOP_PUSH_PLT_PCREL: ++ { ++ opri++; ++ oprs[opri]=(grub_uint64_t)(sym_addr-(target_section_addr+offset+image_target->vaddr_offset)); ++ } ++ break; ++ case R_LARCH_SOP_SUB: ++ { ++ grub_uint64_t opr2=oprs[opri]; ++ opri--; ++ grub_uint64_t opr1=oprs[opri]; ++ opri--; ++ opri++; ++ oprs[opri]=opr1 - opr2; ++ } ++ break; ++ case R_LARCH_SOP_SL: ++ { ++ grub_uint64_t opr2=oprs[opri]; ++ opri--; ++ grub_uint64_t opr1=oprs[opri]; ++ opri--; ++ opri++; ++ oprs[opri]=opr1 << opr2; ++ } ++ break; ++ case R_LARCH_SOP_SR: ++ { ++ grub_uint64_t opr2=oprs[opri]; ++ opri--; ++ grub_uint64_t opr1=oprs[opri]; ++ opri--; ++ opri++; ++ oprs[opri]=opr1 >> opr2; ++ } ++ break; ++ case R_LARCH_SOP_ADD: ++ { ++ grub_uint64_t opr2=oprs[opri]; ++ opri--; ++ grub_uint64_t opr1=oprs[opri]; ++ opri--; ++ opri++; ++ oprs[opri]=opr1 + opr2; ++ } ++ break; ++ case R_LARCH_SOP_AND: ++ { ++ grub_uint64_t opr2=oprs[opri]; ++ opri--; ++ grub_uint64_t opr1=oprs[opri]; ++ opri--; ++ opri++; ++ oprs[opri]=opr1 & opr2; ++ } ++ break; ++ case R_LARCH_SOP_IF_ELSE: ++ { ++ grub_uint64_t opr3=oprs[opri]; ++ opri--; ++ grub_uint64_t opr2=oprs[opri]; ++ opri--; ++ grub_uint64_t opr1=oprs[opri]; ++ opri--; ++ if(opr1){ ++ opri++; ++ oprs[opri]=opr2; ++ } else { ++ opri++; ++ oprs[opri]=opr3; ++ } ++ } ++ break; ++ case R_LARCH_SOP_POP_32_S_10_5: ++ { ++ grub_uint64_t opr1 = oprs[opri]; ++ opri--; ++ *target=(*target) | ((opr1 & 0x1f) << 10); ++ } ++ break; ++ case R_LARCH_SOP_POP_32_U_10_12: ++ { ++ grub_uint64_t opr1 = oprs[opri]; ++ opri--; ++ *target=(*target) | ((opr1 & 0xfff) << 10); ++ } ++ break; ++ case R_LARCH_SOP_POP_32_S_10_12: ++ { ++ if(la_abs==1) ++ la_abs=0; ++ grub_uint64_t opr1 = oprs[opri]; ++ opri--; ++ *target = (*target) | ((opr1 & 0xfff) << 10); ++ } ++ break; ++ case R_LARCH_SOP_POP_32_S_10_16: ++ { ++ grub_uint64_t opr1 = oprs[opri]; ++ opri--; ++ *target = (*target) | ((opr1 & 0xffff) << 10); ++ } ++ break; ++ case R_LARCH_SOP_POP_32_S_10_16_S2: ++ { ++ grub_uint64_t opr1 = oprs[opri]; ++ opri--; ++ *target = (*target) | (((opr1 >> 2) & 0xffff) << 10); ++ } ++ break; ++ case R_LARCH_SOP_POP_32_S_5_20: ++ { ++ grub_uint64_t opr1 = oprs[opri]; ++ opri--; ++ *target = (*target) | ((opr1 & 0xfffff)<<5) ; ++ } ++ break; ++ case R_LARCH_SOP_POP_32_S_0_5_10_16_S2: ++ { ++ grub_uint64_t opr1 = oprs[opri]; ++ opri--; ++ *target =(*target) | (((opr1 >> 2) & 0xffff) << 10); ++ *target =(*target) | ((opr1 >> 18) & 0x1f); ++ } ++ break; ++ case R_LARCH_SOP_POP_32_S_0_10_10_16_S2: ++ { ++ grub_uint64_t opr1 = oprs[opri]; ++ opri--; ++ *target =(*target) | (((opr1 >> 2) & 0xffff) << 10); ++ *target =(*target) | ((opr1 >> 18) & 0x3ff); ++ } ++ break; ++ default: ++ grub_util_error (_("relocation 0x%x is not implemented yet"), ++ (unsigned int) ELF_R_TYPE (info)); ++ break; ++ } ++ break; ++ } + #endif + #if defined(MKIMAGE_ELF32) + case EM_ARM: +@@ -1501,7 +1671,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); + } + +@@ -1511,7 +1684,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; + } +@@ -1557,6 +1734,10 @@ static void + translate_relocation_pe (struct translate_context *ctx, + Elf_Addr addr, + Elf_Addr info, ++#ifdef GRUB_CPU_LOONGARCH64 ++ Elf_Addr sym_addr, ++ Elf_Addr addend, ++#endif + const struct grub_install_image_target_desc *image_target) + { + /* Necessary to relocate only absolute addresses. */ +@@ -1668,6 +1849,133 @@ translate_relocation_pe (struct translate_context *ctx, + } + break; + break; ++ case EM_LOONGARCH64: ++ switch (ELF_R_TYPE (info)) ++ { ++ case R_LARCH_NONE: ++ break; ++ case R_LARCH_32: ++ break; ++ 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_RELATIVE: ++ break; ++ case R_LARCH_COPY: ++ break; ++ case R_LARCH_JUMP_SLOT: ++ break; ++ case R_LARCH_TLS_DTPMOD32: ++ break; ++ case R_LARCH_TLS_DTPMOD64: ++ break; ++ case R_LARCH_TLS_DTPREL32: ++ break; ++ case R_LARCH_TLS_DTPREL64: ++ break; ++ case R_LARCH_TLS_TPREL32: ++ break; ++ case R_LARCH_TLS_TPREL64: ++ break; ++ case R_LARCH_IRELATIVE: ++ break; ++ case R_LARCH_MARK_LA: ++ { ++ ctx->current_address = add_fixup_entry ( ++ &ctx->lst, ++ GRUB_PE32_REL_BASED_LOONGARCH64, ++ addr, 0, ctx->current_address, ++ image_target); ++ } ++ break; ++ case R_LARCH_MARK_PCREL: ++ break; ++ case R_LARCH_SOP_PUSH_PCREL: ++ break; ++ case R_LARCH_SOP_PUSH_ABSOLUTE: ++ break; ++ case R_LARCH_SOP_PUSH_DUP: ++ break; ++ case R_LARCH_SOP_PUSH_GPREL: ++ break; ++ case R_LARCH_SOP_PUSH_TLS_TPREL: ++ break; ++ case R_LARCH_SOP_PUSH_TLS_GOT: ++ break; ++ case R_LARCH_SOP_PUSH_TLS_GD: ++ break; ++ case R_LARCH_SOP_PUSH_PLT_PCREL: ++ break; ++ case R_LARCH_SOP_ASSERT: ++ break; ++ case R_LARCH_SOP_NOT: ++ break; ++ case R_LARCH_SOP_SUB: ++ break; ++ case R_LARCH_SOP_SL: ++ break; ++ case R_LARCH_SOP_SR: ++ break; ++ case R_LARCH_SOP_ADD: ++ break; ++ case R_LARCH_SOP_AND: ++ break; ++ case R_LARCH_SOP_IF_ELSE: ++ break; ++ case R_LARCH_SOP_POP_32_S_10_5: ++ break; ++ case R_LARCH_SOP_POP_32_U_10_12: ++ break; ++ case R_LARCH_SOP_POP_32_S_10_12: ++ break; ++ case R_LARCH_SOP_POP_32_S_10_16: ++ break; ++ case R_LARCH_SOP_POP_32_S_10_16_S2: ++ break; ++ case R_LARCH_SOP_POP_32_S_5_20: ++ break; ++ case R_LARCH_SOP_POP_32_S_0_5_10_16_S2: ++ break; ++ case R_LARCH_SOP_POP_32_S_0_10_10_16_S2: ++ break; ++ case R_LARCH_SOP_POP_32_U: ++ break; ++ case R_LARCH_ADD8: ++ break; ++ case R_LARCH_ADD16: ++ break; ++ case R_LARCH_ADD24: ++ break; ++ case R_LARCH_ADD32: ++ break; ++ case R_LARCH_ADD64: ++ break; ++ case R_LARCH_SUB8: ++ break; ++ case R_LARCH_SUB16: ++ break; ++ case R_LARCH_SUB24: ++ break; ++ case R_LARCH_SUB32: ++ break; ++ case R_LARCH_SUB64: ++ break; ++ case R_LARCH_GNU_VTINHERIT: ++ break; ++ case R_LARCH_GNU_VTENTRY: ++ break; ++ default: ++ grub_util_error (_("relocation 0x%x is not implemented yet"), ++ (unsigned int) ELF_R_TYPE (info)); ++ break; ++ } ++ break; + #if defined(MKIMAGE_ELF32) + case EM_ARM: + switch (ELF_R_TYPE (info)) +@@ -1825,10 +2133,18 @@ static void + translate_relocation (struct translate_context *ctx, + Elf_Addr addr, + Elf_Addr info, ++#ifdef GRUB_CPU_LOONGARCH64 ++ Elf_Addr sym_addr, ++ Elf_Addr addend, ++#endif + const struct grub_install_image_target_desc *image_target) + { + if (image_target->id == IMAGE_EFI) ++#ifdef GRUB_CPU_LOONGARCH64 ++ translate_relocation_pe (ctx, addr, info, sym_addr, addend, image_target); ++#else + translate_relocation_pe (ctx, addr, info, image_target); ++#endif + else + translate_relocation_raw (ctx, addr, info, image_target); + } +@@ -1969,11 +2285,21 @@ make_reloc_section (Elf_Ehdr *e, struct grub_mkimage_layout *layout, + if ((grub_target_to_host32 (s->sh_type) == SHT_REL) || + (grub_target_to_host32 (s->sh_type) == SHT_RELA)) + { ++#ifdef GRUB_CPU_LOONGARCH64 ++ Elf_Rela *r; ++#else + Elf_Rel *r; ++#endif + Elf_Word rtab_size, r_size, num_rs; + Elf_Off rtab_offset; + Elf_Addr section_address; + Elf_Word j; ++#ifdef GRUB_CPU_LOONGARCH64 ++ Elf_Shdr *symtab_section; ++ ++ symtab_section = (Elf_Shdr *) ((char *) smd->sections ++ + (grub_target_to_host32 (s->sh_link) * smd->section_entsize)); ++#endif + + if (!SUFFIX (is_kept_reloc_section) (s, image_target, smd)) + { +@@ -1992,20 +2318,39 @@ make_reloc_section (Elf_Ehdr *e, struct grub_mkimage_layout *layout, + + section_address = smd->vaddrs[grub_le_to_cpu32 (s->sh_info)]; + ++#ifdef GRUB_CPU_LOONGARCH64 ++ for (j = 0, r = (Elf_Rela *) ((char *) e + rtab_offset); ++ j < num_rs; ++ j++, r = (Elf_Rela *) ((char *) r + r_size)) ++#else + for (j = 0, r = (Elf_Rel *) ((char *) e + rtab_offset); + j < num_rs; + j++, r = (Elf_Rel *) ((char *) r + r_size)) ++#endif + { + Elf_Addr info; + Elf_Addr offset; + Elf_Addr addr; ++#ifdef GRUB_CPU_LOONGARCH64 ++ Elf_Addr sym_addr; ++ Elf_Addr addend; ++#endif + + offset = grub_target_to_host (r->r_offset); + info = grub_target_to_host (r->r_info); +- ++#ifdef GRUB_CPU_LOONGARCH64 ++ sym_addr = SUFFIX (get_symbol_address) (e, symtab_section, ++ ELF_R_SYM (info), image_target); ++ addend = (s->sh_type == grub_target_to_host32 (SHT_RELA)) ? ++ grub_target_to_host (r->r_addend) : 0; ++#endif + addr = section_address + offset; + ++#ifdef GRUB_CPU_LOONGARCH64 ++ translate_relocation (&ctx, addr, info, sym_addr, addend, image_target); ++#else + translate_relocation (&ctx, addr, info, image_target); ++#endif + } + } + +diff --git a/util/grub-mknetdir.c b/util/grub-mknetdir.c +index 1a61e05..83e9578 100644 +--- a/util/grub-mknetdir.c ++++ b/util/grub-mknetdir.c +@@ -115,6 +115,7 @@ static struct + [GRUB_INSTALL_PLATFORM_ARM64_EFI] = { "arm64-efi", "efinet", ".efi" }, + [GRUB_INSTALL_PLATFORM_RISCV32_EFI] = { "riscv32-efi", "efinet", ".efi" }, + [GRUB_INSTALL_PLATFORM_RISCV64_EFI] = { "riscv64-efi", "efinet", ".efi" }, ++ [GRUB_INSTALL_PLATFORM_LOONGARCH64_EFI] = { "loongarch64-efi", "efinet", ".efi" }, + }; + + static void +diff --git a/util/grub-module-verifier.c b/util/grub-module-verifier.c +index 163529c..ce77ff7 100644 +--- a/util/grub-module-verifier.c ++++ b/util/grub-module-verifier.c +@@ -176,6 +176,52 @@ struct grub_module_verifier_arch archs[] = { + -1 + } + }, ++ { "loongarch64", 8, 0, EM_LOONGARCH64, GRUB_MODULE_VERIFY_SUPPORTS_REL | GRUB_MODULE_VERIFY_SUPPORTS_RELA, (int[]){ ++ R_LARCH_NONE, ++ R_LARCH_32, ++ R_LARCH_64, ++ R_LARCH_RELATIVE, ++ R_LARCH_COPY, ++ R_LARCH_JUMP_SLOT, ++ R_LARCH_TLS_DTPMOD32, ++ R_LARCH_TLS_DTPMOD64, ++ R_LARCH_TLS_DTPREL32, ++ R_LARCH_TLS_DTPREL64, ++ R_LARCH_TLS_TPREL32, ++ R_LARCH_TLS_TPREL64, ++ R_LARCH_IRELATIVE, ++ R_LARCH_MARK_LA, ++ R_LARCH_MARK_PCREL, ++ R_LARCH_SOP_PUSH_PCREL, ++ R_LARCH_SOP_PUSH_ABSOLUTE, ++ R_LARCH_SOP_PUSH_DUP, ++ R_LARCH_SOP_PUSH_GPREL, ++ R_LARCH_SOP_PUSH_TLS_TPREL, ++ R_LARCH_SOP_PUSH_TLS_GOT, ++ R_LARCH_SOP_PUSH_TLS_GD, ++ R_LARCH_SOP_PUSH_PLT_PCREL, ++ R_LARCH_SOP_ASSERT, ++ R_LARCH_SOP_NOT, ++ R_LARCH_SOP_SUB, ++ R_LARCH_SOP_SL, ++ R_LARCH_SOP_SR, ++ R_LARCH_SOP_ADD, ++ R_LARCH_SOP_AND, ++ R_LARCH_SOP_IF_ELSE, ++ R_LARCH_SOP_POP_32_S_10_5, ++ R_LARCH_SOP_POP_32_U_10_12, ++ R_LARCH_SOP_POP_32_S_10_12, ++ R_LARCH_SOP_POP_32_S_10_16, ++ R_LARCH_SOP_POP_32_S_10_16_S2, ++ R_LARCH_SOP_POP_32_S_5_20, ++ R_LARCH_SOP_POP_32_S_0_5_10_16_S2, ++ R_LARCH_SOP_POP_32_S_0_10_10_16_S2, ++ R_LARCH_SOP_POP_32_U, ++ -1 ++ }, (int[]){ ++ -1 ++ } ++ }, + }; + + struct platform_whitelist { +diff --git a/util/mkimage.c b/util/mkimage.c +index 47cd705..9201002 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_LOONGARCH64, ++ }, + }; + + #include +-- +2.27.0 + diff --git a/0252-LoongArch64-support-boot-parameter-01002-version.patch b/0252-LoongArch64-support-boot-parameter-01002-version.patch new file mode 100644 index 0000000000000000000000000000000000000000..7190e8aad84c7ef4db9e8bbca089a160b5812b21 --- /dev/null +++ b/0252-LoongArch64-support-boot-parameter-01002-version.patch @@ -0,0 +1,1397 @@ +From a218f4865a258e1cd8da9ad7fe210a97b4d08108 Mon Sep 17 00:00:00 2001 +From: loongson Buildteam +Date: Tue, 12 Apr 2022 17:10:45 +0800 +Subject: [PATCH] LoongArch64 support boot parameter 01002 version + + +diff --git a/conf/Makefile.common b/conf/Makefile.common +index d8cc61d..27cadba 100644 +--- a/conf/Makefile.common ++++ b/conf/Makefile.common +@@ -21,8 +21,8 @@ if COND_powerpc_ieee1275 + CFLAGS_PLATFORM += -mcpu=powerpc + endif + if COND_loongarch64 +- CFLAGS_PLATFORM += -fno-strict-aliasing -march=loongarch64 -mabi=lp64 -fno-plt -Wa,-mla-global-with-pcrel +- CPPFLAGS_PLATFORM = -fno-strict-aliasing -march=loongarch64 -mabi=lp64 -fno-plt -Wa,-mla-global-with-pcrel ++ CFLAGS_PLATFORM += -fno-strict-aliasing -march=loongarch64 -mabi=lp64 -fno-plt -Wa,-mla-global-with-abs -mcmodel=large ++ CPPFLAGS_PLATFORM = -fno-strict-aliasing -march=loongarch64 -mabi=lp64 -fno-plt -Wa,-mla-global-with-abs -mcmodel=large + endif + + # Other options +diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def +index 666f87a..ee3c56f 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -330,7 +330,6 @@ kernel = { + loongarch64 = kern/generic/rtc_get_time_ms.c; + loongarch64_efi = kern/loongarch64/efi/init.c; + loongarch64_efi = lib/loongarch64/efi/loongson.c; +- loongarch64_efi = lib/loongarch64/efi/loongson_asm.S; + + powerpc_ieee1275 = kern/powerpc/cache.S; + powerpc_ieee1275 = kern/powerpc/dl.c; +diff --git a/grub-core/kern/elfXX.c b/grub-core/kern/elfXX.c +index 8b1dce9..1859d18 100644 +--- a/grub-core/kern/elfXX.c ++++ b/grub-core/kern/elfXX.c +@@ -134,12 +134,6 @@ grub_elfXX_load (grub_elf_t elf, const char *filename, + load_addr &= 0x3FFFFFFFFFFFFFFFULL; + break; + } +-#ifdef GRUB_CPU_LOONGARCH64 +- grub_uint64_t addr; +- asm volatile ("csrrd %0, 0x181" : "=r" (addr)); +- if ((load_addr >> 48) != (addr >> 48)) +- return grub_error (GRUB_ERR_BAD_OS, "bad address space"); +-#endif + load_addr += (grub_addr_t) load_offset; + + if (load_addr < load_base) +diff --git a/grub-core/lib/loongarch64/efi/loongson.c b/grub-core/lib/loongarch64/efi/loongson.c +index 8b60d82..3c6c322 100644 +--- a/grub-core/lib/loongarch64/efi/loongson.c ++++ b/grub-core/lib/loongarch64/efi/loongson.c +@@ -23,400 +23,14 @@ + #include + #include + +-#define loongson_params (&loongson_boot_params->boot_params.efi.smbios.lp) +-#define loongson_boot_params_size ALIGN_UP (sizeof (*loongson_boot_params), 8) +-#define loongson_reset_code_size (&grub_efi_loongson_reset_end - &grub_efi_loongson_reset_start) +- +-extern grub_uint8_t grub_efi_loongson_reset_start; +-extern grub_uint8_t grub_efi_loongson_reset_end; +- +-static struct +-{ +- grub_efi_loongson_boot_params boot_params; +- grub_efi_loongson_memory_map memory_map; +- grub_efi_loongson_cpu_info cpu_info; +- grub_efi_loongson_system_info system_info; +- grub_efi_loongson_irq_src_routing_table irq_src_routing_table; +- grub_efi_loongson_interface_info interface_info; +- grub_efi_loongson_special_attribute special_attribute; +- grub_efi_loongson_board_devices board_devices; +-} GRUB_PACKED +-* loongson_boot_params; +- +-static void +-grub_efi_loongson_init_reset_system (void) +-{ +- grub_efi_loongson_boot_params *boot_params; +- grub_uint8_t *reset_code_addr = (grub_uint8_t *) loongson_boot_params + +- loongson_boot_params_size; +- +- boot_params = &loongson_boot_params->boot_params; +- grub_efi_loongson_reset_system_addr = +- (grub_uint64_t) grub_efi_system_table->runtime_services->reset_system; +- grub_memcpy (reset_code_addr, &grub_efi_loongson_reset_start, loongson_reset_code_size); +- grub_arch_sync_caches (reset_code_addr, loongson_reset_code_size); +- +- boot_params->reset_system.reset_cold = (grub_uint64_t) reset_code_addr + +- ((grub_uint64_t) &grub_efi_loongson_reset_cold - +- (grub_uint64_t) &grub_efi_loongson_reset_start); +- boot_params->reset_system.reset_warm = (grub_uint64_t) reset_code_addr + +- ((grub_uint64_t) &grub_efi_loongson_reset_warm - +- (grub_uint64_t) &grub_efi_loongson_reset_start); +- boot_params->reset_system.shutdown = (grub_uint64_t) reset_code_addr + +- ((grub_uint64_t) &grub_efi_loongson_reset_shutdown - +- (grub_uint64_t) &grub_efi_loongson_reset_start); +- boot_params->reset_system.do_suspend = (grub_uint64_t) reset_code_addr + +- ((grub_uint64_t) &grub_efi_loongson_reset_suspend - +- (grub_uint64_t) &grub_efi_loongson_reset_start); +-} +- +-static void +-grub_efi_loongson_init_smbios (grub_efi_loongson_smbios_table *smbios_table) +-{ +- grub_efi_loongson_smbios_table *dst = &loongson_boot_params->boot_params.efi.smbios; +- +- dst->vers = smbios_table->vers; +- dst->vga_bios = smbios_table->vga_bios; +-} +- +-static void +-grub_efi_loongson_init_cpu_info (grub_efi_loongson_smbios_table *smbios_table) +-{ +- grub_efi_loongson_cpu_info *src = (void *) smbios_table->lp.cpu_offset; +- grub_efi_loongson_cpu_info *dst = &loongson_boot_params->cpu_info; +- +- if (!src) +- return; +- +- grub_memcpy (dst, src, sizeof (grub_efi_loongson_cpu_info)); +- loongson_params->cpu_offset = (grub_uint64_t) dst - (grub_uint64_t) loongson_params; +-} +- +-static void +-grub_efi_loongson_init_system_info (grub_efi_loongson_smbios_table *smbios_table) +-{ +- grub_efi_loongson_system_info *src = (void *) smbios_table->lp.system_offset; +- grub_efi_loongson_system_info *dst = &loongson_boot_params->system_info; +- +- if (!src) +- return; +- +- grub_memcpy (dst, src, sizeof (grub_efi_loongson_system_info)); +- loongson_params->system_offset = (grub_uint64_t) dst - (grub_uint64_t) loongson_params; +-} +- +-static void +-grub_efi_loongson_init_irq_src_routing_table (grub_efi_loongson_smbios_table *smbios_table) +-{ +- grub_efi_loongson_irq_src_routing_table *src = (void *) smbios_table->lp.irq_offset; +- grub_efi_loongson_irq_src_routing_table *dst = &loongson_boot_params->irq_src_routing_table; +- +- if (!src) +- return; +- +- grub_memcpy (dst, src, sizeof (grub_efi_loongson_irq_src_routing_table)); +- loongson_params->irq_offset = (grub_uint64_t) dst - (grub_uint64_t) loongson_params; +-} +- +-static void +-grub_efi_loongson_init_interface_info (grub_efi_loongson_smbios_table *smbios_table) +-{ +- grub_efi_loongson_interface_info *src = (void *) smbios_table->lp.interface_offset; +- grub_efi_loongson_interface_info *dst = &loongson_boot_params->interface_info; +- +- if (!src) +- return; +- +- grub_memcpy (dst, src, sizeof (grub_efi_loongson_interface_info)); +- loongson_params->interface_offset = (grub_uint64_t) dst - (grub_uint64_t) loongson_params; +-} +- +-static void +-grub_efi_loongson_init_special_attribute (grub_efi_loongson_smbios_table *smbios_table) +-{ +- grub_efi_loongson_special_attribute *src = (void *) smbios_table->lp.special_offset; +- grub_efi_loongson_special_attribute *dst = &loongson_boot_params->special_attribute; +- +- if (!src) +- return; +- +- grub_memcpy (dst, src, sizeof (grub_efi_loongson_special_attribute)); +- loongson_params->special_offset = (grub_uint64_t) dst - (grub_uint64_t) loongson_params; +-} +- +-static void +-grub_efi_loongson_init_board_devices (grub_efi_loongson_smbios_table *smbios_table) +-{ +- grub_efi_loongson_board_devices *src = (void *) smbios_table->lp.boarddev_table_offset; +- grub_efi_loongson_board_devices *dst = &loongson_boot_params->board_devices; +- +- if (!src) +- return; +- +- grub_memcpy (dst, src, sizeof (grub_efi_loongson_board_devices)); +- loongson_params->boarddev_table_offset = (grub_uint64_t) dst - (grub_uint64_t) loongson_params; +-} +- +-#define ADD_MEMORY_DESCRIPTOR(desc, size) \ +- ((grub_efi_memory_descriptor_t *) ((char *) (desc) + (size))) +- +-static void +-grub_efi_loongson_init_memory_map (grub_efi_loongson_smbios_table *smbios_table, +- grub_efi_memory_descriptor_t *mmap_buf, +- grub_efi_uintn_t mmap_size, +- grub_efi_uintn_t desc_size) +-{ +- grub_efi_loongson_memory_map *src = (void *) smbios_table->lp.memory_offset; +- grub_efi_loongson_memory_map *dst = &loongson_boot_params->memory_map; +- grub_efi_memory_descriptor_t *mmap_end; +- grub_efi_memory_descriptor_t *desc; +- grub_efi_memory_descriptor_t *desc_next; +- grub_efi_uint32_t mem_types_reserved[] = +- { +- 1, // GRUB_EFI_RESERVED_MEMORY_TYPE +- 0, // GRUB_EFI_LOADER_CODE +- 0, // GRUB_EFI_LOADER_DATA +- 0, // GRUB_EFI_BOOT_SERVICES_CODE +- 0, // GRUB_EFI_BOOT_SERVICES_DATA +- 1, // GRUB_EFI_RUNTIME_SERVICES_CODE +- 1, // GRUB_EFI_RUNTIME_SERVICES_DATA +- 0, // GRUB_EFI_CONVENTIONAL_MEMORY +- 1, // GRUB_EFI_UNUSABLE_MEMORY +- 0, // GRUB_EFI_ACPI_RECLAIM_MEMORY +- 0, // GRUB_EFI_ACPI_MEMORY_NVS +- 1, // GRUB_EFI_MEMORY_MAPPED_IO +- 1, // GRUB_EFI_MEMORY_MAPPED_IO_PORT_SPACE +- 1, // GRUB_EFI_PAL_CODE +- 1, // GRUB_EFI_PERSISTENT_MEMORY +- }; +- grub_uint32_t need_sort = 1; +- +- if (!src) +- return; +- +- dst->vers = src->vers; +- dst->nr_map = 0; +- dst->mem_freq = src->mem_freq; +- loongson_params->memory_offset = (grub_uint64_t) dst - (grub_uint64_t) loongson_params; +- +- if (!mmap_buf || !mmap_size || !desc_size) +- return; +- +- mmap_end = ADD_MEMORY_DESCRIPTOR (mmap_buf, mmap_size); +- +- /* drop reserved */ +- for (desc = mmap_buf, +- desc_next = desc; +- desc < mmap_end; +- desc = ADD_MEMORY_DESCRIPTOR (desc, desc_size)) +- { +- desc->type = mem_types_reserved[desc->type]; +- if (desc->type) +- continue; +- +- if (desc != desc_next) +- *desc_next = *desc; +- desc_next = ADD_MEMORY_DESCRIPTOR (desc_next, desc_size); +- } +- mmap_end = desc_next; +- +- /* sort: low->high */ +- while (need_sort) +- { +- need_sort = 0; +- +- for (desc = mmap_buf, +- desc_next = ADD_MEMORY_DESCRIPTOR (desc, desc_size); +- (desc < mmap_end) && (desc_next < mmap_end); +- desc = desc_next, +- desc_next = ADD_MEMORY_DESCRIPTOR (desc, desc_size)) +- { +- grub_efi_memory_descriptor_t tmp; +- +- if (desc->physical_start <= desc_next->physical_start) +- continue; +- +- tmp = *desc; +- *desc = *desc_next; +- *desc_next = tmp; +- need_sort = 1; +- } +- } +- +- /* combine continuous memory map */ +- for (desc = mmap_buf, +- desc_next = ADD_MEMORY_DESCRIPTOR (desc, desc_size); +- desc_next < mmap_end; +- desc_next = ADD_MEMORY_DESCRIPTOR (desc_next, desc_size)) +- { +- grub_efi_physical_address_t prev_end = desc->physical_start + (desc->num_pages << 12); +- +- if (prev_end == desc_next->physical_start) +- { +- desc->num_pages += desc_next->num_pages; +- continue; +- } +- +- desc = ADD_MEMORY_DESCRIPTOR (desc, desc_size); +- grub_memcpy (desc, desc_next, desc_size); +- } +- mmap_end = ADD_MEMORY_DESCRIPTOR (desc, desc_size); +- +- /* write to loongson memory map */ +- for (desc = mmap_buf; +- desc < mmap_end; +- desc = ADD_MEMORY_DESCRIPTOR (desc, desc_size)) +- { +- grub_efi_physical_address_t physical_start = grub_vtop ((void *) desc->physical_start); +- grub_efi_physical_address_t physical_end = physical_start + (desc->num_pages << 12); +- +- physical_start = ALIGN_UP (physical_start, 0x100000); +- physical_end = ALIGN_DOWN (physical_end, 0x100000); +- +- if (physical_start >= physical_end || (physical_end - physical_start) < 0x100000) +- continue; +- +- dst->map[dst->nr_map].node_id = (desc->physical_start >> 44) & 0xf; +- dst->map[dst->nr_map].mem_type = GRUB_EFI_LOONGSON_SYSTEM_RAM; +- dst->map[dst->nr_map].mem_start = physical_start; +- dst->map[dst->nr_map].mem_size = (physical_end - physical_start) >> 20; +- +- grub_dprintf ("loongson", "memory map %03u: 0x%016lx 0x%016lx @ %u\n", +- dst->nr_map, physical_start, physical_end - physical_start, +- dst->map[dst->nr_map].node_id); +- +- dst->nr_map ++; +- } +-} +- +-#define BYTES_TO_PAGES(bytes) (((bytes) + 0xfff) >> 12) +-#define SUB_MEMORY_DESCRIPTOR(desc, size) \ +- ((grub_efi_memory_descriptor_t *) ((char *) (desc) - (size))) +- +-void +-grub_efi_loongson_alloc_boot_params (void) +-{ +- grub_efi_memory_descriptor_t *mmap_buf; +- grub_efi_memory_descriptor_t *mmap_end; +- grub_efi_memory_descriptor_t *desc; +- grub_efi_uintn_t mmap_size; +- grub_efi_uintn_t desc_size; +- grub_efi_physical_address_t address; +- grub_efi_allocate_type_t type; +- grub_efi_uintn_t pages; +- grub_efi_status_t status; +- grub_efi_boot_services_t *b; +- int mm_status; +- +- type = GRUB_EFI_ALLOCATE_ADDRESS; +- pages = BYTES_TO_PAGES (loongson_boot_params_size + loongson_reset_code_size); +- +- mmap_size = (1 << 12); +- mmap_buf = grub_malloc (mmap_size); +- if (!mmap_buf) +- grub_fatal ("out of memory!"); +- +- mm_status = grub_efi_get_memory_map (&mmap_size, mmap_buf, 0, &desc_size, 0); +- if (mm_status == 0) +- { +- grub_free (mmap_buf); +- mmap_size += desc_size * 32; +- +- mmap_buf = grub_malloc (mmap_size); +- if (!mmap_buf) +- grub_fatal ("out of memory!"); +- +- mm_status = grub_efi_get_memory_map (&mmap_size, mmap_buf, 0, &desc_size, 0); +- } +- +- if (mm_status < 0) +- grub_fatal ("cannot get memory map!"); +- +- mmap_end = ADD_MEMORY_DESCRIPTOR (mmap_buf, mmap_size); +- +- for (desc = SUB_MEMORY_DESCRIPTOR (mmap_end, desc_size); +- desc >= mmap_buf; +- desc = SUB_MEMORY_DESCRIPTOR (desc, desc_size)) +- { +- if (desc->type != GRUB_EFI_CONVENTIONAL_MEMORY) +- continue; +- if (desc->physical_start >= grub_efi_max_usable_address()) +- continue; +- if (desc->num_pages < pages) +- continue; +- +- address = desc->physical_start; +- break; +- } +- +- grub_free (mmap_buf); +- +- b = grub_efi_system_table->boot_services; +- status = efi_call_4 (b->allocate_pages, type, GRUB_EFI_RUNTIME_SERVICES_DATA, pages, &address); +- if (status != GRUB_EFI_SUCCESS) +- grub_fatal ("cannot allocate Loongson boot parameters!"); +- +- loongson_boot_params = (void *) ((grub_addr_t) address); +-} +- +-void +-grub_efi_loongson_free_boot_params (void) +-{ +- grub_efi_free_pages ((grub_addr_t) loongson_boot_params, +- BYTES_TO_PAGES (loongson_boot_params_size + loongson_reset_code_size)); +-} +- +-void * +-grub_efi_loongson_get_smbios_table (void) ++int ++grub_efi_get_bpi_version (const char *str) + { +- static grub_efi_loongson_smbios_table *smbios_table; +- grub_efi_loongson_boot_params *old_boot_params; +- struct bootparamsinterface* boot_params; +- void * tmp_boot_params = NULL; +- char * p = NULL; +- if(smbios_table) +- return smbios_table; ++ unsigned long version = GRUB_EFI_BPI_VER_NONE; + +- tmp_boot_params = grub_efi_loongson_get_boot_params(); +- if(tmp_boot_params == NULL) +- { +- grub_dprintf("loongson", "tmp_boot_params is NULL\n"); +- return tmp_boot_params; +- } +- +- boot_params = (struct bootparamsinterface *)tmp_boot_params; +- p = (char *)&(boot_params->signature); +- if(grub_strncmp(p, "BPI", 3) == 0) +- { +- grub_dprintf("loongson", "find new bpi\n"); +- return boot_params ? boot_params : 0; +- } +- else +- { +- old_boot_params = (grub_efi_loongson_boot_params *)tmp_boot_params; +- /* +- { +- grub_dprintf("loongson", "smbios addr%llx\n", &old_boot_params->efi.smbios); +- grub_dprintf("loongson", "smbios vers%d\n", (grub_uint16_t)(&old_boot_params->efi.smbios.vers)); +- grub_dprintf("loongson", "smbios vga_bios%d\n", &old_boot_params->efi.smbios.vga_bios); +- grub_dprintf("loongson", "lp memory offset %llx\n", &old_boot_params->efi.smbios.lp.memory_offset); +- grub_dprintf("loongson", "lp cpu offset %llx\n", &old_boot_params->efi.smbios.lp.cpu_offset); +- grub_dprintf("loongson", "lp system offset %llx\n", &old_boot_params->efi.smbios.lp.system_offset); +- grub_dprintf("loongson", "lp irq offset %llx\n", &old_boot_params->efi.smbios.lp.irq_offset); +- grub_dprintf("loongson", "lp interface offset %llx\n", &old_boot_params->efi.smbios.p.interface_offset); +- grub_dprintf("loongson", "lp special offset %llx\n", &old_boot_params->efi.smbios.lp.special_offset); +- grub_dprintf("loongson", "lp boarddev table offset %llx\n", &old_boot_params->efi.smbios.lp.boarddev_table_offset); +- } +- */ +- return old_boot_params ? &old_boot_params->efi.smbios : 0; +- } +- +-} ++ version = grub_strtoul (str + 4, 0, 0); + +-int +-grub_efi_is_loongson (void) +-{ +- return grub_efi_loongson_get_smbios_table () ? 1 : 0; ++ return version; + } + + void * +@@ -424,20 +38,20 @@ grub_efi_loongson_get_boot_params (void) + { + static void * boot_params = NULL; + grub_efi_configuration_table_t *tables; +- grub_efi_guid_t smbios_guid = GRUB_EFI_LOONGSON_SMBIOS_TABLE_GUID; ++ grub_efi_guid_t loongson_bpi_guid = GRUB_EFI_LOONGSON_BPI_TABLE_GUID; + unsigned int i; + + if (boot_params) + return boot_params; + +- /* Look for Loongson SMBIOS in UEFI config tables. */ ++ /* Look for Loongson boot params interface in UEFI config tables. */ + tables = grub_efi_system_table->configuration_table; + + for (i = 0; i < grub_efi_system_table->num_table_entries; i++) +- if (grub_memcmp (&tables[i].vendor_guid, &smbios_guid, sizeof (smbios_guid)) == 0) ++ if (grub_memcmp (&tables[i].vendor_guid, &loongson_bpi_guid, sizeof (loongson_bpi_guid)) == 0) + { + boot_params= tables[i].vendor_table; +- grub_dprintf ("loongson", "found registered SMBIOS @ %p\n", boot_params); ++ grub_dprintf ("loongson", "found registered BPI @ %p\n", boot_params); + break; + } + return boot_params; +@@ -467,8 +81,9 @@ grub_efi_loongson_grub_calculatechecksum8 (const grub_uint8_t *buffer, grub_efi_ + } + + +-grub_uint32_t +-grub_efi_loongson_memmap_sort(struct memmap array[], grub_uint32_t length, mem_map * bpmem, grub_uint32_t index, grub_uint32_t memtype) ++grub_uint32_t ++grub_efi_loongson_memmap_v1_sort(struct memmap_v1 array[], grub_uint32_t length, ++ mem_map_v1 * bpmem, grub_uint32_t index, grub_uint32_t memtype) + { + grub_uint64_t tempmemsize = 0; + grub_uint32_t j = 0; +@@ -479,19 +94,19 @@ grub_efi_loongson_memmap_sort(struct memmap array[], grub_uint32_t length, mem_m + tempmemsize = array[j].memsize; + for(t = j + 1; t < length; t++) + { +- if(array[j].memstart + tempmemsize == array[t].memstart) ++ if(array[j].memstart + tempmemsize == array[t].memstart) + { + tempmemsize += array[t].memsize; + } + else +- { ++ { + break; + } + } + bpmem->map[index].memtype = memtype; + bpmem->map[index].memstart = array[j].memstart; + bpmem->map[index].memsize = tempmemsize; +- grub_dprintf("loongson", "map[%d]:type %x, start 0x%llx, end 0x%llx\n", ++ grub_dprintf("loongson", "v1 map[%d]:type %x, start 0x%llx, end 0x%llx\n", + index, + bpmem->map[index].memtype, + bpmem->map[index].memstart, +@@ -503,3 +118,42 @@ grub_efi_loongson_memmap_sort(struct memmap array[], grub_uint32_t length, mem_m + return index; + } + ++grub_uint32_t ++grub_efi_loongson_memmap_v3_sort(struct memmap_v3 array[], grub_uint32_t length, ++ mem_map_v3 * bpmem, grub_uint32_t index, grub_uint32_t memtype) ++{ ++ grub_uint64_t tempmemsize = 0; ++ grub_uint32_t j = 0; ++ grub_uint32_t t = 0; ++ ++ for(j = 0; j < length;) ++ { ++ tempmemsize = array[j].memsize; ++ for(t = j + 1; t < length; t++) ++ { ++ if(array[j].memstart + tempmemsize == array[t].memstart) ++ { ++ tempmemsize += array[t].memsize; ++ } ++ else ++ { ++ break; ++ } ++ } ++ bpmem->map[index].memtype = memtype; ++ bpmem->map[index].memstart = array[j].memstart; ++ bpmem->map[index].memsize = tempmemsize; ++ bpmem->map[index].attr = array[j].attr; ++ grub_dprintf("loongson", "v3 map[%d]:type %x, start 0x%llx, end 0x%llx, attr:0x%llx\n", ++ index, ++ bpmem->map[index].memtype, ++ bpmem->map[index].memstart, ++ bpmem->map[index].memstart+ bpmem->map[index].memsize, ++ bpmem->map[index].attr ++ ); ++ j = t; ++ index++; ++ } ++ return index; ++} ++ +diff --git a/grub-core/lib/loongarch64/efi/loongson_asm.S b/grub-core/lib/loongarch64/efi/loongson_asm.S +deleted file mode 100644 +index 4a04d34..0000000 +--- a/grub-core/lib/loongarch64/efi/loongson_asm.S ++++ /dev/null +@@ -1,58 +0,0 @@ +-/* +- * GRUB -- GRand Unified Bootloader +- * Copyright (C) 2017 Free Software Foundation, Inc. +- * +- * GRUB is free software: you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation, either version 3 of the License, or +- * (at your option) any later version. +- * +- * GRUB is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with GRUB. If not, see . +- */ +- +-#include +- +- .file "loongson_asm.S" +- .text +- +- .align 4 +- +-VARIABLE (grub_efi_loongson_reset_start) +- +-VARIABLE (grub_efi_loongson_reset_system_addr) +- .dword 0 +- +-reset_system: +- bl 1f +- move $a1, $zero +-1: +- ld.d $t8, $ra, -16 +- move $a2, $zero +- jr $t8 +- move $a3, $zero +- +-FUNCTION(grub_efi_loongson_reset_cold) +- b reset_system +- li.w $a0, 0 +- +-FUNCTION(grub_efi_loongson_reset_warm) +- b reset_system +- li.w $a0, 1 +- +-FUNCTION(grub_efi_loongson_reset_shutdown) +- b reset_system +- li.w $a0, 2 +- +-FUNCTION(grub_efi_loongson_reset_suspend) +- b reset_system +- li.w $a0, 3 +- +-VARIABLE (grub_efi_loongson_reset_end) +- +- +diff --git a/grub-core/lib/loongarch64/relocator.c b/grub-core/lib/loongarch64/relocator.c +index f6c1b01..14bed46 100644 +--- a/grub-core/lib/loongarch64/relocator.c ++++ b/grub-core/lib/loongarch64/relocator.c +@@ -147,6 +147,10 @@ grub_relocator64_boot (struct grub_relocator *rel, + + grub_arch_sync_caches ((void *) relst, relsize); + ++ asm volatile ( ++ "ibar 0 \n" ++ "dbar 0 \n"); ++ + grub_uint64_t val; + __asm__ __volatile__( + "li.w %0, 0x4\n\t" +diff --git a/grub-core/loader/loongarch64/linux.c b/grub-core/loader/loongarch64/linux.c +index c769bb2..e4aaf7b 100644 +--- a/grub-core/loader/loongarch64/linux.c ++++ b/grub-core/loader/loongarch64/linux.c +@@ -56,9 +56,6 @@ static grub_off_t initrd_addr_arg_off; + static int initrd_loaded = 0; + + +-static grub_uint32_t j = 0; +-static grub_uint32_t t = 0; +-grub_uint64_t tempMemsize = 0; + grub_uint32_t free_index = 0; + grub_uint32_t reserve_index = 0; + grub_uint32_t acpi_table_index = 0; +@@ -70,6 +67,15 @@ page_align (grub_size_t size) + return (size + (1 << 12) - 1) & (~((1 << 12) - 1)); + } + ++static inline grub_uint64_t ++grub_efi_max_usable_address(void) ++{ ++ grub_uint64_t addr; ++ asm volatile ("csrrd %0, 0x181" : "=r" (addr)); ++ grub_dprintf("loongson", "max usable addr 0x%llx\n", addr); ++ return addr |= 0xffffffffffUL; ++} ++ + /* Find the optimal number of pages for the memory map. Is it better to + move this code to efi/mm.c? */ + static grub_efi_uintn_t +@@ -130,59 +136,76 @@ grub_linux_boot (void) + state.gpr[5] = (grub_addr_t) linux_args_addr; + grub_dprintf("loongson", "args_addr is %p\n", state.gpr[5]); + +- if(grub_efi_is_loongson ()) + { + grub_efi_uintn_t mmap_size; + grub_efi_uintn_t desc_size; ++ grub_efi_uint32_t desc_version; + grub_efi_memory_descriptor_t *mmap_buf; + grub_err_t err; +- struct bootparamsinterface * boot_params; ++ struct boot_params_interface * boot_params; + void * tmp_boot_params = NULL; +- grub_efi_uint8_t new_interface_flag = 0; +- mem_map * new_interface_mem = NULL; +- char *p = NULL; +- +- struct memmap reserve_mem[GRUB_EFI_LOONGSON_MMAP_MAX]; +- struct memmap free_mem[GRUB_EFI_LOONGSON_MMAP_MAX]; +- struct memmap acpi_table_mem[GRUB_EFI_LOONGSON_MMAP_MAX]; +- struct memmap acpi_nvs_mem[GRUB_EFI_LOONGSON_MMAP_MAX]; +- +- grub_memset(reserve_mem, 0, sizeof(struct memmap) * GRUB_EFI_LOONGSON_MMAP_MAX); +- grub_memset(free_mem, 0, sizeof(struct memmap) * GRUB_EFI_LOONGSON_MMAP_MAX); +- grub_memset(acpi_table_mem, 0, sizeof(struct memmap) * GRUB_EFI_LOONGSON_MMAP_MAX); +- grub_memset(acpi_nvs_mem, 0, sizeof(struct memmap) * GRUB_EFI_LOONGSON_MMAP_MAX); ++ mem_map_v1 * mem_map_v1_table = NULL; ++ mem_map_v3 * mem_map_v3_table = NULL; ++ int bpi_version = 0; ++ ++ struct memmap_v1 reserve_mem_v1[GRUB_EFI_LOONGSON_MMAP_MAX]; ++ struct memmap_v1 free_mem_v1[GRUB_EFI_LOONGSON_MMAP_MAX]; ++ struct memmap_v1 acpi_table_mem_v1[GRUB_EFI_LOONGSON_MMAP_MAX]; ++ struct memmap_v1 acpi_nvs_mem_v1[GRUB_EFI_LOONGSON_MMAP_MAX]; ++ struct memmap_v3 reserve_mem_v3[GRUB_EFI_LOONGSON_MMAP_MAX]; ++ struct memmap_v3 free_mem_v3[GRUB_EFI_LOONGSON_MMAP_MAX]; ++ struct memmap_v3 acpi_table_mem_v3[GRUB_EFI_LOONGSON_MMAP_MAX]; ++ struct memmap_v3 acpi_nvs_mem_v3[GRUB_EFI_LOONGSON_MMAP_MAX]; ++ ++ grub_memset(reserve_mem_v1, 0, sizeof(struct memmap_v1) * GRUB_EFI_LOONGSON_MMAP_MAX); ++ grub_memset(free_mem_v1, 0, sizeof(struct memmap_v1) * GRUB_EFI_LOONGSON_MMAP_MAX); ++ grub_memset(acpi_table_mem_v1, 0, sizeof(struct memmap_v1) * GRUB_EFI_LOONGSON_MMAP_MAX); ++ grub_memset(acpi_nvs_mem_v1, 0, sizeof(struct memmap_v1) * GRUB_EFI_LOONGSON_MMAP_MAX); ++ grub_memset(reserve_mem_v3, 0, sizeof(struct memmap_v3) * GRUB_EFI_LOONGSON_MMAP_MAX); ++ grub_memset(free_mem_v3, 0, sizeof(struct memmap_v3) * GRUB_EFI_LOONGSON_MMAP_MAX); ++ grub_memset(acpi_table_mem_v3, 0, sizeof(struct memmap_v3) * GRUB_EFI_LOONGSON_MMAP_MAX); ++ grub_memset(acpi_nvs_mem_v3, 0, sizeof(struct memmap_v3) * GRUB_EFI_LOONGSON_MMAP_MAX); + + tmp_boot_params = grub_efi_loongson_get_boot_params(); +- if(tmp_boot_params == NULL) ++ if (tmp_boot_params == NULL) + { +- grub_printf("not find param\n"); +- return -1; +- } ++ grub_int8_t signature[8] = {'B','P','I','0','1','0','0','2'}; ++ boot_params = grub_efi_allocate_pages_real (grub_efi_max_usable_address(), ++ page_align (64 * 1024) >> 12, GRUB_EFI_ALLOCATE_MAX_ADDRESS, ++ GRUB_EFI_RUNTIME_SERVICES_DATA); ++ grub_dprintf("loongson", "create bpi, boot_params is %p\n", boot_params); ++ if (! boot_params) ++ return grub_error (GRUB_ERR_IO, "cannot allocate boot params "); ++ ++ memcpy(&boot_params->signature, signature, sizeof(grub_uint64_t)); ++ boot_params->extlist_offset = sizeof(*boot_params); ++ boot_params->flags = 1 << FLAGS_EFI_SUPPORT_BIT; ++ boot_params->systemtable = grub_efi_system_table; ++ ++ mem_map_v3_table = (mem_map_v3 *)((char *)boot_params + boot_params->extlist_offset); ++ memset(&mem_map_v3_table->header, 0, sizeof(struct _extention_list_hdr)); ++ memcpy(&mem_map_v3_table->header.signature, "MEM", sizeof(grub_uint64_t)); ++ mem_map_v3_table->header.revision = 0; ++ mem_map_v3_table->header.length = sizeof(*mem_map_v3_table); ++ } else { ++ boot_params = (struct boot_params_interface *)tmp_boot_params; + +- boot_params = (struct bootparamsinterface *)tmp_boot_params; +- p = (char *)&(boot_params->signature); +- if(grub_strncmp(p, "BPI", 3) == 0) +- { +- /* Check extlist headers */ + ext_list * listpointer = NULL; ++ /* 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) + { +- new_interface_mem = (mem_map *)listpointer; ++ mem_map_v1_table = (mem_map_v1 *)listpointer; ++ break; + } + } +- +- new_interface_flag = 1; +- grub_dprintf("loongson", "get new parameter interface\n"); +- }else{ +- new_interface_flag = 0; +- grub_dprintf("loongson", "get old parameter interface\n"); + } +- state.gpr[6] = (grub_uint64_t)tmp_boot_params; +- grub_dprintf("loongson", "boot_params is %p\n", state.gpr[6]); ++ ++ grub_dprintf("loongson", "boot_params is %p\n", boot_params); ++ state.gpr[6] = (grub_uint64_t)boot_params; + + mmap_size = find_mmap_size (); + if (! mmap_size) +@@ -191,100 +214,156 @@ grub_linux_boot (void) + 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); ++ &desc_size, &desc_version); + if (err) + return err; + +- if(new_interface_flag) +- { +- if (!mmap_buf || !mmap_size || !desc_size) +- return -1; +- tmp_index = new_interface_mem -> mapcount; ++ if (!mmap_buf || !mmap_size || !desc_size) ++ return -1; ++ ++ char *p = (char *)&(boot_params->signature); ++ bpi_version = grub_efi_get_bpi_version(p); ++ grub_dprintf("loongson", "get bpi version:%d\n", bpi_version); + ++ if (bpi_version <= GRUB_EFI_BPI_VER_V2) ++ { + /* +- According to UEFI SPEC,mmap_buf is the accurate Memory Map array \ +- now we can fill platform specific memory structure. +- */ ++ 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)) ++ lsdesc = (grub_efi_memory_descriptor_t *)((char *)lsdesc + desc_size)) + { +- /* Recovery */ +- if((lsdesc->type != GRUB_EFI_ACPI_RECLAIM_MEMORY) && \ +- (lsdesc->type != GRUB_EFI_ACPI_MEMORY_NVS) && \ +- (lsdesc->type != GRUB_EFI_RUNTIME_SERVICES_DATA) && \ +- (lsdesc->type != GRUB_EFI_RUNTIME_SERVICES_CODE) && \ +- (lsdesc->type != GRUB_EFI_RESERVED_MEMORY_TYPE) && \ +- (lsdesc->type != GRUB_EFI_PAL_CODE)) ++ grub_dprintf("loongson", "type:%d, phy_start:0x%llx, phy_end:0x%llx\n", lsdesc->type, ++ lsdesc->physical_start, lsdesc->physical_start + lsdesc->num_pages*4096); ++ ++ /* 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].memtype = GRUB_EFI_LOONGSON_SYSTEM_RAM; +- free_mem[free_index].memstart = (lsdesc->physical_start) & 0xffffffffffff; +- free_mem[free_index].memsize = lsdesc->num_pages * 4096; ++ free_mem_v1[free_index].memtype = GRUB_EFI_LOONGSON_SYSTEM_RAM; ++ free_mem_v1[free_index].memstart = (lsdesc->physical_start) & 0xffffffffffff; ++ free_mem_v1[free_index].memsize = lsdesc->num_pages * 4096; + free_index++; + + /*ACPI*/ +- }else if((lsdesc->type == GRUB_EFI_ACPI_RECLAIM_MEMORY)){ +- acpi_table_mem[acpi_table_index].memtype = GRUB_EFI_LOONGSON_ACPI_TABLE; +- acpi_table_mem[acpi_table_index].memstart = (lsdesc->physical_start) & 0xffffffffffff; +- acpi_table_mem[acpi_table_index].memsize = lsdesc->num_pages * 4096; ++ } else if ((lsdesc->type == GRUB_EFI_ACPI_RECLAIM_MEMORY)){ ++ acpi_table_mem_v1[acpi_table_index].memtype = GRUB_EFI_LOONGSON_ACPI_TABLE; ++ acpi_table_mem_v1[acpi_table_index].memstart = (lsdesc->physical_start) & 0xffffffffffff; ++ acpi_table_mem_v1[acpi_table_index].memsize = lsdesc->num_pages * 4096; + acpi_table_index++; +- }else if((lsdesc->type == GRUB_EFI_ACPI_MEMORY_NVS)){ +- acpi_nvs_mem[acpi_nvs_index].memtype = GRUB_EFI_LOONGSON_ACPI_NVS; +- acpi_nvs_mem[acpi_nvs_index].memstart = (lsdesc->physical_start) & 0xffffffffffff; +- acpi_nvs_mem[acpi_nvs_index].memsize = lsdesc->num_pages * 4096; ++ } else if ((lsdesc->type == GRUB_EFI_ACPI_MEMORY_NVS)){ ++ acpi_nvs_mem_v1[acpi_nvs_index].memtype = GRUB_EFI_LOONGSON_ACPI_NVS; ++ acpi_nvs_mem_v1[acpi_nvs_index].memstart = (lsdesc->physical_start) & 0xffffffffffff; ++ acpi_nvs_mem_v1[acpi_nvs_index].memsize = lsdesc->num_pages * 4096; + acpi_nvs_index++; + + /* Reserve */ +- }else{ +- reserve_mem[reserve_index].memtype = GRUB_EFI_LOONGSON_MEMORY_RESERVED; +- reserve_mem[reserve_index].memstart = (lsdesc->physical_start) & 0xffffffffffff; +- reserve_mem[reserve_index].memsize = lsdesc->num_pages * 4096; ++ } else { ++ reserve_mem_v1[reserve_index].memtype = GRUB_EFI_LOONGSON_MEMORY_RESERVED; ++ reserve_mem_v1[reserve_index].memstart = (lsdesc->physical_start) & 0xffffffffffff; ++ reserve_mem_v1[reserve_index].memsize = lsdesc->num_pages * 4096; + reserve_index++; + } + } + +- /* Recovery sort */ +- for(j = 0; j < free_index;) ++ tmp_index = mem_map_v1_table->mapcount; ++ /*System RAM Sort*/ ++ tmp_index = grub_efi_loongson_memmap_v1_sort(free_mem_v1, free_index, mem_map_v1_table, ++ tmp_index, GRUB_EFI_LOONGSON_SYSTEM_RAM); ++ /*ACPI Sort*/ ++ tmp_index = grub_efi_loongson_memmap_v1_sort(acpi_table_mem_v1, acpi_table_index, ++ mem_map_v1_table, tmp_index, GRUB_EFI_LOONGSON_ACPI_TABLE); ++ tmp_index = grub_efi_loongson_memmap_v1_sort(acpi_nvs_mem_v1, acpi_nvs_index, ++ mem_map_v1_table, tmp_index, GRUB_EFI_LOONGSON_ACPI_NVS); ++ /*Reserve Sort*/ ++ grub_uint64_t loongarch_addr; ++ asm volatile ("csrrd %0, 0x181" : "=r" (loongarch_addr)); ++ if ((loongarch_addr & 0xff00000000000000) == 0x9000000000000000){ ++ tmp_index = grub_efi_loongson_memmap_v1_sort(reserve_mem_v1, reserve_index, mem_map_v1_table, ++ tmp_index, GRUB_EFI_LOONGSON_MEMORY_RESERVED); ++ } else { ++ tmp_index = grub_efi_loongson_memmap_v1_sort(reserve_mem_v1, reserve_index, mem_map_v1_table, ++ tmp_index, GRUB_EFI_LOONGSON_MEMORY_RESERVED + 1); ++ } ++ ++ mem_map_v1_table->mapcount = tmp_index; ++ mem_map_v1_table->header.checksum = 0; ++ ++ checksum = grub_efi_loongson_grub_calculatechecksum8(mem_map_v1_table, mem_map_v1_table->header.length); ++ mem_map_v1_table->header.checksum = checksum; ++ ++ } else { ++ /* ++ 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)) + { +- tempMemsize = free_mem[j].memsize; +- for(t = j + 1; t < free_index; t++) ++ grub_dprintf("loongson", "type:%d, phy_start:0x%llx, phy_end:0x%llx, attribute:0x%llx\n", lsdesc->type, ++ lsdesc->physical_start, lsdesc->physical_start + lsdesc->num_pages*4096, lsdesc->attribute); ++ ++ /* 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)) + { +- if((free_mem[j].memstart + tempMemsize == free_mem[t].memstart) && (free_mem[j].memtype == free_mem[t].memtype)) +- { +- tempMemsize += free_mem[t].memsize; +- }else{ +- break; +- } +- } ++ free_mem_v3[free_index].memtype = GRUB_EFI_LOONGSON_SYSTEM_RAM; ++ free_mem_v3[free_index].memstart = (lsdesc->physical_start) & 0xffffffffffff; ++ free_mem_v3[free_index].memsize = lsdesc->num_pages * 4096; ++ free_mem_v3[free_index].attr = lsdesc->attribute; ++ free_index++; + +- new_interface_mem->map[tmp_index].memtype = GRUB_EFI_LOONGSON_SYSTEM_RAM; +- new_interface_mem->map[tmp_index].memstart = free_mem[j].memstart; +- new_interface_mem->map[tmp_index].memsize = tempMemsize; +- grub_dprintf("loongson", "map[%d]:type %x, start 0x%llx, end 0x%llx\n", +- tmp_index, +- new_interface_mem->map[tmp_index].memtype, +- new_interface_mem->map[tmp_index].memstart, +- new_interface_mem->map[tmp_index].memstart+ new_interface_mem->map[tmp_index].memsize +- ); +- j = t; +- tmp_index++; ++ /*ACPI*/ ++ } else if ((lsdesc->type == GRUB_EFI_ACPI_RECLAIM_MEMORY)){ ++ acpi_table_mem_v3[acpi_table_index].memtype = GRUB_EFI_LOONGSON_ACPI_TABLE; ++ acpi_table_mem_v3[acpi_table_index].memstart = (lsdesc->physical_start) & 0xffffffffffff; ++ acpi_table_mem_v3[acpi_table_index].memsize = lsdesc->num_pages * 4096; ++ acpi_table_mem_v3[acpi_table_index].attr = lsdesc->attribute; ++ acpi_table_index++; ++ } else if ((lsdesc->type == GRUB_EFI_ACPI_MEMORY_NVS)){ ++ acpi_nvs_mem_v3[acpi_nvs_index].memtype = GRUB_EFI_LOONGSON_ACPI_NVS; ++ acpi_nvs_mem_v3[acpi_nvs_index].memstart = (lsdesc->physical_start) & 0xffffffffffff; ++ acpi_nvs_mem_v3[acpi_nvs_index].memsize = lsdesc->num_pages * 4096; ++ acpi_nvs_mem_v3[acpi_nvs_index].attr = lsdesc->attribute; ++ acpi_nvs_index++; ++ ++ /* Reserve */ ++ } else { ++ reserve_mem_v3[reserve_index].memtype = GRUB_EFI_LOONGSON_MEMORY_RESERVED; ++ reserve_mem_v3[reserve_index].memstart = (lsdesc->physical_start) & 0xffffffffffff; ++ reserve_mem_v3[reserve_index].memsize = lsdesc->num_pages * 4096; ++ reserve_mem_v3[reserve_index].attr = lsdesc->attribute; ++ reserve_index++; ++ } + } ++ ++ /*System RAM Sort*/ ++ tmp_index = grub_efi_loongson_memmap_v3_sort(free_mem_v3, free_index, mem_map_v3_table, ++ tmp_index, GRUB_EFI_LOONGSON_SYSTEM_RAM); + /*ACPI Sort*/ +- tmp_index = grub_efi_loongson_memmap_sort(acpi_table_mem, acpi_table_index, new_interface_mem, tmp_index, GRUB_EFI_LOONGSON_ACPI_TABLE); +- tmp_index = grub_efi_loongson_memmap_sort(acpi_nvs_mem, acpi_nvs_index, new_interface_mem, tmp_index, GRUB_EFI_LOONGSON_ACPI_NVS); ++ tmp_index = grub_efi_loongson_memmap_v3_sort(acpi_table_mem_v3, acpi_table_index, ++ mem_map_v3_table, tmp_index, GRUB_EFI_LOONGSON_ACPI_TABLE); ++ tmp_index = grub_efi_loongson_memmap_v3_sort(acpi_nvs_mem_v3, acpi_nvs_index, ++ mem_map_v3_table, tmp_index, GRUB_EFI_LOONGSON_ACPI_NVS); + /*Reserve Sort*/ +- grub_uint64_t loongarch_addr; +- asm volatile ("csrrd %0, 0x181" : "=r" (loongarch_addr)); +- if((loongarch_addr & 0xff00000000000000) == 0x9000000000000000){ +- tmp_index = grub_efi_loongson_memmap_sort(reserve_mem, reserve_index, new_interface_mem, tmp_index, GRUB_EFI_LOONGSON_MEMORY_RESERVED); +- }else{ +- tmp_index = grub_efi_loongson_memmap_sort(reserve_mem, reserve_index, new_interface_mem, tmp_index, GRUB_EFI_LOONGSON_MEMORY_RESERVED + 1); +- } +- +- new_interface_mem->mapcount = tmp_index; +- new_interface_mem->header.checksum = 0; +- +- checksum = grub_efi_loongson_grub_calculatechecksum8(new_interface_mem, new_interface_mem->header.length); +- new_interface_mem->header.checksum = checksum; ++ tmp_index = grub_efi_loongson_memmap_v3_sort(reserve_mem_v3, reserve_index, ++ mem_map_v3_table, tmp_index, GRUB_EFI_LOONGSON_MEMORY_RESERVED); ++ ++ mem_map_v3_table->mapcount = tmp_index; ++ mem_map_v3_table->descver = desc_version; ++ mem_map_v3_table->header.checksum = 0; ++ ++ checksum = grub_efi_loongson_grub_calculatechecksum8(mem_map_v3_table, mem_map_v3_table->header.length); ++ mem_map_v3_table->header.checksum = checksum; + } + } + +@@ -345,6 +424,8 @@ grub_linux_load64 (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. */ + entry_addr = elf->ehdr.ehdr64.e_entry; +@@ -358,8 +439,16 @@ grub_linux_load64 (grub_elf_t elf, const char *filename) + target_addr = base; + linux_size = ALIGN_UP (base + linux_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; ++ entry_addr &= ~ELF64_LOADMASK; ++ } ++ + relocator = grub_relocator_new (); +- // linux_size=0x322fa80; + if (!relocator) + return grub_errno; + +@@ -374,7 +463,7 @@ grub_linux_load64 (grub_elf_t elf, const char *filename) + } + + /* Now load the segments into the area we claimed. */ +- return grub_elf64_load (elf, filename, playground - base, GRUB_ELF_LOAD_FLAGS_NONE, 0, 0); ++ return grub_elf64_load (elf, filename, playground - base, flag, 0, 0); + } + + static grub_err_t +@@ -410,7 +499,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + linux_argc = argc; + /* Main arguments. */ + size = (linux_argc) * sizeof (grub_uint64_t); +- /* Initrd address and size. */ ++ /* Initrd address/size and initrd */ + size += 3 * sizeof (grub_uint64_t); + /* NULL terminator. */ + size += sizeof (grub_uint64_t); +diff --git a/include/grub/loongarch64/efi/loongson.h b/include/grub/loongarch64/efi/loongson.h +index fa32ef5..6668d08 100644 +--- a/include/grub/loongarch64/efi/loongson.h ++++ b/include/grub/loongarch64/efi/loongson.h +@@ -23,7 +23,7 @@ + + #include + +-#define GRUB_EFI_LOONGSON_SMBIOS_TABLE_GUID \ ++#define GRUB_EFI_LOONGSON_BPI_TABLE_GUID \ + { 0x4660f721, 0x2ec5, 0x416a, \ + { 0x89, 0x9a, 0x43, 0x18, 0x02, 0x50, 0xa0, 0xc9 } \ + } +@@ -39,252 +39,93 @@ typedef enum + } + grub_efi_loongson_memory_type; + +-typedef struct +-{ +- grub_uint16_t vers; /* version */ +- grub_uint32_t nr_map; /* number of memory_maps */ +- grub_uint32_t mem_freq; /* memory frequence */ +- struct mem_map { +- grub_uint32_t node_id; /* node_id which memory attached to */ +- grub_uint32_t mem_type; /* system memory, pci memory, pci io, etc. */ +- grub_uint64_t mem_start; /* memory map start address */ +- grub_uint32_t mem_size; /* each memory_map size, not the total size */ +- } map[GRUB_EFI_LOONGSON_MMAP_MAX]; +-} GRUB_PACKED +-grub_efi_loongson_memory_map; +- +-/* +- * Capability and feature descriptor structure for LOONGARCH CPU +- */ +-typedef struct +-{ +- grub_uint16_t vers; /* version */ +- grub_uint32_t processor_id; /* PRID, e.g. 6305, 6306 */ +- grub_uint32_t cputype; /* Loongson_3A/3B, etc. */ +- grub_uint32_t total_node; /* num of total numa nodes */ +- grub_uint16_t cpu_startup_core_id; /* Boot core id */ +- grub_uint16_t reserved_cores_mask; +- grub_uint32_t cpu_clock_freq; /* cpu_clock */ +- grub_uint32_t nr_cpus; +-} GRUB_PACKED +-grub_efi_loongson_cpu_info; +- +-#define GRUB_EFI_LOONGSON_MAX_UARTS 64 +- +-typedef struct +-{ +- grub_uint32_t iotype; /* see include/linux/serial_core.h */ +- grub_uint32_t uartclk; +- grub_uint32_t int_offset; +- grub_uint64_t uart_base; +-} GRUB_PACKED +-grub_efi_loongson_uart_device; +- +-#define GRUB_EFI_LOONGSON_MAX_SENSORS 64 +- +-typedef struct +-{ +- char name[32]; /* a formal name */ +- char label[64]; /* a flexible description */ +- grub_uint32_t type; /* SENSOR_* */ +- grub_uint32_t id; /* instance id of a sensor-class */ +- grub_uint32_t fan_policy; +- grub_uint32_t fan_percent; /* only for constant speed policy */ +- grub_uint64_t base_addr; /* base address of device registers */ +-} GRUB_PACKED +-grub_efi_loongson_sensor_device; +- +-typedef struct +-{ +- grub_uint16_t vers; /* version */ +- grub_uint32_t ccnuma_smp; /* 0: no numa; 1: has numa */ +- grub_uint32_t sing_double_channel; /* 1:single; 2:double */ +- grub_uint32_t nr_uarts; +- grub_efi_loongson_uart_device uarts[GRUB_EFI_LOONGSON_MAX_UARTS]; +- grub_uint32_t nr_sensors; +- grub_efi_loongson_sensor_device sensors[GRUB_EFI_LOONGSON_MAX_SENSORS]; +- char has_ec; +- char ec_name[32]; +- grub_uint64_t ec_base_addr; +- char has_tcm; +- char tcm_name[32]; +- grub_uint64_t tcm_base_addr; +- grub_uint64_t workarounds; /* see workarounds.h */ +-} GRUB_PACKED +-grub_efi_loongson_system_info; +- +-typedef struct +-{ +- grub_uint16_t vers; +- grub_uint16_t size; +- grub_uint16_t rtr_bus; +- grub_uint16_t rtr_devfn; +- grub_uint32_t vendor; +- grub_uint32_t device; +- grub_uint32_t PIC_type; /* conform use HT or PCI to route to CPU-PIC */ +- grub_uint64_t ht_int_bit; /* 3A: 1<<24; 3B: 1<<16 */ +- grub_uint64_t ht_enable; /* irqs used in this PIC */ +- grub_uint32_t node_id; /* node id: 0x0-0; 0x1-1; 0x10-2; 0x11-3 */ +- grub_uint64_t pci_mem_start_addr; +- grub_uint64_t pci_mem_end_addr; +- grub_uint64_t pci_io_start_addr; +- grub_uint64_t pci_io_end_addr; +- grub_uint64_t pci_config_addr; +- grub_uint32_t dma_mask_bits; +-} GRUB_PACKED +-grub_efi_loongson_irq_src_routing_table; +- +-typedef struct +-{ +- grub_uint16_t vers; /* version */ +- grub_uint16_t size; +- grub_uint8_t flag; +- char description[64]; +-} GRUB_PACKED +-grub_efi_loongson_interface_info; +- +-#define GRUB_EFI_LOONGSON_MAX_RESOURCE_NUMBER 128 +- +-typedef struct +-{ +- grub_uint64_t start; /* resource start address */ +- grub_uint64_t end; /* resource end address */ +- char name[64]; +- grub_uint32_t flags; +-} +-grub_efi_loongson_resource; +- +-/* arch specific additions */ +-typedef struct +-{ +-} +-grub_efi_loongson_archdev_data; +- +-typedef struct +-{ +- char name[64]; /* hold the device name */ +- grub_uint32_t num_resources; /* number of device_resource */ +- /* for each device's resource */ +- grub_efi_loongson_resource resource[GRUB_EFI_LOONGSON_MAX_RESOURCE_NUMBER]; +- /* arch specific additions */ +- grub_efi_loongson_archdev_data archdata; +-} +-grub_efi_loongson_board_devices; +- +-typedef struct +-{ +- grub_uint16_t vers; /* version */ +- char special_name[64]; /* special_atribute_name */ +- grub_uint32_t loongson_special_type; /* type of special device */ +- /* for each device's resource */ +- grub_efi_loongson_resource resource[GRUB_EFI_LOONGSON_MAX_RESOURCE_NUMBER]; +-} +-grub_efi_loongson_special_attribute; +- +-typedef struct +-{ +- grub_uint64_t memory_offset; /* efi_loongson_memory_map struct offset */ +- grub_uint64_t cpu_offset; /* efi_loongson_cpuinfo struct offset */ +- grub_uint64_t system_offset; /* efi_loongson_system_info struct offset */ +- grub_uint64_t irq_offset; /* efi_loongson_irq_src_routing_table struct offset */ +- grub_uint64_t interface_offset; /* interface_info struct offset */ +- grub_uint64_t special_offset; /* efi_loongson_special_attribute struct offset */ +- grub_uint64_t boarddev_table_offset; /* efi_loongson_board_devices offset */ +-} +-grub_efi_loongson_params; +- +-typedef struct +-{ +- grub_uint16_t vers; /* version */ +- grub_uint64_t vga_bios; /* vga_bios address */ +- grub_efi_loongson_params lp; +-} +-grub_efi_loongson_smbios_table; +- +-typedef struct +-{ +- grub_uint64_t reset_cold; +- grub_uint64_t reset_warm; +- grub_uint64_t reset_type; +- grub_uint64_t shutdown; +- grub_uint64_t do_suspend; /* NULL if not support */ +-} +-grub_efi_loongson_reset_system; +- +-typedef struct +-{ +- grub_uint64_t mps; /* MPS table */ +- grub_uint64_t acpi; /* ACPI table (IA64 ext 0.71) */ +- grub_uint64_t acpi20; /* ACPI table (ACPI 2.0) */ +- grub_efi_loongson_smbios_table smbios; /* SM BIOS table */ +- grub_uint64_t sal_systab; /* SAL system table */ +- grub_uint64_t boot_info; /* boot info table */ +-} +-grub_efi_loongson; +- +-typedef struct +-{ +- grub_efi_loongson efi; +- grub_efi_loongson_reset_system reset_system; +-} +-grub_efi_loongson_boot_params; +- +-extern grub_uint64_t grub_efi_loongson_reset_system_addr; +- +-extern void grub_efi_loongson_reset_cold (void); +-extern void grub_efi_loongson_reset_warm (void); +-extern void grub_efi_loongson_reset_shutdown (void); +-extern void grub_efi_loongson_reset_suspend (void); +- +-void grub_efi_loongson_alloc_boot_params (void); +-void grub_efi_loongson_free_boot_params (void); +-void * grub_efi_loongson_get_smbios_table (void); +- +-int EXPORT_FUNC(grub_efi_is_loongson) (void); ++typedef enum ++ { ++ GRUB_EFI_BPI_VER_NONE = 0, ++ GRUB_EFI_BPI_VER_V1 = 1000, ++ GRUB_EFI_BPI_VER_V2 = 1001, ++ GRUB_EFI_BPI_VER_V3 = 1002, ++ } ++ grub_efi_loongson_bpi_version; ++ ++#define ELF32_LOADMASK (0xf0000000UL) ++#define ELF64_LOADMASK (0xf000000000000000ULL) ++#define FLAGS_EFI_SUPPORT_BIT 0 + + grub_uint8_t +-EXPORT_FUNC(grub_efi_loongson_calculatesum8) (const grub_uint8_t *Buffer, grub_efi_uintn_t Length); ++EXPORT_FUNC(grub_efi_loongson_calculatesum8) (const grub_uint8_t *Buffer, ++ grub_efi_uintn_t Length); + + grub_uint8_t +-EXPORT_FUNC(grub_efi_loongson_grub_calculatechecksum8) (const grub_uint8_t *Buffer, grub_efi_uintn_t Length); ++EXPORT_FUNC(grub_efi_loongson_grub_calculatechecksum8) (const grub_uint8_t *Buffer, ++ grub_efi_uintn_t Length); + ++int EXPORT_FUNC(grub_efi_get_bpi_version) (const char *str); + + void * + EXPORT_FUNC(grub_efi_loongson_get_boot_params) (void); + +-typedef struct _extention_list_hdr{ ++typedef struct _extention_list_hdr { + grub_uint64_t signature; + grub_uint32_t length; + grub_uint8_t revision; + grub_uint8_t checksum; +- struct _extention_list_hdr *next; ++ union { ++ struct _extention_list_hdr *next; ++ grub_uint64_t next_offset; ++ }; + }GRUB_PACKED + ext_list; + +-typedef struct bootparamsinterface { +- grub_uint64_t signature; //{'B', 'P', 'I', '_', '0', '_', '1'} ++typedef struct boot_params_interface { ++ grub_uint64_t signature; //{'B', 'P', 'I', 'x', 'x', 'x', 'x', 'x'} + grub_efi_system_table_t *systemtable; +- ext_list *extlist; ++ union { ++ ext_list *extlist; ++ grub_uint64_t extlist_offset; ++ }; ++ grub_uint64_t flags; ++}GRUB_PACKED ++boot_params_interface; ++ ++typedef struct { ++ ext_list header; //{MEM} ++ grub_uint8_t mapcount; ++ struct GRUB_PACKED memmap_v1 { ++ grub_uint32_t memtype; ++ grub_uint64_t memstart; ++ grub_uint64_t memsize; ++ } map[GRUB_EFI_LOONGSON_MMAP_MAX]; + }GRUB_PACKED +-bootparamsinterface; ++mem_map_v1; + + typedef struct { +- ext_list header; // {'M', 'E', 'M'} ++ ext_list header; //{MEM} + grub_uint8_t mapcount; +- struct GRUB_PACKED memmap { ++ grub_uint32_t descver; ++ struct GRUB_PACKED memmap_v3 { + grub_uint32_t memtype; ++ grub_uint32_t pad; + grub_uint64_t memstart; ++ grub_uint64_t virtstart; + grub_uint64_t memsize; ++ grub_uint64_t attr; + } map[GRUB_EFI_LOONGSON_MMAP_MAX]; + }GRUB_PACKED +-mem_map; ++mem_map_v3; + + typedef struct { +- ext_list header; // {VBIOS} ++ ext_list header; //{VBIOS} + grub_uint64_t vbiosaddr; + }GRUB_PACKED + vbios; + +-grub_uint32_t +-EXPORT_FUNC (grub_efi_loongson_memmap_sort) (struct memmap array[], grub_uint32_t length, mem_map * bpmem, grub_uint32_t index, grub_uint32_t memtype); ++grub_uint32_t ++EXPORT_FUNC (grub_efi_loongson_memmap_v1_sort) (struct memmap_v1 array[], ++ grub_uint32_t length, mem_map_v1 * mem, ++ grub_uint32_t index, grub_uint32_t memtype); ++grub_uint32_t ++EXPORT_FUNC (grub_efi_loongson_memmap_v3_sort) (struct memmap_v3 array[], ++ grub_uint32_t length, mem_map_v3 * mem, ++ grub_uint32_t index, grub_uint32_t memtype); + #endif /* ! GRUB_EFI_LOONGSON_HEADER */ +diff --git a/include/grub/loongarch64/memory.h b/include/grub/loongarch64/memory.h +index 03398b3..cc9faef 100644 +--- a/include/grub/loongarch64/memory.h ++++ b/include/grub/loongarch64/memory.h +@@ -41,9 +41,11 @@ 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)); +- return (void *) (a | (addr & 0xffffffffffffff00UL)); ++ if (addr & 0x1) ++ return (void *) (a | (addr & 0xffffffffffffff00UL)); ++ else ++ return (void *) a; + } + + static inline void +-- +2.1.0 + diff --git a/grub.macros b/grub.macros index 80e4f76856f4dd625e276505c3ac6acdac1801c0..02fe7100f948dc553cb231f832c626d924cf7f7f 100644 --- a/grub.macros +++ b/grub.macros @@ -95,7 +95,7 @@ %endif -%global efi_only aarch64 %{arm} +%global efi_only aarch64 %{arm} loongarch64 %global efi_arch x86_64 ia64 %{efi_only} %ifarch %{efi_arch} %global with_efi_arch 1 @@ -113,7 +113,7 @@ %{?with_efi_only:%global without_efi_only 1} ### fixme -%ifarch aarch64 %{arm} +%ifarch aarch64 %{arm} loongarch64 %global efi_modules " " %else %global efi_modules " backtrace chain usb usbserial_common usbserial_pl2303 usbserial_ftdi usbserial_usbdebug " @@ -180,6 +180,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 5feaa93fd9c6f076ec0a48bf0bb8ffd7c4c4b4eb..05a6edf60f24b0269bfef7bb42df9fc3d8cf1e6f 100644 --- a/grub.patches +++ b/grub.patches @@ -353,3 +353,5 @@ Patch0352: backport-0079-efi-tpm-Fix-typo-in-grub_efi_tpm2_protocol-struct.patch Patch0353: backport-0080-misc-Add-parentheses-around-ALIGN_UP-and-ALIGN_DOWN-.patch Patch0354: backport-0081-verifiers-Fix-calling-uninitialized-function-pointer.patch Patch0355: backport-templates-Fix-bad-test-on-GRUB_DISABLE_SUBMENU.patch +Patch0356: 0251-Add-loongarch64-support.patch +Patch0357: 0252-LoongArch64-support-boot-parameter-01002-version.patch diff --git a/grub2.spec b/grub2.spec index 204cf77d6332ea6b51203a91455964dbfe1cdf94..dd6b07f7eff01e73102d815ac5a1334cec49caa6 100644 --- a/grub2.spec +++ b/grub2.spec @@ -8,7 +8,7 @@ Name: grub2 Epoch: 1 Version: 2.04 -Release: 22 +Release: 24 Summary: Bootloader with support for Linux, Multiboot and more License: GPLv3+ URL: http://www.gnu.org/software/grub/ @@ -188,6 +188,9 @@ popd %install set -e +%ifarch loongarch64 +%define _unpackaged_files_terminate_build 0 +%endif %do_common_install %if 0%{with_efi_arch} @@ -444,12 +447,27 @@ rm -r /boot/grub2.tmp/ || : %exclude %{_libdir}/grub/%{emuarch}-emu/*.module %endif +%ifnarch loongarch64 %files help %defattr(-,root,root) %doc INSTALL NEWS README THANKS TODO docs/grub.html docs/grub-dev.html docs/font_char_metrics.png %{_datadir}/man/man* +%endif %changelog +* Tue Apr 12 2022 yangqiming - 2.04-24 +- Type:bugfix +- CVE:NA +- SUG:NA +- DESC:LoongArch64 support boot parameter 01002 version + +* Thu Apr 7 2022 yangqiming - 2.04-23 +- Type:bugfix +- CVE:NA +- SUG:NA +- DESC:Add loongarch64 support + + * Sat Feb 26 2022 zhangqiumiao - 2.04-22 - Type:bugfix - CVE:NA @@ -583,7 +601,7 @@ rm -r /boot/grub2.tmp/ || : * Fri Apr 24 2020 fengtao - 2.02-74 - exclude two cmd in grub2-tools -* Wed Mar 3 2020 songnannan - 2.02-73 +* Tue Mar 3 2020 songnannan - 2.02-73 - delete java-1.8.0-openjdk in buildrequires * Thu Feb 20 2020 openEuler Buildteam - 2.02-72