[PATCH 3/3] arm64: kdump: add support access protection for crashkernel region

From: thunder . leizhen
Date: Fri Jul 21 2023 - 04:21:41 EST


From: Zhen Lei <thunder.leizhen@xxxxxxxxxx>

arch_kexec_protect_crashkres() and arch_kexec_unprotect_crashkres()
are meant to be called by kexec_load() in order to protect the memory
allocated for crash dump kernel once the image is loaded.

This is basically revert commit 0d124e96051b
("arm64: kdump : take off the protection on crashkernel memory region"),
except for the crashkernel region has been fallen back. Because we didn't
do page-level mapping for the newly allocated region.

Signed-off-by: Zhen Lei <thunder.leizhen@xxxxxxxxxx>
---
arch/arm64/include/asm/kexec.h | 8 ++++++++
arch/arm64/kernel/machine_kexec.c | 26 ++++++++++++++++++++++++++
arch/arm64/mm/init.c | 4 ++++
3 files changed, 38 insertions(+)

diff --git a/arch/arm64/include/asm/kexec.h b/arch/arm64/include/asm/kexec.h
index 9ac9572a3bbee2c..a55388ff045e980 100644
--- a/arch/arm64/include/asm/kexec.h
+++ b/arch/arm64/include/asm/kexec.h
@@ -102,6 +102,14 @@ void cpu_soft_restart(unsigned long el2_switch, unsigned long entry,

int machine_kexec_post_load(struct kimage *image);
#define machine_kexec_post_load machine_kexec_post_load
+
+extern bool crash_fallback;
+
+void arch_kexec_protect_crashkres(void);
+#define arch_kexec_protect_crashkres arch_kexec_protect_crashkres
+
+void arch_kexec_unprotect_crashkres(void);
+#define arch_kexec_unprotect_crashkres arch_kexec_unprotect_crashkres
#endif

#define ARCH_HAS_KIMAGE_ARCH
diff --git a/arch/arm64/kernel/machine_kexec.c b/arch/arm64/kernel/machine_kexec.c
index 078910db77a41b6..00392b48501d35c 100644
--- a/arch/arm64/kernel/machine_kexec.c
+++ b/arch/arm64/kernel/machine_kexec.c
@@ -269,6 +269,32 @@ void machine_crash_shutdown(struct pt_regs *regs)
pr_info("Starting crashdump kernel...\n");
}

+void arch_kexec_protect_crashkres(void)
+{
+ int i;
+
+ if (crash_fallback)
+ return;
+
+ for (i = 0; i < kexec_crash_image->nr_segments; i++)
+ set_memory_valid(
+ __phys_to_virt(kexec_crash_image->segment[i].mem),
+ kexec_crash_image->segment[i].memsz >> PAGE_SHIFT, 0);
+}
+
+void arch_kexec_unprotect_crashkres(void)
+{
+ int i;
+
+ if (crash_fallback)
+ return;
+
+ for (i = 0; i < kexec_crash_image->nr_segments; i++)
+ set_memory_valid(
+ __phys_to_virt(kexec_crash_image->segment[i].mem),
+ kexec_crash_image->segment[i].memsz >> PAGE_SHIFT, 1);
+}
+
#ifdef CONFIG_HIBERNATION
/*
* To preserve the crash dump kernel image, the relevant memory segments
diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
index d2ab377520b2742..b544ed0ab04193d 100644
--- a/arch/arm64/mm/init.c
+++ b/arch/arm64/mm/init.c
@@ -74,6 +74,7 @@ phys_addr_t __ro_after_init arm64_dma_phys_limit;

#define DEFAULT_CRASH_KERNEL_LOW_SIZE (128UL << 20)

+bool crash_fallback;
static int crashkernel_type __initdata;

static phys_addr_t __init crashkernel_phys_alloc_range(phys_addr_t size,
@@ -199,6 +200,9 @@ static void __init late_reserve_crashkernel(void)
crashk_res.end = crash_base + crash_size - 1;
insert_resource(&iomem_resource, &crashk_res);

+ crash_fallback = true;
+ pr_info("cannot allocate all crashkernel memory as expected, fallen back.\n");
+
ok:
crash_base = crashk_res.start;
crash_size = resource_size(&crashk_res);
--
2.25.1