From 0542ebd7069b1cee7d027fa7640b464fdb0f7502 Mon Sep 17 00:00:00 2001 From: Renbo Date: Fri, 30 Aug 2024 15:18:16 +0800 Subject: [PATCH 01/11] update to kexec-tools-2.0.26-14.1.src.rpm Signed-off-by: Renbo --- ...ls-2.0.25-Add-pstore-segment-support.patch | 216 --- dist | 2 +- dracut-early-kdump.sh | 5 - dracut-module-setup.sh | 22 + gen-kdump-conf.sh | 4 - kdump-lib.sh | 24 +- kdump.sysconfig.aarch64 | 2 +- kdump.sysconfig.loongarch64 | 37 - kdump.sysconfig.s390x | 2 +- kdump.sysconfig.x86_64 | 2 +- kdumpctl | 106 +- kdumpctl.loongarch64 | 1409 ----------------- kexec-tools.spec | 89 +- ...some-functional-issues-and-compilati.patch | 200 --- mkdumprd | 2 +- supported-kdump-targets.txt | 4 +- 16 files changed, 109 insertions(+), 2017 deletions(-) delete mode 100644 1000-kexec-tools-2.0.25-Add-pstore-segment-support.patch delete mode 100644 kdump.sysconfig.loongarch64 delete mode 100755 kdumpctl.loongarch64 delete mode 100644 loongarch64-fix-some-functional-issues-and-compilati.patch diff --git a/1000-kexec-tools-2.0.25-Add-pstore-segment-support.patch b/1000-kexec-tools-2.0.25-Add-pstore-segment-support.patch deleted file mode 100644 index 3d60813..0000000 --- a/1000-kexec-tools-2.0.25-Add-pstore-segment-support.patch +++ /dev/null @@ -1,216 +0,0 @@ -From 40c03992bc470e29d0cc33e6f290916434092d76 Mon Sep 17 00:00:00 2001 -From: Yuanhe Shu -Date: Mon, 18 Sep 2023 19:48:50 +0800 -Subject: [PATCH] Add pstore segment support - -Add pstore segment thus it is able to record log of kdump process - -Signed-off-by: Yuanhe Shu ---- - kexec/arch/arm64/crashdump-arm64.c | 5 ++ - kexec/arch/i386/crashdump-x86.c | 12 ++++- - kexec/kexec.c | 80 ++++++++++++++++++++++++++++++ - kexec/kexec.h | 5 ++ - 4 files changed, 100 insertions(+), 2 deletions(-) - -diff --git a/kexec/arch/arm64/crashdump-arm64.c b/kexec/arch/arm64/crashdump-arm64.c -index 3098315..6aa954c 100644 ---- a/kexec/arch/arm64/crashdump-arm64.c -+++ b/kexec/arch/arm64/crashdump-arm64.c -@@ -125,6 +125,11 @@ static int crash_get_memory_ranges(void) - if (!usablemem_rgns.size) - return -EINVAL; - -+ usablemem_rgns.ranges[usablemem_rgns.size - 1].end -= PSTORE_SIZE; -+ -+ dbgprintf("Created pstore segment at 0x%lx\n", -+ usablemem_rgns.ranges[usablemem_rgns.size - 1].end); -+ - dbgprint_mem_range("Reserved memory range", - usablemem_rgns.ranges, usablemem_rgns.size); - -diff --git a/kexec/arch/i386/crashdump-x86.c b/kexec/arch/i386/crashdump-x86.c -index df1f24c..3614007 100644 ---- a/kexec/arch/i386/crashdump-x86.c -+++ b/kexec/arch/i386/crashdump-x86.c -@@ -823,7 +823,7 @@ int load_crashdump_segments(struct kexec_info *info, char* mod_cmdline, - unsigned long max_addr, unsigned long min_base) - { - void *tmp; -- unsigned long sz, bufsz, memsz, elfcorehdr; -+ unsigned long sz, bufsz, memsz, elfcorehdr, pstore_sz, pstore_start; - int nr_ranges = 0, nr_memmap = 0, align = 1024, i; - struct memory_range *mem_range, *memmap_p; - struct crash_elf_info elf_info; -@@ -923,6 +923,14 @@ int load_crashdump_segments(struct kexec_info *info, char* mod_cmdline, - } - } - -+ pstore_sz = _ALIGN(PSTORE_SIZE, align); -+ pstore_start = (unsigned long)crash_reserved_mem[crash_reserved_mem_nr - 1].start; -+ dbgprintf("Created pstore segment at 0x%lx\n", pstore_start); -+ if (delete_memmap(memmap_p, &nr_memmap, pstore_start, pstore_sz) < 0) { -+ free(memmap_p); -+ return EFAILED; -+ } -+ - /* Create elf header segment and store crash image data. */ - if (arch_options.core_header_type == CORE_TYPE_ELF64) { - if (crash_create_elf64_headers(info, &elf_info, mem_range, -@@ -1004,7 +1012,7 @@ int get_crash_kernel_load_range(uint64_t *start, uint64_t *end) - if (!crash_reserved_mem_nr) - return -1; - -- *start = crash_reserved_mem[crash_reserved_mem_nr - 1].start; -+ *start = crash_reserved_mem[crash_reserved_mem_nr - 1].start + PSTORE_SIZE; - *end = crash_reserved_mem[crash_reserved_mem_nr - 1].end; - - return 0; -diff --git a/kexec/kexec.c b/kexec/kexec.c -index 829a6ea..c1cb00e 100644 ---- a/kexec/kexec.c -+++ b/kexec/kexec.c -@@ -40,6 +40,7 @@ - #endif - #include - #include -+#include - - #include "config.h" - -@@ -638,6 +639,79 @@ char *slurp_decompress_file(const char *filename, off_t *r_size) - return kernel_buf; - } - -+static int readlog(unsigned long long paddrbase) -+{ -+ const char kcore[] = "/proc/kcore"; -+ Elf64_Ehdr *elf64; -+ Elf64_Phdr *load64, *notes64, *lp64; -+ char eheader[MAX_KCORE_ELF_HEADER_SIZE], console_buf[1000000], tty_buf[100000]; -+ int fd, i, segments; -+ unsigned long long console_offset, tty_offset, console_vaddr, tty_vaddr, -+ console_paddr, tty_paddr, page_offset; -+ const unsigned long long pud_mask = ~((1 << 30) - 1); -+ -+ #ifdef __x86_64__ -+ page_offset = 0; -+ #endif -+ #ifdef __aarch64__ -+ page_offset = 0xfffeffffc0000000; -+ #endif -+ console_paddr = paddrbase + 0xe00c; -+ tty_paddr = paddrbase + 0x5000c; -+ -+ if ((fd = open(kcore, O_RDONLY)) < 0) { -+ fprintf(stderr, "Cannot open %s: %s\n", kcore, strerror(errno)); -+ return -1; -+ } -+ -+ if (read(fd, eheader, MAX_KCORE_ELF_HEADER_SIZE) != MAX_KCORE_ELF_HEADER_SIZE) { -+ fprintf(stderr, "Cannot read %s: %s\n", kcore, strerror(errno)); -+ return -1; -+ } -+ -+ elf64 = (Elf64_Ehdr *)&eheader[0]; -+ -+ notes64 = (Elf64_Phdr *)&eheader[elf64->e_phoff]; -+ load64 = notes64 + 1; -+ -+ segments = elf64->e_phnum - 1; -+ -+ if (page_offset == 0) { -+ for ( i = 0; i < segments; i++) { -+ lp64 = load64 + i; -+ if (lp64->p_type == PT_LOAD) -+ if ((page_offset == 0) | page_offset > (lp64->p_vaddr & pud_mask)) -+ page_offset = lp64->p_vaddr & pud_mask; -+ } -+ } -+ console_vaddr = console_paddr + page_offset; -+ tty_vaddr = tty_paddr + page_offset; -+ -+ for ( i = 0; i < segments; i++) { -+ lp64 = load64 + i; -+ if ((console_vaddr >= lp64->p_vaddr) && (console_vaddr < (lp64->p_vaddr + lp64->p_memsz))) { -+ console_offset = console_vaddr - lp64->p_vaddr + lp64->p_offset; -+ tty_offset = tty_vaddr - lp64->p_vaddr + lp64->p_offset; -+ break; -+ } -+ } -+ -+ memset(console_buf, 0, sizeof(console_buf)); -+ memset(tty_buf, 0, sizeof(tty_buf)); -+ -+ off_t c_offset = lseek(fd, console_offset, SEEK_SET); -+ size_t c_size = read(fd, console_buf, 1000000); -+ -+ off_t t_offset = lseek(fd, tty_offset, SEEK_SET); -+ size_t t_size = read(fd, tty_buf, 100000); -+ -+ printf("console log: \n%s\nttylog:\n%s\n", console_buf, tty_buf); -+ -+ close(fd); -+ -+ return 0; -+} -+ - static void update_purgatory(struct kexec_info *info) - { - static const uint8_t null_buf[256]; -@@ -1016,6 +1090,7 @@ void usage(void) - "\n" - " -h, --help Print this help.\n" - " -v, --version Print the version of kexec.\n" -+ " -r, --read Print the logs of kdump process.\n" - " -f, --force Force an immediate kexec,\n" - " don't call shutdown.\n" - " -i, --no-checks Fast reboot, no memory integrity checks.\n" -@@ -1417,6 +1492,7 @@ int main(int argc, char *argv[]) - int opt; - int result = 0; - int fileind; -+ unsigned long long phy_addr; - static const struct option options[] = { - KEXEC_ALL_OPTIONS - { 0, 0, 0, 0}, -@@ -1439,6 +1515,10 @@ int main(int argc, char *argv[]) - case OPT_VERSION: - version(); - return 0; -+ case OPT_READ: -+ phy_addr = strtoul(optarg, &endptr, 0); -+ readlog(phy_addr); -+ return 0; - case OPT_DEBUG: - kexec_debug = 1; - break; -diff --git a/kexec/kexec.h b/kexec/kexec.h -index 8a05644..899f01b 100644 ---- a/kexec/kexec.h -+++ b/kexec/kexec.h -@@ -232,9 +232,11 @@ extern int file_types; - #define OPT_LOAD_LIVE_UPDATE 263 - #define OPT_EXEC_LIVE_UPDATE 264 - #define OPT_MAX 265 -+#define OPT_READ 266 - #define KEXEC_OPTIONS \ - { "help", 0, 0, OPT_HELP }, \ - { "version", 0, 0, OPT_VERSION }, \ -+ { "read", 1, 0, OPT_READ }, \ - { "force", 0, 0, OPT_FORCE }, \ - { "no-checks", 0, 0, OPT_NOCHECKS }, \ - { "no-ifdown", 0, 0, OPT_NOIFDOWN }, \ -@@ -318,6 +320,9 @@ const char * proc_iomem(void); - - #define MAX_LINE 160 - -+#define PSTORE_SIZE 0x60000 -+#define MAX_KCORE_ELF_HEADER_SIZE (32768) -+ - char *concat_cmdline(const char *base, const char *append); - void cmdline_add_liveupdate(char **base); - --- -2.32.0 (Apple Git-132) - diff --git a/dist b/dist index 9c0e36e..1fe92cf 100644 --- a/dist +++ b/dist @@ -1 +1 @@ -an8 +an8_10 diff --git a/dracut-early-kdump.sh b/dracut-early-kdump.sh index 129841e..0124564 100755 --- a/dracut-early-kdump.sh +++ b/dracut-early-kdump.sh @@ -49,11 +49,6 @@ early_kdump_load() EARLY_KEXEC_ARGS=$(prepare_kexec_args "${KEXEC_ARGS}") - if is_secure_boot_enforced; then - dinfo "Secure Boot is enabled. Using kexec file based syscall." - EARLY_KEXEC_ARGS="$EARLY_KEXEC_ARGS -s" - fi - # Here, only output the messages, but do not save these messages # to a file because the target disk may not be mounted yet, the # earlykdump is too early. diff --git a/dracut-module-setup.sh b/dracut-module-setup.sh index 1fa3011..97be76f 100755 --- a/dracut-module-setup.sh +++ b/dracut-module-setup.sh @@ -363,6 +363,14 @@ _get_nic_driver() { ethtool -i "$1" | sed -n -E "s/driver: (.*)/\1/p" } +_get_hpyerv_physical_driver() { + local _physical_nic + + _physical_nic=$(find /sys/class/net/"$1"/ -name 'lower_*' | sed -En "s/\/.*lower_(.*)/\1/p") + [[ -n $_physical_nic ]] || return + _get_nic_driver "$_physical_nic" +} + kdump_install_nic_driver() { local _netif _driver _drivers @@ -382,6 +390,11 @@ kdump_install_nic_driver() { elif [[ $_driver == "team" ]]; then # install the team mode drivers like team_mode_roundrobin.ko as well _driver='=drivers/net/team' + elif [[ $_driver == "hv_netvsc" ]]; then + # A Hyper-V VM may have accelerated networking + # https://learn.microsoft.com/en-us/azure/virtual-network/accelerated-networking-overview + # Install the driver of physical NIC as well + _drivers+=("$(_get_hpyerv_physical_driver "$_netif")") fi _drivers+=("$_driver") @@ -1127,6 +1140,15 @@ install() { 's/\(^[[:space:]]*reserved_memory[[:space:]]*=\)[[:space:]]*[[:digit:]]*/\1 1024/' \ ${initdir}/etc/lvm/lvm.conf &>/dev/null + # Skip initrd-cleanup.service and initrd-parse-etc.service becasue we don't + # need to switch root. Instead of removing them, we use ConditionPathExists + # to check if /proc/vmcore exists to determine if we are in kdump. + sed -i '/\[Unit\]/a ConditionPathExists=!\/proc\/vmcore' \ + "${initdir}/${systemdsystemunitdir}/initrd-cleanup.service" &> /dev/null + + sed -i '/\[Unit\]/a ConditionPathExists=!\/proc\/vmcore' \ + "${initdir}/${systemdsystemunitdir}/initrd-parse-etc.service" &> /dev/null + # Save more memory by dropping switch root capability dracut_no_switch_root } diff --git a/gen-kdump-conf.sh b/gen-kdump-conf.sh index 467a055..4bda9e8 100755 --- a/gen-kdump-conf.sh +++ b/gen-kdump-conf.sh @@ -213,10 +213,6 @@ s390x) update_param core_collector \ "makedumpfile -c --message-level 7 -d 31" ;; -loongarch64) - update_param core_collector \ - "makedumpfile -c --message-level 7 -d 31" - ;; x86_64) ;; *) diff --git a/kdump-lib.sh b/kdump-lib.sh index 4abef85..8dd63a6 100755 --- a/kdump-lib.sh +++ b/kdump-lib.sh @@ -529,11 +529,24 @@ get_dracut_args_target() echo $1 | grep "\-\-mount" | sed "s/.*--mount .\(.*\)/\1/" | cut -d' ' -f1 } +get_reserved_mem_size() +{ + local reserved_mem_size=0 + + if is_fadump_capable; then + reserved_mem_size=$(< /sys/kernel/fadump/mem_reserved) + else + reserved_mem_size=$(< /sys/kernel/kexec_crash_size) + fi + + echo "$reserved_mem_size" +} + check_crash_mem_reserved() { local mem_reserved - mem_reserved=$(cat /sys/kernel/kexec_crash_size) + mem_reserved=$(get_reserved_mem_size) if [ $mem_reserved -eq 0 ]; then derror "No memory reserved for crash kernel" return 1 @@ -700,6 +713,15 @@ prepare_kexec_args() fi fi fi + + # For secureboot enabled machines, use new kexec file based syscall. + # Old syscall will always fail as it does not have capability to do + # kernel signature verification. + if is_secure_boot_enforced; then + dinfo "Secure Boot is enabled. Using kexec file based syscall." + kexec_args="$kexec_args -s" + fi + echo $kexec_args } diff --git a/kdump.sysconfig.aarch64 b/kdump.sysconfig.aarch64 index 938c210..d443b1f 100644 --- a/kdump.sysconfig.aarch64 +++ b/kdump.sysconfig.aarch64 @@ -28,7 +28,7 @@ KDUMP_COMMANDLINE_APPEND="irqpoll nr_cpus=1 reset_devices cgroup_disable=memory # # Example: # KEXEC_ARGS="--elf32-core-headers" -KEXEC_ARGS="" +KEXEC_ARGS="-s" #Where to find the boot image #KDUMP_BOOTDIR="/boot" diff --git a/kdump.sysconfig.loongarch64 b/kdump.sysconfig.loongarch64 deleted file mode 100644 index e2a2d7b..0000000 --- a/kdump.sysconfig.loongarch64 +++ /dev/null @@ -1,37 +0,0 @@ -# Kernel Version string for the -kdump kernel, such as 2.6.13-1544.FC5kdump -# If no version is specified, then the init script will try to find a -# kdump kernel with the same version number as the running kernel. -KDUMP_KERNELVER="" - -# The kdump commandline is the command line that needs to be passed off to -# the kdump kernel. This will likely match the contents of the grub kernel -# line. For example: -# KDUMP_COMMANDLINE="ro root=LABEL=/" -# Dracut depends on proper root= options, so please make sure that appropriate -# root= options are copied from /proc/cmdline. In general it is best to append -# command line options using "KDUMP_COMMANDLINE_APPEND=". -# If a command line is not specified, the default will be taken from -# /proc/cmdline -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" - -# This variable lets us append arguments to the current kdump commandline -# after processed by KDUMP_COMMANDLINE_REMOVE -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 -# -# Example: -# KEXEC_ARGS="--elf32-core-headers" -KEXEC_ARGS="" - -#Where to find the boot image -#KDUMP_BOOTDIR="/boot" - -#What is the image type used for kdump -KDUMP_IMG="vmlinuz" diff --git a/kdump.sysconfig.s390x b/kdump.sysconfig.s390x index 856a843..8e80963 100644 --- a/kdump.sysconfig.s390x +++ b/kdump.sysconfig.s390x @@ -31,7 +31,7 @@ MKDUMPRD_ARGS="" # # Example: # KEXEC_ARGS="--elf32-core-headers" -KEXEC_ARGS="" +KEXEC_ARGS="-s" #Where to find the boot image #KDUMP_BOOTDIR="/boot" diff --git a/kdump.sysconfig.x86_64 b/kdump.sysconfig.x86_64 index 1790f1b..1b4fad7 100644 --- a/kdump.sysconfig.x86_64 +++ b/kdump.sysconfig.x86_64 @@ -28,7 +28,7 @@ KDUMP_COMMANDLINE_APPEND="irqpoll nr_cpus=1 reset_devices cgroup_disable=memory # # Example: # KEXEC_ARGS="--elf32-core-headers" -KEXEC_ARGS="" +KEXEC_ARGS="-s" #Where to find the boot image #KDUMP_BOOTDIR="/boot" diff --git a/kdumpctl b/kdumpctl index 3d0824c..b5bef85 100755 --- a/kdumpctl +++ b/kdumpctl @@ -27,7 +27,6 @@ standard_kexec_args="-d -p" # Some default values in case /etc/sysconfig/kdump doesn't include KDUMP_COMMANDLINE_REMOVE="hugepages hugepagesz slub_debug" -PSTORE_COMMANDLINE_TMP="ramoops.mem_address=0xtmp ramoops.mem_size=0x60000 ramoops.console_size=0x48000 ramoops.ttyprobe_size=0x10000 ramoops.ecc=0 ramoops.dump_oops=0" if [ -f /etc/sysconfig/kdump ]; then . /etc/sysconfig/kdump @@ -539,28 +538,22 @@ check_fs_modified() check_system_modified() { local ret + local CONF_ERROR=2 + local CONF_MODIFY=1 + local CONF_NO_MODIFY=0 + local conf_status=$CONF_NO_MODIFY [[ -f $TARGET_INITRD ]] || return 1 - check_files_modified - ret=$? - if [ $ret -ne 0 ]; then - return $ret - fi - - check_fs_modified - ret=$? - if [ $ret -ne 0 ]; then - return $ret - fi - - check_drivers_modified - ret=$? - if [ $ret -ne 0 ]; then - return $ret - fi + for _func in check_files_modified check_fs_modified check_drivers_modified; do + $_func + ret=$? + # return immediately if an error occurred. + [[ $ret -eq "$CONF_ERROR" ]] && return "$ret" + [[ $ret -eq "$CONF_MODIFY" ]] && { conf_status="$CONF_MODIFY"; } + done - return 0 + return $conf_status } check_rebuild() @@ -654,20 +647,7 @@ function load_kdump_kernel_key() return fi - KDUMP_KEY_ID=$(cat /usr/share/doc/kernel-keys/$KDUMP_KERNELVER/kernel-signing-ppc.cer | - keyctl padd asymmetric kernelkey-$RANDOM %:.ima) -} - -# remove a previously loaded key. There's no real security implication -# to leaving it around, we choose to do this because it makes it easier -# to be idempotent and so as to reduce the potential for confusion. -function remove_kdump_kernel_key() -{ - if [ -z "$KDUMP_KEY_ID" ]; then - return - fi - - keyctl unlink $KDUMP_KEY_ID %:.ima + keyctl padd asymmetric "" %:.ima < "/usr/share/doc/kernel-keys/$KDUMP_KERNELVER/kernel-signing-ppc.cer" } # Load the kdump kernel specified in /etc/sysconfig/kdump @@ -676,39 +656,12 @@ function remove_kdump_kernel_key() load_kdump() { local ret - local PSTORE_START - local OLD_START KEXEC_ARGS=$(prepare_kexec_args "${KEXEC_ARGS}") KDUMP_COMMANDLINE=$(prepare_cmdline "${KDUMP_COMMANDLINE}" "${KDUMP_COMMANDLINE_REMOVE}" "${KDUMP_COMMANDLINE_APPEND}") - # For secureboot enabled machines, use new kexec file based syscall. - # Old syscall will always fail as it does not have capability to - # to kernel signature verification. - if is_secure_boot_enforced; then - dinfo "Secure Boot is enabled. Using kexec file based syscall." - KEXEC_ARGS="$KEXEC_ARGS -s" - load_kdump_kernel_key - fi - ddebug "$KEXEC $KEXEC_ARGS $standard_kexec_args --command-line=$KDUMP_COMMANDLINE --initrd=$TARGET_INITRD $KDUMP_KERNEL" - if [[ $(uname -m) == x86_64 ]]; then - PSTORE_START="0x$(grep Crash /proc/iomem | tail -n 1 | cut -d'-' -f1 | sed -e 's/^[[:space:]]*//')" - else - PSTORE_START="0x$(printf "%x" $(( "0x$(grep Crash /proc/iomem | tail -n 1 | cut -d'-' -f2 | cut -d' ' -f1)" - 0x60000 + 1 )))" - fi - - if [[ $KDUMP_COMMANDLINE == *"ramoops.mem_address"* ]]; then - OLD_START=$(echo $KDUMP_COMMANDLINE | awk -F "ramoops.mem_address=" '{print $2}') - if [[ $OLD_START != $PSTORE_START ]]; then - KDUMP_COMMANDLINE=${KDUMP_COMMANDLINE/"mem_address=${OLD_START}"/"mem_address=${PSTORE_START}"} - fi - else - PSTORE_COMMANDLINE_TMP=${PSTORE_COMMANDLINE_TMP/"0xtmp"/"${PSTORE_START}"} - KDUMP_COMMANDLINE="$KDUMP_COMMANDLINE $PSTORE_COMMANDLINE_TMP" - fi - # The '12' represents an intermediate temporary file descriptor # to store the standard error file descriptor '2', and later # restore the error file descriptor with the file descriptor '12' @@ -727,9 +680,7 @@ load_kdump() set +x exec 2>&12 12>&- - remove_kdump_kernel_key - - if [ $ret == 0 ]; then + if [[ $ret == 0 ]]; then dinfo "kexec: loaded kdump kernel" return 0 else @@ -867,7 +818,7 @@ propagate_ssh_key() show_reserved_mem() { - local mem=$(cat /sys/kernel/kexec_crash_size) + local mem=$(get_reserved_mem_size) local mem_mb=$(expr $mem / 1024 / 1024) dinfo "Reserved "$mem_mb"MB memory for crash kernel" @@ -1028,7 +979,13 @@ start_fadump() start_dump() { - if [ $DEFAULT_DUMP_MODE == "fadump" ]; then + # On secure boot enabled Power systems, load kernel signing key on .ima for signature + # verification using kexec file based syscall. + if [[ "$(uname -m)" == ppc64le ]] && is_secure_boot_enforced; then + load_kdump_kernel_key + fi + + if [[ $DEFAULT_DUMP_MODE == "fadump" ]]; then start_fadump else load_kdump @@ -1289,7 +1246,7 @@ do_estimate() { # The default value when using crashkernel=auto baseline_size=$((baseline * size_mb)) # Current reserved crashkernel size - reserved_size=$(cat /sys/kernel/kexec_crash_size) + reserved_size=$(get_reserved_mem_size) # A pre-estimated value for userspace usage and kernel # runtime allocation, 64M should good for most cases runtime_size=$((64 * size_mb)) @@ -1354,18 +1311,6 @@ do_estimate() { fi } -read_log() -{ - local PSTORE_START - LOG_ARGS="--read" - if [[ $(uname -m) == x86_64 ]]; then - PSTORE_START="0x$(grep Crash /proc/iomem | tail -n 1 | cut -d'-' -f1 | sed -e 's/^[[:space:]]*//')" - else - PSTORE_START="0x$(printf "%x" $(( "0x$(grep Crash /proc/iomem | tail -n 1 | cut -d'-' -f2 | cut -d' ' -f1)" - 0x60000 + 1 )))" - fi - $KEXEC $LOG_ARGS $PSTORE_START -} - if [ ! -f "$KDUMP_CONFIG_FILE" ]; then derror "Error: No kdump config file found!" exit 1 @@ -1424,11 +1369,8 @@ main () estimate) do_estimate ;; - readlog) - read_log - ;; *) - dinfo $"Usage: $0 {estimate|start|stop|status|restart|reload|rebuild|propagate|showmem|readlog}" + dinfo $"Usage: $0 {estimate|start|stop|status|restart|reload|rebuild|propagate|showmem}" exit 1 esac } diff --git a/kdumpctl.loongarch64 b/kdumpctl.loongarch64 deleted file mode 100755 index ba32806..0000000 --- a/kdumpctl.loongarch64 +++ /dev/null @@ -1,1409 +0,0 @@ -#!/bin/bash -KEXEC=/sbin/kexec - -KDUMP_KERNELVER="" -KDUMP_KERNEL="" -KDUMP_COMMANDLINE="" -KEXEC_ARGS="" -KDUMP_CONFIG_FILE="/etc/kdump.conf" -KDUMP_LOG_PATH="/var/log" -MKDUMPRD="/sbin/mkdumprd -f" -MKFADUMPRD="/sbin/mkfadumprd" -DRACUT_MODULES_FILE="/usr/lib/dracut/modules.txt" -SAVE_PATH=/var/crash -SSH_KEY_LOCATION="/root/.ssh/kdump_id_rsa" -INITRD_CHECKSUM_LOCATION="/boot/.fadump_initrd_checksum" -DUMP_TARGET="" -DEFAULT_INITRD="" -DEFAULT_INITRD_BAK="" -KDUMP_INITRD="" -TARGET_INITRD="" -FADUMP_REGISTER_SYS_NODE="/sys/kernel/fadump_registered" -#kdump shall be the default dump mode -DEFAULT_DUMP_MODE="kdump" -image_time=0 - -standard_kexec_args="-d -p" - -# Some default values in case /etc/sysconfig/kdump doesn't include -KDUMP_COMMANDLINE_REMOVE="hugepages hugepagesz slub_debug" - -if [ -f /etc/sysconfig/kdump ]; then - . /etc/sysconfig/kdump -fi - -[[ $dracutbasedir ]] || dracutbasedir=/usr/lib/dracut -. $dracutbasedir/dracut-functions.sh -. /lib/kdump/kdump-lib.sh -. /lib/kdump/kdump-logger.sh - -#initiate the kdump logger -dlog_init -if [ $? -ne 0 ]; then - echo "failed to initiate the kdump logger." - exit 1 -fi - -single_instance_lock() -{ - local rc timeout=5 - - exec 9>/var/lock/kdump - if [ $? -ne 0 ]; then - derror "Create file lock failed" - exit 1 - fi - - flock -n 9 - rc=$? - - while [ $rc -ne 0 ]; do - dinfo "Another app is currently holding the kdump lock; waiting for it to exit..." - flock -w $timeout 9 - rc=$? - done -} - -determine_dump_mode() -{ - # Check if firmware-assisted dump is enabled - # if yes, set the dump mode as fadump - if is_fadump_capable; then - dinfo "Dump mode is fadump" - DEFAULT_DUMP_MODE="fadump" - fi - ddebug "DEFAULT_DUMP_MODE=$DEFAULT_DUMP_MODE" -} - -save_core() -{ - coredir="/var/crash/`date +"%Y-%m-%d-%H:%M"`" - - mkdir -p $coredir - ddebug "cp --sparse=always /proc/vmcore $coredir/vmcore-incomplete" - cp --sparse=always /proc/vmcore $coredir/vmcore-incomplete - if [ $? == 0 ]; then - mv $coredir/vmcore-incomplete $coredir/vmcore - dinfo "saved a vmcore to $coredir" - else - derror "failed to save a vmcore to $coredir" - fi - - # pass the dmesg to Abrt tool if exists, in order - # to collect the kernel oops message. - # https://fedorahosted.org/abrt/ - if [ -x /usr/bin/dumpoops ]; then - ddebug "makedumpfile --dump-dmesg $coredir/vmcore $coredir/dmesg" - makedumpfile --dump-dmesg $coredir/vmcore $coredir/dmesg >/dev/null 2>&1 - ddebug "dumpoops -d $coredir/dmesg" - dumpoops -d $coredir/dmesg >/dev/null 2>&1 - if [ $? == 0 ]; then - dinfo "kernel oops has been collected by abrt tool" - fi - fi -} - -rebuild_fadump_initrd() -{ - if ! $MKFADUMPRD "$DEFAULT_INITRD_BAK" "$TARGET_INITRD" --kver "$KDUMP_KERNELVER"; then - derror "mkfadumprd: failed to make fadump initrd" - return 1 - fi - - sync -f "$TARGET_INITRD" - return 0 -} - -check_earlykdump_is_enabled() -{ - grep -q -w "rd.earlykdump" /proc/cmdline - return $? -} - -rebuild_kdump_initrd() -{ - ddebug "rebuild kdump initrd: $MKDUMPRD $TARGET_INITRD $KDUMP_KERNELVER" - $MKDUMPRD $TARGET_INITRD $KDUMP_KERNELVER - if [ $? != 0 ]; then - derror "mkdumprd: failed to make kdump initrd" - return 1 - fi - - if check_earlykdump_is_enabled; then - dwarn "Tips: If early kdump is enabled, also require rebuilding the system initramfs to make the changes take effect for early kdump." - fi - - sync -f "$TARGET_INITRD" - return 0 -} - -rebuild_initrd() -{ - if [[ ! -w $(dirname $TARGET_INITRD) ]];then - derror "$(dirname $TARGET_INITRD) does not have write permission. Cannot rebuild $TARGET_INITRD" - return 1 - fi - - if [ $DEFAULT_DUMP_MODE == "fadump" ]; then - rebuild_fadump_initrd - else - rebuild_kdump_initrd - fi - - return $? -} - -#$1: the files to be checked with IFS=' ' -check_exist() -{ - for file in $1; do - if [ ! -e "$file" ]; then - derror "Error: $file not found." - return 1 - fi - done -} - -#$1: the files to be checked with IFS=' ' -check_executable() -{ - for file in $1; do - if [ ! -x "$file" ]; then - derror "Error: $file is not executable." - return 1 - fi - done -} - -backup_default_initrd() -{ - ddebug "backup default initrd: $DEFAULT_INITRD" - - if [ ! -f "$DEFAULT_INITRD" ]; then - return - fi - - if [ ! -e $DEFAULT_INITRD_BAK ]; then - dinfo "Backing up $DEFAULT_INITRD before rebuild." - # save checksum to verify before restoring - sha1sum $DEFAULT_INITRD > $INITRD_CHECKSUM_LOCATION - cp $DEFAULT_INITRD $DEFAULT_INITRD_BAK - if [ $? -ne 0 ]; then - dwarn "WARNING: failed to backup $DEFAULT_INITRD." - rm -f $DEFAULT_INITRD_BAK - fi - fi -} - -restore_default_initrd() -{ - ddebug "restore default initrd: $DEFAULT_INITRD" - - if [ ! -f "$DEFAULT_INITRD" ]; then - return - fi - - # If a backup initrd exists, we must be switching back from - # fadump to kdump. Restore the original default initrd. - if [ -f $DEFAULT_INITRD_BAK ] && [ -f $INITRD_CHECKSUM_LOCATION ]; then - # verify checksum before restoring - backup_checksum=`sha1sum $DEFAULT_INITRD_BAK | awk '{ print $1 }'` - default_checksum=`cat $INITRD_CHECKSUM_LOCATION | awk '{ print $1 }'` - if [ "$default_checksum" != "$backup_checksum" ]; then - dwarn "WARNING: checksum mismatch! Can't restore original initrd.." - else - rm -f $INITRD_CHECKSUM_LOCATION - mv $DEFAULT_INITRD_BAK $DEFAULT_INITRD - if [[ $? -eq 0 ]]; then - derror "Restoring original initrd as fadump mode is disabled." - sync -f "$DEFAULT_INITRD" - fi - fi - fi -} - -check_config() -{ - local -A _opt_rec - while read -r config_opt config_val; do - case "$config_opt" in - dracut_args) - if [[ $config_val == *--mount* ]]; then - if [ $(echo $config_val | grep -o "\-\-mount" | wc -l) -ne 1 ]; then - derror "Multiple mount targets specified in one \"dracut_args\"." - return 1 - fi - config_opt=_target - fi - ;; - raw) - if [ -d "/proc/device-tree/ibm,opal/dump" ]; then - derror "WARNING: Won't capture opalcore when 'raw' dump target is used." - return 1 - fi - config_opt=_target - ;; - ext[234]|minix|btrfs|xfs|nfs|ssh) - config_opt=_target - ;; - sshkey|path|core_collector|kdump_post|kdump_pre|extra_bins|extra_modules|failure_action|default|final_action|force_rebuild|force_no_rebuild|fence_kdump_args|fence_kdump_nodes) - ;; - net|options|link_delay|disk_timeout|debug_mem_level|blacklist) - derror "Deprecated kdump config option: $config_opt. Refer to kdump.conf manpage for alternatives." - return 1 - ;; - '') - continue - ;; - *) - derror "Invalid kdump config option $config_opt" - return 1 - ;; - esac - - if [[ -z "$config_val" ]]; then - derror "Invalid kdump config value for option '$config_opt'" - return 1 - fi - - if [ -n "${_opt_rec[$config_opt]}" ]; then - if [ $config_opt == _target ]; then - derror "More than one dump targets specified" - else - derror "Duplicated kdump config value of option $config_opt" - fi - return 1 - fi - _opt_rec[$config_opt]="$config_val" - done <<< "$(read_strip_comments $KDUMP_CONFIG_FILE)" - - check_failure_action_config || return 1 - check_final_action_config || return 1 - check_fence_kdump_config || return 1 - - return 0 -} - -# get_pcs_cluster_modified_files -# return list of modified file for fence_kdump modified in Pacemaker cluster -get_pcs_cluster_modified_files() -{ - local time_stamp - local modified_files - - is_generic_fence_kdump && return 1 - is_pcs_fence_kdump || return 1 - - time_stamp=`pcs cluster cib | xmllint --xpath 'string(/cib/@cib-last-written)' - | \ - xargs -0 date +%s --date` - - if [ -n $time_stamp -a $time_stamp -gt $image_time ]; then - modified_files="cluster-cib" - fi - - if [ -f $FENCE_KDUMP_CONFIG_FILE ]; then - time_stamp=`stat -c "%Y" $FENCE_KDUMP_CONFIG_FILE` - if [ "$time_stamp" -gt "$image_time" ]; then - modified_files="$modified_files $FENCE_KDUMP_CONFIG_FILE" - fi - fi - - echo $modified_files -} - -setup_initrd() -{ - prepare_kdump_bootinfo - if [ $? -ne 0 ]; then - derror "failed to prepare for kdump bootinfo." - return 1 - fi - - DEFAULT_INITRD_BAK="$KDUMP_BOOTDIR/.$(basename $DEFAULT_INITRD).default" - if [ $DEFAULT_DUMP_MODE == "fadump" ]; then - TARGET_INITRD="$DEFAULT_INITRD" - if [ ! -s "$TARGET_INITRD" ]; then - derror "Error: No initrd found to rebuild!" - return 1 - fi - - # backup initrd for reference before replacing it - # with fadump aware initrd - backup_default_initrd - else - TARGET_INITRD="$KDUMP_INITRD" - - # check if a backup of default initrd exists. If yes, - # it signifies a switch from fadump mode. So, restore - # the backed up default initrd. - restore_default_initrd - fi -} - -check_files_modified() -{ - local modified_files="" - - #also rebuild when Pacemaker cluster conf is changed and fence kdump is enabled. - modified_files=$(get_pcs_cluster_modified_files) - - EXTRA_BINS=`grep ^kdump_post $KDUMP_CONFIG_FILE | cut -d\ -f2` - CHECK_FILES=`grep ^kdump_pre $KDUMP_CONFIG_FILE | cut -d\ -f2` - HOOKS="/etc/kdump/post.d/ /etc/kdump/pre.d/" - if [ -d /etc/kdump/post.d ]; then - for file in /etc/kdump/post.d/*; do - if [ -x "$file" ]; then - POST_FILES="$POST_FILES $file" - fi - done - fi - if [ -d /etc/kdump/pre.d ]; then - for file in /etc/kdump/pre.d/*; do - if [ -x "$file" ]; then - PRE_FILES="$PRE_FILES $file" - fi - done - fi - HOOKS="$HOOKS $POST_FILES $PRE_FILES" - CORE_COLLECTOR=`grep ^core_collector $KDUMP_CONFIG_FILE | cut -d\ -f2` - CORE_COLLECTOR=`type -P $CORE_COLLECTOR` - # POST_FILES and PRE_FILES are already checked against executable, need not to check again. - EXTRA_BINS="$EXTRA_BINS $CHECK_FILES" - CHECK_FILES=`grep ^extra_bins $KDUMP_CONFIG_FILE | cut -d\ -f2-` - EXTRA_BINS="$EXTRA_BINS $CHECK_FILES" - files="$KDUMP_CONFIG_FILE $KDUMP_KERNEL $EXTRA_BINS $CORE_COLLECTOR" - [[ -e /etc/fstab ]] && files="$files /etc/fstab" - - # Check for any updated extra module - EXTRA_MODULES="$(grep ^extra_modules $KDUMP_CONFIG_FILE | sed 's/^extra_modules\s*//')" - if [ -n "$EXTRA_MODULES" ]; then - if [ -e /lib/modules/$KDUMP_KERNELVER/modules.dep ]; then - files="$files /lib/modules/$KDUMP_KERNELVER/modules.dep" - fi - for _module in $EXTRA_MODULES; do - _module_file="$(modinfo --set-version "$KDUMP_KERNELVER" --filename "$_module" 2>/dev/null)" - if [[ $? -eq 0 ]]; then - files="$files $_module_file" - for _dep_modules in $(modinfo -F depends $_module | tr ',' ' '); do - files="$files $(modinfo --set-version "$KDUMP_KERNELVER" --filename $_dep_modules 2>/dev/null)" - done - else - # If it's not a module nor builtin, give an error - if ! ( modprobe --set-version "$KDUMP_KERNELVER" --dry-run "$_module" &>/dev/null ); then - dwarn "Module $_module not found" - fi - fi - done - fi - - # HOOKS is mandatory and need to check the modification time - files="$files $HOOKS" - is_lvm2_thinp_dump_target && files="$files $LVM_CONF" - check_exist "$files" && check_executable "$EXTRA_BINS" - [ $? -ne 0 ] && return 2 - - for file in $files; do - if [ -e "$file" ]; then - time_stamp=`stat -c "%Y" $file` - if [ "$time_stamp" -gt "$image_time" ]; then - modified_files="$modified_files $file" - fi - if [ -L "$file" ]; then - file=$(readlink -m $file) - time_stamp=`stat -c "%Y" $file` - if [ "$time_stamp" -gt "$image_time" ]; then - modified_files="$modified_files $file" - fi - fi - else - dwarn "$file doesn't exist" - fi - done - - if [ -n "$modified_files" ]; then - dinfo "Detected change(s) in the following file(s): $modified_files" - return 1 - fi - - return 0 -} - -check_drivers_modified() -{ - local _target _new_drivers _old_drivers _module_name _module_filename - - # If it's dump target is on block device, detect the block driver - _target=$(get_block_dump_target) - if [[ -n "$_target" ]]; then - _record_block_drivers() { - local _drivers - _drivers=$(udevadm info -a "/dev/block/$1" | sed -n 's/\s*DRIVERS=="\(\S\+\)"/\1/p') - for _driver in $_drivers; do - if ! [[ " $_new_drivers " == *" $_driver "* ]]; then - _new_drivers="$_new_drivers $_driver" - fi - done - - ddebug "MAJ:MIN=$1 drivers='$_drivers'" - } - check_block_and_slaves_all _record_block_drivers "$(get_maj_min "$_target")" - fi - - # Include watchdog drivers if watchdog module is not omitted - is_dracut_mod_omitted watchdog || is_dracut_mod_omitted watchdog-modules || _new_drivers+=" $(get_watchdog_drvs)" - - [ -z "$_new_drivers" ] && return 0 - if is_fadump_capable; then - _old_drivers="$(lsinitrd "$TARGET_INITRD" -f /usr/lib/dracut/fadump-kernel-modules.txt | tr '\n' ' ')" - else - _old_drivers="$(lsinitrd "$TARGET_INITRD" -f /usr/lib/dracut/loaded-kernel-modules.txt | tr '\n' ' ')" - fi - - ddebug "Modules required for kdump: '$_new_drivers'" - ddebug "Modules included in old initramfs: '$_old_drivers'" - for _driver in $_new_drivers; do - # Skip deprecated/invalid driver name or built-in module - _module_name=$(modinfo --set-version "$KDUMP_KERNELVER" -F name $_driver 2>/dev/null) - _module_filename=$(modinfo --set-version "$KDUMP_KERNELVER" -n $_driver 2>/dev/null) - if [ $? -ne 0 ] || [ -z "$_module_name" ] || [[ "$_module_filename" = *"(builtin)"* ]]; then - continue - fi - if ! [[ " $_old_drivers " == *" $_module_name "* ]]; then - dinfo "Detected change in block device driver, new loaded module: $_module_name" - return 1 - fi - done -} - -check_fs_modified() -{ - local _old_dev _old_mntpoint _old_fstype - local _new_dev _new_mntpoint _new_fstype - local _target _dracut_args - - # No need to check in case of mount target specified via "dracut_args". - if is_mount_in_dracut_args; then - return 0 - fi - - # No need to check in case of raw target. - # Currently we do not check also if ssh/nfs/thinp target is specified - if is_ssh_dump_target || is_nfs_dump_target || is_raw_dump_target || - is_lvm2_thinp_dump_target; then - return 0 - fi - - _target=$(get_block_dump_target) - _new_fstype=$(get_fs_type_from_target $_target) - if [[ -z "$_target" ]] || [[ -z "$_new_fstype" ]];then - derror "Dump target is invalid" - return 2 - fi - - ddebug "_target=$_target _new_fstype=$_new_fstype" - _new_dev=$(kdump_get_persistent_dev $_target) - if [ -z "$_new_dev" ]; then - perror "Get persistent device name failed" - return 2 - fi - - _new_mntpoint="$(get_kdump_mntpoint_from_target $_target)" - _dracut_args=$(lsinitrd $TARGET_INITRD -f usr/lib/dracut/build-parameter.txt) - if [[ -z "$_dracut_args" ]];then - dwarn "Warning: No dracut arguments found in initrd" - return 0 - fi - - # if --mount argument present then match old and new target, mount - # point and file system. If any of them mismatches then rebuild - echo $_dracut_args | grep "\-\-mount" &> /dev/null - if [[ $? -eq 0 ]];then - set -- $(echo $_dracut_args | awk -F "--mount '" '{print $2}' | cut -d' ' -f1,2,3) - _old_dev=$1 - _old_mntpoint=$2 - _old_fstype=$3 - [[ $_new_dev = $_old_dev && $_new_mntpoint = $_old_mntpoint && $_new_fstype = $_old_fstype ]] && return 0 - # otherwise rebuild if target device is not a root device - else - [[ "$_target" = "$(get_root_fs_device)" ]] && return 0 - fi - - dinfo "Detected change in File System" - return 1 -} - -# returns 0 if system is not modified -# returns 1 if system is modified -# returns 2 if system modification is invalid -check_system_modified() -{ - local ret - - [[ -f $TARGET_INITRD ]] || return 1 - - check_files_modified - ret=$? - if [ $ret -ne 0 ]; then - return $ret - fi - - check_fs_modified - ret=$? - if [ $ret -ne 0 ]; then - return $ret - fi - - check_drivers_modified - ret=$? - if [ $ret -ne 0 ]; then - return $ret - fi - - return 0 -} - -check_rebuild() -{ - local capture_capable_initrd="1" - local _force_rebuild force_rebuild="0" - local _force_no_rebuild force_no_rebuild="0" - local ret system_modified="0" - - setup_initrd - - if [ $? -ne 0 ]; then - return 1 - fi - - _force_no_rebuild=`grep ^force_no_rebuild $KDUMP_CONFIG_FILE 2>/dev/null` - if [ $? -eq 0 ]; then - force_no_rebuild=`echo $_force_no_rebuild | cut -d' ' -f2` - if [ "$force_no_rebuild" != "0" ] && [ "$force_no_rebuild" != "1" ];then - derror "Error: force_no_rebuild value is invalid" - return 1 - fi - fi - - _force_rebuild=`grep ^force_rebuild $KDUMP_CONFIG_FILE 2>/dev/null` - if [ $? -eq 0 ]; then - force_rebuild=`echo $_force_rebuild | cut -d' ' -f2` - if [ "$force_rebuild" != "0" ] && [ "$force_rebuild" != "1" ];then - derror "Error: force_rebuild value is invalid" - return 1 - fi - fi - - if [[ "$force_no_rebuild" == "1" && "$force_rebuild" == "1" ]]; then - derror "Error: force_rebuild and force_no_rebuild are enabled simultaneously in kdump.conf" - return 1 - fi - - # Will not rebuild kdump initrd - if [ "$force_no_rebuild" == "1" ]; then - return 0 - fi - - #check to see if dependent files has been modified - #since last build of the image file - if [ -f $TARGET_INITRD ]; then - image_time=`stat -c "%Y" $TARGET_INITRD 2>/dev/null` - - #in case of fadump mode, check whether the default/target - #initrd is already built with dump capture capability - if [ "$DEFAULT_DUMP_MODE" == "fadump" ]; then - capture_capable_initrd=$(lsinitrd -f $DRACUT_MODULES_FILE $TARGET_INITRD | grep -e ^kdumpbase$ -e ^zz-fadumpinit$ | wc -l) - fi - fi - - check_system_modified - ret=$? - if [ $ret -eq 2 ]; then - return 1 - elif [ $ret -eq 1 ];then - system_modified="1" - fi - - if [ $image_time -eq 0 ]; then - dinfo "No kdump initial ramdisk found." - elif [ "$capture_capable_initrd" == "0" ]; then - dinfo "Rebuild $TARGET_INITRD with dump capture support" - elif [ "$force_rebuild" != "0" ]; then - dinfo "Force rebuild $TARGET_INITRD" - elif [ "$system_modified" != "0" ]; then - : - else - return 0 - fi - - dinfo "Rebuilding $TARGET_INITRD" - rebuild_initrd - return $? -} - -# On ppc64le LPARs, the keys trusted by firmware do not end up in -# .builtin_trusted_keys. So instead, add the key to the .ima keyring -function load_kdump_kernel_key() -{ - # this is only called inside is_secure_boot_enforced, - # no need to retest - - # this is only required if DT /ibm,secure-boot is a file. - # if it is a dir, we are on OpenPower and don't need this. - if ! [ -f /proc/device-tree/ibm,secure-boot ]; then - return - fi - - KDUMP_KEY_ID=$(cat /usr/share/doc/kernel-keys/$KDUMP_KERNELVER/kernel-signing-ppc.cer | - keyctl padd asymmetric kernelkey-$RANDOM %:.ima) -} - -# remove a previously loaded key. There's no real security implication -# to leaving it around, we choose to do this because it makes it easier -# to be idempotent and so as to reduce the potential for confusion. -function remove_kdump_kernel_key() -{ - if [ -z "$KDUMP_KEY_ID" ]; then - return - fi - - keyctl unlink $KDUMP_KEY_ID %:.ima -} - -# Load the kdump kernel specified in /etc/sysconfig/kdump -# If none is specified, try to load a kdump kernel with the same version -# as the currently running kernel. -load_kdump() -{ - local ret - - KEXEC_ARGS=$(prepare_kexec_args "${KEXEC_ARGS}") - KDUMP_COMMANDLINE=$(prepare_cmdline "${KDUMP_COMMANDLINE}" "${KDUMP_COMMANDLINE_REMOVE}" "${KDUMP_COMMANDLINE_APPEND}") - - # For secureboot enabled machines, use new kexec file based syscall. - # Old syscall will always fail as it does not have capability to - # to kernel signature verification. - if is_secure_boot_enforced; then - dinfo "Secure Boot is enabled. Using kexec file based syscall." - KEXEC_ARGS="$KEXEC_ARGS -s" - load_kdump_kernel_key - fi - - ddebug "$KEXEC $KEXEC_ARGS $standard_kexec_args --command-line=$KDUMP_COMMANDLINE --initrd=$TARGET_INITRD $KDUMP_KERNEL" - - # The '12' represents an intermediate temporary file descriptor - # to store the standard error file descriptor '2', and later - # restore the error file descriptor with the file descriptor '12' - # and release it. - exec 12>&2 - exec 2>> $KDUMP_LOG_PATH/kdump.log - chmod 600 $KDUMP_LOG_PATH/kdump.log - PS4='+ $(date "+%Y-%m-%d %H:%M:%S") ${BASH_SOURCE}@${LINENO}: ' - set -x - - $KEXEC $KEXEC_ARGS $standard_kexec_args \ - --command-line="$KDUMP_COMMANDLINE" \ - --initrd=$TARGET_INITRD $KDUMP_KERNEL - - ret=$? - set +x - exec 2>&12 12>&- - - remove_kdump_kernel_key - - if [ $ret == 0 ]; then - dinfo "kexec: loaded kdump kernel" - return 0 - else - derror "kexec: failed to load kdump kernel" - return 1 - fi -} - -check_ssh_config() -{ - while read config_opt config_val; do - case "$config_opt" in - sshkey) - # remove inline comments after the end of a directive. - if [ -f "$config_val" ]; then - # canonicalize the path - SSH_KEY_LOCATION=$(/usr/bin/readlink -m $config_val) - else - dwarn "WARNING: '$config_val' doesn't exist, using default value '$SSH_KEY_LOCATION'" - fi - ;; - path) - SAVE_PATH=$config_val - ;; - ssh) - DUMP_TARGET=$config_val - ;; - *) - ;; - esac - done <<< "$(read_strip_comments $KDUMP_CONFIG_FILE)" - - #make sure they've configured kdump.conf for ssh dumps - local SSH_TARGET=`echo -n $DUMP_TARGET | sed -n '/.*@/p'` - if [ -z "$SSH_TARGET" ]; then - return 1 - fi - return 0 -} - -# ipv6 host address may takes a long time to be ready. -# Instead of checking against ipv6 address, we just check the network reachable -# by the return val of 'ssh' -check_and_wait_network_ready() -{ - local start_time=$(date +%s) - local warn_once=1 - local cur - local diff - local retval - local errmsg - - while true; do - errmsg=$(ssh -i $SSH_KEY_LOCATION -o BatchMode=yes $DUMP_TARGET mkdir -p $SAVE_PATH 2>&1) - retval=$? - - # ssh exits with the exit status of the remote command or with 255 if an error occurred - if [ $retval -eq 0 ]; then - return 0 - elif [ $retval -ne 255 ]; then - derror "Could not create $DUMP_TARGET:$SAVE_PATH, you should check the privilege on server side" - return 1 - fi - - # if server removes the authorized_keys or, no /root/.ssh/kdump_id_rsa - ddebug "$errmsg" - echo $errmsg | grep -q "Permission denied\|No such file or directory\|Host key verification failed" &> /dev/null - if [ $? -eq 0 ]; then - derror "Could not create $DUMP_TARGET:$SAVE_PATH, you probably need to run \"kdumpctl propagate\"" - return 1 - fi - - if [ $warn_once -eq 1 ]; then - dwarn "Network dump target is not usable, waiting for it to be ready..." - warn_once=0 - fi - - cur=$(date +%s) - let "diff = $cur - $start_time" - # 60s time out - if [ $diff -gt 180 ]; then - break; - fi - sleep 1 - done - - dinfo "Could not create $DUMP_TARGET:$SAVE_PATH, ipaddr is not ready yet. You should check network connection" - return 1 -} - -check_ssh_target() -{ - check_and_wait_network_ready - if [ $? -ne 0 ]; then - return 1 - fi - return 0 -} - -propagate_ssh_key() -{ - check_ssh_config - if [ $? -ne 0 ]; then - derror "No ssh config specified in $KDUMP_CONFIG_FILE. Can't propagate" - exit 1 - fi - - local KEYFILE=$SSH_KEY_LOCATION - local errmsg="Failed to propagate ssh key" - - #Check to see if we already created key, if not, create it. - if [ -f $KEYFILE ]; then - dinfo "Using existing keys..." - else - dinfo "Generating new ssh keys... " - /usr/bin/ssh-keygen -t rsa -f $KEYFILE -N "" 2>&1 > /dev/null - dinfo "done." - fi - - #now find the target ssh user and server to contact. - SSH_USER=`echo $DUMP_TARGET | cut -d\ -f2 | cut -d@ -f1` - SSH_SERVER=`echo $DUMP_TARGET | sed -e's/\(.*@\)\(.*$\)/\2/'` - - #now send the found key to the found server - ssh-copy-id -i $KEYFILE $SSH_USER@$SSH_SERVER - RET=$? - if [ $RET == 0 ]; then - dinfo "$KEYFILE has been added to ~$SSH_USER/.ssh/authorized_keys on $SSH_SERVER" - return 0 - else - derror "$errmsg, $KEYFILE failed in transfer to $SSH_SERVER" - exit 1 - fi -} - -show_reserved_mem() -{ - local mem=$(cat /sys/kernel/kexec_crash_size) - local mem_mb=$(expr $mem / 1024 / 1024) - - dinfo "Reserved "$mem_mb"MB memory for crash kernel" -} - -check_current_fadump_status() -{ - # Check if firmware-assisted dump has been registered. - rc=`cat $FADUMP_REGISTER_SYS_NODE` - [ $rc -eq 1 ] && return 0 - return 1 -} - -check_current_status() -{ - if [ $DEFAULT_DUMP_MODE == "fadump" ]; then - check_current_fadump_status - else - check_current_kdump_status - fi - - return $? -} - -save_raw() -{ - local kdump_dir - local raw_target - - raw_target=$(awk '$1 ~ /^raw$/ { print $2; }' $KDUMP_CONFIG_FILE) - [ -z "$raw_target" ] && return 0 - [ -b "$raw_target" ] || { - derror "raw partition $raw_target not found" - return 1 - } - kdump_dir=`grep ^path $KDUMP_CONFIG_FILE | cut -d' ' -f2-` - if [ -z "${kdump_dir}" ]; then - coredir="/var/crash/`date +"%Y-%m-%d-%H:%M"`" - else - coredir="${kdump_dir}/`date +"%Y-%m-%d-%H:%M"`" - fi - - mkdir -p "$coredir" - [ -d "$coredir" ] || { - derror "failed to create $coredir" - return 1 - } - if makedumpfile -R $coredir/vmcore <$raw_target >/dev/null 2>&1; then - # dump found - dinfo "Dump saved to $coredir/vmcore" - # wipe makedumpfile header - dd if=/dev/zero of=$raw_target bs=1b count=1 2>/dev/null - else - rm -rf "$coredir" - fi - - return 0 -} - -local_fs_dump_target() -{ - local _target - - _target=$(egrep "^ext[234]|^xfs|^btrfs|^minix" /etc/kdump.conf) - if [ $? -eq 0 ]; then - echo $_target|awk '{print $2}' - fi -} - -path_to_be_relabeled() -{ - local _path _target _mnt="/" _rmnt - - if is_user_configured_dump_target; then - if is_mount_in_dracut_args; then - return; - fi - - _target=$(local_fs_dump_target) - if [[ -n "$_target" ]]; then - _mnt=$(get_mntpoint_from_target $_target) - if ! is_mounted "$_mnt"; then - return - fi - else - return - fi - fi - - _path=$(get_save_path) - # if $_path is masked by other mount, we will not relabel it. - _rmnt=$(df $_mnt/$_path 2>/dev/null | tail -1 | awk '{ print $NF }') - if [ "$_rmnt" == "$_mnt" ]; then - echo $_mnt/$_path - fi -} - -selinux_relabel() -{ - local _path _i _attr - - _path=$(path_to_be_relabeled) - if [ -z "$_path" ] || ! [ -d "$_path" ] ; then - return - fi - - while IFS= read -r -d '' _i; do - _attr=$(getfattr -m "security.selinux" "$_i" 2>/dev/null) - if [ -z "$_attr" ]; then - restorecon "$_i"; - fi - done < <(find "$_path" -print0) -} - -check_fence_kdump_config() -{ - local hostname=`hostname` - local ipaddrs=`hostname -I` - local nodes=$(get_option_value "fence_kdump_nodes") - - for node in $nodes; do - if [ "$node" = "$hostname" ]; then - derror "Option fence_kdump_nodes cannot contain $hostname" - return 1 - fi - # node can be ipaddr - echo "$ipaddrs " | grep "$node " > /dev/null - if [ $? -eq 0 ]; then - derror "Option fence_kdump_nodes cannot contain $node" - return 1 - fi - done - - return 0 -} - -check_dump_feasibility() -{ - if [ $DEFAULT_DUMP_MODE == "fadump" ]; then - return 0 - fi - - check_kdump_feasibility - return $? -} - -start_fadump() -{ - echo 1 > $FADUMP_REGISTER_SYS_NODE - if ! check_current_fadump_status; then - derror "fadump: failed to register" - return 1 - fi - - dinfo "fadump: registered successfully" - return 0 -} - -start_dump() -{ - if [ $DEFAULT_DUMP_MODE == "fadump" ]; then - start_fadump - else - load_kdump - fi - - return $? -} - -check_failure_action_config() -{ - local default_option - local failure_action - local option="failure_action" - - default_option=$(awk '$1 ~ /^default$/ {print $2;}' $KDUMP_CONFIG_FILE) - failure_action=$(awk '$1 ~ /^failure_action$/ {print $2;}' $KDUMP_CONFIG_FILE) - - if [ -z "$failure_action" -a -z "$default_option" ]; then - return 0 - elif [ -n "$failure_action" -a -n "$default_option" ]; then - derror "Cannot specify 'failure_action' and 'default' option together" - return 1 - fi - - if [ -n "$default_option" ]; then - option="default" - failure_action="$default_option" - fi - - case "$failure_action" in - reboot|halt|poweroff|shell|dump_to_rootfs) - return 0 - ;; - *) - dinfo $"Usage kdump.conf: $option {reboot|halt|poweroff|shell|dump_to_rootfs}" - return 1 - esac -} - -check_final_action_config() -{ - local final_action - - final_action=$(awk '$1 ~ /^final_action$/ {print $2;}' $KDUMP_CONFIG_FILE) - if [ -z "$final_action" ]; then - return 0 - else - case "$final_action" in - reboot|halt|poweroff) - return 0 - ;; - *) - dinfo $"Usage kdump.conf: final_action {reboot|halt|poweroff}" - return 1 - esac - fi -} - -start() -{ - check_dump_feasibility - if [ $? -ne 0 ]; then - derror "Starting kdump: [FAILED]" - return 1 - fi - - check_config - if [ $? -ne 0 ]; then - derror "Starting kdump: [FAILED]" - return 1 - fi - - if sestatus 2>/dev/null | grep -q "SELinux status.*enabled"; then - selinux_relabel - fi - - save_raw - if [ $? -ne 0 ]; then - derror "Starting kdump: [FAILED]" - return 1 - fi - - check_current_status - if [ $? == 0 ]; then - dwarn "Kdump already running: [WARNING]" - return 0 - fi - - if check_ssh_config; then - if ! check_ssh_target; then - derror "Starting kdump: [FAILED]" - return 1 - fi - fi - - check_rebuild - if [ $? != 0 ]; then - derror "Starting kdump: [FAILED]" - return 1 - fi - - start_dump - if [ $? != 0 ]; then - derror "Starting kdump: [FAILED]" - return 1 - fi - - dinfo "Starting kdump: [OK]" -} - -reload() -{ - check_current_status - if [ $? -ne 0 ]; then - dwarn "Kdump was not running: [WARNING]" - fi - - if [ $DEFAULT_DUMP_MODE == "fadump" ]; then - reload_fadump - return $? - else - stop_kdump - fi - - if [ $? -ne 0 ]; then - derror "Stopping kdump: [FAILED]" - return 1 - fi - - dinfo "Stopping kdump: [OK]" - - setup_initrd - if [ $? -ne 0 ]; then - derror "Starting kdump: [FAILED]" - return 1 - fi - - start_dump - if [ $? -ne 0 ]; then - derror "Starting kdump: [FAILED]" - return 1 - fi - - dinfo "Starting kdump: [OK]" -} - -stop_fadump() -{ - echo 0 > $FADUMP_REGISTER_SYS_NODE - if check_current_fadump_status; then - derror "fadump: failed to unregister" - return 1 - fi - - dinfo "fadump: unregistered successfully" - return 0 -} - -stop_kdump() -{ - if is_secure_boot_enforced; then - $KEXEC -s -p -u - else - $KEXEC -p -u - fi - - if [ $? != 0 ]; then - derror "kexec: failed to unload kdump kernel" - return 1 - fi - - dinfo "kexec: unloaded kdump kernel" - return 0 -} - -reload_fadump() -{ - echo 1 > $FADUMP_REGISTER_SYS_NODE - if [ $? == 0 ]; then - dinfo "fadump: re-registered successfully" - return 0 - else - # FADump could fail on older kernel where re-register - # support is not enabled. Try stop/start from userspace - # to handle such scenario. - stop_fadump - if [ $? == 0 ]; then - start_fadump - return $? - fi - fi - - return 1 -} - -stop() -{ - if [ $DEFAULT_DUMP_MODE == "fadump" ]; then - stop_fadump - else - stop_kdump - fi - - if [ $? != 0 ]; then - derror "Stopping kdump: [FAILED]" - return 1 - fi - - dinfo "Stopping kdump: [OK]" - return 0 -} - -rebuild() { - check_config - if [ $? -ne 0 ]; then - return 1 - fi - - if check_ssh_config; then - if ! check_ssh_target; then - return 1 - fi - fi - - setup_initrd - if [ $? -ne 0 ]; then - return 1 - fi - - dinfo "Rebuilding $TARGET_INITRD" - rebuild_initrd - return $? -} - -do_estimate() { - local kdump_mods - local -A large_mods - local baseline - local kernel_size mod_size initrd_size baseline_size runtime_size reserved_size estimated_size recommended_size - local size_mb=$(( 1024 * 1024 )) - - setup_initrd - if [ ! -f "$TARGET_INITRD" ]; then - derror "kdumpctl estimate: kdump initramfs is not built yet." - exit 1 - fi - - kdump_mods="$(lsinitrd "$TARGET_INITRD" -f /usr/lib/dracut/loaded-kernel-modules.txt | tr '\n' ' ')" - baseline=$(kdump_get_arch_recommend_size) - if [[ "${baseline: -1}" == "M" ]]; then - baseline=${baseline%M} - elif [[ "${baseline: -1}" == "G" ]]; then - baseline=$(( ${baseline%G} * 1024 )) - elif [[ "${baseline: -1}" == "T" ]]; then - baseline=$(( ${baseline%Y} * 1048576 )) - fi - - # The default value when using crashkernel=auto - baseline_size=$((baseline * size_mb)) - # Current reserved crashkernel size - reserved_size=$(cat /sys/kernel/kexec_crash_size) - # A pre-estimated value for userspace usage and kernel - # runtime allocation, 64M should good for most cases - runtime_size=$((64 * size_mb)) - # Kernel image size - kernel_size=$(get_kernel_size "$KDUMP_KERNEL") - # Kdump initramfs size - initrd_size=$(du -b "$TARGET_INITRD" | awk '{print $1}') - # Kernel modules static size after loaded - mod_size=0 - while read -r _name _size _; do - if [[ ! " $kdump_mods " == *" $_name "* ]]; then - continue - fi - mod_size=$((mod_size + _size)) - - # Mark module with static size larger than 2M as large module - if [[ $((_size / size_mb)) -ge 1 ]]; then - large_mods[$_name]=$_size - fi - done <<< "$(< /proc/modules)" - - # Extra memory usage required for LUKS2 decryption - crypt_size=0 - for _dev in $(get_all_kdump_crypt_dev); do - _crypt_info=$(cryptsetup luksDump "/dev/block/$_dev") - [[ $(echo "$_crypt_info" | sed -n "s/^Version:\s*\(.*\)/\1/p" ) == "2" ]] || continue - for _mem in $(echo "$_crypt_info" | sed -n "s/\sMemory:\s*\(.*\)/\1/p" | sort -n ); do - crypt_size=$((crypt_size + _mem * 1024)) - break - done - done - [[ $crypt_size -ne 0 ]] && echo -e "Encrypted kdump target requires extra memory, assuming using the keyslot with minimun memory requirement\n" - - estimated_size=$((kernel_size + mod_size + initrd_size + runtime_size + crypt_size)) - if [[ $baseline_size -gt $estimated_size ]]; then - recommended_size=$baseline_size - else - recommended_size=$estimated_size - fi - - echo "Reserved crashkernel: $((reserved_size / size_mb))M" - echo "Recommended crashkernel: $((recommended_size / size_mb))M" - echo - echo "Kernel image size: $((kernel_size / size_mb))M" - echo "Kernel modules size: $((mod_size / size_mb))M" - echo "Initramfs size: $((initrd_size / size_mb))M" - echo "Runtime reservation: $((runtime_size / size_mb))M" - [[ $crypt_size -ne 0 ]] && \ - echo "LUKS required size: $((crypt_size / size_mb))M" - echo -n "Large modules:" - if [[ "${#large_mods[@]}" -eq 0 ]]; then - echo " " - else - echo "" - for _mod in "${!large_mods[@]}"; do - echo " $_mod: ${large_mods[$_mod]}" - done - fi - - if [[ $reserved_size -lt $recommended_size ]]; then - echo "WARNING: Current crashkernel size is lower than recommended size $((recommended_size / size_mb))M." - fi -} - -if [ ! -f "$KDUMP_CONFIG_FILE" ]; then - derror "Error: No kdump config file found!" - exit 1 -fi - -main () -{ - # Determine if the dump mode is kdump or fadump - determine_dump_mode - - case "$1" in - start) - if [ -s /proc/vmcore ]; then - save_core - reboot - else - start - fi - ;; - stop) - stop - ;; - status) - EXIT_CODE=0 - check_current_status - case "$?" in - 0) - dinfo "Kdump is operational" - EXIT_CODE=0 - ;; - 1) - dinfo "Kdump is not operational" - EXIT_CODE=3 - ;; - esac - exit $EXIT_CODE - ;; - reload) - reload - ;; - restart) - stop - start - ;; - rebuild) - rebuild - ;; - condrestart) - ;; - propagate) - propagate_ssh_key - ;; - showmem) - show_reserved_mem - ;; - estimate) - do_estimate - ;; - *) - dinfo $"Usage: $0 {estimate|start|stop|status|restart|reload|rebuild|propagate|showmem}" - exit 1 - esac -} - -# Other kdumpctl instances will block in queue, until this one exits -single_instance_lock - -# To avoid fd 9 leaking, we invoke a subshell, close fd 9 and call main. -# So that fd isn't leaking when main is invoking a subshell. -(exec 9<&-; main $1) - -exit $? diff --git a/kexec-tools.spec b/kexec-tools.spec index 87b931d..4baaa28 100644 --- a/kexec-tools.spec +++ b/kexec-tools.spec @@ -1,8 +1,6 @@ -%define anolis_release .0.3 - Name: kexec-tools Version: 2.0.26 -Release: 8%{anolis_release}%{?dist} +Release: 14%{?dist}.1 License: GPLv2 Group: Applications/System Summary: The kexec/kdump userspace component @@ -23,9 +21,7 @@ Source14: 98-kexec.rules.ppc64 Source15: kdump.conf.5 Source16: kdump.service Source18: kdump.sysconfig.s390x -%ifnarch loongarch64 Source19: eppic_050615.tar.gz -%endif Source20: kdump-lib.sh Source21: kdump-in-cluster-environment.txt Source22: kdump-dep-generator.sh @@ -43,8 +39,6 @@ Source33: kdump-logger.sh Source34: kdump-migrate-action.sh Source35: kdump-restart.sh Source36: mkfadumprd -Source37: kdump.sysconfig.loongarch64 -Source38: kdumpctl.loongarch64 ####################################### # These are sources for mkdumpramfs @@ -114,11 +108,10 @@ ExcludeArch: i686 # Patch601: rhelonly-kexec-tools-2.0.16-koji-build-fail-workaround.patch Patch602: rhelonly-kexec-tools-2.0.18-eppic-fix-issues-with-hardening-flags.patch -Patch603: loongarch64-fix-some-functional-issues-and-compilati.patch -Patch604: 1000-kexec-tools-2.0.25-Add-pstore-segment-support.patch # Patches 701 onward for makedumpfile -Patch701: kexec-tools-2.0.26-makedumpfile-sadump-fix-failure-of-reading-memory-when-5-le.patch +Patch701: rhelonly-kexec-tools-2.0.20-makedumpfile-arm64-Add-support-for-ARMv8.2-LVA-52-bi.patch +Patch702: kexec-tools-2.0.26-makedumpfile-sadump-fix-failure-of-reading-memory-when-5-le.patch %description kexec-tools provides /usr/sbin/kexec binary that facilitates a new @@ -127,35 +120,18 @@ normal or a panic reboot. This package contains the /usr/sbin/kexec binary and ancillary utilities that together form the userspace component of the kernel's kexec feature. -%package doc -Summary: Documents for %{name} -BuildArch: noarch -Requires: %{name} = %{version}-%{release} - -%description doc -Doc pages for %{name}. - %prep %setup -q mkdir -p -m755 kcp tar -z -x -v -f %{SOURCE9} -%ifnarch loongarch64 tar -z -x -v -f %{SOURCE19} -%endif %patch601 -p1 -%ifnarch loongarch64 %patch602 -p1 -%endif -%ifarch loongarch64 -%patch603 -p1 -%endif -%ifnarch loongarch64 -%patch604 -p1 -%endif %patch701 -p1 +%patch702 -p1 %ifarch ppc %define archdef ARCH=ppc @@ -186,15 +162,11 @@ cp %{SOURCE31} . %{SOURCE8} %{_target_cpu} > kdump.conf make -%ifarch %{ix86} x86_64 ppc64 s390x ppc64le aarch64 loongarch64 -%ifnarch loongarch64 +%ifarch %{ix86} x86_64 ppc64 s390x ppc64le aarch64 make -C eppic/libeppic -%endif make -C makedumpfile-1.7.2 LINKTYPE=dynamic USELZO=on USESNAPPY=on USEZSTD=on -%ifnarch loongarch64 make -C makedumpfile-1.7.2 LDFLAGS="$LDFLAGS -I../eppic/libeppic -L../eppic/libeppic" eppic_makedumpfile.so %endif -%endif %install mkdir -p -m755 $RPM_BUILD_ROOT/usr/sbin @@ -213,11 +185,7 @@ mkdir -p -m755 $RPM_BUILD_ROOT%{_bindir} mkdir -p -m755 $RPM_BUILD_ROOT%{_libdir} mkdir -p -m755 $RPM_BUILD_ROOT%{_prefix}/lib/kdump mkdir -p -m755 $RPM_BUILD_ROOT%{_sharedstatedir}/kdump -%ifnarch loongarch64 install -m 755 %{SOURCE1} $RPM_BUILD_ROOT%{_bindir}/kdumpctl -%else -install -m 755 %{SOURCE38} $RPM_BUILD_ROOT%{_bindir}/kdumpctl -%endif install -m 755 build/sbin/kexec $RPM_BUILD_ROOT/usr/sbin/kexec install -m 755 build/sbin/vmcore-dmesg $RPM_BUILD_ROOT/usr/sbin/vmcore-dmesg @@ -257,17 +225,15 @@ install -m 755 -D %{SOURCE22} $RPM_BUILD_ROOT%{_prefix}/lib/systemd/system-gener install -m 755 -D %{SOURCE32} $RPM_BUILD_ROOT%{_prefix}/lib/kernel/install.d/60-kdump.install -%ifarch %{ix86} x86_64 ppc64 s390x ppc64le aarch64 loongarch64 +%ifarch %{ix86} x86_64 ppc64 s390x ppc64le aarch64 install -m 755 makedumpfile-1.7.2/makedumpfile $RPM_BUILD_ROOT/usr/sbin/makedumpfile install -m 644 makedumpfile-1.7.2/makedumpfile.8 $RPM_BUILD_ROOT/%{_mandir}/man8/makedumpfile.8 install -m 644 makedumpfile-1.7.2/makedumpfile.conf.5 $RPM_BUILD_ROOT/%{_mandir}/man5/makedumpfile.conf.5 install -m 644 makedumpfile-1.7.2/makedumpfile.conf $RPM_BUILD_ROOT/%{_sysconfdir}/makedumpfile.conf.sample -%ifnarch loongarch64 install -m 755 makedumpfile-1.7.2/eppic_makedumpfile.so $RPM_BUILD_ROOT/%{_libdir}/eppic_makedumpfile.so mkdir -p $RPM_BUILD_ROOT/usr/share/makedumpfile/eppic_scripts/ install -m 644 makedumpfile-1.7.2/eppic_scripts/* $RPM_BUILD_ROOT/usr/share/makedumpfile/eppic_scripts/ %endif -%endif %define remove_dracut_prefix() %(echo -n %1|sed 's/.*dracut-//g') %define remove_dracut_early_kdump_prefix() %(echo -n %1|sed 's/.*dracut-early-kdump-//g') @@ -391,7 +357,7 @@ done %{_bindir}/* %{_datadir}/kdump %{_prefix}/lib/kdump -%ifarch %{ix86} x86_64 ppc64 s390x ppc64le aarch64 loongarch64 +%ifarch %{ix86} x86_64 ppc64 s390x ppc64le aarch64 %{_sysconfdir}/makedumpfile.conf.sample %endif %config(noreplace,missingok) %{_sysconfdir}/sysconfig/kdump @@ -415,14 +381,8 @@ done %{_unitdir}/kdump.service %{_prefix}/lib/systemd/system-generators/kdump-dep-generator.sh %{_prefix}/lib/kernel/install.d/60-kdump.install -%license COPYING -%ifarch %{ix86} x86_64 ppc64 s390x ppc64le aarch64 -%{_libdir}/eppic_makedumpfile.so -/usr/share/makedumpfile/ -%endif - -%files doc %doc News +%license COPYING %doc TODO %doc kexec-kdump-howto.txt %doc early-kdump-howto.txt @@ -430,16 +390,33 @@ done %doc supported-kdump-targets.txt %doc kdump-in-cluster-environment.txt %doc live-image-kdump-howto.txt +%ifarch %{ix86} x86_64 ppc64 s390x ppc64le aarch64 +%{_libdir}/eppic_makedumpfile.so +/usr/share/makedumpfile/ +%endif %changelog -* Tue Dec 05 2023 Youling Tang - 2.0.26-8.0.1 -- Add LoongArch support -- Add doc sub package (wb-zh951434@alibaba-inc.com) -- Fix kexec error for kexec -s (xiangzao@linux.alibaba.com) -- Reimplement loongarch64 support -- Add pstore segment (xiangzao@linux.alibaba.com) -- Fix loongarch kexec issue cause by pstore segment. (wangming01@loongson.cn) -- Fix loongarch build faild issue. (wangming01@loongson.cn) +* Tue Jun 18 2024 Pingfan Liu - 2.0.26-14.1 +- mkdumprd: Fix makedumpfile parameter check + +* Wed Feb 21 2024 Pingfan Liu - 2.0.26-14 +- dracut-module-setup: Skip initrd-cleanup and initrd-parse-etc in kdump + +* Fri Feb 2 2024 Pingfan Liu - 2.0.26-13 +- dracut-module-setup.sh: also install the driver of physical NIC for Hyper-V VM with accelerated networking + +* Wed Nov 22 2023 Pingfan Liu - 2.0.26-12 +- kdumpctl: Only returns immediately after an error occurs in check_*_modified + +* Thu Nov 9 2023 Pingfan Liu - 2.0.26-11 +- powerpc: update kdumpctl to load kernel signing key for fadump +- powerpc: update kdumpctl to remove deletion of kernel signing key once loaded + +* Tue Sep 26 2023 Pingfan Liu - 2.0.26-10 +- Introduce a function to get reserved memory size + +* Tue Sep 19 2023 Pingfan Liu - 2.0.26-9 +- Add lvm thin provision to kdump supported-kdump-targets.txt * Thu Aug 10 2023 Pingfan Liu - 2.0.26-8 - mkdumprd: Use the correct syntax to redirect the stderr to null diff --git a/loongarch64-fix-some-functional-issues-and-compilati.patch b/loongarch64-fix-some-functional-issues-and-compilati.patch deleted file mode 100644 index 7ecf4ff..0000000 --- a/loongarch64-fix-some-functional-issues-and-compilati.patch +++ /dev/null @@ -1,200 +0,0 @@ -From 7256b086a6016f846cdda5d24b12a6cb612af5f5 Mon Sep 17 00:00:00 2001 -From: Ming Wang -Date: Tue, 9 Jan 2024 09:45:17 +0800 -Subject: [PATCH] loongarch64: fix some functional issues and compilation - errors. - -1. kexec: __NR_kexec_file_load is set to undefined on LoongArch -2. Set up kernel image segment -3. Add 4.19 kernel handling -4. Add kexec-tools-2.0.26 kernel.org missing file(iomem.h). -5. Adjust kernel position alignment rules -6. Fix 4.19 kernel SECTION_BITS issue. - -Signed-off-by: Ming Wang ---- - kexec/arch/loongarch/crashdump-loongarch.c | 22 ++++++++++++++++++++++ - kexec/arch/loongarch/crashdump-loongarch.h | 1 + - kexec/arch/loongarch/iomem.h | 10 ++++++++++ - kexec/arch/loongarch/kexec-elf-loongarch.c | 12 ++++++++++++ - kexec/arch/loongarch/kexec-loongarch.c | 11 ++++++++--- - kexec/arch/loongarch/kexec-pei-loongarch.c | 7 +++++++ - kexec/kexec-syscall.h | 2 +- - makedumpfile-1.7.2/makedumpfile.h | 2 +- - 8 files changed, 62 insertions(+), 5 deletions(-) - create mode 100644 kexec/arch/loongarch/iomem.h - -diff --git a/kexec/arch/loongarch/crashdump-loongarch.c b/kexec/arch/loongarch/crashdump-loongarch.c -index aaf6cf3..81250e4 100644 ---- a/kexec/arch/loongarch/crashdump-loongarch.c -+++ b/kexec/arch/loongarch/crashdump-loongarch.c -@@ -183,6 +183,28 @@ int load_crashdump_segments(struct kexec_info *info) - return 0; - } - -+/* -+ * 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) -+{ -+ struct mem_phdr *phdr; -+ int i; -+ -+ ehdr->e_entry += crash_reserved_mem[usablemem_rgns.size - 1].start; -+ -+ 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; -+ } -+} -+ - int get_crash_kernel_load_range(uint64_t *start, uint64_t *end) - { - if (!usablemem_rgns.size) -diff --git a/kexec/arch/loongarch/crashdump-loongarch.h b/kexec/arch/loongarch/crashdump-loongarch.h -index 3eb4e0a..25ff24b 100644 ---- a/kexec/arch/loongarch/crashdump-loongarch.h -+++ b/kexec/arch/loongarch/crashdump-loongarch.h -@@ -8,6 +8,7 @@ extern struct memory_range elfcorehdr_mem; - - 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); - - #define PAGE_OFFSET 0x9000000000000000ULL -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 -index 2bf128f..0ac451e 100644 ---- a/kexec/arch/loongarch/kexec-elf-loongarch.c -+++ b/kexec/arch/loongarch/kexec-elf-loongarch.c -@@ -90,6 +90,14 @@ int elf_loongarch_load(int argc, char **argv, const char *kernel_buf, - } - } - -+ /* load the kernel */ -+ if (info->kexec_flags & KEXEC_ON_CRASH) -+ /* -+ * offset addresses in elf header in order to load -+ * vmlinux (elf_exec) into crash kernel's memory. -+ */ -+ fixup_elf_addrs(&ehdr); -+ - info->entry = (void *)virt_to_phys(ehdr.e_entry); - - result = elf_exec_load(&ehdr, info); -@@ -99,6 +107,10 @@ int elf_loongarch_load(int argc, char **argv, const char *kernel_buf, - goto exit; - } - -+ /* for vmlinuz kernel image */ -+ if (kernel_size < MiB(16)) -+ kernel_size = MiB(64); -+ - /* load additional data */ - result = loongarch_load_other_segments(info, kernel_segment + kernel_size); - -diff --git a/kexec/arch/loongarch/kexec-loongarch.c b/kexec/arch/loongarch/kexec-loongarch.c -index 4c7361c..51f334a 100644 ---- a/kexec/arch/loongarch/kexec-loongarch.c -+++ b/kexec/arch/loongarch/kexec-loongarch.c -@@ -221,6 +221,10 @@ int arch_process_options(int argc, char **argv) - 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"); -+ remove_parameter(cmdline, "nokaslr"); - break; - case OPT_INITRD: - arch_options.initrd_file = optarg; -@@ -253,8 +257,9 @@ unsigned long loongarch_locate_kernel_segment(struct kexec_info *info) - 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); -- hole = _ALIGN_UP(hole, MiB(1)); -+ mem_min : crash_reserved_mem[usablemem_rgns.size - 1].start) + -+ loongarch_mem.text_offset; -+ hole = _ALIGN_UP(hole, MiB(16)); - hole_end = hole + loongarch_mem.text_offset + loongarch_mem.image_size; - - if ((hole_end > mem_max) || -@@ -265,7 +270,7 @@ unsigned long loongarch_locate_kernel_segment(struct kexec_info *info) - } else { - hole = locate_hole(info, - loongarch_mem.text_offset + loongarch_mem.image_size, -- MiB(1), 0, ULONG_MAX, 1); -+ MiB(16), 0, ULONG_MAX, 1); - - if (hole == ULONG_MAX) - dbgprintf("%s: locate_hole failed\n", __func__); -diff --git a/kexec/arch/loongarch/kexec-pei-loongarch.c b/kexec/arch/loongarch/kexec-pei-loongarch.c -index f86ac61..1a11103 100644 ---- a/kexec/arch/loongarch/kexec-pei-loongarch.c -+++ b/kexec/arch/loongarch/kexec-pei-loongarch.c -@@ -66,6 +66,13 @@ int pei_loongarch_load(int argc, char **argv, const char *buf, - - 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__, -diff --git a/kexec/kexec-syscall.h b/kexec/kexec-syscall.h -index be6ccd5..1e2d12f 100644 ---- a/kexec/kexec-syscall.h -+++ b/kexec/kexec-syscall.h -@@ -59,7 +59,7 @@ - #endif - #endif /*ifndef __NR_kexec_load*/ - --#ifdef __arm__ -+#if defined(__arm__) || defined(__loongarch__) - #undef __NR_kexec_file_load - #endif - -diff --git a/makedumpfile-1.7.2/makedumpfile.h b/makedumpfile-1.7.2/makedumpfile.h -index 1b97d8c..5cb9a08 100644 ---- a/makedumpfile-1.7.2/makedumpfile.h -+++ b/makedumpfile-1.7.2/makedumpfile.h -@@ -1018,7 +1018,7 @@ typedef unsigned long pgd_t; - #define _PAGE_OFFSET (0x9000000000000000ULL) - #define _XKPRANGE (0x8000000000000000ULL) - #define _XKVRANGE (0xc000000000000000ULL) --#define _SECTION_SIZE_BITS (29) -+#define _SECTION_SIZE_BITS (28) - #define _MAX_PHYSMEM_BITS (48) - #define _PAGE_HUGE (1 << 6) /* HUGE is a PMD bit */ - #define _PAGE_PRESENT (1 << 7) --- -2.31.1 - diff --git a/mkdumprd b/mkdumprd index e5c6e06..6977d14 100644 --- a/mkdumprd +++ b/mkdumprd @@ -240,7 +240,7 @@ check_user_configured_target() # $1: core_collector config value verify_core_collector() { local _cmd="${1%% *}" - local _params="${1#* }" + local _params="${1#${_cmd}}" if [ "$_cmd" != "makedumpfile" ]; then if is_raw_dump_target; then diff --git a/supported-kdump-targets.txt b/supported-kdump-targets.txt index f540f59..ba20250 100644 --- a/supported-kdump-targets.txt +++ b/supported-kdump-targets.txt @@ -35,7 +35,8 @@ updating lists accordingly. Supported Dump targets ---------------------- storage: - LVM volume (no thinp) + LVM volume + Thin provisioning volume FC disks (qla2xxx, lpfc, bnx2fc, bfa) software initiator based iSCSI software RAID (mdraid) @@ -79,7 +80,6 @@ Unsupported Dump targets ------------------------ storage: BIOS RAID - Thin provisioning volume Software iSCSI with iBFT (bnx2i, cxgb3i, cxgb4i) Software iSCSI with hybrid (be2iscsi) FCoE -- Gitee From f29e2c13a7b5b9056de392d42b420469779e6290 Mon Sep 17 00:00:00 2001 From: Youling Tang Date: Tue, 12 Jul 2022 17:28:46 +0800 Subject: [PATCH 02/11] Add LoongArch support Signed-off-by: Youling Tang --- ...c-tools-2.0.22-Add-LoongArch-support.patch | 1465 +++++++++++++++++ ...2-makedumpfile-Add-LoongArch-support.patch | 223 +++ kexec-tools.spec | 29 +- 3 files changed, 1713 insertions(+), 4 deletions(-) create mode 100644 kexec-tools-2.0.22-Add-LoongArch-support.patch create mode 100644 kexec-tools-2.0.22-makedumpfile-Add-LoongArch-support.patch diff --git a/kexec-tools-2.0.22-Add-LoongArch-support.patch b/kexec-tools-2.0.22-Add-LoongArch-support.patch new file mode 100644 index 0000000..48e041d --- /dev/null +++ b/kexec-tools-2.0.22-Add-LoongArch-support.patch @@ -0,0 +1,1465 @@ +From f3f3ec14c775b46bd17056534c0588f54a310677 Mon Sep 17 00:00:00 2001 +From: Youling Tang +Date: Mon, 11 Jul 2022 17:22:42 +0800 +Subject: [PATCH] kexec-tools: Add LoongArch support + +Signed-off-by: Youling Tang +--- + config/config.guess | 3 + + config/config.sub | 4 + + configure.ac | 3 + + include/elf.h | 1 + + include/image.h | 1 + + kexec/Makefile | 1 + + kexec/arch/loongarch/Makefile | 27 ++ + kexec/arch/loongarch/crashdump-loongarch.c | 384 ++++++++++++++++++ + kexec/arch/loongarch/crashdump-loongarch.h | 24 ++ + kexec/arch/loongarch/include/arch/options.h | 43 ++ + kexec/arch/loongarch/kexec-elf-loongarch.c | 240 +++++++++++ + .../arch/loongarch/kexec-elf-rel-loongarch.c | 43 ++ + kexec/arch/loongarch/kexec-loongarch.c | 353 ++++++++++++++++ + kexec/arch/loongarch/kexec-loongarch.h | 40 ++ + kexec/kexec-syscall.h | 9 +- + kexec/kexec.c | 6 + + 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 + + 21 files changed, 1212 insertions(+), 1 deletion(-) + 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/include/arch/options.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 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 +--- a/config/config.guess ++++ b/config/config.guess +@@ -1039,6 +1039,9 @@ EOF + mips64el: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" + exit ;; +diff --git a/config/config.sub b/config/config.sub +index 9bc49a7..d5bbcc3 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 + | k1om \ + | le32 | le64 \ + | lm32 \ ++ | loongarch32 | loongarch64 | loongarchx32 \ + | m32c | m32r | m32rle \ + | m5200 | m68000 | m680[012346]0 | m68360 | m683?2 | m68k \ + | m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x \ +diff --git a/configure.ac b/configure.ac +index 3c5201f..7458d0e 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -58,6 +58,9 @@ case $target_cpu in + hppa*) + ARCH="hppa" + ;; ++ loongarch* ) ++ ARCH="loongarch" ++ ;; + * ) + AC_MSG_ERROR([unsupported architecture $target_cpu]) + ;; +diff --git a/include/elf.h b/include/elf.h +index b7677a2..ca42618 100644 +--- a/include/elf.h ++++ b/include/elf.h +@@ -260,6 +260,7 @@ typedef struct + #define EM_XTENSA 94 /* Tensilica Xtensa Architecture */ + #define EM_AARCH64 183 /* ARM AARCH64 */ + #define EM_NUM 184 ++#define EM_LOONGARCH 258 /* Loongson Loongarch*/ + + /* 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 ++++ b/include/image.h +@@ -86,6 +86,7 @@ + #define IH_ARCH_ARC 23 /* Synopsys DesignWare ARC */ + #define IH_ARCH_X86_64 24 /* AMD x86_64, Intel and Via */ + #define IH_ARCH_XTENSA 25 /* Xtensa */ ++#define IH_ARCH_LOONGARCH 26 /* LoongArch Loongson */ + + /* + * Image Types +diff --git a/kexec/Makefile b/kexec/Makefile +index 8e3e9ea..803b41a 100644 +--- a/kexec/Makefile ++++ b/kexec/Makefile +@@ -93,6 +93,7 @@ include $(srcdir)/kexec/arch/s390/Makefile + include $(srcdir)/kexec/arch/sh/Makefile + include $(srcdir)/kexec/arch/x86_64/Makefile + include $(srcdir)/kexec/arch/hppa/Makefile ++include $(srcdir)/kexec/arch/loongarch/Makefile + + KEXEC_SRCS += $($(ARCH)_KEXEC_SRCS) + +diff --git a/kexec/arch/loongarch/Makefile b/kexec/arch/loongarch/Makefile +new file mode 100644 +index 0000000..05ec5ca +--- /dev/null ++++ b/kexec/arch/loongarch/Makefile +@@ -0,0 +1,27 @@ ++# ++# 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-elf-rel-loongarch.c ++loongarch_KEXEC_SRCS += kexec/arch/loongarch/crashdump-loongarch.c ++ ++loongarch_DT_OPS += kexec/dt-ops.c ++ ++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/crashdump-loongarch.h \ ++ kexec/arch/loongarch/include/arch/options.h ++ ++ifdef HAVE_LIBFDT ++LIBS += -lfdt ++else ++include $(srcdir)/kexec/libfdt/Makefile.libfdt ++libfdt_SRCS += $(LIBFDT_SRCS:%=kexec/libfdt/%) ++loongarch_CPPFLAGS += -I$(srcdir)/kexec/libfdt ++loongarch_KEXEC_SRCS += $(libfdt_SRCS) ++endif +diff --git a/kexec/arch/loongarch/crashdump-loongarch.c b/kexec/arch/loongarch/crashdump-loongarch.c +new file mode 100644 +index 0000000..4c3a760 +--- /dev/null ++++ b/kexec/arch/loongarch/crashdump-loongarch.c +@@ -0,0 +1,384 @@ ++/* ++ * kexec: Linux boots Linux ++ * ++ * Copyright (C) 2021 Loongson Technology Co., Ltd. ++ * ++ * 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 ++#include ++#include ++#include "../../kexec.h" ++#include "../../kexec-elf.h" ++#include "../../kexec-syscall.h" ++#include "../../crashdump.h" ++#include "kexec-loongarch.h" ++#include "crashdump-loongarch.h" ++#include "unused.h" ++ ++/* ++ * 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]; ++ ++/* Memory region reserved for storing panic kernel and other data. */ ++struct memory_range crash_reserved_mem; ++ ++/* ++ * Read kernel physical load addr from the file returned by proc_iomem() ++ * (Kernel Code) and store in kexec_info ++ */ ++static int get_kernel_paddr(struct crash_elf_info *elf_info) ++{ ++ uint64_t start; ++ ++ if (xen_present()) /* Kernel not entity mapped under Xen */ ++ 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; ++ } ++ ++ fprintf(stderr, "Cannot determine kernel physical load addr\n"); ++ return -1; ++} ++ ++static int get_kernel_vaddr_and_size(struct crash_elf_info *elf_info, ++ unsigned long start_offset) ++{ ++ uint64_t end; ++ ++ 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" ++ */ ++ 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; ++ } ++ ++ fprintf(stderr, "Cannot determine kernel virtual load addr and size\n"); ++ return -1; ++} ++ ++/* ++ * 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 ++ }; ++ ++ /* 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; ++ } ++ } ++ } ++ ++ /* 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; ++ } ++ ++ for (j = (*nr_ranges - 1); j >= tidx; j--) ++ crash_memory_range[j+1] = crash_memory_range[j]; ++ ++ 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)++; ++ } ++ ++ 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. ++ * ++ * 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. ++ */ ++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++; ++ ++ 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; ++ ++ /* 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; ++ } ++ ++ if (start == BACKUP_SRC_START && end >= (BACKUP_SRC_END + 1)) ++ start = BACKUP_SRC_END + 1; ++ ++ crash_memory_range[memory_ranges].start = start; ++ crash_memory_range[memory_ranges].end = end; ++ crash_memory_range[memory_ranges].type = type; ++ memory_ranges++; ++ ++ /* Segregate linearly mapped region. */ ++ if (MAXMEM && (MAXMEM - 1) >= start && (MAXMEM - 1) <= end) { ++ crash_memory_range[memory_ranges - 1].end = MAXMEM - 1; ++ ++ /* 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); ++ ++ if (exclude_crash_reserve_region(&memory_ranges) < 0) ++ return -1; ++ ++ *range = crash_memory_range; ++ *ranges = memory_ranges; ++ ++ return 0; ++} ++ ++/* Converts unsigned long to ascii string. */ ++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; ++ } ++} ++ ++/* 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) ++{ ++ 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"); ++ ++ add_cmdline(cmdline, str); ++ ++ return 0; ++} ++ ++/* 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; ++ ++ addr = addr / align; ++ ptr = str; ++ strcpy(str, " elfcorehdr="); ++ ptr += strlen(str); ++ ultoa(addr, ptr); ++ strcat(str, "K"); ++ ++ add_cmdline(cmdline, str); ++ ++ return 0; ++} ++ ++ ++static struct crash_elf_info elf_info64 = { ++ class: ELFCLASS64, ++ data : ELFDATA2LSB, ++ machine : EM_LOONGARCH, ++ page_offset : PAGE_OFFSET, ++ lowmem_limit : 0, /* 0 == no limit */ ++}; ++ ++/* ++ * 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. ++ */ ++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 (get_crash_memory_ranges(&mem_range, &nr_ranges) < 0) ++ return -1; ++ ++ 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; ++ } ++ ++ elfcorehdr = add_buffer(info, tmp, sz, sz, align, min_base, max_addr, -1); ++ ++ /* ++ * 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); ++ ++ dbgprintf("CRASH MEMORY RANGES:\n"); ++ dbgprintf("%016lx-%016lx\n", min_base, max_addr); ++ ++ return 0; ++} +diff --git a/kexec/arch/loongarch/crashdump-loongarch.h b/kexec/arch/loongarch/crashdump-loongarch.h +new file mode 100644 +index 0000000..a75310f +--- /dev/null ++++ b/kexec/arch/loongarch/crashdump-loongarch.h +@@ -0,0 +1,24 @@ ++#ifndef CRASHDUMP_LOONGARCH_H ++#define CRASHDUMP_LOONGARCH_H ++ ++struct kexec_info; ++extern struct memory_range crash_reserved_mem; ++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); ++ ++#define PAGE_OFFSET 0x9000000000000000ULL ++#define MAXMEM 0 ++ ++#define CRASH_MAX_MEMMAP_NR (KEXEC_MAX_SEGMENTS + 1) ++#define CRASH_MAX_MEMORY_RANGES (MAX_MEMORY_RANGES + 2) ++ ++#define COMMAND_LINE_SIZE 512 ++ ++/* 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) ++ ++extern struct arch_options_t arch_options; ++#endif /* CRASHDUMP_LOONGARCH_H */ +diff --git a/kexec/arch/loongarch/include/arch/options.h b/kexec/arch/loongarch/include/arch/options.h +new file mode 100644 +index 0000000..8f105a1 +--- /dev/null ++++ b/kexec/arch/loongarch/include/arch/options.h +@@ -0,0 +1,43 @@ ++#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_DTB (OPT_ARCH_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}, \ ++ {"dtb", 1, 0, OPT_DTB}, ++ ++ ++#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 ++ ++#define KEXEC_ALL_OPT_STR KEXEC_ARCH_OPT_STR ++ ++#endif /* KEXEC_ARCH_LOONGARCH_OPTIONS_H */ +diff --git a/kexec/arch/loongarch/kexec-elf-loongarch.c b/kexec/arch/loongarch/kexec-elf-loongarch.c +new file mode 100644 +index 0000000..4e37f27 +--- /dev/null ++++ b/kexec/arch/loongarch/kexec-elf-loongarch.c +@@ -0,0 +1,240 @@ ++/* ++ * kexec-elf-loongarch.c - kexec Elf loader for loongarch ++ * ++ * Copyright (C) 2021 Loongson Technology Co., Ltd. ++ * ++ * 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 "crashdump-loongarch.h" ++#include "kexec-loongarch.h" ++#include ++ ++ ++off_t initrd_base = 0; ++off_t initrd_size = 0; ++ ++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) ++{ ++ struct mem_ehdr ehdr; ++ int result; ++ result = build_elf_exec_info(buf, len, &ehdr, 0); ++ if (result < 0) { ++ if (probe_debug) ++ fprintf(stderr, "Not an ELF executable.\n"); ++ goto out; ++ } ++ ++ /* 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"); ++ } ++ result = -1; ++ goto out; ++ } ++ result = 0; ++ 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" ++ " --dtb=FILE Use FILE as the device tree blob.\n" ++ ); ++} ++ ++int elf_loongarch_load(int argc, char **argv, const char *buf, off_t len, ++ struct kexec_info *info) ++{ ++ 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(); ++ unsigned long initrd_min, hole_max, hole_min = 0; ++ ++ /* ++ * 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(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; ++ hole_min = kernel_addr + kernel_size; ++ } ++ } ++ ++ /* Load the Elf data */ ++ result = elf_exec_load(&ehdr, info); ++ if (result < 0) ++ die("ELF exec load failed\n"); ++ ++ info->entry = (void *)virt_to_phys(ehdr.e_entry); ++ ++ if (arch_options.command_line) ++ command_line_len = strlen(arch_options.command_line) + 1; ++ ++ get_crash_kernel_load_range((uint64_t *)&crash_reserved_mem.start, ++ (uint64_t *)&crash_reserved_mem.end); ++ ++ initrd_min = hole_min; ++ if (info->kexec_flags & KEXEC_ON_CRASH) { ++ hole_max = crash_reserved_mem.end; ++ } else { ++ hole_max = ULONG_MAX; ++ /* ++ * Avoid initrd and crashkernel area conflicts when performing ++ * kexec operations. ++ */ ++ if (crash_reserved_mem.end) ++ initrd_min = crash_reserved_mem.end; ++ } ++ ++ if (info->kexec_flags & KEXEC_ON_CRASH) { ++ result = load_crashdump_segments(info, crash_cmdline, hole_max, 0); ++ if (result < 0) { ++ free(crash_cmdline); ++ return -1; ++ } ++ } ++ ++ 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); ++ } ++ ++ if (info->kexec_flags & KEXEC_ON_CRASH) ++ /* ++ * In case of crashdump segment[0] is kernel. ++ * Put cmdline just after it. ++ */ ++ cmdline_addr = (unsigned long)info->segment[0].mem + ++ info->segment[0].memsz; ++ else ++ cmdline_addr = 0x10000; /* Skip exception handlers */ ++ ++ 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); ++ 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); ++ } ++ ++ /* 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, hole_max, 1); ++ dbgprintf("command line: %s\n", cmdline_buf); ++ /* Prepare and load dtb data */ ++ result = loongarch_load_dtb_segment(info, hole_min, initrd_base, initrd_size, cmdline_buf); ++ if(result) { ++ fprintf(stderr, "kexec: Load dtb segments failed.\n"); ++ return result; ++ } ++ ++ ++ return 0; ++} ++ +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 +--- /dev/null ++++ b/kexec/arch/loongarch/kexec-elf-rel-loongarch.c +@@ -0,0 +1,43 @@ ++/* ++ * kexec-elf-rel-loongarch.c - kexec Elf relocation routines ++ * ++ * Copyright (C) 2021 Loongson Technology Co., Ltd. ++ * ++ * This source code is licensed under the GNU General Public License, ++ * Version 2. See the file COPYING for more details. ++*/ ++ ++#include ++#include ++#include "../../kexec.h" ++#include "../../kexec-elf.h" ++ ++int machine_verify_elf_rel(struct mem_ehdr *ehdr) ++{ ++ if (ehdr->ei_data != ELFDATA2MSB) { ++ return 0; ++ } ++ if (ehdr->ei_class != ELFCLASS32) { ++ return 0; ++ } ++ if (ehdr->e_machine != EM_LOONGARCH) { ++ return 0; ++ } ++ return 1; ++} ++ ++void machine_apply_elf_rel(struct mem_ehdr *UNUSED(ehdr), ++ struct mem_sym *UNUSED(sym), ++ unsigned long r_type, ++ void *UNUSED(location), ++ unsigned long UNUSED(address), ++ unsigned long UNUSED(value)) ++{ ++ 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..2029a19 +--- /dev/null ++++ b/kexec/arch/loongarch/kexec-loongarch.c +@@ -0,0 +1,353 @@ ++/* ++ * kexec-loongarch.c - kexec for loongarch ++ * ++ * Copyright (C) 2021 Loongson Technology Co., Ltd. ++ * ++ * 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 ++#include "../../kexec.h" ++#include "../../kexec-syscall.h" ++#include "../../dt-ops.h" ++#include "kexec-loongarch.h" ++#include ++ ++/* Return a sorted list of memory ranges. */ ++static struct memory_range memory_range[MAX_MEMORY_RANGES]; ++ ++int get_memory_ranges(struct memory_range **range, int *ranges, ++ unsigned long UNUSED(kexec_flags)) ++{ ++ int memory_ranges = 0; ++ ++ const char *iomem = proc_iomem(); ++ char line[MAX_LINE]; ++ FILE *fp; ++ unsigned long long start, end; ++ char *str; ++ int type, consumed, count; ++ ++ fp = fopen(iomem, "r"); ++ if (!fp) { ++ 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; ++ count = sscanf(line, "%llx-%llx : %n", &start, &end, &consumed); ++ if (count != 2) ++ continue; ++ str = line + consumed; ++ end = end + 1; ++ if (memcmp(str, "System RAM\n", 11) == 0) { ++ type = RANGE_RAM; ++ } else if (memcmp(str, "reserved\n", 9) == 0) { ++ type = RANGE_RESERVED; ++ } else { ++ continue; ++ } ++ if (memory_ranges > 0 && ++ memory_range[memory_ranges - 1].end == start && ++ memory_range[memory_ranges - 1].type == type) { ++ memory_range[memory_ranges - 1].end = end; ++ } else { ++ memory_range[memory_ranges].start = start; ++ memory_range[memory_ranges].end = end; ++ memory_range[memory_ranges].type = type; ++ memory_ranges++; ++ } ++ } ++ fclose(fp); ++ *range = memory_range; ++ *ranges = memory_ranges; ++ return 0; ++} ++ ++struct file_type file_type[] = { ++ {"elf-loongarch", elf_loongarch_probe, elf_loongarch_load, elf_loongarch_usage}, ++}; ++int file_types = sizeof(file_type) / sizeof(file_type[0]); ++ ++void arch_usage(void) ++{ ++} ++ ++struct arch_options_t arch_options = { ++ .core_header_type = CORE_TYPE_ELF64, ++}; ++ ++int arch_process_options(int argc, char **argv) ++{ ++ 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: ++ append = optarg; ++ break; ++ case OPT_REUSE_CMDLINE: ++ cmdline = get_command_line(); ++ break; ++ case OPT_RAMDISK: ++ arch_options.initrd_file = optarg; ++ break; ++ case OPT_DTB: ++ arch_options.dtb = optarg; ++ default: ++ break; ++ } ++ } ++ ++ 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; ++} ++ ++const struct arch_map_entry arches[] = { ++ { "loongarch64", KEXEC_ARCH_LOONGARCH }, ++ { NULL, 0 }, ++}; ++ ++/* ++ * struct dtb - Info about a binary device tree. ++ * ++ * @buf: Device tree data. ++ * @size: Device tree data size. ++ * @name: Shorthand name of this dtb for messages. ++ * @path: Filesystem path. ++ */ ++ ++struct dtb { ++ char *buf; ++ off_t size; ++ const char *name; ++ const char *path; ++}; ++ ++/* ++ * set_bootargs - Set the dtb's bootargs. ++ */ ++ ++static int set_bootargs(struct dtb *dtb, const char *command_line) ++{ ++ int result; ++ ++ if (!command_line || !command_line[0]) ++ return 0; ++ ++ result = dtb_set_bootargs(&dtb->buf, &dtb->size, command_line); ++ ++ if (result) { ++ fprintf(stderr, ++ "kexec: Set device tree bootargs failed.\n"); ++ return EFAILED; ++ } ++ ++ return 0; ++} ++ ++/* ++ * read_sys_dtb - Read /sys/firmware/fdt. ++ */ ++ ++static int read_sys_dtb(struct dtb *dtb) ++{ ++ int result; ++ struct stat s; ++ static const char path[] = "/sys/firmware/fdt"; ++ ++ result = stat(path, &s); ++ ++ if (result) { ++ dbgprintf("%s: %s\n", __func__, strerror(errno)); ++ /* ++ * Returning an error directly will result in incompatibility ++ * with older firmware. ++ */ ++ return 1; ++ } ++ ++ dtb->path = path; ++ dtb->buf = slurp_file(path, &dtb->size); ++ ++ return 0; ++} ++ ++/* ++ * read_1st_dtb - Read the 1st stage kernel's dtb. ++ */ ++ ++static int read_1st_dtb(struct dtb *dtb) ++{ ++ int result; ++ ++ dtb->name = "dtb_sys"; ++ result = read_sys_dtb(dtb); ++ ++ if (!result) ++ goto on_success; ++ ++ dbgprintf("%s: not found\n", __func__); ++ return EFAILED; ++ ++on_success: ++ dbgprintf("%s: found %s\n", __func__, dtb->path); ++ return 0; ++} ++ ++/* ++ * setup_2nd_dtb - Setup the 2nd stage kernel's dtb. ++ */ ++ ++static int setup_2nd_dtb(struct dtb *dtb, char *command_line) ++{ ++ int result; ++ ++ result = fdt_check_header(dtb->buf); ++ ++ if (result) { ++ fprintf(stderr, "kexec: Invalid 2nd device tree.\n"); ++ return EFAILED; ++ } ++ ++ result = set_bootargs(dtb, command_line); ++ if (result) { ++ fprintf(stderr, "kexec: cannot set bootargs.\n"); ++ result = -EINVAL; ++ goto on_error; ++ } ++ ++ return result; ++ ++on_error: ++ fprintf(stderr, "kexec: %s failed.\n", __func__); ++ return result; ++} ++ ++/* ++ * loongarch_load_dtb_segment - Prepare the dtb segment. ++ */ ++ ++int loongarch_load_dtb_segment(struct kexec_info *info, unsigned long hole_min, ++ unsigned long initrd_base, unsigned long initrd_size, char *command_line) ++{ ++ int result; ++ unsigned long dtb_base; ++ struct dtb dtb; ++ ++ if (arch_options.dtb) { ++ dtb.name = "dtb_user"; ++ dtb.buf = slurp_file(arch_options.dtb, &dtb.size); ++ } else { ++ result = read_1st_dtb(&dtb); ++ ++ /* ++ * Returning an error directly will result in incompatibility ++ * with older firmware. ++ */ ++ if (result) ++ return 0; ++ } ++ ++ result = setup_2nd_dtb(&dtb, command_line); ++ if (result) ++ return EFAILED; ++ ++ if (arch_options.initrd_file) { ++ result = dtb_set_initrd((char **)&dtb.buf, &dtb.size, initrd_base, ++ initrd_base + initrd_size); ++ if (result) ++ return EFAILED; ++ } ++ ++ /* Check size limit. */ ++ if (dtb.size > KiB(64)) { ++ fprintf(stderr, "kexec: Error: dtb too big.\n"); ++ return EFAILED; ++ } ++ ++ dtb_base = add_buffer(info, dtb.buf, dtb.size, dtb.size, ++ sizeof(void *), _ALIGN_UP(hole_min, getpagesize()), ++ 0xffffffff, 1); ++ ++ /* dtb_base is valid if we got here. */ ++ dbgprintf("dtb: base %lx, size %lxh (%ld)\n", dtb_base, dtb.size, ++ dtb.size); ++ ++ return 0; ++ ++} ++ ++int arch_compat_trampoline(struct kexec_info *UNUSED(info)) ++{ ++ return 0; ++} ++ ++void arch_update_purgatory(struct kexec_info *UNUSED(info)) ++{ ++} ++ ++unsigned long virt_to_phys(unsigned long addr) ++{ ++ return addr & ((1ULL << 48) - 1); ++} ++ ++/* ++ * add_segment() should convert base to a physical address on loongarch, ++ * while the default is just to work with base as is ++ */ ++void add_segment(struct kexec_info *info, const void *buf, size_t bufsz, ++ unsigned long base, size_t memsz) ++{ ++ add_segment_phys_virt(info, buf, bufsz, virt_to_phys(base), memsz, 1); ++} ++ ++/* ++ * add_buffer() should convert base to a physical address on loongarch, ++ * while the default is just to work with base as is ++ */ ++unsigned long add_buffer(struct kexec_info *info, const void *buf, ++ unsigned long bufsz, unsigned long memsz, ++ unsigned long buf_align, unsigned long buf_min, ++ unsigned long buf_max, int buf_end) ++{ ++ 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..93ee3b9 +--- /dev/null ++++ b/kexec/arch/loongarch/kexec-loongarch.h +@@ -0,0 +1,40 @@ ++#ifndef KEXEC_LOONGARCH_H ++#define KEXEC_LOONGARCH_H ++ ++#include ++ ++#define BOOT_BLOCK_VERSION 17 ++#define BOOT_BLOCK_LAST_COMP_VERSION 16 ++ ++#define MAX_MEMORY_RANGES 64 ++#define MAX_LINE 160 ++ ++#define CORE_TYPE_ELF32 1 ++#define CORE_TYPE_ELF64 2 ++ ++#define COMMAND_LINE_SIZE 512 ++ ++#define KiB(x) ((x) * 1024UL) ++ ++int elf_loongarch_probe(const char *buf, off_t len); ++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 loongarch_load_dtb_segment(struct kexec_info *info, unsigned long hole_min, ++ unsigned long initrd_base, unsigned long initrd_size, char *command_line); ++ ++ ++struct arch_options_t { ++ char *command_line; ++ char *initrd_file; ++ char *dtb; ++ int core_header_type; ++}; ++ ++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/kexec-syscall.h b/kexec/kexec-syscall.h +index bea29d4..25a2b30 100644 +--- a/kexec/kexec-syscall.h ++++ b/kexec/kexec-syscall.h +@@ -4,7 +4,6 @@ + #define __LIBRARY__ + #include + #include +- + #define LINUX_REBOOT_CMD_KEXEC_OLD 0x81726354 + #define LINUX_REBOOT_CMD_KEXEC_OLD2 0x18263645 + #define LINUX_REBOOT_CMD_KEXEC 0x45584543 +@@ -51,6 +50,9 @@ + #ifdef __alpha__ + #define __NR_kexec_load 448 + #endif ++#ifdef __loongarch__ ++#define __NR_kexec_load 104 ++#endif + #ifndef __NR_kexec_load + #error Unknown processor architecture. Needs a kexec_load syscall number. + #endif +@@ -107,6 +109,7 @@ static inline long kexec_file_load(int kernel_fd, int initrd_fd, + cmdline_len, cmdline_ptr, flags); + } + ++ + #define KEXEC_ON_CRASH 0x00000001 + #define KEXEC_PRESERVE_CONTEXT 0x00000002 + #define KEXEC_ARCH_MASK 0xffff0000 +@@ -134,6 +137,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) ++#define KEXEC_ARCH_LOONGARCH (258 << 16) + + #define KEXEC_MAX_SEGMENTS 16 + +@@ -177,5 +181,8 @@ static inline long kexec_file_load(int kernel_fd, int initrd_fd, + #if defined(__arm64__) + #define KEXEC_ARCH_NATIVE KEXEC_ARCH_ARM64 + #endif ++#if defined(__loongarch__) ++#define KEXEC_ARCH_NATIVE KEXEC_ARCH_LOONGARCH ++#endif + + #endif /* KEXEC_SYSCALL_H */ +diff --git a/kexec/kexec.c b/kexec/kexec.c +index fd7c8d2..ee892dc 100644 +--- a/kexec/kexec.c ++++ b/kexec/kexec.c +@@ -1202,8 +1202,14 @@ char *get_command_line(void) + *p = '\0'; + + remove_parameter(line, "BOOT_IMAGE"); ++ remove_parameter(line, "kexec"); + if (kexec_flags & KEXEC_ON_CRASH) + remove_parameter(line, "crashkernel"); ++ /* Only for Loongson platform */ ++ remove_parameter(line, "rd_start"); ++ remove_parameter(line, "rd_size"); ++ remove_parameter(line, "initrd"); ++ remove_parameter(line, "e1000e.InterruptThrottleRate"); + + return line; + } +diff --git a/purgatory/Makefile b/purgatory/Makefile +index 2dd6c47..f24cae0 100644 +--- a/purgatory/Makefile ++++ b/purgatory/Makefile +@@ -28,6 +28,7 @@ include $(srcdir)/purgatory/arch/ppc64/Makefile + include $(srcdir)/purgatory/arch/s390/Makefile + include $(srcdir)/purgatory/arch/sh/Makefile + include $(srcdir)/purgatory/arch/x86_64/Makefile ++include $(srcdir)/purgatory/arch/loongarch/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 +--- /dev/null ++++ b/purgatory/arch/loongarch/Makefile +@@ -0,0 +1,10 @@ ++# ++# Purgatory loongarch ++# ++ ++loongarch_PURGATORY_SRCS+= purgatory/arch/loongarch/purgatory-loongarch.c ++loongarch_PURGATORY_SRCS+= purgatory/arch/loongarch/console-loongarch.c ++ ++dist += purgatory/arch/loongarch/Makefile $(loongarch_PURGATORY_SRCS) \ ++ purgatory/arch/loongarch/purgatory-loongarch.h ++ +diff --git a/purgatory/arch/loongarch/console-loongarch.c b/purgatory/arch/loongarch/console-loongarch.c +new file mode 100644 +index 0000000..af34ecf +--- /dev/null ++++ b/purgatory/arch/loongarch/console-loongarch.c +@@ -0,0 +1,7 @@ ++#include ++#include "unused.h" ++ ++void putchar(int UNUSED(ch)) ++{ ++ /* Nothing for now */ ++} +diff --git a/purgatory/arch/loongarch/purgatory-loongarch.c b/purgatory/arch/loongarch/purgatory-loongarch.c +new file mode 100644 +index 0000000..abe9297 +--- /dev/null ++++ b/purgatory/arch/loongarch/purgatory-loongarch.c +@@ -0,0 +1,7 @@ ++#include ++#include "purgatory-loongarch.h" ++ ++void setup_arch(void) ++{ ++ /* Nothing for now */ ++} +diff --git a/purgatory/arch/loongarch/purgatory-loongarch.h b/purgatory/arch/loongarch/purgatory-loongarch.h +new file mode 100644 +index 0000000..cd1ab97 +--- /dev/null ++++ b/purgatory/arch/loongarch/purgatory-loongarch.h +@@ -0,0 +1,6 @@ ++#ifndef PURGATORY_LOONGARCH_H ++#define PURGATORY_LOONGARCH_H ++ ++/* nothing yet */ ++ ++#endif /* PURGATORY_LOONGARCH_H */ +-- +2.20.1 + diff --git a/kexec-tools-2.0.22-makedumpfile-Add-LoongArch-support.patch b/kexec-tools-2.0.22-makedumpfile-Add-LoongArch-support.patch new file mode 100644 index 0000000..2853034 --- /dev/null +++ b/kexec-tools-2.0.22-makedumpfile-Add-LoongArch-support.patch @@ -0,0 +1,223 @@ +From 5b8abae46e753729d69bd72c754843cfa2241653 Mon Sep 17 00:00:00 2001 +From: Youling Tang +Date: Mon, 11 Jul 2022 17:11:16 +0800 +Subject: [PATCH] makedumpfile: Add LoongArch support + +Signed-off-by: Youling Tang +--- + makedumpfile-1.7.1/Makefile | 2 +- + makedumpfile-1.7.1/arch/loongarch64.c | 108 +++++++++++++++++++++++++++++++++++++++++++++ + makedumpfile-1.7.1/makedumpfile.h | 55 +++++++++++++++++++++++ + 3 files changed, 164 insertions(+), 1 deletion(-) + create mode 100644 arch/loongarch64.c + +diff --git a/makedumpfile-1.7.1/Makefile b/makedumpfile-1.7.1/Makefile +index 6fa00bc..e91117b 100644 +--- a/makedumpfile-1.7.1/Makefile ++++ b/makedumpfile-1.7.1/Makefile +@@ -47,7 +47,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 detect_cycle.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.1/arch/loongarch64.c b/makedumpfile-1.7.1/arch/loongarch64.c +new file mode 100644 +index 0000000..338da6b +--- /dev/null ++++ b/makedumpfile-1.7.1/arch/loongarch64.c +@@ -0,0 +1,108 @@ ++/* ++ * loongarch64.c ++ * ++ * Copyright (C) 2021 Loongson Technology Co., Ltd. ++ * ++ * 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 ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program 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. ++ */ ++#ifdef __loongarch64 ++ ++#include "../print_info.h" ++#include "../elf_info.h" ++#include "../makedumpfile.h" ++ ++int ++get_phys_base_loongarch64(void) ++{ ++ info->phys_base = 0ULL; ++ ++ DEBUG_MSG("phys_base : %lx\n", info->phys_base); ++ ++ return TRUE; ++} ++ ++int ++get_machdep_info_loongarch64(void) ++{ ++ 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; ++ ++ DEBUG_MSG("max_physmem_bits : %ld\n", info->max_physmem_bits); ++ DEBUG_MSG("section_size_bits: %ld\n", info->section_size_bits); ++ ++ return TRUE; ++} ++ ++int ++get_versiondep_info_loongarch64(void) ++{ ++ info->page_offset = 0x9000000000000000ULL; ++ ++ DEBUG_MSG("page_offset : %lx\n", info->page_offset); ++ ++ 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; ++ ++ if(vaddr >=0x8000000000000000ULL && vaddr < 0xc000000000000000ULL) ++ return vaddr & ((1ULL << MAX_PHYSMEM_BITS()) - 1); ++ ++ if (SYMBOL(swapper_pg_dir) == NOT_FOUND_SYMBOL) { ++ ERRMSG("Can't get the symbol of swapper_pg_dir.\n"); ++ return NOT_PADDR; ++ } ++ ++ pgda = pgd_offset(SYMBOL(swapper_pg_dir), vaddr); ++ if (!readmem(VADDR, (unsigned long long)pgda, &pgdv, sizeof(pgdv))) { ++ ERRMSG("Can't read pgd\n"); ++ return NOT_PADDR; ++ } ++ ++ pmda = pmd_offset(&pgdv, vaddr); ++ if (!readmem(VADDR, (unsigned long long)pmda, &pmdv, sizeof(pmdv))) { ++ ERRMSG("Can't read pmd\n"); ++ return NOT_PADDR; ++ } ++ ++ if (pmdv & _PAGE_HUGE) { ++ paddr = (pmdv & PMD_MASK) + (vaddr & (PMD_SIZE - 1)); ++ return paddr; ++ } ++ ++ ptea = pte_offset(&pmdv, vaddr); ++ if (!readmem(VADDR, (unsigned long long)ptea, &ptev, sizeof(ptev))) { ++ ERRMSG("Can't read pte\n"); ++ return NOT_PADDR; ++ } ++ ++ if (!(ptev & _PAGE_PRESENT)) { ++ ERRMSG("Can't get a valid pte.\n"); ++ return NOT_PADDR; ++ } else { ++ paddr = PAGEBASE(ptev) + (vaddr & (PAGESIZE() - 1)); ++ } ++ ++ return paddr; ++} ++ ++#endif /* loongarch64 */ +diff --git a/makedumpfile-1.7.1/makedumpfile.h b/makedumpfile-1.7.1/makedumpfile.h +index 93aa774..fcdc778 100644 +--- a/makedumpfile-1.7.1/makedumpfile.h ++++ b/makedumpfile-1.7.1/makedumpfile.h +@@ -991,6 +991,39 @@ typedef unsigned long pgd_t; + + #endif /* mips64 */ + ++#ifdef __loongarch64 ++#define KVBASE (0x8000000000000000UL) ++#define _SECTION_SIZE_BITS (28) ++#define _MAX_PHYSMEM_BITS (48) ++#define _PAGE_PRESENT (1 << 7) ++#define _PAGE_HUGE (1 << 6) ++ ++typedef unsigned long pte_t; ++typedef unsigned long pmd_t; ++typedef unsigned long pgd_t; ++ ++#define PAGE_MASK (~(PAGESIZE() - 1)) ++#define PMD_MASK (~(PMD_SIZE - 1)) ++#define PMD_SHIFT ((PAGESHIFT() - 3) * 2 + 3) ++#define PMD_SIZE (1UL << PMD_SHIFT) ++#define PGDIR_SHIFT ((PAGESHIFT() - 3) * 3 + 3) ++#define PTRS_PER_PTE (1 << (PAGESHIFT() - 3)) ++#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 pmd_page_paddr(pmd) (pmd & (int32_t)PAGE_MASK) ++#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_offset(pgdir, vaddr) ((pgd_t *)(pgdir) + pgd_index(vaddr)) ++ ++#endif /* loongarch64 */ ++ + /* + * The function of dependence on machine + */ +@@ -1162,6 +1195,22 @@ unsigned long long vaddr_to_paddr_mips64(unsigned long vaddr); + #define arch_crashkernel_mem_size() stub_false() + #endif /* mips64 */ + ++#ifdef __loongarch64 /* loongarch64 */ ++int get_phys_base_loongarch64(void); ++int get_machdep_info_loongarch64(void); ++int get_versiondep_info_loongarch64(void); ++unsigned long long vaddr_to_paddr_loongarch64(unsigned long vaddr); ++#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_kaslr_offset(X) stub_false() ++#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 */ ++ + typedef unsigned long long mdf_pfn_t; + + #ifndef ARCH_PFN_OFFSET +@@ -2286,6 +2335,12 @@ int get_xen_info_ia64(void); + #define get_xen_info_arch(X) FALSE + #endif /* mips64 */ + ++#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 */ ++ + struct cycle { + mdf_pfn_t start_pfn; + mdf_pfn_t end_pfn; +-- +2.20.1 + diff --git a/kexec-tools.spec b/kexec-tools.spec index 4baaa28..5f5b43b 100644 --- a/kexec-tools.spec +++ b/kexec-tools.spec @@ -1,6 +1,8 @@ +%define anolis_release .0.1 + Name: kexec-tools Version: 2.0.26 -Release: 14%{?dist}.1 +Release: 14%{anolis_release}%{?dist}.1 License: GPLv2 Group: Applications/System Summary: The kexec/kdump userspace component @@ -21,7 +23,9 @@ Source14: 98-kexec.rules.ppc64 Source15: kdump.conf.5 Source16: kdump.service Source18: kdump.sysconfig.s390x +%ifnarch loongarch64 Source19: eppic_050615.tar.gz +%endif Source20: kdump-lib.sh Source21: kdump-in-cluster-environment.txt Source22: kdump-dep-generator.sh @@ -108,10 +112,12 @@ ExcludeArch: i686 # Patch601: rhelonly-kexec-tools-2.0.16-koji-build-fail-workaround.patch Patch602: rhelonly-kexec-tools-2.0.18-eppic-fix-issues-with-hardening-flags.patch +Patch603: kexec-tools-2.0.22-Add-LoongArch-support.patch # Patches 701 onward for makedumpfile Patch701: rhelonly-kexec-tools-2.0.20-makedumpfile-arm64-Add-support-for-ARMv8.2-LVA-52-bi.patch Patch702: kexec-tools-2.0.26-makedumpfile-sadump-fix-failure-of-reading-memory-when-5-le.patch +Patch703: kexec-tools-2.0.22-makedumpfile-Add-LoongArch-support.patch %description kexec-tools provides /usr/sbin/kexec binary that facilitates a new @@ -125,13 +131,19 @@ component of the kernel's kexec feature. mkdir -p -m755 kcp tar -z -x -v -f %{SOURCE9} +%ifnarch loongarch64 tar -z -x -v -f %{SOURCE19} +%endif %patch601 -p1 +%ifnarch loongarch64 %patch602 -p1 +%endif +%patch603 -p1 %patch701 -p1 %patch702 -p1 +%patch703 -p1 %ifarch ppc %define archdef ARCH=ppc @@ -162,11 +174,15 @@ cp %{SOURCE31} . %{SOURCE8} %{_target_cpu} > kdump.conf make -%ifarch %{ix86} x86_64 ppc64 s390x ppc64le aarch64 +%ifarch %{ix86} x86_64 ppc64 s390x ppc64le aarch64 loongarch64 +%ifnarch loongarch64 make -C eppic/libeppic +%endif make -C makedumpfile-1.7.2 LINKTYPE=dynamic USELZO=on USESNAPPY=on USEZSTD=on +%ifnarch loongarch64 make -C makedumpfile-1.7.2 LDFLAGS="$LDFLAGS -I../eppic/libeppic -L../eppic/libeppic" eppic_makedumpfile.so %endif +%endif %install mkdir -p -m755 $RPM_BUILD_ROOT/usr/sbin @@ -225,15 +241,17 @@ install -m 755 -D %{SOURCE22} $RPM_BUILD_ROOT%{_prefix}/lib/systemd/system-gener install -m 755 -D %{SOURCE32} $RPM_BUILD_ROOT%{_prefix}/lib/kernel/install.d/60-kdump.install -%ifarch %{ix86} x86_64 ppc64 s390x ppc64le aarch64 +%ifarch %{ix86} x86_64 ppc64 s390x ppc64le aarch64 loongarch64 install -m 755 makedumpfile-1.7.2/makedumpfile $RPM_BUILD_ROOT/usr/sbin/makedumpfile install -m 644 makedumpfile-1.7.2/makedumpfile.8 $RPM_BUILD_ROOT/%{_mandir}/man8/makedumpfile.8 install -m 644 makedumpfile-1.7.2/makedumpfile.conf.5 $RPM_BUILD_ROOT/%{_mandir}/man5/makedumpfile.conf.5 install -m 644 makedumpfile-1.7.2/makedumpfile.conf $RPM_BUILD_ROOT/%{_sysconfdir}/makedumpfile.conf.sample +%ifnarch loongarch64 install -m 755 makedumpfile-1.7.2/eppic_makedumpfile.so $RPM_BUILD_ROOT/%{_libdir}/eppic_makedumpfile.so mkdir -p $RPM_BUILD_ROOT/usr/share/makedumpfile/eppic_scripts/ install -m 644 makedumpfile-1.7.2/eppic_scripts/* $RPM_BUILD_ROOT/usr/share/makedumpfile/eppic_scripts/ %endif +%endif %define remove_dracut_prefix() %(echo -n %1|sed 's/.*dracut-//g') %define remove_dracut_early_kdump_prefix() %(echo -n %1|sed 's/.*dracut-early-kdump-//g') @@ -357,7 +375,7 @@ done %{_bindir}/* %{_datadir}/kdump %{_prefix}/lib/kdump -%ifarch %{ix86} x86_64 ppc64 s390x ppc64le aarch64 +%ifarch %{ix86} x86_64 ppc64 s390x ppc64le aarch64 loongarch64 %{_sysconfdir}/makedumpfile.conf.sample %endif %config(noreplace,missingok) %{_sysconfdir}/sysconfig/kdump @@ -396,6 +414,9 @@ done %endif %changelog +* Fri Aug 30 2024 Youling Tang - 2.0.26-14.0.1.1 +- Add LoongArch support + * Tue Jun 18 2024 Pingfan Liu - 2.0.26-14.1 - mkdumprd: Fix makedumpfile parameter check -- Gitee From b4c82b6c95ab67b084b160b29f7e2afb4686dfdd Mon Sep 17 00:00:00 2001 From: Bo Ren Date: Wed, 23 Nov 2022 17:04:36 +0800 Subject: [PATCH 03/11] spec: add doc sub package Signed-off-by: Bo Ren --- kexec-tools.spec | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/kexec-tools.spec b/kexec-tools.spec index 5f5b43b..c27af94 100644 --- a/kexec-tools.spec +++ b/kexec-tools.spec @@ -126,6 +126,14 @@ normal or a panic reboot. This package contains the /usr/sbin/kexec binary and ancillary utilities that together form the userspace component of the kernel's kexec feature. +%package doc +Summary: Documents for %{name} +BuildArch: noarch +Requires: %{name} = %{version}-%{release} + +%description doc +Doc pages for %{name}. + %prep %setup -q @@ -399,8 +407,14 @@ done %{_unitdir}/kdump.service %{_prefix}/lib/systemd/system-generators/kdump-dep-generator.sh %{_prefix}/lib/kernel/install.d/60-kdump.install -%doc News %license COPYING +%ifarch %{ix86} x86_64 ppc64 s390x ppc64le aarch64 +%{_libdir}/eppic_makedumpfile.so +/usr/share/makedumpfile/ +%endif + +%files doc +%doc News %doc TODO %doc kexec-kdump-howto.txt %doc early-kdump-howto.txt @@ -408,14 +422,11 @@ done %doc supported-kdump-targets.txt %doc kdump-in-cluster-environment.txt %doc live-image-kdump-howto.txt -%ifarch %{ix86} x86_64 ppc64 s390x ppc64le aarch64 -%{_libdir}/eppic_makedumpfile.so -/usr/share/makedumpfile/ -%endif %changelog * Fri Aug 30 2024 Youling Tang - 2.0.26-14.0.1.1 - Add LoongArch support +- Add doc sub package (wb-zh951434@alibaba-inc.com) * Tue Jun 18 2024 Pingfan Liu - 2.0.26-14.1 - mkdumprd: Fix makedumpfile parameter check -- Gitee From 4ab27e9a806768266a33ca347d8ee745769aa076 Mon Sep 17 00:00:00 2001 From: Yuanhe Shu Date: Thu, 24 Nov 2022 15:25:13 +0800 Subject: [PATCH 04/11] Fix kexec error for kexec -s On current an8, kexec -s is not supported thus kexec -s would cause kdump service fail. Fix by remove -s in KEXEC_ARGS Signed-off-by: Yuanhe Shu --- kdump.sysconfig.aarch64 | 2 +- kdump.sysconfig.s390x | 2 +- kdump.sysconfig.x86_64 | 2 +- kexec-tools.spec | 1 + 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/kdump.sysconfig.aarch64 b/kdump.sysconfig.aarch64 index d443b1f..938c210 100644 --- a/kdump.sysconfig.aarch64 +++ b/kdump.sysconfig.aarch64 @@ -28,7 +28,7 @@ KDUMP_COMMANDLINE_APPEND="irqpoll nr_cpus=1 reset_devices cgroup_disable=memory # # Example: # KEXEC_ARGS="--elf32-core-headers" -KEXEC_ARGS="-s" +KEXEC_ARGS="" #Where to find the boot image #KDUMP_BOOTDIR="/boot" diff --git a/kdump.sysconfig.s390x b/kdump.sysconfig.s390x index 8e80963..856a843 100644 --- a/kdump.sysconfig.s390x +++ b/kdump.sysconfig.s390x @@ -31,7 +31,7 @@ MKDUMPRD_ARGS="" # # Example: # KEXEC_ARGS="--elf32-core-headers" -KEXEC_ARGS="-s" +KEXEC_ARGS="" #Where to find the boot image #KDUMP_BOOTDIR="/boot" diff --git a/kdump.sysconfig.x86_64 b/kdump.sysconfig.x86_64 index 1b4fad7..1790f1b 100644 --- a/kdump.sysconfig.x86_64 +++ b/kdump.sysconfig.x86_64 @@ -28,7 +28,7 @@ KDUMP_COMMANDLINE_APPEND="irqpoll nr_cpus=1 reset_devices cgroup_disable=memory # # Example: # KEXEC_ARGS="--elf32-core-headers" -KEXEC_ARGS="-s" +KEXEC_ARGS="" #Where to find the boot image #KDUMP_BOOTDIR="/boot" diff --git a/kexec-tools.spec b/kexec-tools.spec index c27af94..4406831 100644 --- a/kexec-tools.spec +++ b/kexec-tools.spec @@ -427,6 +427,7 @@ done * Fri Aug 30 2024 Youling Tang - 2.0.26-14.0.1.1 - Add LoongArch support - Add doc sub package (wb-zh951434@alibaba-inc.com) +- Fix kexec error for kexec -s (xiangzao@linux.alibaba.com) * Tue Jun 18 2024 Pingfan Liu - 2.0.26-14.1 - mkdumprd: Fix makedumpfile parameter check -- Gitee From d6678e8be5ac1a178d32f7577d98006a85e48502 Mon Sep 17 00:00:00 2001 From: Youling Tang Date: Tue, 21 Mar 2023 20:21:18 +0800 Subject: [PATCH 05/11] Reimplement loongarch64 support Signed-off-by: Youling Tang --- kdump.sysconfig.loongarch64 | 53 + ...c-tools-2.0.24-Add-LoongArch-support.patch | 1740 +++++++++-------- kexec-tools.spec | 4 +- 3 files changed, 932 insertions(+), 865 deletions(-) create mode 100644 kdump.sysconfig.loongarch64 rename kexec-tools-2.0.22-Add-LoongArch-support.patch => kexec-tools-2.0.24-Add-LoongArch-support.patch (43%) diff --git a/kdump.sysconfig.loongarch64 b/kdump.sysconfig.loongarch64 new file mode 100644 index 0000000..5e8abaa --- /dev/null +++ b/kdump.sysconfig.loongarch64 @@ -0,0 +1,53 @@ +# Kernel Version string for the -kdump kernel, such as 2.6.13-1544.FC5kdump +# If no version is specified, then the init script will try to find a +# kdump kernel with the same version number as the running kernel. +KDUMP_KERNELVER="" + +# The kdump commandline is the command line that needs to be passed off to +# the kdump kernel. This will likely match the contents of the grub kernel +# line. For example: +# KDUMP_COMMANDLINE="ro root=LABEL=/" +# Dracut depends on proper root= options, so please make sure that appropriate +# root= options are copied from /proc/cmdline. In general it is best to append +# command line options using "KDUMP_COMMANDLINE_APPEND=". +# If a command line is not specified, the default will be taken from +# /proc/cmdline +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 swiotlb ignition.firstboot" + +# This variable lets us append arguments to the current kdump commandline +# after processed by KDUMP_COMMANDLINE_REMOVE +KDUMP_COMMANDLINE_APPEND="irqpoll reset_devices cgroup_disable=memory udev.children-max=2 panic=10 swiotlb=noforce novmcoredd" + +# Any additional kexec arguments required. In most situations, this should +# be left empty +# +# Example: +# KEXEC_ARGS="--elf32-core-headers" +KEXEC_ARGS="" + +#Where to find the boot image +#KDUMP_BOOTDIR="/boot" + +#What is the image type used for kdump +KDUMP_IMG="vmlinuz" + +# 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 diff --git a/kexec-tools-2.0.22-Add-LoongArch-support.patch b/kexec-tools-2.0.24-Add-LoongArch-support.patch similarity index 43% rename from kexec-tools-2.0.22-Add-LoongArch-support.patch rename to kexec-tools-2.0.24-Add-LoongArch-support.patch index 48e041d..e06d5db 100644 --- a/kexec-tools-2.0.22-Add-LoongArch-support.patch +++ b/kexec-tools-2.0.24-Add-LoongArch-support.patch @@ -1,74 +1,72 @@ -From f3f3ec14c775b46bd17056534c0588f54a310677 Mon Sep 17 00:00:00 2001 +From 712e9b12518183fe83572219c9afc23463373ed7 Mon Sep 17 00:00:00 2001 From: Youling Tang -Date: Mon, 11 Jul 2022 17:22:42 +0800 -Subject: [PATCH] kexec-tools: Add LoongArch support +Date: Tue, 21 Mar 2023 19:56:34 +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 | 27 ++ - kexec/arch/loongarch/crashdump-loongarch.c | 384 ++++++++++++++++++ - kexec/arch/loongarch/crashdump-loongarch.h | 24 ++ - kexec/arch/loongarch/include/arch/options.h | 43 ++ - kexec/arch/loongarch/kexec-elf-loongarch.c | 240 +++++++++++ - .../arch/loongarch/kexec-elf-rel-loongarch.c | 43 ++ - kexec/arch/loongarch/kexec-loongarch.c | 353 ++++++++++++++++ - kexec/arch/loongarch/kexec-loongarch.h | 40 ++ + 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 | 6 + + 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 + - 21 files changed, 1212 insertions(+), 1 deletion(-) + 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 8d70ec2..c626f7a 100755 --- a/config/config.guess +++ b/config/config.guess -@@ -1039,6 +1039,9 @@ EOF - mips64el:Linux:*:*) +@@ -983,6 +983,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 9bc49a7..dae00e6 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 +@@ -1185,6 +1185,7 @@ case $cpu-$vendor in | k1om \ | le32 | le64 \ | lm32 \ @@ -76,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 c2510d6..b113fd6 100755 +--- a/configure ++++ b/configure +@@ -3062,6 +3062,9 @@ case $target_cpu in + hppa*) + ARCH="hppa" + ;; ++ loongarch*) ++ ARCH="loongarch" ++ ;; + * ) + as_fn_error $? "unsupported architecture $target_cpu" "$LINENO" 5 + ;; diff --git a/configure.ac b/configure.ac -index 3c5201f..7458d0e 100644 +index cf8e8a2..baf3d99 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]) ;; diff --git a/include/elf.h b/include/elf.h -index b7677a2..ca42618 100644 +index b7677a2..1c8d2cc 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 @@ -115,10 +127,10 @@ index 8e9d81e..7a4bccf 100644 /* * Image Types diff --git a/kexec/Makefile b/kexec/Makefile -index 8e3e9ea..803b41a 100644 +index e69e309..8a52e8d 100644 --- a/kexec/Makefile +++ b/kexec/Makefile -@@ -93,6 +93,7 @@ include $(srcdir)/kexec/arch/s390/Makefile +@@ -92,6 +92,7 @@ include $(srcdir)/kexec/arch/s390/Makefile include $(srcdir)/kexec/arch/sh/Makefile include $(srcdir)/kexec/arch/x86_64/Makefile include $(srcdir)/kexec/arch/hppa/Makefile @@ -128,19 +140,22 @@ index 8e3e9ea..803b41a 100644 diff --git a/kexec/arch/loongarch/Makefile b/kexec/arch/loongarch/Makefile new file mode 100644 -index 0000000..05ec5ca +index 0000000..3b33b96 --- /dev/null +++ b/kexec/arch/loongarch/Makefile -@@ -0,0 +1,27 @@ +@@ -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_DT_OPS += kexec/dt-ops.c ++loongarch_MEM_REGIONS = kexec/mem_regions.c ++ ++loongarch_CPPFLAGS += -I $(srcdir)/kexec/ + +loongarch_ADD_BUFFER = +loongarch_ADD_SEGMENT = @@ -148,742 +163,547 @@ index 0000000..05ec5ca + +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 -+ -+ifdef HAVE_LIBFDT -+LIBS += -lfdt -+else -+include $(srcdir)/kexec/libfdt/Makefile.libfdt -+libfdt_SRCS += $(LIBFDT_SRCS:%=kexec/libfdt/%) -+loongarch_CPPFLAGS += -I$(srcdir)/kexec/libfdt -+loongarch_KEXEC_SRCS += $(libfdt_SRCS) -+endif diff --git a/kexec/arch/loongarch/crashdump-loongarch.c b/kexec/arch/loongarch/crashdump-loongarch.c new file mode 100644 -index 0000000..4c3a760 +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) 2022 Loongson Technology Corporation Limited. ++ * Youling Tang + * -+ * Copyright (C) 2021 Loongson Technology Co., Ltd. ++ * 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. */ -+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; -+ -+ if (!elf_info->kern_paddr_start) -+ return -1; ++ int i; + -+ 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 + * -+ * 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. ++ * This function creates and loads an additional segment of elf core header ++ : which is used to construct /proc/vmcore on crash dump 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..a75310f ---- /dev/null -+++ b/kexec/arch/loongarch/crashdump-loongarch.h -@@ -0,0 +1,24 @@ -+#ifndef CRASHDUMP_LOONGARCH_H -+#define CRASHDUMP_LOONGARCH_H + -+struct kexec_info; -+extern struct memory_range crash_reserved_mem; -+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 ++ 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..8f105a1 +index 0000000..25a7dc1 --- /dev/null +++ b/kexec/arch/loongarch/include/arch/options.h -@@ -0,0 +1,43 @@ +@@ -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_DTB (OPT_ARCH_MAX + 3) ++#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}, \ -+ {"dtb", 1, 0, OPT_DTB}, -+ -+ -+#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..4e37f27 +index 0000000..0ac451e --- /dev/null +++ b/kexec/arch/loongarch/kexec-elf-loongarch.c -@@ -0,0 +1,240 @@ +@@ -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 -+ -+ -+off_t initrd_base = 0; -+off_t initrd_size = 0; -+ -+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); ++#include "arch/options.h" + -+ return 0; -+} ++off_t initrd_base, initrd_size; + -+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" -+ " --dtb=FILE Use FILE as the device tree blob.\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(); -+ unsigned long initrd_min, hole_max, hole_min = 0; + -+ /* -+ * 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; -+ hole_min = kernel_addr + kernel_size; -+ } ++ 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"); -+ -+ info->entry = (void *)virt_to_phys(ehdr.e_entry); -+ -+ if (arch_options.command_line) -+ command_line_len = strlen(arch_options.command_line) + 1; ++ kernel_segment = loongarch_locate_kernel_segment(info); + -+ get_crash_kernel_load_range((uint64_t *)&crash_reserved_mem.start, -+ (uint64_t *)&crash_reserved_mem.end); -+ -+ initrd_min = hole_min; -+ if (info->kexec_flags & KEXEC_ON_CRASH) { -+ hole_max = crash_reserved_mem.end; -+ } else { -+ hole_max = ULONG_MAX; -+ /* -+ * Avoid initrd and crashkernel area conflicts when performing -+ * kexec operations. -+ */ -+ if (crash_reserved_mem.end) -+ initrd_min = crash_reserved_mem.end; ++ 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, hole_max, 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) { ++ info->entry = (void *)virt_to_phys(ehdr.e_entry); + -+ initrd_buf = slurp_decompress_file(arch_options.initrd_file, &initrd_size); ++ result = elf_exec_load(&ehdr, info); + -+ initrd_base = add_buffer(info, initrd_buf, initrd_size, -+ initrd_size, sizeof(void *), -+ _ALIGN_UP(initrd_min, -+ pagesize), hole_max, 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); ++ 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, hole_max, 1); -+ dbgprintf("command line: %s\n", cmdline_buf); -+ /* Prepare and load dtb data */ -+ result = loongarch_load_dtb_segment(info, hole_min, initrd_base, initrd_size, cmdline_buf); -+ if(result) { -+ fprintf(stderr, "kexec: Load dtb segments failed.\n"); -+ return result; -+ } ++ /* for vmlinuz kernel image */ ++ if (kernel_size < MiB(16)) ++ kernel_size = MiB(64); + ++ /* load additional data */ ++ result = loongarch_load_other_segments(info, kernel_segment + kernel_size); + -+ return 0; ++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. @@ -894,63 +714,168 @@ index 0000000..72307b3 +#include "../../kexec.h" +#include "../../kexec-elf.h" + -+int machine_verify_elf_rel(struct mem_ehdr *ehdr) -+{ -+ if (ehdr->ei_data != ELFDATA2MSB) { -+ return 0; -+ } -+ if (ehdr->ei_class != ELFCLASS32) { -+ return 0; -+ } -+ if (ehdr->e_machine != EM_LOONGARCH) { -+ return 0; -+ } -+ return 1; ++int machine_verify_elf_rel(struct mem_ehdr *ehdr) ++{ ++ if (ehdr->ei_data != ELFDATA2MSB) ++ return 0; ++ ++ if (ehdr->ei_class != ELFCLASS32) ++ return 0; ++ ++ if (ehdr->e_machine != EM_LOONGARCH) ++ return 0; ++ ++ return 1; ++} ++ ++void machine_apply_elf_rel(struct mem_ehdr *UNUSED(ehdr), ++ struct mem_sym *UNUSED(sym), ++ unsigned long r_type, ++ void *UNUSED(location), ++ unsigned long UNUSED(address), ++ unsigned long UNUSED(value)) ++{ ++ switch (r_type) { ++ ++ default: ++ die("Unknown rela relocation: %lu\n", r_type); ++ break; ++ } ++} +diff --git a/kexec/arch/loongarch/kexec-loongarch.c b/kexec/arch/loongarch/kexec-loongarch.c +new file mode 100644 +index 0000000..7e004eb +--- /dev/null ++++ b/kexec/arch/loongarch/kexec-loongarch.c +@@ -0,0 +1,397 @@ ++/* ++ * kexec-loongarch.c - kexec for loongarch ++ * ++ * 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 ++#include ++#include ++#include ++#include ++ ++#include "kexec.h" ++#include "kexec-loongarch.h" ++#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; +} + -+void machine_apply_elf_rel(struct mem_ehdr *UNUSED(ehdr), -+ struct mem_sym *UNUSED(sym), -+ unsigned long r_type, -+ void *UNUSED(location), -+ unsigned long UNUSED(address), -+ unsigned long UNUSED(value)) ++/* Adds the "elfcorehdr=size@start" command line parameter to command line. */ ++static int cmdline_add_elfcorehdr(char *cmdline, unsigned long addr, ++ unsigned long size) +{ -+ switch(r_type) { ++ int cmdlen, len; ++ char str[50], *ptr; + -+ 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..2029a19 ---- /dev/null -+++ b/kexec/arch/loongarch/kexec-loongarch.c -@@ -0,0 +1,353 @@ -+/* -+ * kexec-loongarch.c - kexec for loongarch -+ * -+ * Copyright (C) 2021 Loongson Technology Co., Ltd. -+ * -+ * This source code is licensed under the GNU General Public License, -+ * Version 2. See the file COPYING for more details. -+ */ ++ 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); + -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "../../kexec.h" -+#include "../../kexec-syscall.h" -+#include "../../dt-ops.h" -+#include "kexec-loongarch.h" -+#include ++ return 0; ++} + +/* Return a sorted list of memory ranges. */ +static struct memory_range memory_range[MAX_MEMORY_RANGES]; @@ -972,6 +897,7 @@ index 0000000..2029a19 + 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; @@ -980,13 +906,13 @@ index 0000000..2029a19 + 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) { @@ -1001,16 +927,42 @@ index 0000000..2029a19 + 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 = { @@ -1019,11 +971,11 @@ index 0000000..2029a19 + +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; @@ -1036,12 +988,15 @@ index 0000000..2029a19 + break; + case OPT_REUSE_CMDLINE: + 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; -+ case OPT_DTB: -+ arch_options.dtb = optarg; + default: + break; + } @@ -1062,171 +1017,93 @@ index 0000000..2029a19 + { NULL, 0 }, +}; + -+/* -+ * struct dtb - Info about a binary device tree. -+ * -+ * @buf: Device tree data. -+ * @size: Device tree data size. -+ * @name: Shorthand name of this dtb for messages. -+ * @path: Filesystem path. -+ */ -+ -+struct dtb { -+ char *buf; -+ off_t size; -+ const char *name; -+ const char *path; -+}; -+ -+/* -+ * set_bootargs - Set the dtb's bootargs. -+ */ -+ -+static int set_bootargs(struct dtb *dtb, const char *command_line) -+{ -+ int result; -+ -+ if (!command_line || !command_line[0]) -+ return 0; -+ -+ result = dtb_set_bootargs(&dtb->buf, &dtb->size, command_line); -+ -+ if (result) { -+ fprintf(stderr, -+ "kexec: Set device tree bootargs failed.\n"); -+ return EFAILED; -+ } -+ -+ return 0; -+} -+ -+/* -+ * read_sys_dtb - Read /sys/firmware/fdt. -+ */ -+ -+static int read_sys_dtb(struct dtb *dtb) ++unsigned long loongarch_locate_kernel_segment(struct kexec_info *info) +{ -+ int result; -+ struct stat s; -+ static const char path[] = "/sys/firmware/fdt"; ++ unsigned long hole; + -+ result = stat(path, &s); ++ 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 (result) { -+ dbgprintf("%s: %s\n", __func__, strerror(errno)); -+ /* -+ * Returning an error directly will result in incompatibility -+ * with older firmware. -+ */ -+ return 1; ++ if (hole == ULONG_MAX) ++ dbgprintf("%s: locate_hole failed\n", __func__); + } + -+ dtb->path = path; -+ dtb->buf = slurp_file(path, &dtb->size); -+ -+ return 0; -+} -+ -+/* -+ * read_1st_dtb - Read the 1st stage kernel's dtb. -+ */ -+ -+static int read_1st_dtb(struct dtb *dtb) -+{ -+ int result; -+ -+ dtb->name = "dtb_sys"; -+ result = read_sys_dtb(dtb); -+ -+ if (!result) -+ goto on_success; -+ -+ dbgprintf("%s: not found\n", __func__); -+ return EFAILED; -+ -+on_success: -+ dbgprintf("%s: found %s\n", __func__, dtb->path); -+ return 0; ++ return hole; +} + +/* -+ * setup_2nd_dtb - Setup the 2nd stage kernel's dtb. ++ * loongarch_load_other_segments - Prepare the initrd and cmdline segments. + */ + -+static int setup_2nd_dtb(struct dtb *dtb, char *command_line) ++int loongarch_load_other_segments(struct kexec_info *info, unsigned long hole_min) +{ -+ int result; -+ -+ result = fdt_check_header(dtb->buf); ++ unsigned long initrd_min, hole_max; ++ char *initrd_buf = NULL; ++ unsigned long pagesize = getpagesize(); + -+ if (result) { -+ fprintf(stderr, "kexec: Invalid 2nd device tree.\n"); -+ return EFAILED; -+ } ++ 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; ++ } + -+ result = set_bootargs(dtb, command_line); -+ if (result) { -+ fprintf(stderr, "kexec: cannot set bootargs.\n"); -+ result = -EINVAL; -+ goto on_error; ++ strncat(cmdline, arch_options.command_line, sizeof(cmdline) - 1); + } + -+ return result; ++ /* Put the other segments after the image. */ + -+on_error: -+ fprintf(stderr, "kexec: %s failed.\n", __func__); -+ return result; -+} ++ 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; + -+/* -+ * loongarch_load_dtb_segment - Prepare the dtb segment. -+ */ ++ if (arch_options.initrd_file) { + -+int loongarch_load_dtb_segment(struct kexec_info *info, unsigned long hole_min, -+ unsigned long initrd_base, unsigned long initrd_size, char *command_line) -+{ -+ int result; -+ unsigned long dtb_base; -+ struct dtb dtb; ++ initrd_buf = slurp_decompress_file(arch_options.initrd_file, &initrd_size); + -+ if (arch_options.dtb) { -+ dtb.name = "dtb_user"; -+ dtb.buf = slurp_file(arch_options.dtb, &dtb.size); -+ } else { -+ result = read_1st_dtb(&dtb); ++ 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); + -+ /* -+ * Returning an error directly will result in incompatibility -+ * with older firmware. -+ */ -+ if (result) -+ return 0; ++ cmdline_add_initrd(cmdline, initrd_base, initrd_size); + } + -+ result = setup_2nd_dtb(&dtb, command_line); -+ if (result) -+ return EFAILED; -+ -+ if (arch_options.initrd_file) { -+ result = dtb_set_initrd((char **)&dtb.buf, &dtb.size, initrd_base, -+ initrd_base + initrd_size); -+ if (result) -+ return EFAILED; -+ } ++ if (info->kexec_flags & KEXEC_ON_CRASH) { ++ cmdline_add_elfcorehdr(cmdline, elfcorehdr_mem.start, ++ elfcorehdr_mem.end - elfcorehdr_mem.start + 1); + -+ /* Check size limit. */ -+ if (dtb.size > KiB(64)) { -+ fprintf(stderr, "kexec: Error: dtb too big.\n"); -+ return EFAILED; ++ 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); + } + -+ dtb_base = add_buffer(info, dtb.buf, dtb.size, dtb.size, ++ cmdline[sizeof(cmdline) - 1] = 0; ++ add_buffer(info, cmdline, sizeof(cmdline), sizeof(cmdline), + sizeof(void *), _ALIGN_UP(hole_min, getpagesize()), + 0xffffffff, 1); + -+ /* dtb_base is valid if we got here. */ -+ dbgprintf("dtb: base %lx, size %lxh (%ld)\n", dtb_base, dtb.size, -+ dtb.size); ++ dbgprintf("%s:%d: command_line: %s\n", __func__, __LINE__, cmdline); + + return 0; + @@ -1268,53 +1145,47 @@ index 0000000..2029a19 + 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..93ee3b9 +index 0000000..5120a26 --- /dev/null +++ b/kexec/arch/loongarch/kexec-loongarch.h -@@ -0,0 +1,40 @@ +@@ -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 + +#define KiB(x) ((x) * 1024UL) ++#define MiB(x) (KiB(x) * 1024UL) + -+int elf_loongarch_probe(const char *buf, off_t len); ++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 loongarch_load_dtb_segment(struct kexec_info *info, unsigned long hole_min, -+ unsigned long initrd_base, unsigned long initrd_size, char *command_line); + ++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; @@ -1323,41 +1194,176 @@ index 0000000..93ee3b9 + 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 bea29d4..25a2b30 100644 +index bea29d4..1e2d12f 100644 --- a/kexec/kexec-syscall.h +++ b/kexec/kexec-syscall.h -@@ -4,7 +4,6 @@ - #define __LIBRARY__ - #include - #include -- - #define LINUX_REBOOT_CMD_KEXEC_OLD 0x81726354 - #define LINUX_REBOOT_CMD_KEXEC_OLD2 0x18263645 - #define LINUX_REBOOT_CMD_KEXEC 0x45584543 -@@ -51,6 +50,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 +@@ -56,7 +59,7 @@ + #endif + #endif /*ifndef __NR_kexec_load*/ + +-#ifdef __arm__ ++#if defined(__arm__) || defined(__loongarch__) + #undef __NR_kexec_file_load #endif -@@ -107,6 +109,7 @@ static inline long kexec_file_load(int kernel_fd, int initrd_fd, - cmdline_len, cmdline_ptr, flags); - } -+ - #define KEXEC_ON_CRASH 0x00000001 - #define KEXEC_PRESERVE_CONTEXT 0x00000002 - #define KEXEC_ARCH_MASK 0xffff0000 @@ -134,6 +137,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) @@ -1376,26 +1382,32 @@ index bea29d4..25a2b30 100644 #endif /* KEXEC_SYSCALL_H */ diff --git a/kexec/kexec.c b/kexec/kexec.c -index fd7c8d2..ee892dc 100644 +index 829a6ea..0e92d96 100644 --- a/kexec/kexec.c +++ b/kexec/kexec.c -@@ -1202,8 +1202,14 @@ char *get_command_line(void) - *p = '\0'; +@@ -1095,7 +1095,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; - remove_parameter(line, "BOOT_IMAGE"); -+ remove_parameter(line, "kexec"); - if (kexec_flags & KEXEC_ON_CRASH) - remove_parameter(line, "crashkernel"); -+ /* Only for Loongson platform */ -+ remove_parameter(line, "rd_start"); -+ remove_parameter(line, "rd_size"); -+ remove_parameter(line, "initrd"); -+ remove_parameter(line, "e1000e.InterruptThrottleRate"); +diff --git a/kexec/kexec.h b/kexec/kexec.h +index 0f97a97..7a62186 100644 +--- a/kexec/kexec.h ++++ b/kexec/kexec.h +@@ -304,6 +304,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); - return line; - } + int kexec_iomem_for_each_line(char *match, diff --git a/purgatory/Makefile b/purgatory/Makefile -index 2dd6c47..f24cae0 100644 +index b8cbae3..51ef1ec 100644 --- a/purgatory/Makefile +++ b/purgatory/Makefile @@ -28,6 +28,7 @@ include $(srcdir)/purgatory/arch/ppc64/Makefile @@ -1461,5 +1473,5 @@ index 0000000..cd1ab97 + +#endif /* PURGATORY_LOONGARCH_H */ -- -2.20.1 +2.27.0 diff --git a/kexec-tools.spec b/kexec-tools.spec index 4406831..9d324cc 100644 --- a/kexec-tools.spec +++ b/kexec-tools.spec @@ -43,6 +43,7 @@ Source33: kdump-logger.sh Source34: kdump-migrate-action.sh Source35: kdump-restart.sh Source36: mkfadumprd +Source37: kdump.sysconfig.loongarch64 ####################################### # These are sources for mkdumpramfs @@ -112,7 +113,7 @@ ExcludeArch: i686 # Patch601: rhelonly-kexec-tools-2.0.16-koji-build-fail-workaround.patch Patch602: rhelonly-kexec-tools-2.0.18-eppic-fix-issues-with-hardening-flags.patch -Patch603: kexec-tools-2.0.22-Add-LoongArch-support.patch +Patch603: kexec-tools-2.0.24-Add-LoongArch-support.patch # Patches 701 onward for makedumpfile Patch701: rhelonly-kexec-tools-2.0.20-makedumpfile-arm64-Add-support-for-ARMv8.2-LVA-52-bi.patch @@ -428,6 +429,7 @@ done - Add LoongArch support - Add doc sub package (wb-zh951434@alibaba-inc.com) - Fix kexec error for kexec -s (xiangzao@linux.alibaba.com) +- Reimplement loongarch64 support * Tue Jun 18 2024 Pingfan Liu - 2.0.26-14.1 - mkdumprd: Fix makedumpfile parameter check -- Gitee From 89da64476a2849035d172ddbdcd0f3d713799658 Mon Sep 17 00:00:00 2001 From: Zhao Hang Date: Fri, 30 Jun 2023 15:29:05 +0800 Subject: [PATCH 06/11] Remove loongarch64 arch Signed-off-by: Zhao Hang --- kexec-tools.spec | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kexec-tools.spec b/kexec-tools.spec index 9d324cc..4c8dcea 100644 --- a/kexec-tools.spec +++ b/kexec-tools.spec @@ -7,6 +7,7 @@ License: GPLv2 Group: Applications/System Summary: The kexec/kdump userspace component +Excludearch: loongarch64 Source0: http://kernel.org/pub/linux/utils/kernel/kexec/%{name}-%{version}.tar.xz Source1: kdumpctl Source2: kdump.sysconfig @@ -430,6 +431,7 @@ done - Add doc sub package (wb-zh951434@alibaba-inc.com) - Fix kexec error for kexec -s (xiangzao@linux.alibaba.com) - Reimplement loongarch64 support +- Remove loongarch64 arch (wb-zh951434@alibaba-inc.com) * Tue Jun 18 2024 Pingfan Liu - 2.0.26-14.1 - mkdumprd: Fix makedumpfile parameter check -- Gitee From 9cc8dcc48965e462fff28757c12b7b3ed9934ace Mon Sep 17 00:00:00 2001 From: Ming Wang Date: Wed, 5 Jul 2023 14:48:58 +0800 Subject: [PATCH 07/11] loongarch64: rebase the LoongArch patch to kexec-tools-2.0.25 Fix kexec compilation error under LoongArch64 architecture. Signed-off-by: Ming Wang --- gen-kdump-conf.sh | 4 ++ ...c-tools-2.0.25-Add-LoongArch-support.patch | 41 ++++++------------- kexec-tools.spec | 2 +- 3 files changed, 17 insertions(+), 30 deletions(-) rename kexec-tools-2.0.24-Add-LoongArch-support.patch => kexec-tools-2.0.25-Add-LoongArch-support.patch (98%) diff --git a/gen-kdump-conf.sh b/gen-kdump-conf.sh index 4bda9e8..467a055 100755 --- a/gen-kdump-conf.sh +++ b/gen-kdump-conf.sh @@ -213,6 +213,10 @@ s390x) update_param core_collector \ "makedumpfile -c --message-level 7 -d 31" ;; +loongarch64) + update_param core_collector \ + "makedumpfile -c --message-level 7 -d 31" + ;; x86_64) ;; *) diff --git a/kexec-tools-2.0.24-Add-LoongArch-support.patch b/kexec-tools-2.0.25-Add-LoongArch-support.patch similarity index 98% rename from kexec-tools-2.0.24-Add-LoongArch-support.patch rename to kexec-tools-2.0.25-Add-LoongArch-support.patch index e06d5db..ce20c7e 100644 --- a/kexec-tools-2.0.24-Add-LoongArch-support.patch +++ b/kexec-tools-2.0.25-Add-LoongArch-support.patch @@ -1,9 +1,11 @@ -From 712e9b12518183fe83572219c9afc23463373ed7 Mon Sep 17 00:00:00 2001 +From 017e67e3949994e51da55a662b647381fc268195 Mon Sep 17 00:00:00 2001 From: Youling Tang Date: Tue, 21 Mar 2023 19:56:34 +0800 Subject: [PATCH] Add loongarch64 support Signed-off-by: Youling Tang +Signed-off-by: root +Signed-off-by: Ming Wang --- config/config.guess | 3 + config/config.sub | 1 + @@ -20,7 +22,7 @@ Signed-off-by: Youling Tang 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.c | 378 ++++++++++++++++++ kexec/arch/loongarch/kexec-loongarch.h | 60 +++ kexec/arch/loongarch/kexec-pei-loongarch.c | 124 ++++++ kexec/kexec-syscall.h | 9 +- @@ -31,7 +33,7 @@ Signed-off-by: Youling Tang purgatory/arch/loongarch/console-loongarch.c | 7 + .../arch/loongarch/purgatory-loongarch.c | 7 + .../arch/loongarch/purgatory-loongarch.h | 6 + - 26 files changed, 1191 insertions(+), 2 deletions(-) + 26 files changed, 1172 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 @@ -75,7 +77,7 @@ index 9bc49a7..dae00e6 100755 | m5200 | m68000 | m680[012346]0 | m68360 | m683?2 | m68k \ | m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x \ diff --git a/configure b/configure -index c2510d6..b113fd6 100755 +index bcd3cd9..182e4ff 100755 --- a/configure +++ b/configure @@ -3062,6 +3062,9 @@ case $target_cpu in @@ -89,7 +91,7 @@ index c2510d6..b113fd6 100755 as_fn_error $? "unsupported architecture $target_cpu" "$LINENO" 5 ;; diff --git a/configure.ac b/configure.ac -index cf8e8a2..baf3d99 100644 +index 0d825ef..819df6b 100644 --- a/configure.ac +++ b/configure.ac @@ -58,6 +58,9 @@ case $target_cpu in @@ -744,10 +746,10 @@ index 0000000..59f7f5d +} diff --git a/kexec/arch/loongarch/kexec-loongarch.c b/kexec/arch/loongarch/kexec-loongarch.c new file mode 100644 -index 0000000..7e004eb +index 0000000..b173f6d --- /dev/null +++ b/kexec/arch/loongarch/kexec-loongarch.c -@@ -0,0 +1,397 @@ +@@ -0,0 +1,378 @@ +/* + * kexec-loongarch.c - kexec for loongarch + * @@ -782,25 +784,6 @@ index 0000000..7e004eb +#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) @@ -1395,7 +1378,7 @@ index 829a6ea..0e92d96 100644 char *start, *end; diff --git a/kexec/kexec.h b/kexec/kexec.h -index 0f97a97..7a62186 100644 +index 8a05644..0d820ad 100644 --- a/kexec/kexec.h +++ b/kexec/kexec.h @@ -304,6 +304,7 @@ int arch_compat_trampoline(struct kexec_info *info); @@ -1407,7 +1390,7 @@ index 0f97a97..7a62186 100644 int kexec_iomem_for_each_line(char *match, diff --git a/purgatory/Makefile b/purgatory/Makefile -index b8cbae3..51ef1ec 100644 +index 15adb12..4d2d071 100644 --- a/purgatory/Makefile +++ b/purgatory/Makefile @@ -28,6 +28,7 @@ include $(srcdir)/purgatory/arch/ppc64/Makefile @@ -1473,5 +1456,5 @@ index 0000000..cd1ab97 + +#endif /* PURGATORY_LOONGARCH_H */ -- -2.27.0 +2.31.1 diff --git a/kexec-tools.spec b/kexec-tools.spec index 4c8dcea..13c27a3 100644 --- a/kexec-tools.spec +++ b/kexec-tools.spec @@ -114,7 +114,7 @@ ExcludeArch: i686 # Patch601: rhelonly-kexec-tools-2.0.16-koji-build-fail-workaround.patch Patch602: rhelonly-kexec-tools-2.0.18-eppic-fix-issues-with-hardening-flags.patch -Patch603: kexec-tools-2.0.24-Add-LoongArch-support.patch +Patch603: kexec-tools-2.0.25-Add-LoongArch-support.patch # Patches 701 onward for makedumpfile Patch701: rhelonly-kexec-tools-2.0.20-makedumpfile-arm64-Add-support-for-ARMv8.2-LVA-52-bi.patch -- Gitee From 223bae85765049da831dea65d84d85483962c9cc Mon Sep 17 00:00:00 2001 From: Ming Wang Date: Wed, 5 Jul 2023 14:52:15 +0800 Subject: [PATCH 08/11] Revert "Remove loongarch64 arch" This reverts commit 406c03873d6677afd2237a9093a3d5c9168d718c. The patch "loongarch64: rebase the LoongArch patch to kexec-tools-2.0.25" have been fixed loongarch64 compilation errors. So reverts this commit. Signed-off-by: Ming Wang --- kexec-tools.spec | 2 -- 1 file changed, 2 deletions(-) diff --git a/kexec-tools.spec b/kexec-tools.spec index 13c27a3..aa3dd9a 100644 --- a/kexec-tools.spec +++ b/kexec-tools.spec @@ -7,7 +7,6 @@ License: GPLv2 Group: Applications/System Summary: The kexec/kdump userspace component -Excludearch: loongarch64 Source0: http://kernel.org/pub/linux/utils/kernel/kexec/%{name}-%{version}.tar.xz Source1: kdumpctl Source2: kdump.sysconfig @@ -431,7 +430,6 @@ done - Add doc sub package (wb-zh951434@alibaba-inc.com) - Fix kexec error for kexec -s (xiangzao@linux.alibaba.com) - Reimplement loongarch64 support -- Remove loongarch64 arch (wb-zh951434@alibaba-inc.com) * Tue Jun 18 2024 Pingfan Liu - 2.0.26-14.1 - mkdumprd: Fix makedumpfile parameter check -- Gitee From e9159bb366925e83d3328b26eca47b3cf0d2c1ce Mon Sep 17 00:00:00 2001 From: Yuanhe Shu Date: Mon, 18 Sep 2023 19:56:48 +0800 Subject: [PATCH 09/11] Add pstore segment Add pstore segment to record logs of kdump process Signed-off-by: Yuanhe Shu --- ...ls-2.0.25-Add-pstore-segment-support.patch | 216 ++++++++++++++++++ kdumpctl | 36 ++- kexec-tools.spec | 5 +- 3 files changed, 255 insertions(+), 2 deletions(-) create mode 100644 1000-kexec-tools-2.0.25-Add-pstore-segment-support.patch diff --git a/1000-kexec-tools-2.0.25-Add-pstore-segment-support.patch b/1000-kexec-tools-2.0.25-Add-pstore-segment-support.patch new file mode 100644 index 0000000..3d60813 --- /dev/null +++ b/1000-kexec-tools-2.0.25-Add-pstore-segment-support.patch @@ -0,0 +1,216 @@ +From 40c03992bc470e29d0cc33e6f290916434092d76 Mon Sep 17 00:00:00 2001 +From: Yuanhe Shu +Date: Mon, 18 Sep 2023 19:48:50 +0800 +Subject: [PATCH] Add pstore segment support + +Add pstore segment thus it is able to record log of kdump process + +Signed-off-by: Yuanhe Shu +--- + kexec/arch/arm64/crashdump-arm64.c | 5 ++ + kexec/arch/i386/crashdump-x86.c | 12 ++++- + kexec/kexec.c | 80 ++++++++++++++++++++++++++++++ + kexec/kexec.h | 5 ++ + 4 files changed, 100 insertions(+), 2 deletions(-) + +diff --git a/kexec/arch/arm64/crashdump-arm64.c b/kexec/arch/arm64/crashdump-arm64.c +index 3098315..6aa954c 100644 +--- a/kexec/arch/arm64/crashdump-arm64.c ++++ b/kexec/arch/arm64/crashdump-arm64.c +@@ -125,6 +125,11 @@ static int crash_get_memory_ranges(void) + if (!usablemem_rgns.size) + return -EINVAL; + ++ usablemem_rgns.ranges[usablemem_rgns.size - 1].end -= PSTORE_SIZE; ++ ++ dbgprintf("Created pstore segment at 0x%lx\n", ++ usablemem_rgns.ranges[usablemem_rgns.size - 1].end); ++ + dbgprint_mem_range("Reserved memory range", + usablemem_rgns.ranges, usablemem_rgns.size); + +diff --git a/kexec/arch/i386/crashdump-x86.c b/kexec/arch/i386/crashdump-x86.c +index df1f24c..3614007 100644 +--- a/kexec/arch/i386/crashdump-x86.c ++++ b/kexec/arch/i386/crashdump-x86.c +@@ -823,7 +823,7 @@ int load_crashdump_segments(struct kexec_info *info, char* mod_cmdline, + unsigned long max_addr, unsigned long min_base) + { + void *tmp; +- unsigned long sz, bufsz, memsz, elfcorehdr; ++ unsigned long sz, bufsz, memsz, elfcorehdr, pstore_sz, pstore_start; + int nr_ranges = 0, nr_memmap = 0, align = 1024, i; + struct memory_range *mem_range, *memmap_p; + struct crash_elf_info elf_info; +@@ -923,6 +923,14 @@ int load_crashdump_segments(struct kexec_info *info, char* mod_cmdline, + } + } + ++ pstore_sz = _ALIGN(PSTORE_SIZE, align); ++ pstore_start = (unsigned long)crash_reserved_mem[crash_reserved_mem_nr - 1].start; ++ dbgprintf("Created pstore segment at 0x%lx\n", pstore_start); ++ if (delete_memmap(memmap_p, &nr_memmap, pstore_start, pstore_sz) < 0) { ++ free(memmap_p); ++ return EFAILED; ++ } ++ + /* Create elf header segment and store crash image data. */ + if (arch_options.core_header_type == CORE_TYPE_ELF64) { + if (crash_create_elf64_headers(info, &elf_info, mem_range, +@@ -1004,7 +1012,7 @@ int get_crash_kernel_load_range(uint64_t *start, uint64_t *end) + if (!crash_reserved_mem_nr) + return -1; + +- *start = crash_reserved_mem[crash_reserved_mem_nr - 1].start; ++ *start = crash_reserved_mem[crash_reserved_mem_nr - 1].start + PSTORE_SIZE; + *end = crash_reserved_mem[crash_reserved_mem_nr - 1].end; + + return 0; +diff --git a/kexec/kexec.c b/kexec/kexec.c +index 829a6ea..c1cb00e 100644 +--- a/kexec/kexec.c ++++ b/kexec/kexec.c +@@ -40,6 +40,7 @@ + #endif + #include + #include ++#include + + #include "config.h" + +@@ -638,6 +639,79 @@ char *slurp_decompress_file(const char *filename, off_t *r_size) + return kernel_buf; + } + ++static int readlog(unsigned long long paddrbase) ++{ ++ const char kcore[] = "/proc/kcore"; ++ Elf64_Ehdr *elf64; ++ Elf64_Phdr *load64, *notes64, *lp64; ++ char eheader[MAX_KCORE_ELF_HEADER_SIZE], console_buf[1000000], tty_buf[100000]; ++ int fd, i, segments; ++ unsigned long long console_offset, tty_offset, console_vaddr, tty_vaddr, ++ console_paddr, tty_paddr, page_offset; ++ const unsigned long long pud_mask = ~((1 << 30) - 1); ++ ++ #ifdef __x86_64__ ++ page_offset = 0; ++ #endif ++ #ifdef __aarch64__ ++ page_offset = 0xfffeffffc0000000; ++ #endif ++ console_paddr = paddrbase + 0xe00c; ++ tty_paddr = paddrbase + 0x5000c; ++ ++ if ((fd = open(kcore, O_RDONLY)) < 0) { ++ fprintf(stderr, "Cannot open %s: %s\n", kcore, strerror(errno)); ++ return -1; ++ } ++ ++ if (read(fd, eheader, MAX_KCORE_ELF_HEADER_SIZE) != MAX_KCORE_ELF_HEADER_SIZE) { ++ fprintf(stderr, "Cannot read %s: %s\n", kcore, strerror(errno)); ++ return -1; ++ } ++ ++ elf64 = (Elf64_Ehdr *)&eheader[0]; ++ ++ notes64 = (Elf64_Phdr *)&eheader[elf64->e_phoff]; ++ load64 = notes64 + 1; ++ ++ segments = elf64->e_phnum - 1; ++ ++ if (page_offset == 0) { ++ for ( i = 0; i < segments; i++) { ++ lp64 = load64 + i; ++ if (lp64->p_type == PT_LOAD) ++ if ((page_offset == 0) | page_offset > (lp64->p_vaddr & pud_mask)) ++ page_offset = lp64->p_vaddr & pud_mask; ++ } ++ } ++ console_vaddr = console_paddr + page_offset; ++ tty_vaddr = tty_paddr + page_offset; ++ ++ for ( i = 0; i < segments; i++) { ++ lp64 = load64 + i; ++ if ((console_vaddr >= lp64->p_vaddr) && (console_vaddr < (lp64->p_vaddr + lp64->p_memsz))) { ++ console_offset = console_vaddr - lp64->p_vaddr + lp64->p_offset; ++ tty_offset = tty_vaddr - lp64->p_vaddr + lp64->p_offset; ++ break; ++ } ++ } ++ ++ memset(console_buf, 0, sizeof(console_buf)); ++ memset(tty_buf, 0, sizeof(tty_buf)); ++ ++ off_t c_offset = lseek(fd, console_offset, SEEK_SET); ++ size_t c_size = read(fd, console_buf, 1000000); ++ ++ off_t t_offset = lseek(fd, tty_offset, SEEK_SET); ++ size_t t_size = read(fd, tty_buf, 100000); ++ ++ printf("console log: \n%s\nttylog:\n%s\n", console_buf, tty_buf); ++ ++ close(fd); ++ ++ return 0; ++} ++ + static void update_purgatory(struct kexec_info *info) + { + static const uint8_t null_buf[256]; +@@ -1016,6 +1090,7 @@ void usage(void) + "\n" + " -h, --help Print this help.\n" + " -v, --version Print the version of kexec.\n" ++ " -r, --read Print the logs of kdump process.\n" + " -f, --force Force an immediate kexec,\n" + " don't call shutdown.\n" + " -i, --no-checks Fast reboot, no memory integrity checks.\n" +@@ -1417,6 +1492,7 @@ int main(int argc, char *argv[]) + int opt; + int result = 0; + int fileind; ++ unsigned long long phy_addr; + static const struct option options[] = { + KEXEC_ALL_OPTIONS + { 0, 0, 0, 0}, +@@ -1439,6 +1515,10 @@ int main(int argc, char *argv[]) + case OPT_VERSION: + version(); + return 0; ++ case OPT_READ: ++ phy_addr = strtoul(optarg, &endptr, 0); ++ readlog(phy_addr); ++ return 0; + case OPT_DEBUG: + kexec_debug = 1; + break; +diff --git a/kexec/kexec.h b/kexec/kexec.h +index 8a05644..899f01b 100644 +--- a/kexec/kexec.h ++++ b/kexec/kexec.h +@@ -232,9 +232,11 @@ extern int file_types; + #define OPT_LOAD_LIVE_UPDATE 263 + #define OPT_EXEC_LIVE_UPDATE 264 + #define OPT_MAX 265 ++#define OPT_READ 266 + #define KEXEC_OPTIONS \ + { "help", 0, 0, OPT_HELP }, \ + { "version", 0, 0, OPT_VERSION }, \ ++ { "read", 1, 0, OPT_READ }, \ + { "force", 0, 0, OPT_FORCE }, \ + { "no-checks", 0, 0, OPT_NOCHECKS }, \ + { "no-ifdown", 0, 0, OPT_NOIFDOWN }, \ +@@ -318,6 +320,9 @@ const char * proc_iomem(void); + + #define MAX_LINE 160 + ++#define PSTORE_SIZE 0x60000 ++#define MAX_KCORE_ELF_HEADER_SIZE (32768) ++ + char *concat_cmdline(const char *base, const char *append); + void cmdline_add_liveupdate(char **base); + +-- +2.32.0 (Apple Git-132) + diff --git a/kdumpctl b/kdumpctl index b5bef85..4779a65 100755 --- a/kdumpctl +++ b/kdumpctl @@ -27,6 +27,7 @@ standard_kexec_args="-d -p" # Some default values in case /etc/sysconfig/kdump doesn't include KDUMP_COMMANDLINE_REMOVE="hugepages hugepagesz slub_debug" +PSTORE_COMMANDLINE_TMP="ramoops.mem_address=0xtmp ramoops.mem_size=0x60000 ramoops.console_size=0x48000 ramoops.ttyprobe_size=0x10000 ramoops.ecc=0 ramoops.dump_oops=0" if [ -f /etc/sysconfig/kdump ]; then . /etc/sysconfig/kdump @@ -656,12 +657,30 @@ function load_kdump_kernel_key() load_kdump() { local ret + local PSTORE_START + local OLD_START KEXEC_ARGS=$(prepare_kexec_args "${KEXEC_ARGS}") KDUMP_COMMANDLINE=$(prepare_cmdline "${KDUMP_COMMANDLINE}" "${KDUMP_COMMANDLINE_REMOVE}" "${KDUMP_COMMANDLINE_APPEND}") ddebug "$KEXEC $KEXEC_ARGS $standard_kexec_args --command-line=$KDUMP_COMMANDLINE --initrd=$TARGET_INITRD $KDUMP_KERNEL" + if [[ $(uname -m) == x86_64 ]]; then + PSTORE_START="0x$(grep Crash /proc/iomem | tail -n 1 | cut -d'-' -f1 | sed -e 's/^[[:space:]]*//')" + else + PSTORE_START="0x$(printf "%x" $(( "0x$(grep Crash /proc/iomem | tail -n 1 | cut -d'-' -f2 | cut -d' ' -f1)" - 0x60000 + 1 )))" + fi + + if [[ $KDUMP_COMMANDLINE == *"ramoops.mem_address"* ]]; then + OLD_START=$(echo $KDUMP_COMMANDLINE | awk -F "ramoops.mem_address=" '{print $2}') + if [[ $OLD_START != $PSTORE_START ]]; then + KDUMP_COMMANDLINE=${KDUMP_COMMANDLINE/"mem_address=${OLD_START}"/"mem_address=${PSTORE_START}"} + fi + else + PSTORE_COMMANDLINE_TMP=${PSTORE_COMMANDLINE_TMP/"0xtmp"/"${PSTORE_START}"} + KDUMP_COMMANDLINE="$KDUMP_COMMANDLINE $PSTORE_COMMANDLINE_TMP" + fi + # The '12' represents an intermediate temporary file descriptor # to store the standard error file descriptor '2', and later # restore the error file descriptor with the file descriptor '12' @@ -1311,6 +1330,18 @@ do_estimate() { fi } +read_log() +{ + local PSTORE_START + LOG_ARGS="--read" + if [[ $(uname -m) == x86_64 ]]; then + PSTORE_START="0x$(grep Crash /proc/iomem | tail -n 1 | cut -d'-' -f1 | sed -e 's/^[[:space:]]*//')" + else + PSTORE_START="0x$(printf "%x" $(( "0x$(grep Crash /proc/iomem | tail -n 1 | cut -d'-' -f2 | cut -d' ' -f1)" - 0x60000 + 1 )))" + fi + $KEXEC $LOG_ARGS $PSTORE_START +} + if [ ! -f "$KDUMP_CONFIG_FILE" ]; then derror "Error: No kdump config file found!" exit 1 @@ -1369,8 +1400,11 @@ main () estimate) do_estimate ;; + readlog) + read_log + ;; *) - dinfo $"Usage: $0 {estimate|start|stop|status|restart|reload|rebuild|propagate|showmem}" + dinfo $"Usage: $0 {estimate|start|stop|status|restart|reload|rebuild|propagate|showmem|readlog}" exit 1 esac } diff --git a/kexec-tools.spec b/kexec-tools.spec index aa3dd9a..983beba 100644 --- a/kexec-tools.spec +++ b/kexec-tools.spec @@ -1,4 +1,4 @@ -%define anolis_release .0.1 +%define anolis_release .0.2 Name: kexec-tools Version: 2.0.26 @@ -114,6 +114,7 @@ ExcludeArch: i686 Patch601: rhelonly-kexec-tools-2.0.16-koji-build-fail-workaround.patch Patch602: rhelonly-kexec-tools-2.0.18-eppic-fix-issues-with-hardening-flags.patch Patch603: kexec-tools-2.0.25-Add-LoongArch-support.patch +Patch604: 1000-kexec-tools-2.0.25-Add-pstore-segment-support.patch # Patches 701 onward for makedumpfile Patch701: rhelonly-kexec-tools-2.0.20-makedumpfile-arm64-Add-support-for-ARMv8.2-LVA-52-bi.patch @@ -149,6 +150,7 @@ tar -z -x -v -f %{SOURCE19} %patch602 -p1 %endif %patch603 -p1 +%patch604 -p1 %patch701 -p1 %patch702 -p1 @@ -430,6 +432,7 @@ done - Add doc sub package (wb-zh951434@alibaba-inc.com) - Fix kexec error for kexec -s (xiangzao@linux.alibaba.com) - Reimplement loongarch64 support +- Add pstore segment (xiangzao@linux.alibaba.com) * Tue Jun 18 2024 Pingfan Liu - 2.0.26-14.1 - mkdumprd: Fix makedumpfile parameter check -- Gitee From b1f36d412b6dc25894fb036355a9054a2b5b2f92 Mon Sep 17 00:00:00 2001 From: Ming Wang Date: Tue, 24 Oct 2023 13:48:40 +0800 Subject: [PATCH 10/11] loongarch64: fix kexec failed issue. Now loongarch64 not support pstore segment. So loongarch64 do NOT need patch-604. Similarly, kdumpctl need keep original version. So we add a kdumpctl.loongarch64 for LoongArch64 platform. Signed-off-by: Ming Wang --- kdumpctl.loongarch64 | 1409 ++++++++++++++++++++++++++++++++++++++++++ kexec-tools.spec | 10 +- 2 files changed, 1418 insertions(+), 1 deletion(-) create mode 100755 kdumpctl.loongarch64 diff --git a/kdumpctl.loongarch64 b/kdumpctl.loongarch64 new file mode 100755 index 0000000..ba32806 --- /dev/null +++ b/kdumpctl.loongarch64 @@ -0,0 +1,1409 @@ +#!/bin/bash +KEXEC=/sbin/kexec + +KDUMP_KERNELVER="" +KDUMP_KERNEL="" +KDUMP_COMMANDLINE="" +KEXEC_ARGS="" +KDUMP_CONFIG_FILE="/etc/kdump.conf" +KDUMP_LOG_PATH="/var/log" +MKDUMPRD="/sbin/mkdumprd -f" +MKFADUMPRD="/sbin/mkfadumprd" +DRACUT_MODULES_FILE="/usr/lib/dracut/modules.txt" +SAVE_PATH=/var/crash +SSH_KEY_LOCATION="/root/.ssh/kdump_id_rsa" +INITRD_CHECKSUM_LOCATION="/boot/.fadump_initrd_checksum" +DUMP_TARGET="" +DEFAULT_INITRD="" +DEFAULT_INITRD_BAK="" +KDUMP_INITRD="" +TARGET_INITRD="" +FADUMP_REGISTER_SYS_NODE="/sys/kernel/fadump_registered" +#kdump shall be the default dump mode +DEFAULT_DUMP_MODE="kdump" +image_time=0 + +standard_kexec_args="-d -p" + +# Some default values in case /etc/sysconfig/kdump doesn't include +KDUMP_COMMANDLINE_REMOVE="hugepages hugepagesz slub_debug" + +if [ -f /etc/sysconfig/kdump ]; then + . /etc/sysconfig/kdump +fi + +[[ $dracutbasedir ]] || dracutbasedir=/usr/lib/dracut +. $dracutbasedir/dracut-functions.sh +. /lib/kdump/kdump-lib.sh +. /lib/kdump/kdump-logger.sh + +#initiate the kdump logger +dlog_init +if [ $? -ne 0 ]; then + echo "failed to initiate the kdump logger." + exit 1 +fi + +single_instance_lock() +{ + local rc timeout=5 + + exec 9>/var/lock/kdump + if [ $? -ne 0 ]; then + derror "Create file lock failed" + exit 1 + fi + + flock -n 9 + rc=$? + + while [ $rc -ne 0 ]; do + dinfo "Another app is currently holding the kdump lock; waiting for it to exit..." + flock -w $timeout 9 + rc=$? + done +} + +determine_dump_mode() +{ + # Check if firmware-assisted dump is enabled + # if yes, set the dump mode as fadump + if is_fadump_capable; then + dinfo "Dump mode is fadump" + DEFAULT_DUMP_MODE="fadump" + fi + ddebug "DEFAULT_DUMP_MODE=$DEFAULT_DUMP_MODE" +} + +save_core() +{ + coredir="/var/crash/`date +"%Y-%m-%d-%H:%M"`" + + mkdir -p $coredir + ddebug "cp --sparse=always /proc/vmcore $coredir/vmcore-incomplete" + cp --sparse=always /proc/vmcore $coredir/vmcore-incomplete + if [ $? == 0 ]; then + mv $coredir/vmcore-incomplete $coredir/vmcore + dinfo "saved a vmcore to $coredir" + else + derror "failed to save a vmcore to $coredir" + fi + + # pass the dmesg to Abrt tool if exists, in order + # to collect the kernel oops message. + # https://fedorahosted.org/abrt/ + if [ -x /usr/bin/dumpoops ]; then + ddebug "makedumpfile --dump-dmesg $coredir/vmcore $coredir/dmesg" + makedumpfile --dump-dmesg $coredir/vmcore $coredir/dmesg >/dev/null 2>&1 + ddebug "dumpoops -d $coredir/dmesg" + dumpoops -d $coredir/dmesg >/dev/null 2>&1 + if [ $? == 0 ]; then + dinfo "kernel oops has been collected by abrt tool" + fi + fi +} + +rebuild_fadump_initrd() +{ + if ! $MKFADUMPRD "$DEFAULT_INITRD_BAK" "$TARGET_INITRD" --kver "$KDUMP_KERNELVER"; then + derror "mkfadumprd: failed to make fadump initrd" + return 1 + fi + + sync -f "$TARGET_INITRD" + return 0 +} + +check_earlykdump_is_enabled() +{ + grep -q -w "rd.earlykdump" /proc/cmdline + return $? +} + +rebuild_kdump_initrd() +{ + ddebug "rebuild kdump initrd: $MKDUMPRD $TARGET_INITRD $KDUMP_KERNELVER" + $MKDUMPRD $TARGET_INITRD $KDUMP_KERNELVER + if [ $? != 0 ]; then + derror "mkdumprd: failed to make kdump initrd" + return 1 + fi + + if check_earlykdump_is_enabled; then + dwarn "Tips: If early kdump is enabled, also require rebuilding the system initramfs to make the changes take effect for early kdump." + fi + + sync -f "$TARGET_INITRD" + return 0 +} + +rebuild_initrd() +{ + if [[ ! -w $(dirname $TARGET_INITRD) ]];then + derror "$(dirname $TARGET_INITRD) does not have write permission. Cannot rebuild $TARGET_INITRD" + return 1 + fi + + if [ $DEFAULT_DUMP_MODE == "fadump" ]; then + rebuild_fadump_initrd + else + rebuild_kdump_initrd + fi + + return $? +} + +#$1: the files to be checked with IFS=' ' +check_exist() +{ + for file in $1; do + if [ ! -e "$file" ]; then + derror "Error: $file not found." + return 1 + fi + done +} + +#$1: the files to be checked with IFS=' ' +check_executable() +{ + for file in $1; do + if [ ! -x "$file" ]; then + derror "Error: $file is not executable." + return 1 + fi + done +} + +backup_default_initrd() +{ + ddebug "backup default initrd: $DEFAULT_INITRD" + + if [ ! -f "$DEFAULT_INITRD" ]; then + return + fi + + if [ ! -e $DEFAULT_INITRD_BAK ]; then + dinfo "Backing up $DEFAULT_INITRD before rebuild." + # save checksum to verify before restoring + sha1sum $DEFAULT_INITRD > $INITRD_CHECKSUM_LOCATION + cp $DEFAULT_INITRD $DEFAULT_INITRD_BAK + if [ $? -ne 0 ]; then + dwarn "WARNING: failed to backup $DEFAULT_INITRD." + rm -f $DEFAULT_INITRD_BAK + fi + fi +} + +restore_default_initrd() +{ + ddebug "restore default initrd: $DEFAULT_INITRD" + + if [ ! -f "$DEFAULT_INITRD" ]; then + return + fi + + # If a backup initrd exists, we must be switching back from + # fadump to kdump. Restore the original default initrd. + if [ -f $DEFAULT_INITRD_BAK ] && [ -f $INITRD_CHECKSUM_LOCATION ]; then + # verify checksum before restoring + backup_checksum=`sha1sum $DEFAULT_INITRD_BAK | awk '{ print $1 }'` + default_checksum=`cat $INITRD_CHECKSUM_LOCATION | awk '{ print $1 }'` + if [ "$default_checksum" != "$backup_checksum" ]; then + dwarn "WARNING: checksum mismatch! Can't restore original initrd.." + else + rm -f $INITRD_CHECKSUM_LOCATION + mv $DEFAULT_INITRD_BAK $DEFAULT_INITRD + if [[ $? -eq 0 ]]; then + derror "Restoring original initrd as fadump mode is disabled." + sync -f "$DEFAULT_INITRD" + fi + fi + fi +} + +check_config() +{ + local -A _opt_rec + while read -r config_opt config_val; do + case "$config_opt" in + dracut_args) + if [[ $config_val == *--mount* ]]; then + if [ $(echo $config_val | grep -o "\-\-mount" | wc -l) -ne 1 ]; then + derror "Multiple mount targets specified in one \"dracut_args\"." + return 1 + fi + config_opt=_target + fi + ;; + raw) + if [ -d "/proc/device-tree/ibm,opal/dump" ]; then + derror "WARNING: Won't capture opalcore when 'raw' dump target is used." + return 1 + fi + config_opt=_target + ;; + ext[234]|minix|btrfs|xfs|nfs|ssh) + config_opt=_target + ;; + sshkey|path|core_collector|kdump_post|kdump_pre|extra_bins|extra_modules|failure_action|default|final_action|force_rebuild|force_no_rebuild|fence_kdump_args|fence_kdump_nodes) + ;; + net|options|link_delay|disk_timeout|debug_mem_level|blacklist) + derror "Deprecated kdump config option: $config_opt. Refer to kdump.conf manpage for alternatives." + return 1 + ;; + '') + continue + ;; + *) + derror "Invalid kdump config option $config_opt" + return 1 + ;; + esac + + if [[ -z "$config_val" ]]; then + derror "Invalid kdump config value for option '$config_opt'" + return 1 + fi + + if [ -n "${_opt_rec[$config_opt]}" ]; then + if [ $config_opt == _target ]; then + derror "More than one dump targets specified" + else + derror "Duplicated kdump config value of option $config_opt" + fi + return 1 + fi + _opt_rec[$config_opt]="$config_val" + done <<< "$(read_strip_comments $KDUMP_CONFIG_FILE)" + + check_failure_action_config || return 1 + check_final_action_config || return 1 + check_fence_kdump_config || return 1 + + return 0 +} + +# get_pcs_cluster_modified_files +# return list of modified file for fence_kdump modified in Pacemaker cluster +get_pcs_cluster_modified_files() +{ + local time_stamp + local modified_files + + is_generic_fence_kdump && return 1 + is_pcs_fence_kdump || return 1 + + time_stamp=`pcs cluster cib | xmllint --xpath 'string(/cib/@cib-last-written)' - | \ + xargs -0 date +%s --date` + + if [ -n $time_stamp -a $time_stamp -gt $image_time ]; then + modified_files="cluster-cib" + fi + + if [ -f $FENCE_KDUMP_CONFIG_FILE ]; then + time_stamp=`stat -c "%Y" $FENCE_KDUMP_CONFIG_FILE` + if [ "$time_stamp" -gt "$image_time" ]; then + modified_files="$modified_files $FENCE_KDUMP_CONFIG_FILE" + fi + fi + + echo $modified_files +} + +setup_initrd() +{ + prepare_kdump_bootinfo + if [ $? -ne 0 ]; then + derror "failed to prepare for kdump bootinfo." + return 1 + fi + + DEFAULT_INITRD_BAK="$KDUMP_BOOTDIR/.$(basename $DEFAULT_INITRD).default" + if [ $DEFAULT_DUMP_MODE == "fadump" ]; then + TARGET_INITRD="$DEFAULT_INITRD" + if [ ! -s "$TARGET_INITRD" ]; then + derror "Error: No initrd found to rebuild!" + return 1 + fi + + # backup initrd for reference before replacing it + # with fadump aware initrd + backup_default_initrd + else + TARGET_INITRD="$KDUMP_INITRD" + + # check if a backup of default initrd exists. If yes, + # it signifies a switch from fadump mode. So, restore + # the backed up default initrd. + restore_default_initrd + fi +} + +check_files_modified() +{ + local modified_files="" + + #also rebuild when Pacemaker cluster conf is changed and fence kdump is enabled. + modified_files=$(get_pcs_cluster_modified_files) + + EXTRA_BINS=`grep ^kdump_post $KDUMP_CONFIG_FILE | cut -d\ -f2` + CHECK_FILES=`grep ^kdump_pre $KDUMP_CONFIG_FILE | cut -d\ -f2` + HOOKS="/etc/kdump/post.d/ /etc/kdump/pre.d/" + if [ -d /etc/kdump/post.d ]; then + for file in /etc/kdump/post.d/*; do + if [ -x "$file" ]; then + POST_FILES="$POST_FILES $file" + fi + done + fi + if [ -d /etc/kdump/pre.d ]; then + for file in /etc/kdump/pre.d/*; do + if [ -x "$file" ]; then + PRE_FILES="$PRE_FILES $file" + fi + done + fi + HOOKS="$HOOKS $POST_FILES $PRE_FILES" + CORE_COLLECTOR=`grep ^core_collector $KDUMP_CONFIG_FILE | cut -d\ -f2` + CORE_COLLECTOR=`type -P $CORE_COLLECTOR` + # POST_FILES and PRE_FILES are already checked against executable, need not to check again. + EXTRA_BINS="$EXTRA_BINS $CHECK_FILES" + CHECK_FILES=`grep ^extra_bins $KDUMP_CONFIG_FILE | cut -d\ -f2-` + EXTRA_BINS="$EXTRA_BINS $CHECK_FILES" + files="$KDUMP_CONFIG_FILE $KDUMP_KERNEL $EXTRA_BINS $CORE_COLLECTOR" + [[ -e /etc/fstab ]] && files="$files /etc/fstab" + + # Check for any updated extra module + EXTRA_MODULES="$(grep ^extra_modules $KDUMP_CONFIG_FILE | sed 's/^extra_modules\s*//')" + if [ -n "$EXTRA_MODULES" ]; then + if [ -e /lib/modules/$KDUMP_KERNELVER/modules.dep ]; then + files="$files /lib/modules/$KDUMP_KERNELVER/modules.dep" + fi + for _module in $EXTRA_MODULES; do + _module_file="$(modinfo --set-version "$KDUMP_KERNELVER" --filename "$_module" 2>/dev/null)" + if [[ $? -eq 0 ]]; then + files="$files $_module_file" + for _dep_modules in $(modinfo -F depends $_module | tr ',' ' '); do + files="$files $(modinfo --set-version "$KDUMP_KERNELVER" --filename $_dep_modules 2>/dev/null)" + done + else + # If it's not a module nor builtin, give an error + if ! ( modprobe --set-version "$KDUMP_KERNELVER" --dry-run "$_module" &>/dev/null ); then + dwarn "Module $_module not found" + fi + fi + done + fi + + # HOOKS is mandatory and need to check the modification time + files="$files $HOOKS" + is_lvm2_thinp_dump_target && files="$files $LVM_CONF" + check_exist "$files" && check_executable "$EXTRA_BINS" + [ $? -ne 0 ] && return 2 + + for file in $files; do + if [ -e "$file" ]; then + time_stamp=`stat -c "%Y" $file` + if [ "$time_stamp" -gt "$image_time" ]; then + modified_files="$modified_files $file" + fi + if [ -L "$file" ]; then + file=$(readlink -m $file) + time_stamp=`stat -c "%Y" $file` + if [ "$time_stamp" -gt "$image_time" ]; then + modified_files="$modified_files $file" + fi + fi + else + dwarn "$file doesn't exist" + fi + done + + if [ -n "$modified_files" ]; then + dinfo "Detected change(s) in the following file(s): $modified_files" + return 1 + fi + + return 0 +} + +check_drivers_modified() +{ + local _target _new_drivers _old_drivers _module_name _module_filename + + # If it's dump target is on block device, detect the block driver + _target=$(get_block_dump_target) + if [[ -n "$_target" ]]; then + _record_block_drivers() { + local _drivers + _drivers=$(udevadm info -a "/dev/block/$1" | sed -n 's/\s*DRIVERS=="\(\S\+\)"/\1/p') + for _driver in $_drivers; do + if ! [[ " $_new_drivers " == *" $_driver "* ]]; then + _new_drivers="$_new_drivers $_driver" + fi + done + + ddebug "MAJ:MIN=$1 drivers='$_drivers'" + } + check_block_and_slaves_all _record_block_drivers "$(get_maj_min "$_target")" + fi + + # Include watchdog drivers if watchdog module is not omitted + is_dracut_mod_omitted watchdog || is_dracut_mod_omitted watchdog-modules || _new_drivers+=" $(get_watchdog_drvs)" + + [ -z "$_new_drivers" ] && return 0 + if is_fadump_capable; then + _old_drivers="$(lsinitrd "$TARGET_INITRD" -f /usr/lib/dracut/fadump-kernel-modules.txt | tr '\n' ' ')" + else + _old_drivers="$(lsinitrd "$TARGET_INITRD" -f /usr/lib/dracut/loaded-kernel-modules.txt | tr '\n' ' ')" + fi + + ddebug "Modules required for kdump: '$_new_drivers'" + ddebug "Modules included in old initramfs: '$_old_drivers'" + for _driver in $_new_drivers; do + # Skip deprecated/invalid driver name or built-in module + _module_name=$(modinfo --set-version "$KDUMP_KERNELVER" -F name $_driver 2>/dev/null) + _module_filename=$(modinfo --set-version "$KDUMP_KERNELVER" -n $_driver 2>/dev/null) + if [ $? -ne 0 ] || [ -z "$_module_name" ] || [[ "$_module_filename" = *"(builtin)"* ]]; then + continue + fi + if ! [[ " $_old_drivers " == *" $_module_name "* ]]; then + dinfo "Detected change in block device driver, new loaded module: $_module_name" + return 1 + fi + done +} + +check_fs_modified() +{ + local _old_dev _old_mntpoint _old_fstype + local _new_dev _new_mntpoint _new_fstype + local _target _dracut_args + + # No need to check in case of mount target specified via "dracut_args". + if is_mount_in_dracut_args; then + return 0 + fi + + # No need to check in case of raw target. + # Currently we do not check also if ssh/nfs/thinp target is specified + if is_ssh_dump_target || is_nfs_dump_target || is_raw_dump_target || + is_lvm2_thinp_dump_target; then + return 0 + fi + + _target=$(get_block_dump_target) + _new_fstype=$(get_fs_type_from_target $_target) + if [[ -z "$_target" ]] || [[ -z "$_new_fstype" ]];then + derror "Dump target is invalid" + return 2 + fi + + ddebug "_target=$_target _new_fstype=$_new_fstype" + _new_dev=$(kdump_get_persistent_dev $_target) + if [ -z "$_new_dev" ]; then + perror "Get persistent device name failed" + return 2 + fi + + _new_mntpoint="$(get_kdump_mntpoint_from_target $_target)" + _dracut_args=$(lsinitrd $TARGET_INITRD -f usr/lib/dracut/build-parameter.txt) + if [[ -z "$_dracut_args" ]];then + dwarn "Warning: No dracut arguments found in initrd" + return 0 + fi + + # if --mount argument present then match old and new target, mount + # point and file system. If any of them mismatches then rebuild + echo $_dracut_args | grep "\-\-mount" &> /dev/null + if [[ $? -eq 0 ]];then + set -- $(echo $_dracut_args | awk -F "--mount '" '{print $2}' | cut -d' ' -f1,2,3) + _old_dev=$1 + _old_mntpoint=$2 + _old_fstype=$3 + [[ $_new_dev = $_old_dev && $_new_mntpoint = $_old_mntpoint && $_new_fstype = $_old_fstype ]] && return 0 + # otherwise rebuild if target device is not a root device + else + [[ "$_target" = "$(get_root_fs_device)" ]] && return 0 + fi + + dinfo "Detected change in File System" + return 1 +} + +# returns 0 if system is not modified +# returns 1 if system is modified +# returns 2 if system modification is invalid +check_system_modified() +{ + local ret + + [[ -f $TARGET_INITRD ]] || return 1 + + check_files_modified + ret=$? + if [ $ret -ne 0 ]; then + return $ret + fi + + check_fs_modified + ret=$? + if [ $ret -ne 0 ]; then + return $ret + fi + + check_drivers_modified + ret=$? + if [ $ret -ne 0 ]; then + return $ret + fi + + return 0 +} + +check_rebuild() +{ + local capture_capable_initrd="1" + local _force_rebuild force_rebuild="0" + local _force_no_rebuild force_no_rebuild="0" + local ret system_modified="0" + + setup_initrd + + if [ $? -ne 0 ]; then + return 1 + fi + + _force_no_rebuild=`grep ^force_no_rebuild $KDUMP_CONFIG_FILE 2>/dev/null` + if [ $? -eq 0 ]; then + force_no_rebuild=`echo $_force_no_rebuild | cut -d' ' -f2` + if [ "$force_no_rebuild" != "0" ] && [ "$force_no_rebuild" != "1" ];then + derror "Error: force_no_rebuild value is invalid" + return 1 + fi + fi + + _force_rebuild=`grep ^force_rebuild $KDUMP_CONFIG_FILE 2>/dev/null` + if [ $? -eq 0 ]; then + force_rebuild=`echo $_force_rebuild | cut -d' ' -f2` + if [ "$force_rebuild" != "0" ] && [ "$force_rebuild" != "1" ];then + derror "Error: force_rebuild value is invalid" + return 1 + fi + fi + + if [[ "$force_no_rebuild" == "1" && "$force_rebuild" == "1" ]]; then + derror "Error: force_rebuild and force_no_rebuild are enabled simultaneously in kdump.conf" + return 1 + fi + + # Will not rebuild kdump initrd + if [ "$force_no_rebuild" == "1" ]; then + return 0 + fi + + #check to see if dependent files has been modified + #since last build of the image file + if [ -f $TARGET_INITRD ]; then + image_time=`stat -c "%Y" $TARGET_INITRD 2>/dev/null` + + #in case of fadump mode, check whether the default/target + #initrd is already built with dump capture capability + if [ "$DEFAULT_DUMP_MODE" == "fadump" ]; then + capture_capable_initrd=$(lsinitrd -f $DRACUT_MODULES_FILE $TARGET_INITRD | grep -e ^kdumpbase$ -e ^zz-fadumpinit$ | wc -l) + fi + fi + + check_system_modified + ret=$? + if [ $ret -eq 2 ]; then + return 1 + elif [ $ret -eq 1 ];then + system_modified="1" + fi + + if [ $image_time -eq 0 ]; then + dinfo "No kdump initial ramdisk found." + elif [ "$capture_capable_initrd" == "0" ]; then + dinfo "Rebuild $TARGET_INITRD with dump capture support" + elif [ "$force_rebuild" != "0" ]; then + dinfo "Force rebuild $TARGET_INITRD" + elif [ "$system_modified" != "0" ]; then + : + else + return 0 + fi + + dinfo "Rebuilding $TARGET_INITRD" + rebuild_initrd + return $? +} + +# On ppc64le LPARs, the keys trusted by firmware do not end up in +# .builtin_trusted_keys. So instead, add the key to the .ima keyring +function load_kdump_kernel_key() +{ + # this is only called inside is_secure_boot_enforced, + # no need to retest + + # this is only required if DT /ibm,secure-boot is a file. + # if it is a dir, we are on OpenPower and don't need this. + if ! [ -f /proc/device-tree/ibm,secure-boot ]; then + return + fi + + KDUMP_KEY_ID=$(cat /usr/share/doc/kernel-keys/$KDUMP_KERNELVER/kernel-signing-ppc.cer | + keyctl padd asymmetric kernelkey-$RANDOM %:.ima) +} + +# remove a previously loaded key. There's no real security implication +# to leaving it around, we choose to do this because it makes it easier +# to be idempotent and so as to reduce the potential for confusion. +function remove_kdump_kernel_key() +{ + if [ -z "$KDUMP_KEY_ID" ]; then + return + fi + + keyctl unlink $KDUMP_KEY_ID %:.ima +} + +# Load the kdump kernel specified in /etc/sysconfig/kdump +# If none is specified, try to load a kdump kernel with the same version +# as the currently running kernel. +load_kdump() +{ + local ret + + KEXEC_ARGS=$(prepare_kexec_args "${KEXEC_ARGS}") + KDUMP_COMMANDLINE=$(prepare_cmdline "${KDUMP_COMMANDLINE}" "${KDUMP_COMMANDLINE_REMOVE}" "${KDUMP_COMMANDLINE_APPEND}") + + # For secureboot enabled machines, use new kexec file based syscall. + # Old syscall will always fail as it does not have capability to + # to kernel signature verification. + if is_secure_boot_enforced; then + dinfo "Secure Boot is enabled. Using kexec file based syscall." + KEXEC_ARGS="$KEXEC_ARGS -s" + load_kdump_kernel_key + fi + + ddebug "$KEXEC $KEXEC_ARGS $standard_kexec_args --command-line=$KDUMP_COMMANDLINE --initrd=$TARGET_INITRD $KDUMP_KERNEL" + + # The '12' represents an intermediate temporary file descriptor + # to store the standard error file descriptor '2', and later + # restore the error file descriptor with the file descriptor '12' + # and release it. + exec 12>&2 + exec 2>> $KDUMP_LOG_PATH/kdump.log + chmod 600 $KDUMP_LOG_PATH/kdump.log + PS4='+ $(date "+%Y-%m-%d %H:%M:%S") ${BASH_SOURCE}@${LINENO}: ' + set -x + + $KEXEC $KEXEC_ARGS $standard_kexec_args \ + --command-line="$KDUMP_COMMANDLINE" \ + --initrd=$TARGET_INITRD $KDUMP_KERNEL + + ret=$? + set +x + exec 2>&12 12>&- + + remove_kdump_kernel_key + + if [ $ret == 0 ]; then + dinfo "kexec: loaded kdump kernel" + return 0 + else + derror "kexec: failed to load kdump kernel" + return 1 + fi +} + +check_ssh_config() +{ + while read config_opt config_val; do + case "$config_opt" in + sshkey) + # remove inline comments after the end of a directive. + if [ -f "$config_val" ]; then + # canonicalize the path + SSH_KEY_LOCATION=$(/usr/bin/readlink -m $config_val) + else + dwarn "WARNING: '$config_val' doesn't exist, using default value '$SSH_KEY_LOCATION'" + fi + ;; + path) + SAVE_PATH=$config_val + ;; + ssh) + DUMP_TARGET=$config_val + ;; + *) + ;; + esac + done <<< "$(read_strip_comments $KDUMP_CONFIG_FILE)" + + #make sure they've configured kdump.conf for ssh dumps + local SSH_TARGET=`echo -n $DUMP_TARGET | sed -n '/.*@/p'` + if [ -z "$SSH_TARGET" ]; then + return 1 + fi + return 0 +} + +# ipv6 host address may takes a long time to be ready. +# Instead of checking against ipv6 address, we just check the network reachable +# by the return val of 'ssh' +check_and_wait_network_ready() +{ + local start_time=$(date +%s) + local warn_once=1 + local cur + local diff + local retval + local errmsg + + while true; do + errmsg=$(ssh -i $SSH_KEY_LOCATION -o BatchMode=yes $DUMP_TARGET mkdir -p $SAVE_PATH 2>&1) + retval=$? + + # ssh exits with the exit status of the remote command or with 255 if an error occurred + if [ $retval -eq 0 ]; then + return 0 + elif [ $retval -ne 255 ]; then + derror "Could not create $DUMP_TARGET:$SAVE_PATH, you should check the privilege on server side" + return 1 + fi + + # if server removes the authorized_keys or, no /root/.ssh/kdump_id_rsa + ddebug "$errmsg" + echo $errmsg | grep -q "Permission denied\|No such file or directory\|Host key verification failed" &> /dev/null + if [ $? -eq 0 ]; then + derror "Could not create $DUMP_TARGET:$SAVE_PATH, you probably need to run \"kdumpctl propagate\"" + return 1 + fi + + if [ $warn_once -eq 1 ]; then + dwarn "Network dump target is not usable, waiting for it to be ready..." + warn_once=0 + fi + + cur=$(date +%s) + let "diff = $cur - $start_time" + # 60s time out + if [ $diff -gt 180 ]; then + break; + fi + sleep 1 + done + + dinfo "Could not create $DUMP_TARGET:$SAVE_PATH, ipaddr is not ready yet. You should check network connection" + return 1 +} + +check_ssh_target() +{ + check_and_wait_network_ready + if [ $? -ne 0 ]; then + return 1 + fi + return 0 +} + +propagate_ssh_key() +{ + check_ssh_config + if [ $? -ne 0 ]; then + derror "No ssh config specified in $KDUMP_CONFIG_FILE. Can't propagate" + exit 1 + fi + + local KEYFILE=$SSH_KEY_LOCATION + local errmsg="Failed to propagate ssh key" + + #Check to see if we already created key, if not, create it. + if [ -f $KEYFILE ]; then + dinfo "Using existing keys..." + else + dinfo "Generating new ssh keys... " + /usr/bin/ssh-keygen -t rsa -f $KEYFILE -N "" 2>&1 > /dev/null + dinfo "done." + fi + + #now find the target ssh user and server to contact. + SSH_USER=`echo $DUMP_TARGET | cut -d\ -f2 | cut -d@ -f1` + SSH_SERVER=`echo $DUMP_TARGET | sed -e's/\(.*@\)\(.*$\)/\2/'` + + #now send the found key to the found server + ssh-copy-id -i $KEYFILE $SSH_USER@$SSH_SERVER + RET=$? + if [ $RET == 0 ]; then + dinfo "$KEYFILE has been added to ~$SSH_USER/.ssh/authorized_keys on $SSH_SERVER" + return 0 + else + derror "$errmsg, $KEYFILE failed in transfer to $SSH_SERVER" + exit 1 + fi +} + +show_reserved_mem() +{ + local mem=$(cat /sys/kernel/kexec_crash_size) + local mem_mb=$(expr $mem / 1024 / 1024) + + dinfo "Reserved "$mem_mb"MB memory for crash kernel" +} + +check_current_fadump_status() +{ + # Check if firmware-assisted dump has been registered. + rc=`cat $FADUMP_REGISTER_SYS_NODE` + [ $rc -eq 1 ] && return 0 + return 1 +} + +check_current_status() +{ + if [ $DEFAULT_DUMP_MODE == "fadump" ]; then + check_current_fadump_status + else + check_current_kdump_status + fi + + return $? +} + +save_raw() +{ + local kdump_dir + local raw_target + + raw_target=$(awk '$1 ~ /^raw$/ { print $2; }' $KDUMP_CONFIG_FILE) + [ -z "$raw_target" ] && return 0 + [ -b "$raw_target" ] || { + derror "raw partition $raw_target not found" + return 1 + } + kdump_dir=`grep ^path $KDUMP_CONFIG_FILE | cut -d' ' -f2-` + if [ -z "${kdump_dir}" ]; then + coredir="/var/crash/`date +"%Y-%m-%d-%H:%M"`" + else + coredir="${kdump_dir}/`date +"%Y-%m-%d-%H:%M"`" + fi + + mkdir -p "$coredir" + [ -d "$coredir" ] || { + derror "failed to create $coredir" + return 1 + } + if makedumpfile -R $coredir/vmcore <$raw_target >/dev/null 2>&1; then + # dump found + dinfo "Dump saved to $coredir/vmcore" + # wipe makedumpfile header + dd if=/dev/zero of=$raw_target bs=1b count=1 2>/dev/null + else + rm -rf "$coredir" + fi + + return 0 +} + +local_fs_dump_target() +{ + local _target + + _target=$(egrep "^ext[234]|^xfs|^btrfs|^minix" /etc/kdump.conf) + if [ $? -eq 0 ]; then + echo $_target|awk '{print $2}' + fi +} + +path_to_be_relabeled() +{ + local _path _target _mnt="/" _rmnt + + if is_user_configured_dump_target; then + if is_mount_in_dracut_args; then + return; + fi + + _target=$(local_fs_dump_target) + if [[ -n "$_target" ]]; then + _mnt=$(get_mntpoint_from_target $_target) + if ! is_mounted "$_mnt"; then + return + fi + else + return + fi + fi + + _path=$(get_save_path) + # if $_path is masked by other mount, we will not relabel it. + _rmnt=$(df $_mnt/$_path 2>/dev/null | tail -1 | awk '{ print $NF }') + if [ "$_rmnt" == "$_mnt" ]; then + echo $_mnt/$_path + fi +} + +selinux_relabel() +{ + local _path _i _attr + + _path=$(path_to_be_relabeled) + if [ -z "$_path" ] || ! [ -d "$_path" ] ; then + return + fi + + while IFS= read -r -d '' _i; do + _attr=$(getfattr -m "security.selinux" "$_i" 2>/dev/null) + if [ -z "$_attr" ]; then + restorecon "$_i"; + fi + done < <(find "$_path" -print0) +} + +check_fence_kdump_config() +{ + local hostname=`hostname` + local ipaddrs=`hostname -I` + local nodes=$(get_option_value "fence_kdump_nodes") + + for node in $nodes; do + if [ "$node" = "$hostname" ]; then + derror "Option fence_kdump_nodes cannot contain $hostname" + return 1 + fi + # node can be ipaddr + echo "$ipaddrs " | grep "$node " > /dev/null + if [ $? -eq 0 ]; then + derror "Option fence_kdump_nodes cannot contain $node" + return 1 + fi + done + + return 0 +} + +check_dump_feasibility() +{ + if [ $DEFAULT_DUMP_MODE == "fadump" ]; then + return 0 + fi + + check_kdump_feasibility + return $? +} + +start_fadump() +{ + echo 1 > $FADUMP_REGISTER_SYS_NODE + if ! check_current_fadump_status; then + derror "fadump: failed to register" + return 1 + fi + + dinfo "fadump: registered successfully" + return 0 +} + +start_dump() +{ + if [ $DEFAULT_DUMP_MODE == "fadump" ]; then + start_fadump + else + load_kdump + fi + + return $? +} + +check_failure_action_config() +{ + local default_option + local failure_action + local option="failure_action" + + default_option=$(awk '$1 ~ /^default$/ {print $2;}' $KDUMP_CONFIG_FILE) + failure_action=$(awk '$1 ~ /^failure_action$/ {print $2;}' $KDUMP_CONFIG_FILE) + + if [ -z "$failure_action" -a -z "$default_option" ]; then + return 0 + elif [ -n "$failure_action" -a -n "$default_option" ]; then + derror "Cannot specify 'failure_action' and 'default' option together" + return 1 + fi + + if [ -n "$default_option" ]; then + option="default" + failure_action="$default_option" + fi + + case "$failure_action" in + reboot|halt|poweroff|shell|dump_to_rootfs) + return 0 + ;; + *) + dinfo $"Usage kdump.conf: $option {reboot|halt|poweroff|shell|dump_to_rootfs}" + return 1 + esac +} + +check_final_action_config() +{ + local final_action + + final_action=$(awk '$1 ~ /^final_action$/ {print $2;}' $KDUMP_CONFIG_FILE) + if [ -z "$final_action" ]; then + return 0 + else + case "$final_action" in + reboot|halt|poweroff) + return 0 + ;; + *) + dinfo $"Usage kdump.conf: final_action {reboot|halt|poweroff}" + return 1 + esac + fi +} + +start() +{ + check_dump_feasibility + if [ $? -ne 0 ]; then + derror "Starting kdump: [FAILED]" + return 1 + fi + + check_config + if [ $? -ne 0 ]; then + derror "Starting kdump: [FAILED]" + return 1 + fi + + if sestatus 2>/dev/null | grep -q "SELinux status.*enabled"; then + selinux_relabel + fi + + save_raw + if [ $? -ne 0 ]; then + derror "Starting kdump: [FAILED]" + return 1 + fi + + check_current_status + if [ $? == 0 ]; then + dwarn "Kdump already running: [WARNING]" + return 0 + fi + + if check_ssh_config; then + if ! check_ssh_target; then + derror "Starting kdump: [FAILED]" + return 1 + fi + fi + + check_rebuild + if [ $? != 0 ]; then + derror "Starting kdump: [FAILED]" + return 1 + fi + + start_dump + if [ $? != 0 ]; then + derror "Starting kdump: [FAILED]" + return 1 + fi + + dinfo "Starting kdump: [OK]" +} + +reload() +{ + check_current_status + if [ $? -ne 0 ]; then + dwarn "Kdump was not running: [WARNING]" + fi + + if [ $DEFAULT_DUMP_MODE == "fadump" ]; then + reload_fadump + return $? + else + stop_kdump + fi + + if [ $? -ne 0 ]; then + derror "Stopping kdump: [FAILED]" + return 1 + fi + + dinfo "Stopping kdump: [OK]" + + setup_initrd + if [ $? -ne 0 ]; then + derror "Starting kdump: [FAILED]" + return 1 + fi + + start_dump + if [ $? -ne 0 ]; then + derror "Starting kdump: [FAILED]" + return 1 + fi + + dinfo "Starting kdump: [OK]" +} + +stop_fadump() +{ + echo 0 > $FADUMP_REGISTER_SYS_NODE + if check_current_fadump_status; then + derror "fadump: failed to unregister" + return 1 + fi + + dinfo "fadump: unregistered successfully" + return 0 +} + +stop_kdump() +{ + if is_secure_boot_enforced; then + $KEXEC -s -p -u + else + $KEXEC -p -u + fi + + if [ $? != 0 ]; then + derror "kexec: failed to unload kdump kernel" + return 1 + fi + + dinfo "kexec: unloaded kdump kernel" + return 0 +} + +reload_fadump() +{ + echo 1 > $FADUMP_REGISTER_SYS_NODE + if [ $? == 0 ]; then + dinfo "fadump: re-registered successfully" + return 0 + else + # FADump could fail on older kernel where re-register + # support is not enabled. Try stop/start from userspace + # to handle such scenario. + stop_fadump + if [ $? == 0 ]; then + start_fadump + return $? + fi + fi + + return 1 +} + +stop() +{ + if [ $DEFAULT_DUMP_MODE == "fadump" ]; then + stop_fadump + else + stop_kdump + fi + + if [ $? != 0 ]; then + derror "Stopping kdump: [FAILED]" + return 1 + fi + + dinfo "Stopping kdump: [OK]" + return 0 +} + +rebuild() { + check_config + if [ $? -ne 0 ]; then + return 1 + fi + + if check_ssh_config; then + if ! check_ssh_target; then + return 1 + fi + fi + + setup_initrd + if [ $? -ne 0 ]; then + return 1 + fi + + dinfo "Rebuilding $TARGET_INITRD" + rebuild_initrd + return $? +} + +do_estimate() { + local kdump_mods + local -A large_mods + local baseline + local kernel_size mod_size initrd_size baseline_size runtime_size reserved_size estimated_size recommended_size + local size_mb=$(( 1024 * 1024 )) + + setup_initrd + if [ ! -f "$TARGET_INITRD" ]; then + derror "kdumpctl estimate: kdump initramfs is not built yet." + exit 1 + fi + + kdump_mods="$(lsinitrd "$TARGET_INITRD" -f /usr/lib/dracut/loaded-kernel-modules.txt | tr '\n' ' ')" + baseline=$(kdump_get_arch_recommend_size) + if [[ "${baseline: -1}" == "M" ]]; then + baseline=${baseline%M} + elif [[ "${baseline: -1}" == "G" ]]; then + baseline=$(( ${baseline%G} * 1024 )) + elif [[ "${baseline: -1}" == "T" ]]; then + baseline=$(( ${baseline%Y} * 1048576 )) + fi + + # The default value when using crashkernel=auto + baseline_size=$((baseline * size_mb)) + # Current reserved crashkernel size + reserved_size=$(cat /sys/kernel/kexec_crash_size) + # A pre-estimated value for userspace usage and kernel + # runtime allocation, 64M should good for most cases + runtime_size=$((64 * size_mb)) + # Kernel image size + kernel_size=$(get_kernel_size "$KDUMP_KERNEL") + # Kdump initramfs size + initrd_size=$(du -b "$TARGET_INITRD" | awk '{print $1}') + # Kernel modules static size after loaded + mod_size=0 + while read -r _name _size _; do + if [[ ! " $kdump_mods " == *" $_name "* ]]; then + continue + fi + mod_size=$((mod_size + _size)) + + # Mark module with static size larger than 2M as large module + if [[ $((_size / size_mb)) -ge 1 ]]; then + large_mods[$_name]=$_size + fi + done <<< "$(< /proc/modules)" + + # Extra memory usage required for LUKS2 decryption + crypt_size=0 + for _dev in $(get_all_kdump_crypt_dev); do + _crypt_info=$(cryptsetup luksDump "/dev/block/$_dev") + [[ $(echo "$_crypt_info" | sed -n "s/^Version:\s*\(.*\)/\1/p" ) == "2" ]] || continue + for _mem in $(echo "$_crypt_info" | sed -n "s/\sMemory:\s*\(.*\)/\1/p" | sort -n ); do + crypt_size=$((crypt_size + _mem * 1024)) + break + done + done + [[ $crypt_size -ne 0 ]] && echo -e "Encrypted kdump target requires extra memory, assuming using the keyslot with minimun memory requirement\n" + + estimated_size=$((kernel_size + mod_size + initrd_size + runtime_size + crypt_size)) + if [[ $baseline_size -gt $estimated_size ]]; then + recommended_size=$baseline_size + else + recommended_size=$estimated_size + fi + + echo "Reserved crashkernel: $((reserved_size / size_mb))M" + echo "Recommended crashkernel: $((recommended_size / size_mb))M" + echo + echo "Kernel image size: $((kernel_size / size_mb))M" + echo "Kernel modules size: $((mod_size / size_mb))M" + echo "Initramfs size: $((initrd_size / size_mb))M" + echo "Runtime reservation: $((runtime_size / size_mb))M" + [[ $crypt_size -ne 0 ]] && \ + echo "LUKS required size: $((crypt_size / size_mb))M" + echo -n "Large modules:" + if [[ "${#large_mods[@]}" -eq 0 ]]; then + echo " " + else + echo "" + for _mod in "${!large_mods[@]}"; do + echo " $_mod: ${large_mods[$_mod]}" + done + fi + + if [[ $reserved_size -lt $recommended_size ]]; then + echo "WARNING: Current crashkernel size is lower than recommended size $((recommended_size / size_mb))M." + fi +} + +if [ ! -f "$KDUMP_CONFIG_FILE" ]; then + derror "Error: No kdump config file found!" + exit 1 +fi + +main () +{ + # Determine if the dump mode is kdump or fadump + determine_dump_mode + + case "$1" in + start) + if [ -s /proc/vmcore ]; then + save_core + reboot + else + start + fi + ;; + stop) + stop + ;; + status) + EXIT_CODE=0 + check_current_status + case "$?" in + 0) + dinfo "Kdump is operational" + EXIT_CODE=0 + ;; + 1) + dinfo "Kdump is not operational" + EXIT_CODE=3 + ;; + esac + exit $EXIT_CODE + ;; + reload) + reload + ;; + restart) + stop + start + ;; + rebuild) + rebuild + ;; + condrestart) + ;; + propagate) + propagate_ssh_key + ;; + showmem) + show_reserved_mem + ;; + estimate) + do_estimate + ;; + *) + dinfo $"Usage: $0 {estimate|start|stop|status|restart|reload|rebuild|propagate|showmem}" + exit 1 + esac +} + +# Other kdumpctl instances will block in queue, until this one exits +single_instance_lock + +# To avoid fd 9 leaking, we invoke a subshell, close fd 9 and call main. +# So that fd isn't leaking when main is invoking a subshell. +(exec 9<&-; main $1) + +exit $? diff --git a/kexec-tools.spec b/kexec-tools.spec index 983beba..15a96f4 100644 --- a/kexec-tools.spec +++ b/kexec-tools.spec @@ -1,4 +1,4 @@ -%define anolis_release .0.2 +%define anolis_release .0.3 Name: kexec-tools Version: 2.0.26 @@ -44,6 +44,7 @@ Source34: kdump-migrate-action.sh Source35: kdump-restart.sh Source36: mkfadumprd Source37: kdump.sysconfig.loongarch64 +Source38: kdumpctl.loongarch64 ####################################### # These are sources for mkdumpramfs @@ -150,7 +151,9 @@ tar -z -x -v -f %{SOURCE19} %patch602 -p1 %endif %patch603 -p1 +%ifnarch loongarch64 %patch604 -p1 +%endif %patch701 -p1 %patch702 -p1 @@ -212,7 +215,11 @@ mkdir -p -m755 $RPM_BUILD_ROOT%{_bindir} mkdir -p -m755 $RPM_BUILD_ROOT%{_libdir} mkdir -p -m755 $RPM_BUILD_ROOT%{_prefix}/lib/kdump mkdir -p -m755 $RPM_BUILD_ROOT%{_sharedstatedir}/kdump +%ifnarch loongarch64 install -m 755 %{SOURCE1} $RPM_BUILD_ROOT%{_bindir}/kdumpctl +%else +install -m 755 %{SOURCE38} $RPM_BUILD_ROOT%{_bindir}/kdumpctl +%endif install -m 755 build/sbin/kexec $RPM_BUILD_ROOT/usr/sbin/kexec install -m 755 build/sbin/vmcore-dmesg $RPM_BUILD_ROOT/usr/sbin/vmcore-dmesg @@ -433,6 +440,7 @@ done - Fix kexec error for kexec -s (xiangzao@linux.alibaba.com) - Reimplement loongarch64 support - Add pstore segment (xiangzao@linux.alibaba.com) +- Fix loongarch kexec issue cause by pstore segment. (wangming01@loongson.cn) * Tue Jun 18 2024 Pingfan Liu - 2.0.26-14.1 - mkdumprd: Fix makedumpfile parameter check -- Gitee From 9242bf920c69ea26c5dd18a8c6e282b6afaacef7 Mon Sep 17 00:00:00 2001 From: Ming Wang Date: Wed, 3 Jan 2024 09:11:35 +0800 Subject: [PATCH 11/11] loongarch64: remove loongarch architecture-related support patches loongarch architecture has been supported upstream since 2.0.26. We just need a patch to fix some compatibility issues. 1. kexec: __NR_kexec_file_load is set to undefined on LoongArch 2. Set up kernel image segment 3. Add 4.19 kernel handling 4. Add kexec-tools-2.0.26 kernel.org missing file(iomem.h). 5. Adjust kernel position alignment rules 6. Fix 4.19 kernel SECTION_BITS issue. Signed-off-by: Ming Wang --- kdump.sysconfig.loongarch64 | 20 +- ...2-makedumpfile-Add-LoongArch-support.patch | 223 --- ...c-tools-2.0.25-Add-LoongArch-support.patch | 1460 ----------------- kexec-tools.spec | 13 +- ...some-functional-issues-and-compilati.patch | 200 +++ 5 files changed, 208 insertions(+), 1708 deletions(-) delete mode 100644 kexec-tools-2.0.22-makedumpfile-Add-LoongArch-support.patch delete mode 100644 kexec-tools-2.0.25-Add-LoongArch-support.patch create mode 100644 loongarch64-fix-some-functional-issues-and-compilati.patch diff --git a/kdump.sysconfig.loongarch64 b/kdump.sysconfig.loongarch64 index 5e8abaa..e2a2d7b 100644 --- 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 swiotlb ignition.firstboot" +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="irqpoll reset_devices cgroup_disable=memory udev.children-max=2 panic=10 swiotlb=noforce 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 @@ -35,19 +35,3 @@ KEXEC_ARGS="" #What is the image type used for kdump KDUMP_IMG="vmlinuz" - -# 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 diff --git a/kexec-tools-2.0.22-makedumpfile-Add-LoongArch-support.patch b/kexec-tools-2.0.22-makedumpfile-Add-LoongArch-support.patch deleted file mode 100644 index 2853034..0000000 --- a/kexec-tools-2.0.22-makedumpfile-Add-LoongArch-support.patch +++ /dev/null @@ -1,223 +0,0 @@ -From 5b8abae46e753729d69bd72c754843cfa2241653 Mon Sep 17 00:00:00 2001 -From: Youling Tang -Date: Mon, 11 Jul 2022 17:11:16 +0800 -Subject: [PATCH] makedumpfile: Add LoongArch support - -Signed-off-by: Youling Tang ---- - makedumpfile-1.7.1/Makefile | 2 +- - makedumpfile-1.7.1/arch/loongarch64.c | 108 +++++++++++++++++++++++++++++++++++++++++++++ - makedumpfile-1.7.1/makedumpfile.h | 55 +++++++++++++++++++++++ - 3 files changed, 164 insertions(+), 1 deletion(-) - create mode 100644 arch/loongarch64.c - -diff --git a/makedumpfile-1.7.1/Makefile b/makedumpfile-1.7.1/Makefile -index 6fa00bc..e91117b 100644 ---- a/makedumpfile-1.7.1/Makefile -+++ b/makedumpfile-1.7.1/Makefile -@@ -47,7 +47,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 detect_cycle.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.1/arch/loongarch64.c b/makedumpfile-1.7.1/arch/loongarch64.c -new file mode 100644 -index 0000000..338da6b ---- /dev/null -+++ b/makedumpfile-1.7.1/arch/loongarch64.c -@@ -0,0 +1,108 @@ -+/* -+ * loongarch64.c -+ * -+ * Copyright (C) 2021 Loongson Technology Co., Ltd. -+ * -+ * 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 -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program 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. -+ */ -+#ifdef __loongarch64 -+ -+#include "../print_info.h" -+#include "../elf_info.h" -+#include "../makedumpfile.h" -+ -+int -+get_phys_base_loongarch64(void) -+{ -+ info->phys_base = 0ULL; -+ -+ DEBUG_MSG("phys_base : %lx\n", info->phys_base); -+ -+ return TRUE; -+} -+ -+int -+get_machdep_info_loongarch64(void) -+{ -+ 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; -+ -+ DEBUG_MSG("max_physmem_bits : %ld\n", info->max_physmem_bits); -+ DEBUG_MSG("section_size_bits: %ld\n", info->section_size_bits); -+ -+ return TRUE; -+} -+ -+int -+get_versiondep_info_loongarch64(void) -+{ -+ info->page_offset = 0x9000000000000000ULL; -+ -+ DEBUG_MSG("page_offset : %lx\n", info->page_offset); -+ -+ 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; -+ -+ if(vaddr >=0x8000000000000000ULL && vaddr < 0xc000000000000000ULL) -+ return vaddr & ((1ULL << MAX_PHYSMEM_BITS()) - 1); -+ -+ if (SYMBOL(swapper_pg_dir) == NOT_FOUND_SYMBOL) { -+ ERRMSG("Can't get the symbol of swapper_pg_dir.\n"); -+ return NOT_PADDR; -+ } -+ -+ pgda = pgd_offset(SYMBOL(swapper_pg_dir), vaddr); -+ if (!readmem(VADDR, (unsigned long long)pgda, &pgdv, sizeof(pgdv))) { -+ ERRMSG("Can't read pgd\n"); -+ return NOT_PADDR; -+ } -+ -+ pmda = pmd_offset(&pgdv, vaddr); -+ if (!readmem(VADDR, (unsigned long long)pmda, &pmdv, sizeof(pmdv))) { -+ ERRMSG("Can't read pmd\n"); -+ return NOT_PADDR; -+ } -+ -+ if (pmdv & _PAGE_HUGE) { -+ paddr = (pmdv & PMD_MASK) + (vaddr & (PMD_SIZE - 1)); -+ return paddr; -+ } -+ -+ ptea = pte_offset(&pmdv, vaddr); -+ if (!readmem(VADDR, (unsigned long long)ptea, &ptev, sizeof(ptev))) { -+ ERRMSG("Can't read pte\n"); -+ return NOT_PADDR; -+ } -+ -+ if (!(ptev & _PAGE_PRESENT)) { -+ ERRMSG("Can't get a valid pte.\n"); -+ return NOT_PADDR; -+ } else { -+ paddr = PAGEBASE(ptev) + (vaddr & (PAGESIZE() - 1)); -+ } -+ -+ return paddr; -+} -+ -+#endif /* loongarch64 */ -diff --git a/makedumpfile-1.7.1/makedumpfile.h b/makedumpfile-1.7.1/makedumpfile.h -index 93aa774..fcdc778 100644 ---- a/makedumpfile-1.7.1/makedumpfile.h -+++ b/makedumpfile-1.7.1/makedumpfile.h -@@ -991,6 +991,39 @@ typedef unsigned long pgd_t; - - #endif /* mips64 */ - -+#ifdef __loongarch64 -+#define KVBASE (0x8000000000000000UL) -+#define _SECTION_SIZE_BITS (28) -+#define _MAX_PHYSMEM_BITS (48) -+#define _PAGE_PRESENT (1 << 7) -+#define _PAGE_HUGE (1 << 6) -+ -+typedef unsigned long pte_t; -+typedef unsigned long pmd_t; -+typedef unsigned long pgd_t; -+ -+#define PAGE_MASK (~(PAGESIZE() - 1)) -+#define PMD_MASK (~(PMD_SIZE - 1)) -+#define PMD_SHIFT ((PAGESHIFT() - 3) * 2 + 3) -+#define PMD_SIZE (1UL << PMD_SHIFT) -+#define PGDIR_SHIFT ((PAGESHIFT() - 3) * 3 + 3) -+#define PTRS_PER_PTE (1 << (PAGESHIFT() - 3)) -+#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 pmd_page_paddr(pmd) (pmd & (int32_t)PAGE_MASK) -+#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_offset(pgdir, vaddr) ((pgd_t *)(pgdir) + pgd_index(vaddr)) -+ -+#endif /* loongarch64 */ -+ - /* - * The function of dependence on machine - */ -@@ -1162,6 +1195,22 @@ unsigned long long vaddr_to_paddr_mips64(unsigned long vaddr); - #define arch_crashkernel_mem_size() stub_false() - #endif /* mips64 */ - -+#ifdef __loongarch64 /* loongarch64 */ -+int get_phys_base_loongarch64(void); -+int get_machdep_info_loongarch64(void); -+int get_versiondep_info_loongarch64(void); -+unsigned long long vaddr_to_paddr_loongarch64(unsigned long vaddr); -+#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_kaslr_offset(X) stub_false() -+#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 */ -+ - typedef unsigned long long mdf_pfn_t; - - #ifndef ARCH_PFN_OFFSET -@@ -2286,6 +2335,12 @@ int get_xen_info_ia64(void); - #define get_xen_info_arch(X) FALSE - #endif /* mips64 */ - -+#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 */ -+ - struct cycle { - mdf_pfn_t start_pfn; - mdf_pfn_t end_pfn; --- -2.20.1 - diff --git a/kexec-tools-2.0.25-Add-LoongArch-support.patch b/kexec-tools-2.0.25-Add-LoongArch-support.patch deleted file mode 100644 index ce20c7e..0000000 --- a/kexec-tools-2.0.25-Add-LoongArch-support.patch +++ /dev/null @@ -1,1460 +0,0 @@ -From 017e67e3949994e51da55a662b647381fc268195 Mon Sep 17 00:00:00 2001 -From: Youling Tang -Date: Tue, 21 Mar 2023 19:56:34 +0800 -Subject: [PATCH] Add loongarch64 support - -Signed-off-by: Youling Tang -Signed-off-by: root -Signed-off-by: Ming Wang ---- - config/config.guess | 3 + - config/config.sub | 1 + - configure | 3 + - configure.ac | 3 + - include/elf.h | 1 + - include/image.h | 1 + - kexec/Makefile | 1 + - 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 | 378 ++++++++++++++++++ - 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 + - 26 files changed, 1172 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..c626f7a 100755 ---- a/config/config.guess -+++ b/config/config.guess -@@ -983,6 +983,9 @@ EOF - k1om:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; -+ loongarch32:Linux:*:* | loongarch64:Linux:*:* | loongarchx32:Linux:*:*) -+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" -+ exit ;; - m32r*:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; -diff --git a/config/config.sub b/config/config.sub -index 9bc49a7..dae00e6 100755 ---- a/config/config.sub -+++ b/config/config.sub -@@ -1185,6 +1185,7 @@ case $cpu-$vendor in - | k1om \ - | le32 | le64 \ - | lm32 \ -+ | loongarch32 | loongarch64 | loongarchx32 \ - | m32c | m32r | m32rle \ - | m5200 | m68000 | m680[012346]0 | m68360 | m683?2 | m68k \ - | m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x \ -diff --git a/configure b/configure -index bcd3cd9..182e4ff 100755 ---- a/configure -+++ b/configure -@@ -3062,6 +3062,9 @@ case $target_cpu in - hppa*) - ARCH="hppa" - ;; -+ loongarch*) -+ ARCH="loongarch" -+ ;; - * ) - as_fn_error $? "unsupported architecture $target_cpu" "$LINENO" 5 - ;; -diff --git a/configure.ac b/configure.ac -index 0d825ef..819df6b 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -58,6 +58,9 @@ case $target_cpu in - hppa*) - ARCH="hppa" - ;; -+ loongarch*) -+ ARCH="loongarch" -+ ;; - * ) - AC_MSG_ERROR([unsupported architecture $target_cpu]) - ;; -diff --git a/include/elf.h b/include/elf.h -index b7677a2..1c8d2cc 100644 ---- a/include/elf.h -+++ b/include/elf.h -@@ -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_LOONGARCH 258 /* Loongson Loongarch*/ - #define EM_NUM 184 - - /* If it is necessary to assign new unofficial EM_* values, please -diff --git a/include/image.h b/include/image.h -index 8e9d81e..7a4bccf 100644 ---- a/include/image.h -+++ b/include/image.h -@@ -86,6 +86,7 @@ - #define IH_ARCH_ARC 23 /* Synopsys DesignWare ARC */ - #define IH_ARCH_X86_64 24 /* AMD x86_64, Intel and Via */ - #define IH_ARCH_XTENSA 25 /* Xtensa */ -+#define IH_ARCH_LOONGARCH 26 /* LoongArch Loongson */ - - /* - * Image Types -diff --git a/kexec/Makefile b/kexec/Makefile -index e69e309..8a52e8d 100644 ---- a/kexec/Makefile -+++ b/kexec/Makefile -@@ -92,6 +92,7 @@ include $(srcdir)/kexec/arch/s390/Makefile - include $(srcdir)/kexec/arch/sh/Makefile - include $(srcdir)/kexec/arch/x86_64/Makefile - include $(srcdir)/kexec/arch/hppa/Makefile -+include $(srcdir)/kexec/arch/loongarch/Makefile - - KEXEC_SRCS += $($(ARCH)_KEXEC_SRCS) - -diff --git a/kexec/arch/loongarch/Makefile b/kexec/arch/loongarch/Makefile -new file mode 100644 -index 0000000..3b33b96 ---- /dev/null -+++ b/kexec/arch/loongarch/Makefile -@@ -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..81250e4 ---- /dev/null -+++ b/kexec/arch/loongarch/crashdump-loongarch.c -@@ -0,0 +1,220 @@ -+/* -+ * LoongArch crashdump. -+ * -+ * 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. -+ */ -+ -+#define _GNU_SOURCE -+ -+#include -+#include -+ -+#include "kexec.h" -+#include "crashdump.h" -+#include "crashdump-loongarch.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, -+}; -+ -+struct memory_range elfcorehdr_mem; -+ -+static struct crash_elf_info elf_info64 = { -+ .class = ELFCLASS64, -+ .data = ELFDATA2LSB, -+ .machine = EM_LOONGARCH, -+ .page_offset = PAGE_OFFSET, -+}; -+ -+/* -+ * 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 iomem_range_callback(void *UNUSED(data), int UNUSED(nr), -+ char *str, unsigned long long base, -+ unsigned long long length) -+{ -+ 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; -+ -+ return 0; -+} -+ -+int is_crashkernel_mem_reserved(void) -+{ -+ if (!usablemem_rgns.size) -+ kexec_iomem_for_each_line(NULL, iomem_range_callback, NULL); -+ -+ return usablemem_rgns.size; -+} -+ -+/* -+ * 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) -+{ -+ int i; -+ -+ /* -+ * First read all memory regions that can be considered as -+ * system memory including the crash area. -+ */ -+ if (!usablemem_rgns.size) -+ kexec_iomem_for_each_line(NULL, iomem_range_callback, NULL); -+ -+ /* allow one or two regions for crash dump kernel */ -+ if (!usablemem_rgns.size) -+ return -EINVAL; -+ -+ dbgprint_mem_range("Reserved memory range", -+ usablemem_rgns.ranges, usablemem_rgns.size); -+ -+ 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; -+ } -+ } -+ -+ /* -+ * Make sure that the memory regions are sorted. -+ */ -+ mem_regions_sort(&system_memory_rgns); -+ -+ dbgprint_mem_range("Coredump memory ranges", -+ system_memory_rgns.ranges, system_memory_rgns.size); -+ -+ /* -+ * 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; -+} -+ -+/* -+ * 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. -+ * -+ * Return 0 in case of success and -1 in case of error. -+ */ -+ -+int load_crashdump_segments(struct kexec_info *info) -+{ -+ unsigned long elfcorehdr; -+ unsigned long bufsz; -+ void *buf; -+ int err; -+ -+ /* -+ * First fetch all the memory (RAM) ranges that we are going to -+ * pass to the crash dump kernel during panic. -+ */ -+ -+ err = crash_get_memory_ranges(); -+ -+ if (err) -+ return EFAILED; -+ -+ err = crash_create_elf64_headers(info, &elf_info64, -+ system_memory_rgns.ranges, system_memory_rgns.size, -+ &buf, &bufsz, ELF_CORE_HEADER_ALIGN); -+ -+ if (err) -+ return EFAILED; -+ -+ 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); -+ -+ elfcorehdr_mem.start = elfcorehdr; -+ elfcorehdr_mem.end = elfcorehdr + bufsz - 1; -+ -+ dbgprintf("%s: elfcorehdr 0x%llx-0x%llx\n", __func__, -+ elfcorehdr_mem.start, elfcorehdr_mem.end); -+ -+ return 0; -+} -+ -+/* -+ * 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) -+{ -+ struct mem_phdr *phdr; -+ int i; -+ -+ ehdr->e_entry += crash_reserved_mem[usablemem_rgns.size - 1].start; -+ -+ 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; -+ } -+} -+ -+int get_crash_kernel_load_range(uint64_t *start, uint64_t *end) -+{ -+ if (!usablemem_rgns.size) -+ kexec_iomem_for_each_line(NULL, iomem_range_callback, NULL); -+ -+ if (!usablemem_rgns.size) -+ return -1; -+ -+ *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 -+ -+struct kexec_info; -+extern struct memory_ranges usablemem_rgns; -+extern struct memory_range crash_reserved_mem[]; -+extern struct memory_range elfcorehdr_mem; -+ -+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); -+ -+#define PAGE_OFFSET 0x9000000000000000ULL -+#define MAXMEM 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 -+ -+#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 @@ -+/* -+ * LoongArch binary image header. -+ */ -+ -+#if !defined(__LOONGARCH_IMAGE_HEADER_H) -+#define __LOONGARCH_IMAGE_HEADER_H -+ -+#include -+#include -+ -+/** -+ * 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; -+}; -+ -+static const uint8_t loongarch_image_pe_sig[2] = {'M', 'Z'}; -+ -+/** -+ * loongarch_header_check_pe_sig - Helper to check the loongarch image header. -+ * -+ * Returns non-zero if 'MZ' signature is found. -+ */ -+ -+static inline int loongarch_header_check_pe_sig(const struct loongarch_image_header *h) -+{ -+ if (!h) -+ return 0; -+ -+ return (h->pe_sig[0] == loongarch_image_pe_sig[0] -+ && h->pe_sig[1] == loongarch_image_pe_sig[1]); -+} -+ -+static inline uint64_t loongarch_header_text_offset( -+ const struct loongarch_image_header *h) -+{ -+ if (!h) -+ return 0; -+ -+ return le64toh(h->text_offset); -+} -+ -+static inline uint64_t loongarch_header_image_size( -+ const struct loongarch_image_header *h) -+{ -+ if (!h) -+ return 0; -+ -+ return le64toh(h->image_size); -+} -+ -+static inline uint64_t loongarch_header_kernel_entry( -+ const struct loongarch_image_header *h) -+{ -+ if (!h) -+ return 0; -+ -+ 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..25a7dc1 ---- /dev/null -+++ b/kexec/arch/loongarch/include/arch/options.h -@@ -0,0 +1,28 @@ -+#ifndef KEXEC_ARCH_LOONGARCH_OPTIONS_H -+#define KEXEC_ARCH_LOONGARCH_OPTIONS_H -+ -+#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) -+ -+#define KEXEC_ARCH_OPTIONS \ -+ KEXEC_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..0ac451e ---- /dev/null -+++ b/kexec/arch/loongarch/kexec-elf-loongarch.c -@@ -0,0 +1,129 @@ -+/* -+ * kexec-elf-loongarch.c - kexec Elf loader for loongarch -+ * -+ * 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 "kexec.h" -+#include "kexec-elf.h" -+#include "kexec-syscall.h" -+#include "crashdump-loongarch.h" -+#include "kexec-loongarch.h" -+#include "arch/options.h" -+ -+off_t initrd_base, initrd_size; -+ -+int elf_loongarch_probe(const char *kernel_buf, off_t kernel_size) -+{ -+ struct mem_ehdr ehdr; -+ int result; -+ -+ result = build_elf_exec_info(kernel_buf, kernel_size, &ehdr, 0); -+ if (result < 0) { -+ dbgprintf("%s: Not an ELF executable.\n", __func__); -+ goto out; -+ } -+ -+ /* Verify the architecuture specific bits. */ -+ if (ehdr.e_machine != EM_LOONGARCH) { -+ dbgprintf("%s: Not an LoongArch ELF executable.\n", __func__); -+ result = -1; -+ goto out; -+ } -+ -+ result = 0; -+out: -+ free_elf_info(&ehdr); -+ return result; -+} -+ -+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 result; -+ -+ result = build_elf_exec_info(kernel_buf, kernel_size, &ehdr, 0); -+ -+ if (result < 0) { -+ dbgprintf("%s: build_elf_exec_info failed\n", __func__); -+ goto exit; -+ } -+ -+ 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; -+ } -+ -+ 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); -+ if (result) { -+ dbgprintf("%s: Creating eflcorehdr failed.\n", -+ __func__); -+ goto exit; -+ } -+ } -+ -+ /* load the kernel */ -+ if (info->kexec_flags & KEXEC_ON_CRASH) -+ /* -+ * offset addresses in elf header in order to load -+ * vmlinux (elf_exec) into crash kernel's memory. -+ */ -+ fixup_elf_addrs(&ehdr); -+ -+ info->entry = (void *)virt_to_phys(ehdr.e_entry); -+ -+ result = elf_exec_load(&ehdr, info); -+ -+ if (result) { -+ dbgprintf("%s: elf_exec_load failed\n", __func__); -+ goto exit; -+ } -+ -+ /* for vmlinuz kernel image */ -+ if (kernel_size < MiB(16)) -+ kernel_size = MiB(64); -+ -+ /* 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..59f7f5d ---- /dev/null -+++ b/kexec/arch/loongarch/kexec-elf-rel-loongarch.c -@@ -0,0 +1,42 @@ -+/* -+ * kexec-elf-rel-loongarch.c - kexec Elf relocation routines -+ * -+ * 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. -+*/ -+ -+#include -+#include -+#include "../../kexec.h" -+#include "../../kexec-elf.h" -+ -+int machine_verify_elf_rel(struct mem_ehdr *ehdr) -+{ -+ if (ehdr->ei_data != ELFDATA2MSB) -+ return 0; -+ -+ if (ehdr->ei_class != ELFCLASS32) -+ return 0; -+ -+ if (ehdr->e_machine != EM_LOONGARCH) -+ return 0; -+ -+ return 1; -+} -+ -+void machine_apply_elf_rel(struct mem_ehdr *UNUSED(ehdr), -+ struct mem_sym *UNUSED(sym), -+ unsigned long r_type, -+ void *UNUSED(location), -+ unsigned long UNUSED(address), -+ unsigned long UNUSED(value)) -+{ -+ switch (r_type) { -+ -+ default: -+ die("Unknown rela relocation: %lu\n", r_type); -+ break; -+ } -+} -diff --git a/kexec/arch/loongarch/kexec-loongarch.c b/kexec/arch/loongarch/kexec-loongarch.c -new file mode 100644 -index 0000000..b173f6d ---- /dev/null -+++ b/kexec/arch/loongarch/kexec-loongarch.c -@@ -0,0 +1,378 @@ -+/* -+ * kexec-loongarch.c - kexec for loongarch -+ * -+ * 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 -+#include -+#include -+#include -+#include -+ -+#include "kexec.h" -+#include "kexec-loongarch.h" -+#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; -+ -+/* 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]; -+ -+int get_memory_ranges(struct memory_range **range, int *ranges, -+ unsigned long UNUSED(kexec_flags)) -+{ -+ int memory_ranges = 0; -+ -+ const char *iomem = proc_iomem(); -+ char line[MAX_LINE]; -+ FILE *fp; -+ unsigned long long start, end; -+ char *str; -+ int type, consumed, count; -+ -+ fp = fopen(iomem, "r"); -+ if (!fp) { -+ 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; -+ count = sscanf(line, "%llx-%llx : %n", &start, &end, &consumed); -+ if (count != 2) -+ continue; -+ str = line + consumed; -+ end = end + 1; -+ if (!strncmp(str, SYSTEM_RAM, strlen(SYSTEM_RAM))) -+ type = RANGE_RAM; -+ else if (!strncmp(str, IOMEM_RESERVED, strlen(IOMEM_RESERVED))) -+ type = RANGE_RESERVED; -+ else -+ continue; -+ -+ if (memory_ranges > 0 && -+ memory_range[memory_ranges - 1].end == start && -+ memory_range[memory_ranges - 1].type == type) { -+ memory_range[memory_ranges - 1].end = end; -+ } else { -+ memory_range[memory_ranges].start = start; -+ memory_range[memory_ranges].end = end; -+ memory_range[memory_ranges].type = type; -+ memory_ranges++; -+ } -+ } -+ 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 = { -+ .core_header_type = CORE_TYPE_ELF64, -+}; -+ -+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 }, -+ }; -+ 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: -+ append = optarg; -+ break; -+ case OPT_REUSE_CMDLINE: -+ 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_INITRD: -+ arch_options.initrd_file = optarg; -+ break; -+ default: -+ break; -+ } -+ } -+ -+ 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; -+} -+ -+const struct arch_map_entry arches[] = { -+ { "loongarch64", KEXEC_ARCH_LOONGARCH }, -+ { 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; -+} -+ -+void arch_update_purgatory(struct kexec_info *UNUSED(info)) -+{ -+} -+ -+unsigned long virt_to_phys(unsigned long addr) -+{ -+ return addr & ((1ULL << 48) - 1); -+} -+ -+/* -+ * add_segment() should convert base to a physical address on loongarch, -+ * while the default is just to work with base as is -+ */ -+void add_segment(struct kexec_info *info, const void *buf, size_t bufsz, -+ unsigned long base, size_t memsz) -+{ -+ add_segment_phys_virt(info, buf, bufsz, virt_to_phys(base), memsz, 1); -+} -+ -+/* -+ * add_buffer() should convert base to a physical address on loongarch, -+ * while the default is just to work with base as is -+ */ -+unsigned long add_buffer(struct kexec_info *info, const void *buf, -+ unsigned long bufsz, unsigned long memsz, -+ unsigned long buf_align, unsigned long buf_min, -+ unsigned long buf_max, int buf_end) -+{ -+ return add_buffer_phys_virt(info, buf, bufsz, memsz, buf_align, -+ buf_min, buf_max, buf_end, 1); -+} -diff --git a/kexec/arch/loongarch/kexec-loongarch.h b/kexec/arch/loongarch/kexec-loongarch.h -new file mode 100644 -index 0000000..5120a26 ---- /dev/null -+++ b/kexec/arch/loongarch/kexec-loongarch.h -@@ -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 CORE_TYPE_ELF64 1 -+ -+#define COMMAND_LINE_SIZE 512 -+ -+#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 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 bea29d4..1e2d12f 100644 ---- a/kexec/kexec-syscall.h -+++ b/kexec/kexec-syscall.h -@@ -39,6 +39,9 @@ - #ifdef __s390__ - #define __NR_kexec_load 277 - #endif -+#ifdef __loongarch__ -+#define __NR_kexec_load 104 -+#endif - #if defined(__arm__) || defined(__arm64__) - #define __NR_kexec_load __NR_SYSCALL_BASE + 347 - #endif -@@ -56,7 +59,7 @@ - #endif - #endif /*ifndef __NR_kexec_load*/ - --#ifdef __arm__ -+#if defined(__arm__) || defined(__loongarch__) - #undef __NR_kexec_file_load - #endif - -@@ -134,6 +137,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) -+#define KEXEC_ARCH_LOONGARCH (258 << 16) - - #define KEXEC_MAX_SEGMENTS 16 - -@@ -177,5 +181,8 @@ static inline long kexec_file_load(int kernel_fd, int initrd_fd, - #if defined(__arm64__) - #define KEXEC_ARCH_NATIVE KEXEC_ARCH_ARM64 - #endif -+#if defined(__loongarch__) -+#define KEXEC_ARCH_NATIVE KEXEC_ARCH_LOONGARCH -+#endif - - #endif /* KEXEC_SYSCALL_H */ -diff --git a/kexec/kexec.c b/kexec/kexec.c -index 829a6ea..0e92d96 100644 ---- a/kexec/kexec.c -+++ b/kexec/kexec.c -@@ -1095,7 +1095,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 8a05644..0d820ad 100644 ---- a/kexec/kexec.h -+++ b/kexec/kexec.h -@@ -304,6 +304,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 15adb12..4d2d071 100644 ---- a/purgatory/Makefile -+++ b/purgatory/Makefile -@@ -28,6 +28,7 @@ include $(srcdir)/purgatory/arch/ppc64/Makefile - include $(srcdir)/purgatory/arch/s390/Makefile - include $(srcdir)/purgatory/arch/sh/Makefile - include $(srcdir)/purgatory/arch/x86_64/Makefile -+include $(srcdir)/purgatory/arch/loongarch/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 ---- /dev/null -+++ b/purgatory/arch/loongarch/Makefile -@@ -0,0 +1,10 @@ -+# -+# Purgatory loongarch -+# -+ -+loongarch_PURGATORY_SRCS+= purgatory/arch/loongarch/purgatory-loongarch.c -+loongarch_PURGATORY_SRCS+= purgatory/arch/loongarch/console-loongarch.c -+ -+dist += purgatory/arch/loongarch/Makefile $(loongarch_PURGATORY_SRCS) \ -+ purgatory/arch/loongarch/purgatory-loongarch.h -+ -diff --git a/purgatory/arch/loongarch/console-loongarch.c b/purgatory/arch/loongarch/console-loongarch.c -new file mode 100644 -index 0000000..af34ecf ---- /dev/null -+++ b/purgatory/arch/loongarch/console-loongarch.c -@@ -0,0 +1,7 @@ -+#include -+#include "unused.h" -+ -+void putchar(int UNUSED(ch)) -+{ -+ /* Nothing for now */ -+} -diff --git a/purgatory/arch/loongarch/purgatory-loongarch.c b/purgatory/arch/loongarch/purgatory-loongarch.c -new file mode 100644 -index 0000000..abe9297 ---- /dev/null -+++ b/purgatory/arch/loongarch/purgatory-loongarch.c -@@ -0,0 +1,7 @@ -+#include -+#include "purgatory-loongarch.h" -+ -+void setup_arch(void) -+{ -+ /* Nothing for now */ -+} -diff --git a/purgatory/arch/loongarch/purgatory-loongarch.h b/purgatory/arch/loongarch/purgatory-loongarch.h -new file mode 100644 -index 0000000..cd1ab97 ---- /dev/null -+++ b/purgatory/arch/loongarch/purgatory-loongarch.h -@@ -0,0 +1,6 @@ -+#ifndef PURGATORY_LOONGARCH_H -+#define PURGATORY_LOONGARCH_H -+ -+/* nothing yet */ -+ -+#endif /* PURGATORY_LOONGARCH_H */ --- -2.31.1 - diff --git a/kexec-tools.spec b/kexec-tools.spec index 15a96f4..727ad04 100644 --- a/kexec-tools.spec +++ b/kexec-tools.spec @@ -1,4 +1,4 @@ -%define anolis_release .0.3 +%define anolis_release .0.1 Name: kexec-tools Version: 2.0.26 @@ -114,13 +114,11 @@ ExcludeArch: i686 # Patch601: rhelonly-kexec-tools-2.0.16-koji-build-fail-workaround.patch Patch602: rhelonly-kexec-tools-2.0.18-eppic-fix-issues-with-hardening-flags.patch -Patch603: kexec-tools-2.0.25-Add-LoongArch-support.patch +Patch603: loongarch64-fix-some-functional-issues-and-compilati.patch Patch604: 1000-kexec-tools-2.0.25-Add-pstore-segment-support.patch # Patches 701 onward for makedumpfile -Patch701: rhelonly-kexec-tools-2.0.20-makedumpfile-arm64-Add-support-for-ARMv8.2-LVA-52-bi.patch -Patch702: kexec-tools-2.0.26-makedumpfile-sadump-fix-failure-of-reading-memory-when-5-le.patch -Patch703: kexec-tools-2.0.22-makedumpfile-Add-LoongArch-support.patch +Patch701: kexec-tools-2.0.26-makedumpfile-sadump-fix-failure-of-reading-memory-when-5-le.patch %description kexec-tools provides /usr/sbin/kexec binary that facilitates a new @@ -150,14 +148,14 @@ tar -z -x -v -f %{SOURCE19} %ifnarch loongarch64 %patch602 -p1 %endif +%ifarch loongarch64 %patch603 -p1 +%endif %ifnarch loongarch64 %patch604 -p1 %endif %patch701 -p1 -%patch702 -p1 -%patch703 -p1 %ifarch ppc %define archdef ARCH=ppc @@ -441,6 +439,7 @@ done - Reimplement loongarch64 support - Add pstore segment (xiangzao@linux.alibaba.com) - Fix loongarch kexec issue cause by pstore segment. (wangming01@loongson.cn) +- Fix loongarch build faild issue. (wangming01@loongson.cn) * Tue Jun 18 2024 Pingfan Liu - 2.0.26-14.1 - mkdumprd: Fix makedumpfile parameter check diff --git a/loongarch64-fix-some-functional-issues-and-compilati.patch b/loongarch64-fix-some-functional-issues-and-compilati.patch new file mode 100644 index 0000000..7ecf4ff --- /dev/null +++ b/loongarch64-fix-some-functional-issues-and-compilati.patch @@ -0,0 +1,200 @@ +From 7256b086a6016f846cdda5d24b12a6cb612af5f5 Mon Sep 17 00:00:00 2001 +From: Ming Wang +Date: Tue, 9 Jan 2024 09:45:17 +0800 +Subject: [PATCH] loongarch64: fix some functional issues and compilation + errors. + +1. kexec: __NR_kexec_file_load is set to undefined on LoongArch +2. Set up kernel image segment +3. Add 4.19 kernel handling +4. Add kexec-tools-2.0.26 kernel.org missing file(iomem.h). +5. Adjust kernel position alignment rules +6. Fix 4.19 kernel SECTION_BITS issue. + +Signed-off-by: Ming Wang +--- + kexec/arch/loongarch/crashdump-loongarch.c | 22 ++++++++++++++++++++++ + kexec/arch/loongarch/crashdump-loongarch.h | 1 + + kexec/arch/loongarch/iomem.h | 10 ++++++++++ + kexec/arch/loongarch/kexec-elf-loongarch.c | 12 ++++++++++++ + kexec/arch/loongarch/kexec-loongarch.c | 11 ++++++++--- + kexec/arch/loongarch/kexec-pei-loongarch.c | 7 +++++++ + kexec/kexec-syscall.h | 2 +- + makedumpfile-1.7.2/makedumpfile.h | 2 +- + 8 files changed, 62 insertions(+), 5 deletions(-) + create mode 100644 kexec/arch/loongarch/iomem.h + +diff --git a/kexec/arch/loongarch/crashdump-loongarch.c b/kexec/arch/loongarch/crashdump-loongarch.c +index aaf6cf3..81250e4 100644 +--- a/kexec/arch/loongarch/crashdump-loongarch.c ++++ b/kexec/arch/loongarch/crashdump-loongarch.c +@@ -183,6 +183,28 @@ int load_crashdump_segments(struct kexec_info *info) + return 0; + } + ++/* ++ * 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) ++{ ++ struct mem_phdr *phdr; ++ int i; ++ ++ ehdr->e_entry += crash_reserved_mem[usablemem_rgns.size - 1].start; ++ ++ 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; ++ } ++} ++ + int get_crash_kernel_load_range(uint64_t *start, uint64_t *end) + { + if (!usablemem_rgns.size) +diff --git a/kexec/arch/loongarch/crashdump-loongarch.h b/kexec/arch/loongarch/crashdump-loongarch.h +index 3eb4e0a..25ff24b 100644 +--- a/kexec/arch/loongarch/crashdump-loongarch.h ++++ b/kexec/arch/loongarch/crashdump-loongarch.h +@@ -8,6 +8,7 @@ extern struct memory_range elfcorehdr_mem; + + 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); + + #define PAGE_OFFSET 0x9000000000000000ULL +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 +index 2bf128f..0ac451e 100644 +--- a/kexec/arch/loongarch/kexec-elf-loongarch.c ++++ b/kexec/arch/loongarch/kexec-elf-loongarch.c +@@ -90,6 +90,14 @@ int elf_loongarch_load(int argc, char **argv, const char *kernel_buf, + } + } + ++ /* load the kernel */ ++ if (info->kexec_flags & KEXEC_ON_CRASH) ++ /* ++ * offset addresses in elf header in order to load ++ * vmlinux (elf_exec) into crash kernel's memory. ++ */ ++ fixup_elf_addrs(&ehdr); ++ + info->entry = (void *)virt_to_phys(ehdr.e_entry); + + result = elf_exec_load(&ehdr, info); +@@ -99,6 +107,10 @@ int elf_loongarch_load(int argc, char **argv, const char *kernel_buf, + goto exit; + } + ++ /* for vmlinuz kernel image */ ++ if (kernel_size < MiB(16)) ++ kernel_size = MiB(64); ++ + /* load additional data */ + result = loongarch_load_other_segments(info, kernel_segment + kernel_size); + +diff --git a/kexec/arch/loongarch/kexec-loongarch.c b/kexec/arch/loongarch/kexec-loongarch.c +index 4c7361c..51f334a 100644 +--- a/kexec/arch/loongarch/kexec-loongarch.c ++++ b/kexec/arch/loongarch/kexec-loongarch.c +@@ -221,6 +221,10 @@ int arch_process_options(int argc, char **argv) + 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"); ++ remove_parameter(cmdline, "nokaslr"); + break; + case OPT_INITRD: + arch_options.initrd_file = optarg; +@@ -253,8 +257,9 @@ unsigned long loongarch_locate_kernel_segment(struct kexec_info *info) + 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); +- hole = _ALIGN_UP(hole, MiB(1)); ++ mem_min : crash_reserved_mem[usablemem_rgns.size - 1].start) + ++ loongarch_mem.text_offset; ++ hole = _ALIGN_UP(hole, MiB(16)); + hole_end = hole + loongarch_mem.text_offset + loongarch_mem.image_size; + + if ((hole_end > mem_max) || +@@ -265,7 +270,7 @@ unsigned long loongarch_locate_kernel_segment(struct kexec_info *info) + } else { + hole = locate_hole(info, + loongarch_mem.text_offset + loongarch_mem.image_size, +- MiB(1), 0, ULONG_MAX, 1); ++ MiB(16), 0, ULONG_MAX, 1); + + if (hole == ULONG_MAX) + dbgprintf("%s: locate_hole failed\n", __func__); +diff --git a/kexec/arch/loongarch/kexec-pei-loongarch.c b/kexec/arch/loongarch/kexec-pei-loongarch.c +index f86ac61..1a11103 100644 +--- a/kexec/arch/loongarch/kexec-pei-loongarch.c ++++ b/kexec/arch/loongarch/kexec-pei-loongarch.c +@@ -66,6 +66,13 @@ int pei_loongarch_load(int argc, char **argv, const char *buf, + + 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__, +diff --git a/kexec/kexec-syscall.h b/kexec/kexec-syscall.h +index be6ccd5..1e2d12f 100644 +--- a/kexec/kexec-syscall.h ++++ b/kexec/kexec-syscall.h +@@ -59,7 +59,7 @@ + #endif + #endif /*ifndef __NR_kexec_load*/ + +-#ifdef __arm__ ++#if defined(__arm__) || defined(__loongarch__) + #undef __NR_kexec_file_load + #endif + +diff --git a/makedumpfile-1.7.2/makedumpfile.h b/makedumpfile-1.7.2/makedumpfile.h +index 1b97d8c..5cb9a08 100644 +--- a/makedumpfile-1.7.2/makedumpfile.h ++++ b/makedumpfile-1.7.2/makedumpfile.h +@@ -1018,7 +1018,7 @@ typedef unsigned long pgd_t; + #define _PAGE_OFFSET (0x9000000000000000ULL) + #define _XKPRANGE (0x8000000000000000ULL) + #define _XKVRANGE (0xc000000000000000ULL) +-#define _SECTION_SIZE_BITS (29) ++#define _SECTION_SIZE_BITS (28) + #define _MAX_PHYSMEM_BITS (48) + #define _PAGE_HUGE (1 << 6) /* HUGE is a PMD bit */ + #define _PAGE_PRESENT (1 << 7) +-- +2.31.1 + -- Gitee