From: Weilong Chen chenweilong@huawei.com
ascend inclusion category: feature bugzilla: NA CVE: NA
-------------------------------------------------
When the CPU is hunged up by hardware errors, board can't restart by software reset. It needs to be reset by an external reset (for example: saftyisland). Bios check this kind reset, enter the crash kernel and dump the vmcore.
Usage: 1. add a node name:kexecmailbox to dts config. 2. after kexec run, set sysctl -w kernel.kexec_bios_start=1.
Reviewed-by: Ding Tianhong dingtianhong@huawei.com Reviewed-by: Kefeng Wang wangkefeng.wang@huawei.com Reviewed-by: Hanjun Guo guohanjun@huawei.com Signed-off-by: Weilong Chen chenweilong@huawei.com Acked-by: Kefeng Wang wangkefeng.wang@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- arch/arm64/Kconfig | 12 +++++ arch/arm64/configs/hulk_defconfig | 1 + arch/arm64/kernel/Makefile | 1 + arch/arm64/kernel/kexec_mailbox.c | 83 +++++++++++++++++++++++++++++++ include/linux/kexec.h | 8 +++ kernel/kexec_core.c | 32 ++++++++++++ kernel/sysctl.c | 9 ++++ 7 files changed, 146 insertions(+) create mode 100644 arch/arm64/kernel/kexec_mailbox.c
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index cfde721a5961..d93dae75f1a6 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -1560,6 +1560,18 @@ config ASCEND_SHARE_POOL help This feature allows multiple processes to share virtual memory both in kernel and user level, which is only enabled for ascend platform. + +config ASCEND_BOOT_CRASH_KERNEL + bool "Support of boot crash kernel from bios" + default y + help + When the CPU is hunged up by hardware errors, board can't restart + by software reset. It needs to be reset by an external reset + (for example: saftyisland). Bios check this kind reset, enter + the crash kernel and dump the vmcore. + Usage: + 1. add a node name:kexecmailbox to dts config. + 2. after kexec run, set sysctl -w kernel.kexec_bios_start=1. endif
endmenu diff --git a/arch/arm64/configs/hulk_defconfig b/arch/arm64/configs/hulk_defconfig index 3b2b957f9ae0..e763311a3f8f 100644 --- a/arch/arm64/configs/hulk_defconfig +++ b/arch/arm64/configs/hulk_defconfig @@ -482,6 +482,7 @@ CONFIG_ASCEND_CHARGE_MIGRATE_HUGEPAGES=y CONFIG_ASCEND_WATCHDOG_SYSFS_CONFIGURE=y CONFIG_ASCEND_AUTO_TUNING_HUGEPAGE=y CONFIG_ASCEND_SHARE_POOL=y +CONFIG_ASCEND_BOOT_CRASH_KERNEL=y CONFIG_ARM64_CNP=y
# diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile index d9237117da97..8a15d44fff67 100644 --- a/arch/arm64/kernel/Makefile +++ b/arch/arm64/kernel/Makefile @@ -54,6 +54,7 @@ arm64-obj-$(CONFIG_RANDOMIZE_BASE) += kaslr.o arm64-obj-$(CONFIG_HIBERNATION) += hibernate.o hibernate-asm.o arm64-obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o \ cpu-reset.o +arm64-obj-$(CONFIG_ASCEND_BOOT_CRASH_KERNEL) += kexec_mailbox.o arm64-obj-$(CONFIG_ARM64_RELOC_TEST) += arm64-reloc-test.o arm64-reloc-test-y := reloc_test_core.o reloc_test_syms.o arm64-obj-$(CONFIG_CRASH_DUMP) += crash_dump.o diff --git a/arch/arm64/kernel/kexec_mailbox.c b/arch/arm64/kernel/kexec_mailbox.c new file mode 100644 index 000000000000..1f16fb29c9e4 --- /dev/null +++ b/arch/arm64/kernel/kexec_mailbox.c @@ -0,0 +1,83 @@ +/* + * Huawei Ascend Kexec Mailbox + * + * Copyright (C) 2020 Huawei Limited + * Author: Huawei OS Kernel Lab + * + * This code is based on the hisilicon ascend platform. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/kernel.h> +#include <linux/kexec.h> +#include <linux/of.h> +#include <linux/of_address.h> + +#include <asm/cacheflush.h> + +#define MAGIC_NO 0x42494F53UL +#define MAILBOX_ADDR 0x880000000UL + +struct kexec_mailbox { + unsigned long magic; + phys_addr_t reboot_code_phys; + unsigned long kimage_head; + unsigned long kimage_start; + unsigned long kimage_pad; +}; + +/* Global variables for the arm64_relocate_new_kernel routine. */ +extern const unsigned char arm64_relocate_new_kernel[]; +extern const unsigned long arm64_relocate_new_kernel_size; + +unsigned long mailbox_addr = MAILBOX_ADDR; + +int bios_setup_kimage(struct kimage *kimage) +{ + struct kexec_mailbox *bios_addr; + phys_addr_t reboot_code_buffer_phys; + void *reboot_code_buffer; + struct device_node *np; + + /* setup mailbox addr */ + np = of_find_node_by_name(NULL, "kexecmailbox"); + if (np) { + struct resource res; + + of_address_to_resource(np, 0, &res); + mailbox_addr = res.start; + of_node_put(np); + pr_info("kexec_mailbox: use dtb config addr %lx\n", mailbox_addr); + } else + pr_info("kexec_mailbox: use default addr %lx\n", mailbox_addr); + + bios_addr = ioremap_cache(mailbox_addr, sizeof(struct kexec_mailbox)); + if (!bios_addr) + return -EINVAL; + + reboot_code_buffer_phys = page_to_phys(kimage->control_code_page); + reboot_code_buffer = phys_to_virt(reboot_code_buffer_phys); + memcpy(reboot_code_buffer, arm64_relocate_new_kernel, + arm64_relocate_new_kernel_size); + __flush_dcache_area(reboot_code_buffer, arm64_relocate_new_kernel_size); + __flush_icache_range((uintptr_t)reboot_code_buffer, + arm64_relocate_new_kernel_size); + + bios_addr->magic = MAGIC_NO; + bios_addr->reboot_code_phys = reboot_code_buffer_phys; + bios_addr->kimage_head = kimage->head; + bios_addr->kimage_start = kimage->start; + bios_addr->kimage_pad = 0; + pr_info("kexec_mailbox: magic %lx, reboot_code_phys %llx kimage_head %lx kimage_start %lx kimage_pad %lx\n", + bios_addr->magic, + bios_addr->reboot_code_phys, bios_addr->kimage_head, + bios_addr->kimage_start, bios_addr->kimage_pad); + __flush_dcache_area(bios_addr, sizeof(struct kexec_mailbox)); + __flush_icache_range((uintptr_t)bios_addr, sizeof(struct kexec_mailbox)); + + iounmap((void __iomem *)mailbox_addr); + return 0; +} diff --git a/include/linux/kexec.h b/include/linux/kexec.h index d6b8d0a69720..f22c6d882af5 100644 --- a/include/linux/kexec.h +++ b/include/linux/kexec.h @@ -285,6 +285,14 @@ extern struct kimage *kexec_image; extern struct kimage *kexec_crash_image; extern int kexec_load_disabled;
+#ifdef CONFIG_ASCEND_BOOT_CRASH_KERNEL +extern int bios_setup_kimage(struct kimage *kimage); +extern int kexec_bios_start; +extern int kexec_sysctl_handler(struct ctl_table *table, int write, + void __user *buffer, size_t *lenp, + loff_t *ppos); +#endif + #ifndef kexec_flush_icache_page #define kexec_flush_icache_page(page) #endif diff --git a/kernel/kexec_core.c b/kernel/kexec_core.c index b36c9c46cd2c..38f930887207 100644 --- a/kernel/kexec_core.c +++ b/kernel/kexec_core.c @@ -987,6 +987,34 @@ struct kimage *kexec_image; struct kimage *kexec_crash_image; int kexec_load_disabled;
+#ifdef CONFIG_ASCEND_BOOT_CRASH_KERNEL +int kexec_bios_start; +int kexec_sysctl_handler(struct ctl_table *table, int write, + void __user *buffer, size_t *lenp, + loff_t *ppos) +{ + int err; + + err = proc_dointvec(table, write, buffer, lenp, ppos); + if (err) + return err; + + if (write && kexec_bios_start) { + if (mutex_trylock(&kexec_mutex)) { + if (kexec_crash_image) + err = bios_setup_kimage(kexec_crash_image); + else + err = -EINVAL; + mutex_unlock(&kexec_mutex); + } + } + if (err) + kexec_bios_start = 0; + + return err; +} +#endif + /* * No panic_cpu check version of crash_kexec(). This function is called * only when panic_cpu holds the current CPU number; this is the only CPU @@ -994,6 +1022,10 @@ int kexec_load_disabled; */ void __noclone __crash_kexec(struct pt_regs *regs) { +#ifdef CONFIG_ASCEND_BOOT_CRASH_KERNEL + if (kexec_bios_start) + return; +#endif /* Take the kexec_mutex here to prevent sys_kexec_load * running on one cpu from replacing the crash kernel * we are using after a panic on a different cpu. diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 26c215fb37dc..dd01fd0e121f 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -668,6 +668,15 @@ static struct ctl_table kern_table[] = { .extra1 = &one, .extra2 = &one, }, +#ifdef CONFIG_ASCEND_BOOT_CRASH_KERNEL + { + .procname = "kexec_bios_start", + .data = &kexec_bios_start, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = kexec_sysctl_handler, + }, +#endif #endif #ifdef CONFIG_MODULES {