From 22543e469b46aa5be882fe876e53f099a2cd9210 Mon Sep 17 00:00:00 2001 From: Youling Tang Date: Tue, 21 Mar 2023 16:11:59 +0800 Subject: [PATCH] Reimplement loongarch64 support Signed-off-by: Youling Tang --- ...loongarch64-support-for-makedumpfile.patch | 155 +- kdump.sysconfig.loongarch64 | 34 +- ...tch => kexec-add-loongarch64-support.patch | 1548 ++++++++++------- kexec-tools.spec | 19 +- 4 files changed, 997 insertions(+), 759 deletions(-) rename fix-add-64-bit-loongArch-support-2.patch => add-loongarch64-support-for-makedumpfile.patch (56%) rename fix-add-64-bit-loongArch-support-1.patch => kexec-add-loongarch64-support.patch (40%) diff --git a/fix-add-64-bit-loongArch-support-2.patch b/add-loongarch64-support-for-makedumpfile.patch similarity index 56% rename from fix-add-64-bit-loongArch-support-2.patch rename to add-loongarch64-support-for-makedumpfile.patch index 43965fd..88adaaa 100644 --- a/fix-add-64-bit-loongArch-support-2.patch +++ b/add-loongarch64-support-for-makedumpfile.patch @@ -1,38 +1,11 @@ -From dd302cc20cf48e312e608ebf2946e8b5432881c7 Mon Sep 17 00:00:00 2001 -From: wu-leilei -Date: Tue, 19 Apr 2022 11:51:24 +0800 -Subject: [PATCH] add 64 bit loongArch support - ---- - makedumpfile-1.7.0/Makefile | 2 +- - makedumpfile-1.7.0/arch/loongarch64.c | 108 ++++++++++++++++++++++++++ - makedumpfile-1.7.0/makedumpfile.h | 55 +++++++++++++ - 3 files changed, 164 insertions(+), 1 deletion(-) - create mode 100644 makedumpfile-1.7.0/arch/loongarch64.c - -diff --git a/makedumpfile-1.7.0/Makefile b/makedumpfile-1.7.0/Makefile -index 35bc04d..5940450 100644 ---- a/makedumpfile-1.7.0/Makefile -+++ b/makedumpfile-1.7.0/Makefile -@@ -48,7 +48,7 @@ endif - SRC_BASE = makedumpfile.c makedumpfile.h diskdump_mod.h sadump_mod.h sadump_info.h - SRC_PART = print_info.c dwarf_info.c elf_info.c erase_info.c sadump_info.c cache.c tools.c printk.c - OBJ_PART=$(patsubst %.c,%.o,$(SRC_PART)) --SRC_ARCH = arch/arm.c arch/arm64.c arch/x86.c arch/x86_64.c arch/ia64.c arch/ppc64.c arch/s390x.c arch/ppc.c arch/sparc64.c arch/mips64.c -+SRC_ARCH = arch/arm.c arch/arm64.c arch/x86.c arch/x86_64.c arch/ia64.c arch/ppc64.c arch/s390x.c arch/ppc.c arch/sparc64.c arch/mips64.c arch/loongarch64.c - OBJ_ARCH=$(patsubst %.c,%.o,$(SRC_ARCH)) - - LIBS = -ldw -lbz2 -ldl -lelf -lz -diff --git a/makedumpfile-1.7.0/arch/loongarch64.c b/makedumpfile-1.7.0/arch/loongarch64.c -new file mode 100644 -index 0000000..338da6b ---- /dev/null -+++ b/makedumpfile-1.7.0/arch/loongarch64.c -@@ -0,0 +1,108 @@ +diff -Naru ./makedumpfile-1.7.0/arch/loongarch64.c ./makedumpfile-1.7.0-la/arch/loongarch64.c +--- ./makedumpfile-1.7.0/arch/loongarch64.c 1970-01-01 08:00:00.000000000 +0800 ++++ ./makedumpfile-1.7.0-la/arch/loongarch64.c 2023-03-21 17:16:18.829859520 +0800 +@@ -0,0 +1,113 @@ +/* + * loongarch64.c + * -+ * Copyright (C) 2021 Loongson Technology Co., Ltd. ++ * Copyright (C) 2022 Loongson Technology Corporation Limited + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by @@ -44,7 +17,7 @@ index 0000000..338da6b + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ -+#ifdef __loongarch64 ++#ifdef __loongarch64__ + +#include "../print_info.h" +#include "../elf_info.h" @@ -53,49 +26,55 @@ index 0000000..338da6b +int +get_phys_base_loongarch64(void) +{ -+ info->phys_base = 0ULL; ++ info->phys_base = 0ULL; + -+ DEBUG_MSG("phys_base : %lx\n", info->phys_base); ++ DEBUG_MSG("phys_base : %lx\n", info->phys_base); + -+ return TRUE; ++ return TRUE; +} + +int +get_machdep_info_loongarch64(void) +{ -+ info->section_size_bits = _SECTION_SIZE_BITS; ++ info->section_size_bits = _SECTION_SIZE_BITS; ++ ++ /* Check if we can get MAX_PHYSMEM_BITS from vmcoreinfo */ ++ if (NUMBER(MAX_PHYSMEM_BITS) != NOT_FOUND_NUMBER) ++ info->max_physmem_bits = NUMBER(MAX_PHYSMEM_BITS); ++ else ++ info->max_physmem_bits = _MAX_PHYSMEM_BITS; + -+ /* Check if we can get MAX_PHYSMEM_BITS from vmcoreinfo */ -+ if (NUMBER(MAX_PHYSMEM_BITS) != NOT_FOUND_NUMBER) -+ info->max_physmem_bits = NUMBER(MAX_PHYSMEM_BITS); -+ else -+ info->max_physmem_bits = _MAX_PHYSMEM_BITS; ++ /* Check if we can get SECTION_SIZE_BITS from vmcoreinfo */ ++ if (NUMBER(SECTION_SIZE_BITS) != NOT_FOUND_NUMBER) ++ info->section_size_bits = NUMBER(SECTION_SIZE_BITS); ++ else ++ info->section_size_bits = _SECTION_SIZE_BITS; + -+ DEBUG_MSG("max_physmem_bits : %ld\n", info->max_physmem_bits); -+ DEBUG_MSG("section_size_bits: %ld\n", info->section_size_bits); ++ DEBUG_MSG("max_physmem_bits : %ld\n", info->max_physmem_bits); ++ DEBUG_MSG("section_size_bits: %ld\n", info->section_size_bits); + -+ return TRUE; ++ return TRUE; +} + +int +get_versiondep_info_loongarch64(void) +{ -+ info->page_offset = 0x9000000000000000ULL; ++ info->page_offset = _PAGE_OFFSET; + -+ DEBUG_MSG("page_offset : %lx\n", info->page_offset); ++ DEBUG_MSG("page_offset : %lx\n", info->page_offset); + -+ return TRUE; ++ return TRUE; +} + +unsigned long long +vaddr_to_paddr_loongarch64(unsigned long vaddr) +{ + unsigned long long paddr = NOT_PADDR; -+ pgd_t *pgda, pgdv; -+ pmd_t *pmda, pmdv; -+ pte_t *ptea, ptev; ++ pgd_t *pgda, pgdv; ++ pmd_t *pmda, pmdv; ++ pte_t *ptea, ptev; + -+ if(vaddr >=0x8000000000000000ULL && vaddr < 0xc000000000000000ULL) ++ if (vaddr >= _XKPRANGE && vaddr < _XKVRANGE) + return vaddr & ((1ULL << MAX_PHYSMEM_BITS()) - 1); + + if (SYMBOL(swapper_pg_dir) == NOT_FOUND_SYMBOL) { @@ -129,28 +108,29 @@ index 0000000..338da6b + if (!(ptev & _PAGE_PRESENT)) { + ERRMSG("Can't get a valid pte.\n"); + return NOT_PADDR; -+ } else { -+ paddr = PAGEBASE(ptev) + (vaddr & (PAGESIZE() - 1)); + } + ++ paddr = PAGEBASE(ptev) + (vaddr & (PAGESIZE() - 1)); + return paddr; +} + +#endif /* loongarch64 */ -diff --git a/makedumpfile-1.7.0/makedumpfile.h b/makedumpfile-1.7.0/makedumpfile.h -index e59239d..fee3989 100644 ---- a/makedumpfile-1.7.0/makedumpfile.h -+++ b/makedumpfile-1.7.0/makedumpfile.h -@@ -996,6 +996,39 @@ typedef unsigned long pgd_t; +diff -Naru ./makedumpfile-1.7.0/makedumpfile.h ./makedumpfile-1.7.0-la/makedumpfile.h +--- ./makedumpfile-1.7.0/makedumpfile.h 2023-03-21 17:13:47.443586419 +0800 ++++ ./makedumpfile-1.7.0-la/makedumpfile.h 2023-03-21 17:16:18.829859520 +0800 +@@ -1030,6 +1030,42 @@ + #endif /* sw_64 */ - #endif /* mips64 */ -+#ifdef __loongarch64 -+#define KVBASE (0x8000000000000000UL) -+#define _SECTION_SIZE_BITS (28) ++#ifdef __loongarch64__ ++#define KVBASE (0x8000000000000000ULL) ++#define _PAGE_OFFSET (0x9000000000000000ULL) ++#define _XKPRANGE (0x8000000000000000ULL) ++#define _XKVRANGE (0xc000000000000000ULL) ++#define _SECTION_SIZE_BITS (29) +#define _MAX_PHYSMEM_BITS (48) ++#define _PAGE_HUGE (1 << 6) /* HUGE is a PMD bit */ +#define _PAGE_PRESENT (1 << 7) -+#define _PAGE_HUGE (1 << 6) + +typedef unsigned long pte_t; +typedef unsigned long pmd_t; @@ -165,27 +145,27 @@ index e59239d..fee3989 100644 +#define PTRS_PER_PMD PTRS_PER_PTE +#define PTRS_PER_PGD PTRS_PER_PTE + -+#define pte_index(vaddr) (((vaddr) >> PAGESHIFT()) & (PTRS_PER_PTE - 1)) ++#define pte_index(vaddr) (((vaddr) >> PAGESHIFT()) & (PTRS_PER_PTE - 1)) +#define pmd_page_paddr(pmd) (pmd & (int32_t)PAGE_MASK) -+#define pte_offset(dir, vaddr) ((pte_t*)pmd_page_paddr((*dir)) + pte_index(vaddr)) ++#define pte_offset(dir, vaddr) ((pte_t *)pmd_page_paddr((*dir)) + pte_index(vaddr)) + +#define pmd_index(vaddr) (((vaddr) >> PMD_SHIFT) & (PTRS_PER_PMD - 1)) +#define pgd_page_paddr(pgd) (pgd & (int32_t)PAGE_MASK) +#define pmd_offset(pgd, vaddr) ((pmd_t *)pgd_page_paddr((*pgd)) + pmd_index(vaddr)) + -+#define pgd_index(vaddr) (((vaddr) >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1)) ++#define pgd_index(vaddr) (((vaddr) >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1)) +#define pgd_offset(pgdir, vaddr) ((pgd_t *)(pgdir) + pgd_index(vaddr)) + -+#endif /* loongarch64 */ ++#endif /* loongarch64 */ + /* * The function of dependence on machine */ -@@ -1167,6 +1200,22 @@ unsigned long long vaddr_to_paddr_mips64(unsigned long vaddr); - #define arch_crashkernel_mem_size() stub_false() - #endif /* mips64 */ +@@ -1218,6 +1254,22 @@ + #endif /* sw_64 */ + -+#ifdef __loongarch64 /* loongarch64 */ ++#ifdef __loongarch64__ /* loongarch64 */ +int get_phys_base_loongarch64(void); +int get_machdep_info_loongarch64(void); +int get_versiondep_info_loongarch64(void); @@ -193,30 +173,39 @@ index e59239d..fee3989 100644 +#define find_vmemmap() stub_false() +#define get_phys_base() get_phys_base_loongarch64() +#define get_machdep_info() get_machdep_info_loongarch64() -+#define get_versiondep_info() get_versiondep_info_loongarch64() ++#define get_versiondep_info() get_versiondep_info_loongarch64() +#define get_kaslr_offset(X) stub_false() -+#define vaddr_to_paddr(X) vaddr_to_paddr_loongarch64(X) ++#define vaddr_to_paddr(X) vaddr_to_paddr_loongarch64(X) +#define paddr_to_vaddr(X) paddr_to_vaddr_general(X) +#define is_phys_addr(X) stub_true_ul(X) +#define arch_crashkernel_mem_size() stub_false() -+#endif /* loongarch64 */ ++#endif /* loongarch64 */ + typedef unsigned long long mdf_pfn_t; #ifndef ARCH_PFN_OFFSET -@@ -2301,6 +2350,12 @@ int get_xen_info_ia64(void); - #define get_xen_info_arch(X) FALSE - #endif /* mips64 */ +@@ -2359,6 +2411,12 @@ + #endif /* sw_64 */ + -+#ifdef __loongarch64 /* loongarch64 */ ++#ifdef __loongarch64__ /* loongarch64 */ +#define kvtop_xen(X) FALSE +#define get_xen_basic_info_arch(X) FALSE +#define get_xen_info_arch(X) FALSE -+#endif /* loongarch64 */ ++#endif /* loongarch64 */ + struct cycle { mdf_pfn_t start_pfn; mdf_pfn_t end_pfn; --- -2.27.0 - +diff -Naru ./makedumpfile-1.7.0/Makefile ./makedumpfile-1.7.0-la/Makefile +--- ./makedumpfile-1.7.0/Makefile 2023-03-21 17:13:47.443586419 +0800 ++++ ./makedumpfile-1.7.0-la/Makefile 2023-03-21 17:16:18.829859520 +0800 +@@ -48,7 +48,7 @@ + SRC_BASE = makedumpfile.c makedumpfile.h diskdump_mod.h sadump_mod.h sadump_info.h + SRC_PART = print_info.c dwarf_info.c elf_info.c erase_info.c sadump_info.c cache.c tools.c printk.c + OBJ_PART=$(patsubst %.c,%.o,$(SRC_PART)) +-SRC_ARCH = arch/arm.c arch/arm64.c arch/x86.c arch/x86_64.c arch/ia64.c arch/ppc64.c arch/s390x.c arch/ppc.c arch/sparc64.c arch/mips64.c arch/sw_64.c ++SRC_ARCH = arch/arm.c arch/arm64.c arch/x86.c arch/x86_64.c arch/ia64.c arch/ppc64.c arch/s390x.c arch/ppc.c arch/sparc64.c arch/mips64.c arch/loongarch64.c arch/sw_64.c + OBJ_ARCH=$(patsubst %.c,%.o,$(SRC_ARCH)) + + LIBS = -ldw -lbz2 -ldl -lelf -lz diff --git a/kdump.sysconfig.loongarch64 b/kdump.sysconfig.loongarch64 index 86c6d89..e2a2d7b 100755 --- a/kdump.sysconfig.loongarch64 +++ b/kdump.sysconfig.loongarch64 @@ -17,11 +17,11 @@ KDUMP_COMMANDLINE="" # This variable lets us remove arguments from the current kdump commandline # as taken from either KDUMP_COMMANDLINE above, or from /proc/cmdline # NOTE: some arguments such as crashkernel will always be removed -KDUMP_COMMANDLINE_REMOVE="hugepages hugepagesz slub_debug quiet log_buf_len rd_start rd_size initrd resume=UUID" +KDUMP_COMMANDLINE_REMOVE="hugepages hugepagesz slub_debug quiet log_buf_len rd_start rd_size initrd" # This variable lets us append arguments to the current kdump commandline # after processed by KDUMP_COMMANDLINE_REMOVE -KDUMP_COMMANDLINE_APPEND="nr_cpus=1 init 3 irqpoll reset_devices cgroup_disable=memory udev.children-max=2 panic=10 novmcoredd" +KDUMP_COMMANDLINE_APPEND="init 3 irqpoll reset_devices cgroup_disable=memory udev.children-max=2 panic=10 novmcoredd" # Any additional kexec arguments required. In most situations, this should # be left empty @@ -34,32 +34,4 @@ KEXEC_ARGS="" #KDUMP_BOOTDIR="/boot" #What is the image type used for kdump -KDUMP_IMG="vmlinux" - -#Please replace with the capture kernel to be reboot and the -#the corresponding initrd only for LoongArch architecture -# Example: -# DEFAULT_KDUMP_KERNEL="/boot/vmlinux-4.19.190-4.lns8.loongarch64+kdump" -# DEFAULT_TARGET_INITRD="/boot/initramfs-4.19.190-4.lns8.loongarch64+kdump.img" -# If a DEFAULT_KDUMP_KERNEL is not specified, the default is set to -# "/boot/vmlinux-$(uname -r)+kdump" -DEFAULT_KDUMP_KERNEL="" -# If a DEFAULT_TARGET_INITRD is not specified, the default is set to -# "/boot/initramfs-$(uname -r)+kdump.img" -DEFAULT_TARGET_INITRD="" - -# Logging is controlled by following variables in the first kernel: -# - @var KDUMP_STDLOGLVL - logging level to standard error (console output) -# - @var KDUMP_SYSLOGLVL - logging level to syslog (by logger command) -# - @var KDUMP_KMSGLOGLVL - logging level to /dev/kmsg (only for boot-time) -# -# In the second kernel, kdump will use the rd.kdumploglvl option to set the -# log level in the above KDUMP_COMMANDLINE_APPEND. -# - @var rd.kdumploglvl - logging level to syslog (by logger command) -# - for example: add the rd.kdumploglvl=3 option to KDUMP_COMMANDLINE_APPEND -# -# Logging levels: no logging(0), error(1),warn(2),info(3),debug(4) -# -# KDUMP_STDLOGLVL=3 -# KDUMP_SYSLOGLVL=0 -# KDUMP_KMSGLOGLVL=0 +KDUMP_IMG="vmlinuz" diff --git a/fix-add-64-bit-loongArch-support-1.patch b/kexec-add-loongarch64-support.patch similarity index 40% rename from fix-add-64-bit-loongArch-support-1.patch rename to kexec-add-loongarch64-support.patch index ebd99e3..0e4ae3d 100644 --- a/fix-add-64-bit-loongArch-support-1.patch +++ b/kexec-add-loongarch64-support.patch @@ -1,72 +1,72 @@ -From 2b338585c875753c7d1d555b62c96f14e648ad7f Mon Sep 17 00:00:00 2001 -From: wu-leilei -Date: Tue, 19 Apr 2022 15:54:42 +0800 -Subject: [PATCH] add 64 bit loongArch support +From c969d18e44f06b807029bfe0d354a5a6857c4f96 Mon Sep 17 00:00:00 2001 +From: Youling Tang +Date: Mon, 20 Mar 2023 10:49:36 +0800 +Subject: [PATCH] Add loongarch64 support +Signed-off-by: Youling Tang --- config/config.guess | 3 + - config/config.sub | 4 + + config/config.sub | 1 + + configure | 3 + configure.ac | 3 + include/elf.h | 1 + include/image.h | 1 + kexec/Makefile | 1 + - kexec/arch/loongarch/Makefile | 16 + - kexec/arch/loongarch/crashdump-loongarch.c | 384 ++++++++++++++++++ - kexec/arch/loongarch/crashdump-loongarch.h | 24 ++ - kexec/arch/loongarch/include/arch/options.h | 41 ++ - kexec/arch/loongarch/kexec-elf-loongarch.c | 212 ++++++++++ - .../arch/loongarch/kexec-elf-rel-loongarch.c | 43 ++ - kexec/arch/loongarch/kexec-loongarch.c | 169 ++++++++ - kexec/arch/loongarch/kexec-loongarch.h | 34 ++ - kexec/kexec-syscall.h | 7 + + kexec/arch/loongarch/Makefile | 22 + + kexec/arch/loongarch/crashdump-loongarch.c | 220 ++++++++++ + kexec/arch/loongarch/crashdump-loongarch.h | 26 ++ + kexec/arch/loongarch/image-header.h | 79 ++++ + kexec/arch/loongarch/include/arch/options.h | 28 ++ + kexec/arch/loongarch/iomem.h | 10 + + kexec/arch/loongarch/kexec-elf-loongarch.c | 129 ++++++ + .../arch/loongarch/kexec-elf-rel-loongarch.c | 42 ++ + kexec/arch/loongarch/kexec-loongarch.c | 397 ++++++++++++++++++ + kexec/arch/loongarch/kexec-loongarch.h | 60 +++ + kexec/arch/loongarch/kexec-pei-loongarch.c | 124 ++++++ + kexec/kexec-syscall.h | 9 +- + kexec/kexec.c | 2 +- + kexec/kexec.h | 1 + purgatory/Makefile | 1 + purgatory/arch/loongarch/Makefile | 10 + purgatory/arch/loongarch/console-loongarch.c | 7 + .../arch/loongarch/purgatory-loongarch.c | 7 + .../arch/loongarch/purgatory-loongarch.h | 6 + - 20 files changed, 974 insertions(+) + 26 files changed, 1191 insertions(+), 2 deletions(-) create mode 100644 kexec/arch/loongarch/Makefile create mode 100644 kexec/arch/loongarch/crashdump-loongarch.c create mode 100644 kexec/arch/loongarch/crashdump-loongarch.h + create mode 100644 kexec/arch/loongarch/image-header.h create mode 100644 kexec/arch/loongarch/include/arch/options.h + create mode 100644 kexec/arch/loongarch/iomem.h create mode 100644 kexec/arch/loongarch/kexec-elf-loongarch.c create mode 100644 kexec/arch/loongarch/kexec-elf-rel-loongarch.c create mode 100644 kexec/arch/loongarch/kexec-loongarch.c create mode 100644 kexec/arch/loongarch/kexec-loongarch.h + create mode 100644 kexec/arch/loongarch/kexec-pei-loongarch.c create mode 100644 purgatory/arch/loongarch/Makefile create mode 100644 purgatory/arch/loongarch/console-loongarch.c create mode 100644 purgatory/arch/loongarch/purgatory-loongarch.c create mode 100644 purgatory/arch/loongarch/purgatory-loongarch.h diff --git a/config/config.guess b/config/config.guess -index 8d70ec2..1cbf692 100755 +index 183653d..9b863dd 100755 --- a/config/config.guess +++ b/config/config.guess -@@ -1039,6 +1039,9 @@ EOF - mips64el:Linux:*:*) +@@ -992,6 +992,9 @@ EOF + k1om:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; + loongarch32:Linux:*:* | loongarch64:Linux:*:* | loongarchx32:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; - openrisc*:Linux:*:*) - echo or1k-unknown-linux-"$LIBC" + m32r*:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; diff --git a/config/config.sub b/config/config.sub -index 9bc49a7..d5bbcc3 100755 +index ca63c8c..1a5ab38 100755 --- a/config/config.sub +++ b/config/config.sub -@@ -1107,6 +1107,9 @@ case $cpu-$vendor in - arm64-*) - cpu=aarch64 - ;; -+ loongarch-*) -+ cpu=loongarch64 -+ ;; - - # Recognize the canonical CPU Types that limit and/or modify the - # company names they are paired with. -@@ -1185,6 +1188,7 @@ case $cpu-$vendor in +@@ -1186,6 +1186,7 @@ case $cpu-$vendor in | k1om \ | le32 | le64 \ | lm32 \ @@ -74,32 +74,46 @@ index 9bc49a7..d5bbcc3 100755 | m32c | m32r | m32rle \ | m5200 | m68000 | m680[012346]0 | m68360 | m683?2 | m68k \ | m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x \ +diff --git a/configure b/configure +index 3cfc954..7e9bc6f 100755 +--- a/configure ++++ b/configure +@@ -3065,6 +3065,9 @@ case $target_cpu in + sw_64*) + ARCH="sw_64" + ;; ++ loongarch*) ++ ARCH="loongarch" ++ ;; + * ) + as_fn_error $? "unsupported architecture $target_cpu" "$LINENO" 5 + ;; diff --git a/configure.ac b/configure.ac -index 1427ced..c28ccfd 100644 +index 0a8a5fb..f40e96e 100644 --- a/configure.ac +++ b/configure.ac @@ -58,6 +58,9 @@ case $target_cpu in hppa*) ARCH="hppa" ;; -+ loongarch* ) ++ loongarch*) + ARCH="loongarch" + ;; - * ) - AC_MSG_ERROR([unsupported architecture $target_cpu]) - ;; + sw_64*) + ARCH="sw_64" + ;; diff --git a/include/elf.h b/include/elf.h -index b7677a2..ca42618 100644 +index 390fc91..9b6fafb 100644 --- a/include/elf.h +++ b/include/elf.h -@@ -260,6 +260,7 @@ typedef struct +@@ -259,6 +259,7 @@ typedef struct + #define EM_ARC_A5 93 /* ARC Cores Tangent-A5 */ #define EM_XTENSA 94 /* Tensilica Xtensa Architecture */ #define EM_AARCH64 183 /* ARM AARCH64 */ - #define EM_NUM 184 +#define EM_LOONGARCH 258 /* Loongson Loongarch*/ + #define EM_NUM 184 /* If it is necessary to assign new unofficial EM_* values, please - pick large random numbers (0x8523, 0xa7f2, etc.) to minimize the diff --git a/include/image.h b/include/image.h index 8e9d81e..7a4bccf 100644 --- a/include/image.h @@ -113,7 +127,7 @@ index 8e9d81e..7a4bccf 100644 /* * Image Types diff --git a/kexec/Makefile b/kexec/Makefile -index e69e309..8a52e8d 100644 +index 7d2544b..3416ca6 100644 --- a/kexec/Makefile +++ b/kexec/Makefile @@ -92,6 +92,7 @@ include $(srcdir)/kexec/arch/s390/Makefile @@ -121,726 +135,575 @@ index e69e309..8a52e8d 100644 include $(srcdir)/kexec/arch/x86_64/Makefile include $(srcdir)/kexec/arch/hppa/Makefile +include $(srcdir)/kexec/arch/loongarch/Makefile + include $(srcdir)/kexec/arch/sw_64/Makefile KEXEC_SRCS += $($(ARCH)_KEXEC_SRCS) - diff --git a/kexec/arch/loongarch/Makefile b/kexec/arch/loongarch/Makefile new file mode 100644 -index 0000000..b7553bc +index 0000000..3b33b96 --- /dev/null +++ b/kexec/arch/loongarch/Makefile -@@ -0,0 +1,16 @@ +@@ -0,0 +1,22 @@ +# +# kexec loongarch (linux booting linux) +# +loongarch_KEXEC_SRCS = kexec/arch/loongarch/kexec-loongarch.c +loongarch_KEXEC_SRCS += kexec/arch/loongarch/kexec-elf-loongarch.c ++loongarch_KEXEC_SRCS += kexec/arch/loongarch/kexec-pei-loongarch.c +loongarch_KEXEC_SRCS += kexec/arch/loongarch/kexec-elf-rel-loongarch.c +loongarch_KEXEC_SRCS += kexec/arch/loongarch/crashdump-loongarch.c + ++loongarch_MEM_REGIONS = kexec/mem_regions.c ++ ++loongarch_CPPFLAGS += -I $(srcdir)/kexec/ ++ +loongarch_ADD_BUFFER = +loongarch_ADD_SEGMENT = +loongarch_VIRT_TO_PHYS = + +dist += kexec/arch/loongarch/Makefile $(loongarch_KEXEC_SRCS) \ + kexec/arch/loongarch/kexec-loongarch.h \ ++ kexec/arch/loongarch/image-header.h \ + kexec/arch/loongarch/crashdump-loongarch.h \ + kexec/arch/loongarch/include/arch/options.h diff --git a/kexec/arch/loongarch/crashdump-loongarch.c b/kexec/arch/loongarch/crashdump-loongarch.c new file mode 100644 -index 0000000..1c27aa7 +index 0000000..81250e4 --- /dev/null +++ b/kexec/arch/loongarch/crashdump-loongarch.c -@@ -0,0 +1,384 @@ +@@ -0,0 +1,220 @@ +/* -+ * kexec: Linux boots Linux ++ * LoongArch crashdump. + * -+ * Copyright (C) 2021 Loongson Technology Co., Ltd. ++ * Copyright (C) 2022 Loongson Technology Corporation Limited. ++ * Youling Tang ++ * ++ * derived from crashdump-arm64.c + * + * This source code is licensed under the GNU General Public License, + * Version 2. See the file COPYING for more details. + */ -+#include -+#include -+#include ++ ++#define _GNU_SOURCE ++ +#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "../../kexec.h" -+#include "../../kexec-elf.h" -+#include "../../kexec-syscall.h" -+#include "../../crashdump.h" -+#include "kexec-loongarch.h" ++#include ++ ++#include "kexec.h" ++#include "crashdump.h" +#include "crashdump-loongarch.h" -+#include "unused.h" ++#include "iomem.h" ++#include "kexec-loongarch.h" ++#include "kexec-elf.h" ++#include "mem_regions.h" ++ ++/* memory ranges of crashed kernel */ ++static struct memory_ranges system_memory_rgns; ++ ++/* memory range reserved for crashkernel */ ++struct memory_range crash_reserved_mem[CRASH_MAX_RESERVED_RANGES]; ++struct memory_ranges usablemem_rgns = { ++ .size = 0, ++ .max_size = CRASH_MAX_RESERVED_RANGES, ++ .ranges = crash_reserved_mem, ++}; + -+/* -+ * Stores a sorted list of RAM memory ranges for which to create elf headers. -+ * A separate program header is created for backup region -+ */ -+static struct memory_range crash_memory_range[CRASH_MAX_MEMORY_RANGES]; ++struct memory_range elfcorehdr_mem; + -+/* Memory region reserved for storing panic kernel and other data. */ -+static struct memory_range crash_reserved_mem; ++static struct crash_elf_info elf_info64 = { ++ .class = ELFCLASS64, ++ .data = ELFDATA2LSB, ++ .machine = EM_LOONGARCH, ++ .page_offset = PAGE_OFFSET, ++}; + +/* -+ * Read kernel physical load addr from the file returned by proc_iomem() -+ * (Kernel Code) and store in kexec_info ++ * iomem_range_callback() - callback called for each iomem region ++ * @data: not used ++ * @nr: not used ++ * @str: name of the memory region ++ * @base: start address of the memory region ++ * @length: size of the memory region ++ * ++ * This function is called once for each memory region found in /proc/iomem. ++ * It locates system RAM and crashkernel reserved memory and places these to ++ * variables, respectively, system_memory_rgns and usablemem_rgns. + */ -+static int get_kernel_paddr(struct crash_elf_info *elf_info) ++ ++static int iomem_range_callback(void *UNUSED(data), int UNUSED(nr), ++ char *str, unsigned long long base, ++ unsigned long long length) +{ -+ uint64_t start; ++ if (strncmp(str, CRASH_KERNEL, strlen(CRASH_KERNEL)) == 0) ++ return mem_regions_alloc_and_add(&usablemem_rgns, ++ base, length, RANGE_RAM); ++ else if (strncmp(str, SYSTEM_RAM, strlen(SYSTEM_RAM)) == 0) ++ return mem_regions_alloc_and_add(&system_memory_rgns, ++ base, length, RANGE_RAM); ++ else if (strncmp(str, KERNEL_CODE, strlen(KERNEL_CODE)) == 0) ++ elf_info64.kern_paddr_start = base; ++ else if (strncmp(str, KERNEL_DATA, strlen(KERNEL_DATA)) == 0) ++ elf_info64.kern_size = base + length - elf_info64.kern_paddr_start; + -+ if (xen_present()) /* Kernel not entity mapped under Xen */ -+ return 0; ++ return 0; ++} + -+ if (parse_iomem_single("Kernel code\n", &start, NULL) == 0) { -+ elf_info->kern_paddr_start = start; -+ dbgprintf("kernel load physical addr start = 0x%" PRIu64 "\n", start); -+ return 0; -+ } ++int is_crashkernel_mem_reserved(void) ++{ ++ if (!usablemem_rgns.size) ++ kexec_iomem_for_each_line(NULL, iomem_range_callback, NULL); + -+ fprintf(stderr, "Cannot determine kernel physical load addr\n"); -+ return -1; ++ return usablemem_rgns.size; +} + -+static int get_kernel_vaddr_and_size(struct crash_elf_info *elf_info, -+ unsigned long start_offset) ++/* ++ * crash_get_memory_ranges() - read system physical memory ++ * ++ * Function reads through system physical memory and stores found memory ++ * regions in system_memory_ranges. ++ * Regions are sorted in ascending order. ++ * ++ * Returns 0 in case of success and a negative value otherwise. ++ */ ++static int crash_get_memory_ranges(void) +{ -+ uint64_t end; ++ int i; + -+ if (!elf_info->kern_paddr_start) -+ return -1; -+ -+ elf_info->kern_vaddr_start = elf_info->kern_paddr_start | -+ start_offset; + /* -+ * If "Kernel bss" exists, the kernel ends there, else fall -+ * through and say that it ends at "Kernel data" ++ * First read all memory regions that can be considered as ++ * system memory including the crash area. + */ -+ if (parse_iomem_single("Kernel bss\n", NULL, &end) == 0 || -+ parse_iomem_single("Kernel data\n", NULL, &end) == 0) { -+ elf_info->kern_size = end - elf_info->kern_paddr_start; -+ dbgprintf("kernel_vaddr= 0x%llx paddr %llx\n", -+ elf_info->kern_vaddr_start, -+ elf_info->kern_paddr_start); -+ dbgprintf("kernel size = 0x%lx\n", elf_info->kern_size); -+ return 0; -+ } ++ if (!usablemem_rgns.size) ++ kexec_iomem_for_each_line(NULL, iomem_range_callback, NULL); + -+ fprintf(stderr, "Cannot determine kernel virtual load addr and size\n"); -+ return -1; -+} ++ /* allow one or two regions for crash dump kernel */ ++ if (!usablemem_rgns.size) ++ return -EINVAL; + -+/* -+ * Removes crash reserve region from list of memory chunks for whom elf program -+ * headers have to be created. Assuming crash reserve region to be a single -+ * continuous area fully contained inside one of the memory chunks -+ */ -+static int exclude_crash_reserve_region(int *nr_ranges) -+{ -+ int i, j, tidx = -1; -+ unsigned long long cstart, cend; -+ struct memory_range temp_region = { -+ .start = 0, -+ .end = 0 -+ }; ++ dbgprint_mem_range("Reserved memory range", ++ usablemem_rgns.ranges, usablemem_rgns.size); + -+ /* Crash reserved region. */ -+ cstart = crash_reserved_mem.start; -+ cend = crash_reserved_mem.end; -+ -+ for (i = 0; i < (*nr_ranges); i++) { -+ unsigned long long mstart, mend; -+ -+ mstart = crash_memory_range[i].start; -+ mend = crash_memory_range[i].end; -+ -+ if (cstart < mend && cend > mstart) { -+ if (cstart != mstart && cend != mend) { -+ /* Split memory region */ -+ crash_memory_range[i].end = cstart - 1; -+ temp_region.start = cend + 1; -+ temp_region.end = mend; -+ temp_region.type = RANGE_RAM; -+ tidx = i+1; -+ } else if (cstart != mstart) { -+ crash_memory_range[i].end = cstart - 1; -+ } else { -+ crash_memory_range[i].start = cend + 1; -+ } ++ for (i = 0; i < usablemem_rgns.size; i++) { ++ if (mem_regions_alloc_and_exclude(&system_memory_rgns, ++ &crash_reserved_mem[i])) { ++ fprintf(stderr, "Cannot allocate memory for ranges\n"); ++ return -ENOMEM; + } + } + -+ /* Insert split memory region, if any. */ -+ if (tidx >= 0) { -+ if (*nr_ranges == CRASH_MAX_MEMORY_RANGES) { -+ /* No space to insert another element. */ -+ fprintf(stderr, "Error: Number of crash memory ranges" -+ " excedeed the max limit\n"); -+ return -1; -+ } ++ /* ++ * Make sure that the memory regions are sorted. ++ */ ++ mem_regions_sort(&system_memory_rgns); + -+ for (j = (*nr_ranges - 1); j >= tidx; j--) -+ crash_memory_range[j+1] = crash_memory_range[j]; ++ dbgprint_mem_range("Coredump memory ranges", ++ system_memory_rgns.ranges, system_memory_rgns.size); + -+ crash_memory_range[tidx].start = temp_region.start; -+ crash_memory_range[tidx].end = temp_region.end; -+ crash_memory_range[tidx].type = temp_region.type; -+ (*nr_ranges)++; -+ } ++ /* ++ * For additional kernel code/data segment. ++ * kern_paddr_start/kern_size are determined in iomem_range_callback ++ */ ++ elf_info64.kern_vaddr_start = get_kernel_sym("_text"); ++ if (!elf_info64.kern_vaddr_start) ++ elf_info64.kern_vaddr_start = UINT64_MAX; + + return 0; +} + +/* -+ * Reads the appropriate file and retrieves the SYSTEM RAM regions for whom to -+ * create Elf headers. Keeping it separate from get_memory_ranges() as -+ * requirements are different in the case of normal kexec and crashdumps. ++ * load_crashdump_segments() - load the elf core header ++ * @info: kexec info structure ++ * ++ * This function creates and loads an additional segment of elf core header ++ : which is used to construct /proc/vmcore on crash dump kernel. + * -+ * Normal kexec needs to look at all of available physical memory irrespective -+ * of the fact how much of it is being used by currently running kernel. -+ * Crashdumps need to have access to memory regions actually being used by -+ * running kernel. Expecting a different file/data structure than /proc/iomem -+ * to look into down the line. May be something like /proc/kernelmem or may -+ * be zone data structures exported from kernel. ++ * Return 0 in case of success and -1 in case of error. + */ -+static int get_crash_memory_ranges(struct memory_range **range, int *ranges) -+{ -+ const char *iomem = proc_iomem(); -+ int memory_ranges = 0; -+ char line[MAX_LINE]; -+ FILE *fp; -+ unsigned long long start, end; -+ -+ fp = fopen(iomem, "r"); -+ if (!fp) { -+ fprintf(stderr, "Cannot open %s: %s\n", iomem, strerror(errno)); -+ return -1; -+ } + -+ /* Separate segment for backup region */ -+ crash_memory_range[0].start = BACKUP_SRC_START; -+ crash_memory_range[0].end = BACKUP_SRC_END; -+ crash_memory_range[0].type = RANGE_RAM; -+ memory_ranges++; ++int load_crashdump_segments(struct kexec_info *info) ++{ ++ unsigned long elfcorehdr; ++ unsigned long bufsz; ++ void *buf; ++ int err; + -+ while (fgets(line, sizeof(line), fp) != 0) { -+ char *str; -+ int type, consumed, count; -+ if (memory_ranges >= CRASH_MAX_MEMORY_RANGES) -+ break; -+ count = sscanf(line, "%llx-%llx : %n", -+ &start, &end, &consumed); -+ if (count != 2) -+ continue; -+ str = line + consumed; ++ /* ++ * First fetch all the memory (RAM) ranges that we are going to ++ * pass to the crash dump kernel during panic. ++ */ + -+ /* Only Dumping memory of type System RAM. */ -+ if (memcmp(str, "System RAM\n", 11) == 0) { -+ type = RANGE_RAM; -+ } else if (memcmp(str, "Crash kernel\n", 13) == 0) { -+ /* -+ * Reserved memory region. New kernel can -+ * use this region to boot into. -+ */ -+ crash_reserved_mem.start = start; -+ crash_reserved_mem.end = end; -+ crash_reserved_mem.type = RANGE_RAM; -+ continue; -+ } else { -+ continue; -+ } ++ err = crash_get_memory_ranges(); + -+ if (start == BACKUP_SRC_START && end >= (BACKUP_SRC_END + 1)) -+ start = BACKUP_SRC_END + 1; ++ if (err) ++ return EFAILED; + -+ crash_memory_range[memory_ranges].start = start; -+ crash_memory_range[memory_ranges].end = end; -+ crash_memory_range[memory_ranges].type = type; -+ memory_ranges++; ++ err = crash_create_elf64_headers(info, &elf_info64, ++ system_memory_rgns.ranges, system_memory_rgns.size, ++ &buf, &bufsz, ELF_CORE_HEADER_ALIGN); + -+ /* Segregate linearly mapped region. */ -+ if (MAXMEM && (MAXMEM - 1) >= start && (MAXMEM - 1) <= end) { -+ crash_memory_range[memory_ranges - 1].end = MAXMEM - 1; ++ if (err) ++ return EFAILED; + -+ /* Add segregated region. */ -+ crash_memory_range[memory_ranges].start = MAXMEM; -+ crash_memory_range[memory_ranges].end = end; -+ crash_memory_range[memory_ranges].type = type; -+ memory_ranges++; -+ } -+ } -+ fclose(fp); ++ elfcorehdr = add_buffer(info, buf, bufsz, bufsz, 1024, ++ crash_reserved_mem[usablemem_rgns.size - 1].start, ++ crash_reserved_mem[usablemem_rgns.size - 1].end, -1); + -+ if (exclude_crash_reserve_region(&memory_ranges) < 0) -+ return -1; ++ elfcorehdr_mem.start = elfcorehdr; ++ elfcorehdr_mem.end = elfcorehdr + bufsz - 1; + -+ *range = crash_memory_range; -+ *ranges = memory_ranges; ++ dbgprintf("%s: elfcorehdr 0x%llx-0x%llx\n", __func__, ++ elfcorehdr_mem.start, elfcorehdr_mem.end); + + return 0; +} + -+/* Converts unsigned long to ascii string. */ -+void ultoa(unsigned long i, char *str) ++/* ++ * e_entry and p_paddr are actually in virtual address space. ++ * Those values will be translated to physcal addresses by using ++ * virt_to_phys() in add_segment(). ++ * So let's fix up those values for later use so the memory base will be ++ * correctly replaced with crash_reserved_mem[usablemem_rgns.size - 1].start. ++ */ ++void fixup_elf_addrs(struct mem_ehdr *ehdr) +{ -+ int j = 0, k; -+ char tmp; ++ struct mem_phdr *phdr; ++ int i; + -+ do { -+ str[j++] = i % 10 + '0'; -+ } while ((i /= 10) > 0); -+ str[j] = '\0'; ++ ehdr->e_entry += crash_reserved_mem[usablemem_rgns.size - 1].start; + -+ /* Reverse the string. */ -+ for (j = 0, k = strlen(str) - 1; j < k; j++, k--) { -+ tmp = str[k]; -+ str[k] = str[j]; -+ str[j] = tmp; ++ for (i = 0; i < ehdr->e_phnum; i++) { ++ phdr = &ehdr->e_phdr[i]; ++ if (phdr->p_type != PT_LOAD) ++ continue; ++ phdr->p_paddr += crash_reserved_mem[usablemem_rgns.size - 1].start; + } +} + -+/* Append str to cmdline */ -+static void add_cmdline(char *cmdline, char *str) -+{ -+ int cmdline_size; -+ int cmdlen = strlen(cmdline) + strlen(str); -+ -+ cmdline_size = COMMAND_LINE_SIZE; -+ if (cmdlen > (cmdline_size - 1)) -+ die("Command line overflow\n"); -+ strcat(cmdline, str); -+} -+ -+/* -+ * Adds the appropriate mem= options to command line, indicating the -+ * memory region the new kernel can use to boot into. -+ */ -+static int cmdline_add_mem(char *cmdline, unsigned long addr, -+ unsigned long size) ++int get_crash_kernel_load_range(uint64_t *start, uint64_t *end) +{ -+ char str[50], *ptr; ++ if (!usablemem_rgns.size) ++ kexec_iomem_for_each_line(NULL, iomem_range_callback, NULL); + -+ addr = addr / 1024; -+ size = size / 1024; -+ ptr = str; -+ strcpy(str, " mem="); -+ ptr += strlen(str); -+ ultoa(size, ptr); -+ strcat(str, "K@"); -+ ptr = str + strlen(str); -+ ultoa(addr, ptr); -+ strcat(str, "K"); ++ if (!usablemem_rgns.size) ++ return -1; + -+ add_cmdline(cmdline, str); ++ *start = crash_reserved_mem[usablemem_rgns.size - 1].start; ++ *end = crash_reserved_mem[usablemem_rgns.size - 1].end; + + return 0; +} +diff --git a/kexec/arch/loongarch/crashdump-loongarch.h b/kexec/arch/loongarch/crashdump-loongarch.h +new file mode 100644 +index 0000000..25ff24b +--- /dev/null ++++ b/kexec/arch/loongarch/crashdump-loongarch.h +@@ -0,0 +1,26 @@ ++#ifndef CRASHDUMP_LOONGARCH_H ++#define CRASHDUMP_LOONGARCH_H + -+/* Adds the elfcorehdr= command line parameter to command line. */ -+static int cmdline_add_elfcorehdr(char *cmdline, unsigned long addr) -+{ -+ int align = 1024; -+ char str[30], *ptr; -+ -+ /* -+ * Passing in elfcorehdr=xxxK format. Saves space required in cmdline. -+ * Ensure 1K alignment -+ */ -+ if (addr % align) -+ return -1; ++struct kexec_info; ++extern struct memory_ranges usablemem_rgns; ++extern struct memory_range crash_reserved_mem[]; ++extern struct memory_range elfcorehdr_mem; + -+ addr = addr / align; -+ ptr = str; -+ strcpy(str, " elfcorehdr="); -+ ptr += strlen(str); -+ ultoa(addr, ptr); -+ strcat(str, "K"); ++int load_crashdump_segments(struct kexec_info *info); ++int is_crashkernel_mem_reserved(void); ++void fixup_elf_addrs(struct mem_ehdr *ehdr); ++int get_crash_kernel_load_range(uint64_t *start, uint64_t *end); + -+ add_cmdline(cmdline, str); ++#define PAGE_OFFSET 0x9000000000000000ULL ++#define MAXMEM 0 + -+ return 0; -+} ++#define CRASH_MAX_MEMMAP_NR (KEXEC_MAX_SEGMENTS + 1) ++#define CRASH_MAX_MEMORY_RANGES (MAX_MEMORY_RANGES + 2) + ++/* crash dump kernel support at most two regions, low_region and high region. */ ++#define CRASH_MAX_RESERVED_RANGES 2 + -+static struct crash_elf_info elf_info64 = { -+ class: ELFCLASS64, -+ data : ELFDATA2LSB, -+ machine : EM_LOONGARCH, -+ page_offset : PAGE_OFFSET, -+ lowmem_limit : 0, /* 0 == no limit */ -+}; ++#define COMMAND_LINE_SIZE 512 + ++extern struct arch_options_t arch_options; ++#endif /* CRASHDUMP_LOONGARCH_H */ +diff --git a/kexec/arch/loongarch/image-header.h b/kexec/arch/loongarch/image-header.h +new file mode 100644 +index 0000000..3b75765 +--- /dev/null ++++ b/kexec/arch/loongarch/image-header.h +@@ -0,0 +1,79 @@ +/* -+ * Loads additional segments in case of a panic kernel is being loaded. -+ * One segment for backup region, another segment for storing elf headers -+ * for crash memory image. ++ * LoongArch binary image header. + */ -+int load_crashdump_segments(struct kexec_info *info, char* mod_cmdline, -+ unsigned long max_addr, unsigned long min_base) -+{ -+ void *tmp; -+ unsigned long sz, elfcorehdr; -+ int nr_ranges, align = 1024; -+ struct memory_range *mem_range; -+ crash_create_elf_headers_func crash_create = crash_create_elf64_headers; -+ struct crash_elf_info *elf_info = &elf_info64; -+ unsigned long start_offset = PAGE_OFFSET; -+ -+ if (get_kernel_paddr(elf_info)) -+ return -1; + -+ if (get_kernel_vaddr_and_size(elf_info, start_offset)) -+ return -1; ++#if !defined(__LOONGARCH_IMAGE_HEADER_H) ++#define __LOONGARCH_IMAGE_HEADER_H + -+ if (get_crash_memory_ranges(&mem_range, &nr_ranges) < 0) -+ return -1; ++#include ++#include + -+ if (min_base < crash_reserved_mem.start) -+ min_base = crash_reserved_mem.start; -+ if (max_addr > crash_reserved_mem.end) -+ max_addr = crash_reserved_mem.end; -+ -+ info->backup_src_start = BACKUP_SRC_START; -+ info->backup_src_size = BACKUP_SRC_SIZE; -+ /* Create a backup region segment to store backup data*/ -+ sz = _ALIGN(BACKUP_SRC_SIZE, align); -+ tmp = xmalloc(sz); -+ memset(tmp, 0, sz); -+ info->backup_start = add_buffer(info, tmp, sz, sz, align, -+ min_base, max_addr, -1); -+ -+ if (crash_create(info, elf_info, crash_memory_range, nr_ranges, -+ &tmp, &sz, ELF_CORE_HEADER_ALIGN) < 0) { -+ free(tmp); -+ return -1; -+ } ++/** ++ * struct loongarch_image_header ++ * ++ * @pe_sig: Optional PE format 'MZ' signature. ++ * @reserved_1: Reserved. ++ * @kernel_entry: Kernel image entry pointer. ++ * @image_size: An estimated size of the memory image size in LSB byte order. ++ * @text_offset: The image load offset in LSB byte order. ++ * @reserved_2: Reserved. ++ * @reserved_3: Reserved. ++ * @pe_header: Optional offset to a PE format header. ++ **/ ++ ++struct loongarch_image_header { ++ uint8_t pe_sig[2]; ++ uint16_t reserved_1[3]; ++ uint64_t kernel_entry; ++ uint64_t image_size; ++ uint64_t text_offset; ++ uint64_t reserved_2[3]; ++ uint32_t reserved_3; ++ uint32_t pe_header; ++}; + -+ elfcorehdr = add_buffer(info, tmp, sz, sz, align, min_base, max_addr, -1); ++static const uint8_t loongarch_image_pe_sig[2] = {'M', 'Z'}; + -+ /* -+ * backup segment is after elfcorehdr, so use elfcorehdr as top of -+ * kernel's available memory -+ */ -+ add_cmdline(mod_cmdline, " init 3 nr_cpus=1"); -+ cmdline_add_mem(mod_cmdline, min_base, max_addr - min_base + 1); -+ cmdline_add_elfcorehdr(mod_cmdline, elfcorehdr); ++/** ++ * loongarch_header_check_pe_sig - Helper to check the loongarch image header. ++ * ++ * Returns non-zero if 'MZ' signature is found. ++ */ + -+ dbgprintf("CRASH MEMORY RANGES:\n"); -+ dbgprintf("%016lx-%016lx\n", min_base, max_addr); ++static inline int loongarch_header_check_pe_sig(const struct loongarch_image_header *h) ++{ ++ if (!h) ++ return 0; + -+ return 0; ++ return (h->pe_sig[0] == loongarch_image_pe_sig[0] ++ && h->pe_sig[1] == loongarch_image_pe_sig[1]); +} -diff --git a/kexec/arch/loongarch/crashdump-loongarch.h b/kexec/arch/loongarch/crashdump-loongarch.h -new file mode 100644 -index 0000000..3e6638a ---- /dev/null -+++ b/kexec/arch/loongarch/crashdump-loongarch.h -@@ -0,0 +1,24 @@ -+#ifndef CRASHDUMP_LOONGARCH_H -+#define CRASHDUMP_LOONGARCH_H + -+struct kexec_info; -+int load_crashdump_segments(struct kexec_info *info, char *mod_cmdline, -+ unsigned long max_addr, unsigned long min_base); -+void ultoa(unsigned long i, char *str); ++static inline uint64_t loongarch_header_text_offset( ++ const struct loongarch_image_header *h) ++{ ++ if (!h) ++ return 0; + -+#define PAGE_OFFSET 0x9000000000000000ULL -+#define MAXMEM 0 -+#define __pa(x) ((unsigned long)(X) & 0x7fffffff) ++ return le64toh(h->text_offset); ++} + -+#define CRASH_MAX_MEMMAP_NR (KEXEC_MAX_SEGMENTS + 1) -+#define CRASH_MAX_MEMORY_RANGES (MAX_MEMORY_RANGES + 2) ++static inline uint64_t loongarch_header_image_size( ++ const struct loongarch_image_header *h) ++{ ++ if (!h) ++ return 0; + -+#define COMMAND_LINE_SIZE 512 ++ return le64toh(h->image_size); ++} + -+/* Backup Region, First 1M of System RAM. */ -+#define BACKUP_SRC_START 0x00000000 -+#define BACKUP_SRC_END 0x000fffff -+#define BACKUP_SRC_SIZE (BACKUP_SRC_END - BACKUP_SRC_START + 1) ++static inline uint64_t loongarch_header_kernel_entry( ++ const struct loongarch_image_header *h) ++{ ++ if (!h) ++ return 0; + -+extern struct arch_options_t arch_options; -+#endif /* CRASHDUMP_LOONGARCH_H */ ++ return le64toh(h->kernel_entry); ++} ++ ++#endif diff --git a/kexec/arch/loongarch/include/arch/options.h b/kexec/arch/loongarch/include/arch/options.h new file mode 100644 -index 0000000..2bbd350 +index 0000000..25a7dc1 --- /dev/null +++ b/kexec/arch/loongarch/include/arch/options.h -@@ -0,0 +1,41 @@ +@@ -0,0 +1,28 @@ +#ifndef KEXEC_ARCH_LOONGARCH_OPTIONS_H +#define KEXEC_ARCH_LOONGARCH_OPTIONS_H + -+#define OPT_ARCH_MAX (OPT_MAX + 0) -+#define OPT_APPEND (OPT_ARCH_MAX + 0) -+#define OPT_RAMDISK (OPT_ARCH_MAX+1) -+#define OPT_REUSE_CMDLINE (OPT_ARCH_MAX + 2) ++#define OPT_APPEND ((OPT_MAX)+0) ++#define OPT_INITRD ((OPT_MAX)+1) ++#define OPT_REUSE_CMDLINE ((OPT_MAX)+2) ++#define OPT_ARCH_MAX ((OPT_MAX)+3) + -+/* Options relevant to the architecture (excluding loader-specific ones), -+ * in this case none: -+ */ +#define KEXEC_ARCH_OPTIONS \ + KEXEC_OPTIONS \ -+ {"command-line", 1, 0, OPT_APPEND}, \ -+ {"append", 1, 0, OPT_APPEND}, \ -+ {"initrd", 1, 0, OPT_RAMDISK}, \ -+ {"reuse-cmdline", 0, NULL, OPT_REUSE_CMDLINE}, -+ -+ -+#define KEXEC_ARCH_OPT_STR KEXEC_OPT_STR "" -+ -+/* The following two #defines list ALL of the options added by all of the -+ * architecture's loaders. -+ * o main() uses this complete list to scan for its options, ignoring -+ * arch-specific/loader-specific ones. -+ * o Then, arch_process_options() uses this complete list to scan for its -+ * options, ignoring general/loader-specific ones. -+ * o Then, the file_type[n].load re-scans for options, using -+ * KEXEC_ARCH_OPTIONS plus its loader-specific options subset. -+ * Any unrecognised options cause an error here. -+ * -+ * This is done so that main()'s/arch_process_options()'s getopt_long() calls -+ * don't choose a kernel filename from random arguments to options they don't -+ * recognise -- as they now recognise (if not act upon) all possible options. -+ */ -+#define KEXEC_ALL_OPTIONS \ -+ KEXEC_ARCH_OPTIONS -+ ++ { "append", 1, NULL, OPT_APPEND }, \ ++ { "command-line", 1, NULL, OPT_APPEND }, \ ++ { "initrd", 1, NULL, OPT_INITRD }, \ ++ { "ramdisk", 1, NULL, OPT_INITRD }, \ ++ { "reuse-cmdline", 0, NULL, OPT_REUSE_CMDLINE }, \ ++ ++#define KEXEC_ARCH_OPT_STR KEXEC_OPT_STR /* Only accept long arch options. */ ++#define KEXEC_ALL_OPTIONS KEXEC_ARCH_OPTIONS +#define KEXEC_ALL_OPT_STR KEXEC_ARCH_OPT_STR + ++static const char loongarch_opts_usage[] __attribute__ ((unused)) = ++" --append=STRING Set the kernel command line to STRING.\n" ++" --command-line=STRING Set the kernel command line to STRING.\n" ++" --initrd=FILE Use FILE as the kernel initial ramdisk.\n" ++" --ramdisk=FILE Use FILE as the kernel initial ramdisk.\n" ++" --reuse-cmdline Use kernel command line from running system.\n"; ++ +#endif /* KEXEC_ARCH_LOONGARCH_OPTIONS_H */ +diff --git a/kexec/arch/loongarch/iomem.h b/kexec/arch/loongarch/iomem.h +new file mode 100644 +index 0000000..7671e26 +--- /dev/null ++++ b/kexec/arch/loongarch/iomem.h +@@ -0,0 +1,10 @@ ++#ifndef IOMEM_H ++#define IOMEM_H ++ ++#define SYSTEM_RAM "System RAM\n" ++#define KERNEL_CODE "Kernel code\n" ++#define KERNEL_DATA "Kernel data\n" ++#define CRASH_KERNEL "Crash kernel\n" ++#define IOMEM_RESERVED "Reserved\n" ++ ++#endif diff --git a/kexec/arch/loongarch/kexec-elf-loongarch.c b/kexec/arch/loongarch/kexec-elf-loongarch.c new file mode 100644 -index 0000000..6cfb539 +index 0000000..0ac451e --- /dev/null +++ b/kexec/arch/loongarch/kexec-elf-loongarch.c -@@ -0,0 +1,212 @@ +@@ -0,0 +1,129 @@ +/* + * kexec-elf-loongarch.c - kexec Elf loader for loongarch + * -+ * Copyright (C) 2021 Loongson Technology Co., Ltd. ++ * Copyright (C) 2022 Loongson Technology Corporation Limited. ++ * Youling Tang + * + * This source code is licensed under the GNU General Public License, + * Version 2. See the file COPYING for more details. +*/ + +#define _GNU_SOURCE -+#include -+#include -+#include ++ ++#include +#include -+#include -+#include -+#include -+#include -+#include +#include -+#include -+#include -+#include "../../kexec.h" -+#include "../../kexec-elf.h" -+#include "../../kexec-syscall.h" ++ ++#include "kexec.h" ++#include "kexec-elf.h" ++#include "kexec-syscall.h" +#include "crashdump-loongarch.h" +#include "kexec-loongarch.h" -+#include -+ ++#include "arch/options.h" + -+off_t initrd_base = 0; -+off_t initrd_size = 0; ++off_t initrd_base, initrd_size; + -+static const int probe_debug = 0; -+ -+#define BOOTLOADER "kexec" -+#define UPSZ(X) _ALIGN_UP(sizeof(X), 4) -+ -+#define CMDLINE_PREFIX "kexec " -+static char cmdline_buf[COMMAND_LINE_SIZE] = CMDLINE_PREFIX; -+ -+/* Adds the rd_start= command line parameter to command line. */ -+static int cmdline_add_rd_start(char *cmdline, unsigned long addr) -+{ -+ int cmdlen, len; -+ char str[40], *ptr; -+ -+ ptr = str; -+ strcpy(str, " rd_start="); -+ ptr += strlen(str); -+ ultoa(addr, ptr); -+ len = strlen(str); -+ cmdlen = strlen(cmdline) + len; -+ if (cmdlen > (COMMAND_LINE_SIZE - 1)) -+ die("Command line overflow\n"); -+ strcat(cmdline, str); -+ -+ return 0; -+} -+ -+/* Adds the rd_size= command line parameter to command line. */ -+static int cmdline_add_rd_size(char *cmdline, unsigned long addr) -+{ -+ int cmdlen, len; -+ char str[30], *ptr; -+ -+ ptr = str; -+ strcpy(str, " rd_size="); -+ ptr += strlen(str); -+ ultoa(addr, ptr); -+ len = strlen(str); -+ cmdlen = strlen(cmdline) + len; -+ if (cmdlen > (COMMAND_LINE_SIZE - 1)) -+ die("Command line overflow\n"); -+ strcat(cmdline, str); -+ -+ return 0; -+} -+ -+int elf_loongarch_probe(const char *buf, off_t len) ++int elf_loongarch_probe(const char *kernel_buf, off_t kernel_size) +{ + struct mem_ehdr ehdr; + int result; -+ result = build_elf_exec_info(buf, len, &ehdr, 0); ++ ++ result = build_elf_exec_info(kernel_buf, kernel_size, &ehdr, 0); + if (result < 0) { -+ if (probe_debug) -+ fprintf(stderr, "Not an ELF executable.\n"); ++ dbgprintf("%s: Not an ELF executable.\n", __func__); + goto out; + } + -+ /* Verify the architecuture specific bits */ ++ /* Verify the architecuture specific bits. */ + if (ehdr.e_machine != EM_LOONGARCH) { -+ /* for a different architecture */ -+ if (probe_debug) { -+ fprintf(stderr, "Not LoongArch ELF executable.\n"); -+ } ++ dbgprintf("%s: Not an LoongArch ELF executable.\n", __func__); + result = -1; + goto out; + } ++ + result = 0; -+ out: ++out: + free_elf_info(&ehdr); + return result; +} + -+void elf_loongarch_usage(void) -+{ -+ printf( " --command-line=STRING Set the kernel command line to STRING\n" -+ " --append=STRING Set the kernel command line to STRING\n" -+ " --reuse-cmdline Use kernel command line from running system.\n" -+ " --initrd=FILE Use FILE as initial ramdisk.\n" -+ ); -+} -+ -+int elf_loongarch_load(int argc, char **argv, const char *buf, off_t len, -+ struct kexec_info *info) ++int elf_loongarch_load(int argc, char **argv, const char *kernel_buf, ++ off_t kernel_size, struct kexec_info *info) +{ ++ const struct loongarch_image_header *header = NULL; ++ unsigned long kernel_segment; + struct mem_ehdr ehdr; -+ int command_line_len = 0; + int result; -+ size_t i; -+ unsigned long cmdline_addr = 0; -+ char *crash_cmdline; -+ char *initrd_buf = NULL; -+ unsigned long long kernel_addr = 0, kernel_size = 0; -+ unsigned long pagesize = getpagesize(); + -+ /* -+ * Need to append some command line parameters internally in case of -+ * taking crash dumps. -+ */ -+ if (info->kexec_flags & KEXEC_ON_CRASH) { -+ crash_cmdline = xmalloc(COMMAND_LINE_SIZE); -+ memset((void *)crash_cmdline, 0, COMMAND_LINE_SIZE); -+ } else { -+ crash_cmdline = NULL; -+ } ++ result = build_elf_exec_info(kernel_buf, kernel_size, &ehdr, 0); + -+ result = build_elf_exec_info(buf, len, &ehdr, 0); -+ if (result < 0) -+ die("ELF exec parse failed\n"); -+ -+ /* Read in the PT_LOAD segments*/ -+ for (i = 0; i < ehdr.e_phnum; i++) { -+ struct mem_phdr *phdr; -+ phdr = &ehdr.e_phdr[i]; -+ if (phdr->p_type == PT_LOAD) { -+ phdr->p_paddr = virt_to_phys(phdr->p_paddr); -+ kernel_addr = phdr->p_paddr; -+ kernel_size = phdr->p_memsz; -+ } ++ if (result < 0) { ++ dbgprintf("%s: build_elf_exec_info failed\n", __func__); ++ goto exit; + } + -+ /* Load the Elf data */ -+ result = elf_exec_load(&ehdr, info); -+ if (result < 0) -+ die("ELF exec load failed\n"); ++ kernel_segment = loongarch_locate_kernel_segment(info); + -+ info->entry = (void *)virt_to_phys(ehdr.e_entry); -+ -+ if (arch_options.command_line) -+ command_line_len = strlen(arch_options.command_line) + 1; ++ if (kernel_segment == ULONG_MAX) { ++ dbgprintf("%s: Kernel segment is not allocated\n", __func__); ++ result = EFAILED; ++ goto exit; ++ } + ++ dbgprintf("%s: kernel_segment: %016lx\n", __func__, kernel_segment); ++ dbgprintf("%s: image_size: %016lx\n", __func__, ++ kernel_size); ++ dbgprintf("%s: text_offset: %016lx\n", __func__, ++ loongarch_mem.text_offset); ++ dbgprintf("%s: phys_offset: %016lx\n", __func__, ++ loongarch_mem.phys_offset); ++ dbgprintf("%s: PE format: %s\n", __func__, ++ (loongarch_header_check_pe_sig(header) ? "yes" : "no")); ++ ++ /* create and initialize elf core header segment */ + if (info->kexec_flags & KEXEC_ON_CRASH) { -+ result = load_crashdump_segments(info, crash_cmdline, 0x0fffffff, 0); -+ if (result < 0) { -+ free(crash_cmdline); -+ return -1; ++ result = load_crashdump_segments(info); ++ if (result) { ++ dbgprintf("%s: Creating eflcorehdr failed.\n", ++ __func__); ++ goto exit; + } + } + -+ if (arch_options.command_line) -+ strncat(cmdline_buf, arch_options.command_line, command_line_len); -+ -+ if (crash_cmdline) { -+ strncat(cmdline_buf, crash_cmdline, -+ sizeof(crash_cmdline) - -+ strlen(crash_cmdline) - 1); -+ free(crash_cmdline); -+ } -+ ++ /* load the kernel */ + if (info->kexec_flags & KEXEC_ON_CRASH) + /* -+ * In case of crashdump segment[0] is kernel. -+ * Put cmdline just after it. ++ * offset addresses in elf header in order to load ++ * vmlinux (elf_exec) into crash kernel's memory. + */ -+ cmdline_addr = (unsigned long)info->segment[0].mem + -+ info->segment[0].memsz; -+ else -+ cmdline_addr = 0x10000; /* Skip exception handlers */ ++ fixup_elf_addrs(&ehdr); + -+ if (arch_options.initrd_file) { -+ initrd_buf = slurp_decompress_file(arch_options.initrd_file, &initrd_size); ++ info->entry = (void *)virt_to_phys(ehdr.e_entry); + -+ initrd_base = add_buffer(info, initrd_buf, initrd_size, -+ initrd_size, sizeof(void *), -+ _ALIGN_UP(kernel_addr + kernel_size, -+ pagesize), 0x0fffffff, 1); -+ cmdline_add_rd_start(cmdline_buf, PAGE_OFFSET + initrd_base); -+ cmdline_add_rd_size(cmdline_buf, initrd_size); -+ dbgprintf("initrd_base: %lx, initrd_size: %lx\n", initrd_base, initrd_size); ++ result = elf_exec_load(&ehdr, info); ++ ++ if (result) { ++ dbgprintf("%s: elf_exec_load failed\n", __func__); ++ goto exit; + } + -+ /* This is a legacy method for command line passing used currently */ -+ add_buffer(info, cmdline_buf, sizeof(cmdline_buf), -+ sizeof(cmdline_buf), sizeof(void *), -+ cmdline_addr, 0x0fffffff, 1); -+ dbgprintf("command line: %s\n", cmdline_buf); ++ /* for vmlinuz kernel image */ ++ if (kernel_size < MiB(16)) ++ kernel_size = MiB(64); + -+ return 0; ++ /* load additional data */ ++ result = loongarch_load_other_segments(info, kernel_segment + kernel_size); ++ ++exit: ++ free_elf_info(&ehdr); ++ if (result) ++ fprintf(stderr, "kexec: Bad elf image file, load failed.\n"); ++ return result; +} + ++void elf_loongarch_usage(void) ++{ ++ printf( ++" An LoongArch ELF image, little endian.\n" ++" Typically vmlinux or a stripped version of vmlinux.\n\n"); ++} diff --git a/kexec/arch/loongarch/kexec-elf-rel-loongarch.c b/kexec/arch/loongarch/kexec-elf-rel-loongarch.c new file mode 100644 -index 0000000..72307b3 +index 0000000..59f7f5d --- /dev/null +++ b/kexec/arch/loongarch/kexec-elf-rel-loongarch.c -@@ -0,0 +1,43 @@ +@@ -0,0 +1,42 @@ +/* + * kexec-elf-rel-loongarch.c - kexec Elf relocation routines + * -+ * Copyright (C) 2021 Loongson Technology Co., Ltd. ++ * Copyright (C) 2022 Loongson Technology Corporation Limited. + * + * This source code is licensed under the GNU General Public License, + * Version 2. See the file COPYING for more details. @@ -853,15 +716,15 @@ index 0000000..72307b3 + +int machine_verify_elf_rel(struct mem_ehdr *ehdr) +{ -+ if (ehdr->ei_data != ELFDATA2MSB) { ++ if (ehdr->ei_data != ELFDATA2MSB) + return 0; -+ } -+ if (ehdr->ei_class != ELFCLASS32) { ++ ++ if (ehdr->ei_class != ELFCLASS32) + return 0; -+ } -+ if (ehdr->e_machine != EM_LOONGARCH) { ++ ++ if (ehdr->e_machine != EM_LOONGARCH) + return 0; -+ } ++ + return 1; +} + @@ -872,39 +735,147 @@ index 0000000..72307b3 + unsigned long UNUSED(address), + unsigned long UNUSED(value)) +{ -+ switch(r_type) { ++ switch (r_type) { + + default: + die("Unknown rela relocation: %lu\n", r_type); + break; + } -+ return; +} diff --git a/kexec/arch/loongarch/kexec-loongarch.c b/kexec/arch/loongarch/kexec-loongarch.c new file mode 100644 -index 0000000..75fce91 +index 0000000..7e004eb --- /dev/null +++ b/kexec/arch/loongarch/kexec-loongarch.c -@@ -0,0 +1,169 @@ +@@ -0,0 +1,397 @@ +/* + * kexec-loongarch.c - kexec for loongarch + * -+ * Copyright (C) 2021 Loongson Technology Co., Ltd. ++ * Copyright (C) 2022 Loongson Technology Corporation Limited. ++ * Youling Tang + * + * This source code is licensed under the GNU General Public License, + * Version 2. See the file COPYING for more details. + */ + -+#include -+#include ++#include +#include -+#include -+#include +#include -+#include "../../kexec.h" -+#include "../../kexec-syscall.h" ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "kexec.h" +#include "kexec-loongarch.h" -+#include ++#include "crashdump-loongarch.h" ++#include "iomem.h" ++#include "kexec-syscall.h" ++#include "mem_regions.h" ++#include "arch/options.h" ++ ++#define CMDLINE_PREFIX "kexec " ++static char cmdline[COMMAND_LINE_SIZE] = CMDLINE_PREFIX; ++ ++/* Converts unsigned long to ascii string. */ ++static void ultoa(unsigned long i, char *str) ++{ ++ int j = 0, k; ++ char tmp; ++ ++ do { ++ str[j++] = i % 10 + '0'; ++ } while ((i /= 10) > 0); ++ str[j] = '\0'; ++ ++ /* Reverse the string. */ ++ for (j = 0, k = strlen(str) - 1; j < k; j++, k--) { ++ tmp = str[k]; ++ str[k] = str[j]; ++ str[j] = tmp; ++ } ++} ++ ++/* Adds "initrd=start,size" parameters to command line. */ ++static int cmdline_add_initrd(char *cmdline, unsigned long addr, ++ unsigned long size) ++{ ++ int cmdlen, len; ++ char str[50], *ptr; ++ ++ ptr = str; ++ strcpy(str, " initrd="); ++ ptr += strlen(str); ++ ultoa(addr, ptr); ++ strcat(str, ","); ++ ptr = str + strlen(str); ++ ultoa(size, ptr); ++ len = strlen(str); ++ cmdlen = strlen(cmdline) + len; ++ if (cmdlen > (COMMAND_LINE_SIZE - 1)) ++ die("Command line overflow\n"); ++ strcat(cmdline, str); ++ ++ return 0; ++} ++ ++/* Adds the appropriate "mem=size@start" options to command line, indicating the ++ * memory region the new kernel can use to boot into. */ ++static int cmdline_add_mem(char *cmdline, unsigned long addr, ++ unsigned long size) ++{ ++ int cmdlen, len; ++ char str[50], *ptr; ++ ++ addr = addr/1024; ++ size = size/1024; ++ ptr = str; ++ strcpy(str, " mem="); ++ ptr += strlen(str); ++ ultoa(size, ptr); ++ strcat(str, "K@"); ++ ptr = str + strlen(str); ++ ultoa(addr, ptr); ++ strcat(str, "K"); ++ len = strlen(str); ++ cmdlen = strlen(cmdline) + len; ++ if (cmdlen > (COMMAND_LINE_SIZE - 1)) ++ die("Command line overflow\n"); ++ strcat(cmdline, str); ++ ++ return 0; ++} ++ ++/* Adds the "elfcorehdr=size@start" command line parameter to command line. */ ++static int cmdline_add_elfcorehdr(char *cmdline, unsigned long addr, ++ unsigned long size) ++{ ++ int cmdlen, len; ++ char str[50], *ptr; ++ ++ addr = addr/1024; ++ size = size/1024; ++ ptr = str; ++ strcpy(str, " elfcorehdr="); ++ ptr += strlen(str); ++ ultoa(size, ptr); ++ strcat(str, "K@"); ++ ptr = str + strlen(str); ++ ultoa(addr, ptr); ++ strcat(str, "K"); ++ len = strlen(str); ++ cmdlen = strlen(cmdline) + len; ++ if (cmdlen > (COMMAND_LINE_SIZE - 1)) ++ die("Command line overflow\n"); ++ strcat(cmdline, str); ++ ++ return 0; ++} + +/* Return a sorted list of memory ranges. */ +static struct memory_range memory_range[MAX_MEMORY_RANGES]; @@ -926,6 +897,7 @@ index 0000000..75fce91 + fprintf(stderr, "Cannot open %s: %s\n", iomem, strerror(errno)); + return -1; + } ++ + while (fgets(line, sizeof(line), fp) != 0) { + if (memory_ranges >= MAX_MEMORY_RANGES) + break; @@ -934,13 +906,13 @@ index 0000000..75fce91 + continue; + str = line + consumed; + end = end + 1; -+ if (memcmp(str, "System RAM\n", 11) == 0) { ++ if (!strncmp(str, SYSTEM_RAM, strlen(SYSTEM_RAM))) + type = RANGE_RAM; -+ } else if (memcmp(str, "reserved\n", 9) == 0) { ++ else if (!strncmp(str, IOMEM_RESERVED, strlen(IOMEM_RESERVED))) + type = RANGE_RESERVED; -+ } else { ++ else + continue; -+ } ++ + if (memory_ranges > 0 && + memory_range[memory_ranges - 1].end == start && + memory_range[memory_ranges - 1].type == type) { @@ -955,16 +927,42 @@ index 0000000..75fce91 + fclose(fp); + *range = memory_range; + *ranges = memory_ranges; ++ ++ dbgprint_mem_range("MEMORY RANGES:", *range, *ranges); + return 0; +} + +struct file_type file_type[] = { + {"elf-loongarch", elf_loongarch_probe, elf_loongarch_load, elf_loongarch_usage}, ++ {"pei-loongarch", pei_loongarch_probe, pei_loongarch_load, pei_loongarch_usage}, +}; +int file_types = sizeof(file_type) / sizeof(file_type[0]); + ++/* loongarch global varables. */ ++ ++struct loongarch_mem loongarch_mem; ++ ++/** ++ * loongarch_process_image_header - Process the loongarch image header. ++ */ ++ ++int loongarch_process_image_header(const struct loongarch_image_header *h) ++{ ++ ++ if (!loongarch_header_check_pe_sig(h)) ++ return EFAILED; ++ ++ if (h->image_size) { ++ loongarch_mem.text_offset = loongarch_header_text_offset(h); ++ loongarch_mem.image_size = loongarch_header_image_size(h); ++ } ++ ++ return 0; ++} ++ +void arch_usage(void) +{ ++ printf(loongarch_opts_usage); +} + +struct arch_options_t arch_options = { @@ -973,23 +971,30 @@ index 0000000..75fce91 + +int arch_process_options(int argc, char **argv) +{ ++ static const char short_options[] = KEXEC_ARCH_OPT_STR ""; + static const struct option options[] = { + KEXEC_ARCH_OPTIONS + { 0 }, + }; -+ static const char short_options[] = KEXEC_ARCH_OPT_STR; + int opt; ++ char *cmdline = NULL; ++ const char *append = NULL; + + while ((opt = getopt_long(argc, argv, short_options, + options, 0)) != -1) { + switch (opt) { + case OPT_APPEND: -+ arch_options.command_line = optarg; ++ append = optarg; + break; + case OPT_REUSE_CMDLINE: -+ arch_options.command_line = get_command_line(); ++ cmdline = get_command_line(); ++ remove_parameter(cmdline, "kexec"); ++ remove_parameter(cmdline, "initrd"); ++ remove_parameter(cmdline, "rd_start"); ++ remove_parameter(cmdline, "rd_size"); ++ remove_parameter(cmdline, "vfio_iommu_type1.allow_unsafe_interrupts"); + break; -+ case OPT_RAMDISK: ++ case OPT_INITRD: + arch_options.initrd_file = optarg; + break; + default: @@ -997,6 +1002,13 @@ index 0000000..75fce91 + } + } + ++ arch_options.command_line = concat_cmdline(cmdline, append); ++ ++ dbgprintf("%s:%d: command_line: %s\n", __func__, __LINE__, ++ arch_options.command_line); ++ dbgprintf("%s:%d: initrd: %s\n", __func__, __LINE__, ++ arch_options.initrd_file); ++ + return 0; +} + @@ -1005,6 +1017,98 @@ index 0000000..75fce91 + { NULL, 0 }, +}; + ++unsigned long loongarch_locate_kernel_segment(struct kexec_info *info) ++{ ++ unsigned long hole; ++ ++ if (info->kexec_flags & KEXEC_ON_CRASH) { ++ unsigned long hole_end; ++ ++ hole = (crash_reserved_mem[usablemem_rgns.size - 1].start < mem_min ? ++ mem_min : crash_reserved_mem[usablemem_rgns.size - 1].start) + ++ loongarch_mem.text_offset; ++ hole = _ALIGN_UP(hole, MiB(1)); ++ hole_end = hole + loongarch_mem.text_offset + loongarch_mem.image_size; ++ ++ if ((hole_end > mem_max) || ++ (hole_end > crash_reserved_mem[usablemem_rgns.size - 1].end)) { ++ dbgprintf("%s: Crash kernel out of range\n", __func__); ++ hole = ULONG_MAX; ++ } ++ } else { ++ hole = locate_hole(info, ++ loongarch_mem.text_offset + loongarch_mem.image_size, ++ MiB(1), 0, ULONG_MAX, 1); ++ ++ if (hole == ULONG_MAX) ++ dbgprintf("%s: locate_hole failed\n", __func__); ++ } ++ ++ return hole; ++} ++ ++/* ++ * loongarch_load_other_segments - Prepare the initrd and cmdline segments. ++ */ ++ ++int loongarch_load_other_segments(struct kexec_info *info, unsigned long hole_min) ++{ ++ unsigned long initrd_min, hole_max; ++ char *initrd_buf = NULL; ++ unsigned long pagesize = getpagesize(); ++ ++ if (arch_options.command_line) { ++ if (strlen(arch_options.command_line) > ++ sizeof(cmdline) - 1) { ++ fprintf(stderr, ++ "Kernel command line too long for kernel!\n"); ++ return EFAILED; ++ } ++ ++ strncat(cmdline, arch_options.command_line, sizeof(cmdline) - 1); ++ } ++ ++ /* Put the other segments after the image. */ ++ ++ initrd_min = hole_min; ++ if (info->kexec_flags & KEXEC_ON_CRASH) ++ hole_max = crash_reserved_mem[usablemem_rgns.size - 1].end; ++ else ++ hole_max = ULONG_MAX; ++ ++ if (arch_options.initrd_file) { ++ ++ initrd_buf = slurp_decompress_file(arch_options.initrd_file, &initrd_size); ++ ++ initrd_base = add_buffer(info, initrd_buf, initrd_size, ++ initrd_size, sizeof(void *), ++ _ALIGN_UP(initrd_min, ++ pagesize), hole_max, 1); ++ dbgprintf("initrd_base: %lx, initrd_size: %lx\n", initrd_base, initrd_size); ++ ++ cmdline_add_initrd(cmdline, initrd_base, initrd_size); ++ } ++ ++ if (info->kexec_flags & KEXEC_ON_CRASH) { ++ cmdline_add_elfcorehdr(cmdline, elfcorehdr_mem.start, ++ elfcorehdr_mem.end - elfcorehdr_mem.start + 1); ++ ++ cmdline_add_mem(cmdline, crash_reserved_mem[usablemem_rgns.size - 1].start, ++ crash_reserved_mem[usablemem_rgns.size - 1].end - ++ crash_reserved_mem[usablemem_rgns.size - 1].start + 1); ++ } ++ ++ cmdline[sizeof(cmdline) - 1] = 0; ++ add_buffer(info, cmdline, sizeof(cmdline), sizeof(cmdline), ++ sizeof(void *), _ALIGN_UP(hole_min, getpagesize()), ++ 0xffffffff, 1); ++ ++ dbgprintf("%s:%d: command_line: %s\n", __func__, __LINE__, cmdline); ++ ++ return 0; ++ ++} ++ +int arch_compat_trampoline(struct kexec_info *UNUSED(info)) +{ + return 0; @@ -1016,7 +1120,7 @@ index 0000000..75fce91 + +unsigned long virt_to_phys(unsigned long addr) +{ -+ return addr & 0x7fffffff; ++ return addr & ((1ULL << 48) - 1); +} + +/* @@ -1041,75 +1145,226 @@ index 0000000..75fce91 + return add_buffer_phys_virt(info, buf, bufsz, memsz, buf_align, + buf_min, buf_max, buf_end, 1); +} -+ -+int is_crashkernel_mem_reserved(void) -+{ -+ uint64_t start, end; -+ -+ return parse_iomem_single("Crash kernel\n", &start, &end) == 0 ? -+ (start != end) : 0; -+} -+ -+int get_crash_kernel_load_range(uint64_t *start, uint64_t *end) -+{ -+ return parse_iomem_single("Crash kernel\n", start, end); -+} -+ diff --git a/kexec/arch/loongarch/kexec-loongarch.h b/kexec/arch/loongarch/kexec-loongarch.h new file mode 100644 -index 0000000..750608e +index 0000000..5120a26 --- /dev/null +++ b/kexec/arch/loongarch/kexec-loongarch.h -@@ -0,0 +1,34 @@ +@@ -0,0 +1,60 @@ +#ifndef KEXEC_LOONGARCH_H +#define KEXEC_LOONGARCH_H + +#include + ++#include "image-header.h" ++ +#define BOOT_BLOCK_VERSION 17 +#define BOOT_BLOCK_LAST_COMP_VERSION 16 + -+#define MAX_MEMORY_RANGES 64 -+#define MAX_LINE 160 ++#define MAX_MEMORY_RANGES 64 ++#define MAX_LINE 160 + -+#define CORE_TYPE_ELF32 1 -+#define CORE_TYPE_ELF64 2 ++#define CORE_TYPE_ELF64 1 + -+#define COMMAND_LINE_SIZE 512 ++#define COMMAND_LINE_SIZE 512 + -+int elf_loongarch_probe(const char *buf, off_t len); ++#define KiB(x) ((x) * 1024UL) ++#define MiB(x) (KiB(x) * 1024UL) ++ ++int elf_loongarch_probe(const char *kernel_buf, off_t kernel_size); +int elf_loongarch_load(int argc, char **argv, const char *buf, off_t len, + struct kexec_info *info); +void elf_loongarch_usage(void); -+int is_crashkernel_mem_reserved(void); -+int get_crash_kernel_load_range(uint64_t *start, uint64_t *end); ++ ++int pei_loongarch_probe(const char *buf, off_t len); ++int pei_loongarch_load(int argc, char **argv, const char *buf, off_t len, ++ struct kexec_info *info); ++void pei_loongarch_usage(void); ++ ++int loongarch_process_image_header(const struct loongarch_image_header *h); ++ ++unsigned long loongarch_locate_kernel_segment(struct kexec_info *info); ++int loongarch_load_other_segments(struct kexec_info *info, ++ unsigned long hole_min); + +struct arch_options_t { + char *command_line; + char *initrd_file; ++ char *dtb; + int core_header_type; +}; + ++/** ++ * struct loongarch_mem - Memory layout info. ++ */ ++ ++struct loongarch_mem { ++ uint64_t phys_offset; ++ uint64_t text_offset; ++ uint64_t image_size; ++}; ++ ++extern struct loongarch_mem loongarch_mem; ++ +extern struct memory_ranges usablemem_rgns; +extern struct arch_options_t arch_options; +extern off_t initrd_base, initrd_size; + +#endif /* KEXEC_LOONGARCH_H */ +diff --git a/kexec/arch/loongarch/kexec-pei-loongarch.c b/kexec/arch/loongarch/kexec-pei-loongarch.c +new file mode 100644 +index 0000000..1a11103 +--- /dev/null ++++ b/kexec/arch/loongarch/kexec-pei-loongarch.c +@@ -0,0 +1,124 @@ ++/* ++ * LoongArch kexec PE format binary image support. ++ * ++ * Copyright (C) 2022 Loongson Technology Corporation Limited. ++ * Youling Tang ++ * ++ * derived from kexec-image-arm64.c ++ * ++ * This source code is licensed under the GNU General Public License, ++ * Version 2. See the file COPYING for more details. ++ */ ++ ++#define _GNU_SOURCE ++ ++#include ++#include ++#include ++ ++#include "kexec.h" ++#include "kexec-elf.h" ++#include "image-header.h" ++#include "kexec-syscall.h" ++#include "crashdump-loongarch.h" ++#include "kexec-loongarch.h" ++#include "arch/options.h" ++ ++int pei_loongarch_probe(const char *kernel_buf, off_t kernel_size) ++{ ++ const struct loongarch_image_header *h; ++ ++ if (kernel_size < sizeof(struct loongarch_image_header)) { ++ dbgprintf("%s: No loongarch image header.\n", __func__); ++ return -1; ++ } ++ ++ h = (const struct loongarch_image_header *)(kernel_buf); ++ ++ if (!loongarch_header_check_pe_sig(h)) { ++ dbgprintf("%s: Bad loongarch PE image header.\n", __func__); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++int pei_loongarch_load(int argc, char **argv, const char *buf, ++ off_t len, struct kexec_info *info) ++{ ++ int result; ++ unsigned long hole_min = 0; ++ unsigned long kernel_segment, kernel_entry; ++ const struct loongarch_image_header *header; ++ ++ header = (const struct loongarch_image_header *)(buf); ++ ++ if (loongarch_process_image_header(header)) ++ return EFAILED; ++ ++ kernel_segment = loongarch_locate_kernel_segment(info); ++ ++ if (kernel_segment == ULONG_MAX) { ++ dbgprintf("%s: Kernel segment is not allocated\n", __func__); ++ result = EFAILED; ++ goto exit; ++ } ++ ++ kernel_entry = virt_to_phys(loongarch_header_kernel_entry(header)); ++ ++ if (info->kexec_flags & KEXEC_ON_CRASH) ++ /* ++ * offset addresses in order to load vmlinux.efi into ++ * crash kernel's memory. ++ */ ++ kernel_entry += crash_reserved_mem[usablemem_rgns.size - 1].start; ++ ++ dbgprintf("%s: kernel_segment: %016lx\n", __func__, kernel_segment); ++ dbgprintf("%s: kernel_entry: %016lx\n", __func__, kernel_entry); ++ dbgprintf("%s: image_size: %016lx\n", __func__, ++ loongarch_mem.image_size); ++ dbgprintf("%s: text_offset: %016lx\n", __func__, ++ loongarch_mem.text_offset); ++ dbgprintf("%s: phys_offset: %016lx\n", __func__, ++ loongarch_mem.phys_offset); ++ dbgprintf("%s: PE format: %s\n", __func__, ++ (loongarch_header_check_pe_sig(header) ? "yes" : "no")); ++ ++ /* Get kernel entry point */ ++ info->entry = (void *)kernel_entry; ++ ++ hole_min = kernel_segment + loongarch_mem.image_size; ++ ++ /* Create and initialize elf core header segment */ ++ if (info->kexec_flags & KEXEC_ON_CRASH) { ++ result = load_crashdump_segments(info); ++ if (result) { ++ dbgprintf("%s: Creating eflcorehdr failed.\n", ++ __func__); ++ goto exit; ++ } ++ } ++ ++ /* Load the kernel */ ++ add_segment(info, buf, len, kernel_segment, loongarch_mem.image_size); ++ ++ /* Prepare and load dtb and initrd data */ ++ result = loongarch_load_other_segments(info, hole_min); ++ if (result) { ++ fprintf(stderr, "kexec: Load dtb and initrd segments failed.\n"); ++ goto exit; ++ } ++ ++exit: ++ if (result) ++ fprintf(stderr, "kexec: load failed.\n"); ++ ++ return result; ++} ++ ++void pei_loongarch_usage(void) ++{ ++ printf( ++" An LoongArch PE format binary image, uncompressed, little endian.\n" ++" Typically a vmlinux.efi file.\n\n"); ++} diff --git a/kexec/kexec-syscall.h b/kexec/kexec-syscall.h -index 993f7ec..8ef54d6 100644 +index dc71dc9..45992f4 100644 --- a/kexec/kexec-syscall.h +++ b/kexec/kexec-syscall.h -@@ -51,6 +51,9 @@ - #ifdef __alpha__ - #define __NR_kexec_load 448 +@@ -39,6 +39,9 @@ + #ifdef __s390__ + #define __NR_kexec_load 277 #endif +#ifdef __loongarch__ +#define __NR_kexec_load 104 +#endif - #ifndef __NR_kexec_load - #error Unknown processor architecture. Needs a kexec_load syscall number. + #if defined(__arm__) || defined(__arm64__) + #define __NR_kexec_load __NR_SYSCALL_BASE + 347 #endif -@@ -136,6 +139,7 @@ static inline long kexec_file_load(int kernel_fd, int initrd_fd, +@@ -59,7 +62,7 @@ + #endif + #endif /*ifndef __NR_kexec_load*/ + +-#ifdef __arm__ ++#if defined(__arm__) || defined(__loongarch__) + #undef __NR_kexec_file_load + #endif + +@@ -139,6 +142,7 @@ static inline long kexec_file_load(int kernel_fd, int initrd_fd, #define KEXEC_ARCH_MIPS_LE (10 << 16) #define KEXEC_ARCH_MIPS ( 8 << 16) #define KEXEC_ARCH_CRIS (76 << 16) @@ -1117,7 +1372,7 @@ index 993f7ec..8ef54d6 100644 #define KEXEC_MAX_SEGMENTS 16 -@@ -179,5 +183,8 @@ static inline long kexec_file_load(int kernel_fd, int initrd_fd, +@@ -182,5 +186,8 @@ static inline long kexec_file_load(int kernel_fd, int initrd_fd, #if defined(__arm64__) #define KEXEC_ARCH_NATIVE KEXEC_ARCH_ARM64 #endif @@ -1126,8 +1381,33 @@ index 993f7ec..8ef54d6 100644 +#endif #endif /* KEXEC_SYSCALL_H */ +diff --git a/kexec/kexec.c b/kexec/kexec.c +index 5b8beca..cf90e5d 100644 +--- a/kexec/kexec.c ++++ b/kexec/kexec.c +@@ -1081,7 +1081,7 @@ static int k_status(unsigned long kexec_flags) + /* + * Remove parameter from a kernel command line. Helper function by get_command_line(). + */ +-static void remove_parameter(char *line, const char *param_name) ++void remove_parameter(char *line, const char *param_name) + { + char *start, *end; + +diff --git a/kexec/kexec.h b/kexec/kexec.h +index 9cbc77f..5500627 100644 +--- a/kexec/kexec.h ++++ b/kexec/kexec.h +@@ -306,6 +306,7 @@ int arch_compat_trampoline(struct kexec_info *info); + void arch_update_purgatory(struct kexec_info *info); + int is_crashkernel_mem_reserved(void); + int get_crash_kernel_load_range(uint64_t *start, uint64_t *end); ++void remove_parameter(char *line, const char *param_name); + char *get_command_line(void); + + int kexec_iomem_for_each_line(char *match, diff --git a/purgatory/Makefile b/purgatory/Makefile -index 2dd6c47..f24cae0 100644 +index 1955748..1850999 100644 --- a/purgatory/Makefile +++ b/purgatory/Makefile @@ -28,6 +28,7 @@ include $(srcdir)/purgatory/arch/ppc64/Makefile @@ -1135,9 +1415,9 @@ index 2dd6c47..f24cae0 100644 include $(srcdir)/purgatory/arch/sh/Makefile include $(srcdir)/purgatory/arch/x86_64/Makefile +include $(srcdir)/purgatory/arch/loongarch/Makefile + include $(srcdir)/purgatory/arch/sw_64/Makefile PURGATORY_SRCS+=$($(ARCH)_PURGATORY_SRCS) - diff --git a/purgatory/arch/loongarch/Makefile b/purgatory/arch/loongarch/Makefile new file mode 100644 index 0000000..b0c47b2 @@ -1193,5 +1473,5 @@ index 0000000..cd1ab97 + +#endif /* PURGATORY_LOONGARCH_H */ -- -2.27.0 +2.33.0 diff --git a/kexec-tools.spec b/kexec-tools.spec index b930891..b443126 100644 --- a/kexec-tools.spec +++ b/kexec-tools.spec @@ -4,7 +4,7 @@ Name: kexec-tools Version: 2.0.23 -Release: 10 +Release: 11 License: GPLv2 Summary: The kexec/kdump userspace component URL: https://www.kernel.org/ @@ -78,12 +78,10 @@ Patch0006: arm64-make-phys_offset-signed.patch Patch0007: arm64-crashdump-unify-routine-to-get-page_offset.patch Patch0008: arm64-read-VA_BITS-from-kcore-for-52-bits-VA-kernel.patch Patch0009: arm64-fix-PAGE_OFFSET-calc-for-flipped-mm.patch -%ifarch loongarch64 -Patch0010: fix-add-64-bit-loongArch-support-1.patch -Patch0011: fix-add-64-bit-loongArch-support-2.patch -%endif -Patch00012: sw_64.patch -Patch00013: makedumpfile-1.7.0-sw.patch +Patch00010: sw_64.patch +Patch00011: makedumpfile-1.7.0-sw.patch +Patch00012: kexec-add-loongarch64-support.patch +Patch00013: add-loongarch64-support-for-makedumpfile.patch %description kexec-tools provides /sbin/kexec binary that facilitates a new kernel to boot using the kernel's kexec feature either on a @@ -118,15 +116,11 @@ tar -z -x -v -f %{SOURCE19} %patch0008 -p1 %patch0009 -p1 -%ifarch loongarch64 %patch0010 -p1 %patch0011 -p1 -%endif -%ifarch sw_64 %patch00012 -p1 %patch00013 -p1 -%endif %build @@ -312,6 +306,9 @@ done %endif %changelog +* Tue Mar 21 2023 Youling Tang - 2.0.23-11 +- Reimplement loongarch64 support. + * Mon Dec 12 2022 guojiancheng - 2.0.23-10 - Add sw support -- Gitee