aboutsummaryrefslogtreecommitdiff
path: root/arch/riscv/kernel/machine_kexec.c
diff options
context:
space:
mode:
authorGravatar Nick Kossifidis <mick@ics.forth.gr> 2021-04-19 03:55:38 +0300
committerGravatar Palmer Dabbelt <palmerdabbelt@google.com> 2021-04-26 08:25:23 -0700
commite53d28180d4d0fd12b6d2bde49cb87aa775b6ba8 (patch)
tree9d1a42513601c0eed0654b85a60f4818ae982e41 /arch/riscv/kernel/machine_kexec.c
parentRISC-V: Improve init_resources() (diff)
downloadlinux-e53d28180d4d0fd12b6d2bde49cb87aa775b6ba8.tar.gz
linux-e53d28180d4d0fd12b6d2bde49cb87aa775b6ba8.tar.bz2
linux-e53d28180d4d0fd12b6d2bde49cb87aa775b6ba8.zip
RISC-V: Add kdump support
This patch adds support for kdump, the kernel will reserve a region for the crash kernel and jump there on panic. In order for userspace tools (kexec-tools) to prepare the crash kernel kexec image, we also need to expose some information on /proc/iomem for the memory regions used by the kernel and for the region reserved for crash kernel. Note that on userspace the device tree is used to determine the system's memory layout so the "System RAM" on /proc/iomem is ignored. I tested this on riscv64 qemu and works as expected, you may test it by triggering a crash through /proc/sysrq_trigger: echo c > /proc/sysrq_trigger Signed-off-by: Nick Kossifidis <mick@ics.forth.gr> Signed-off-by: Palmer Dabbelt <palmerdabbelt@google.com>
Diffstat (limited to 'arch/riscv/kernel/machine_kexec.c')
-rw-r--r--arch/riscv/kernel/machine_kexec.c43
1 files changed, 25 insertions, 18 deletions
diff --git a/arch/riscv/kernel/machine_kexec.c b/arch/riscv/kernel/machine_kexec.c
index e165c7874740..cc048143fba5 100644
--- a/arch/riscv/kernel/machine_kexec.c
+++ b/arch/riscv/kernel/machine_kexec.c
@@ -59,11 +59,6 @@ machine_kexec_prepare(struct kimage *image)
kexec_image_info(image);
- if (image->type == KEXEC_TYPE_CRASH) {
- pr_warn("Loading a crash kernel is unsupported for now.\n");
- return -EINVAL;
- }
-
/* Find the Flattened Device Tree and save its physical address */
for (i = 0; i < image->nr_segments; i++) {
if (image->segment[i].memsz <= sizeof(fdt))
@@ -85,17 +80,21 @@ machine_kexec_prepare(struct kimage *image)
}
/* Copy the assembler code for relocation to the control page */
- control_code_buffer = page_address(image->control_code_page);
- control_code_buffer_sz = page_size(image->control_code_page);
- if (unlikely(riscv_kexec_relocate_size > control_code_buffer_sz)) {
- pr_err("Relocation code doesn't fit within a control page\n");
- return -EINVAL;
- }
- memcpy(control_code_buffer, riscv_kexec_relocate,
- riscv_kexec_relocate_size);
+ if (image->type != KEXEC_TYPE_CRASH) {
+ control_code_buffer = page_address(image->control_code_page);
+ control_code_buffer_sz = page_size(image->control_code_page);
- /* Mark the control page executable */
- set_memory_x((unsigned long) control_code_buffer, 1);
+ if (unlikely(riscv_kexec_relocate_size > control_code_buffer_sz)) {
+ pr_err("Relocation code doesn't fit within a control page\n");
+ return -EINVAL;
+ }
+
+ memcpy(control_code_buffer, riscv_kexec_relocate,
+ riscv_kexec_relocate_size);
+
+ /* Mark the control page executable */
+ set_memory_x((unsigned long) control_code_buffer, 1);
+ }
return 0;
}
@@ -147,6 +146,9 @@ void machine_shutdown(void)
void
machine_crash_shutdown(struct pt_regs *regs)
{
+ crash_save_cpu(regs, smp_processor_id());
+ machine_shutdown();
+ pr_info("Starting crashdump kernel...\n");
}
/**
@@ -169,7 +171,12 @@ machine_kexec(struct kimage *image)
unsigned long this_hart_id = raw_smp_processor_id();
unsigned long fdt_addr = internal->fdt_addr;
void *control_code_buffer = page_address(image->control_code_page);
- riscv_kexec_do_relocate do_relocate = control_code_buffer;
+ riscv_kexec_method kexec_method = NULL;
+
+ if (image->type != KEXEC_TYPE_CRASH)
+ kexec_method = control_code_buffer;
+ else
+ kexec_method = (riscv_kexec_method) &riscv_kexec_norelocate;
pr_notice("Will call new kernel at %08lx from hart id %lx\n",
jump_addr, this_hart_id);
@@ -180,7 +187,7 @@ machine_kexec(struct kimage *image)
/* Jump to the relocation code */
pr_notice("Bye...\n");
- do_relocate(first_ind_entry, jump_addr, fdt_addr,
- this_hart_id, va_pa_offset);
+ kexec_method(first_ind_entry, jump_addr, fdt_addr,
+ this_hart_id, va_pa_offset);
unreachable();
}