Linux-RISC-V Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/2] kexec-tools: Fix split crash kernel reservations
@ 2026-08-18 12:35 Rui Qi
  2026-08-18 12:35 ` [PATCH 1/2] kexec: Print crash kernel reserved size from sysfs Rui Qi
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Rui Qi @ 2026-08-18 12:35 UTC (permalink / raw)
  To: kexec; +Cc: horms, linux-riscv, Rui Qi

Hi,

This series fixes two kexec-tools issues seen with split crash kernel
reservations.

The first patch makes --print-ckr-size prefer
/sys/kernel/kexec_crash_size. This restores the option's original
user-visible contract: report the same crash kernel reserved size and
unit as the kernel sysfs attribute when that attribute is available.
The existing arch load-range based calculation is kept as a fallback for
older kernels.

The second patch fixes the RISC-V kexec_load crash path. RISC-V records
all Crash kernel ranges from /proc/iomem, but it currently writes only
the selected load range to linux,usable-memory-range. On systems with
high/low crash kernel reservations, that prevents the crash kernel from
seeing the low reservation after boot.

Keep placing the crash image segments in the selected load range, but
pass all crash kernel ranges to the crash kernel through
linux,usable-memory-range. This follows the split-reservation handoff
model already used by arm64 kexec-tools, where
linux,usable-memory-range = <BASE1 SIZE1 BASE2 SIZE2> advertises both
high and low crash kernel ranges to the crash dump kernel.

Tested on riscv64 with:

  /proc/iomem:
    f7e00000-ffdfffff       : Crash kernel  (128 MiB low)
    1f88c00000-1ff6bfffff   : Crash kernel  (1760 MiB high)

  /sys/kernel/kexec_crash_size:
    1979711488

With the patched kexec binary:

  kexec --print-ckr-size
    1979711488

  kexec -c -p ... followed by a panic completed kdump successfully.
  The crash kernel reported both ranges as System RAM in /proc/iomem:

    f7e00000-ffdfffff       : System RAM
    1f88c00000-1ff6bfffff   : System RAM

The vmcore was saved successfully.

Rui Qi (2):
  kexec: Print crash kernel reserved size from sysfs
  RISC-V: Pass all crash kernel ranges to crash kernel

 kexec/arch/riscv/crashdump-riscv.c | 14 ++++++++
 kexec/arch/riscv/kexec-riscv.c     | 35 +++++++++++++++++--
 kexec/arch/riscv/kexec-riscv.h     |  1 +
 kexec/dt-ops.c                     | 55 ++++++++++++++++++++++++------
 kexec/dt-ops.h                     |  5 ++-
 kexec/kexec.c                      | 27 ++++++++++++---
 6 files changed, 118 insertions(+), 19 deletions(-)

-- 
2.52.0

_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH 1/2] kexec: Print crash kernel reserved size from sysfs
  2026-08-18 12:35 [PATCH 0/2] kexec-tools: Fix split crash kernel reservations Rui Qi
@ 2026-08-18 12:35 ` Rui Qi
  2026-08-18 12:35 ` [PATCH 2/2] RISC-V: Pass all crash kernel ranges to crash kernel Rui Qi
  2026-08-24 15:27 ` [PATCH 0/2] kexec-tools: Fix split crash kernel reservations Simon Horman
  2 siblings, 0 replies; 4+ messages in thread
From: Rui Qi @ 2026-08-18 12:35 UTC (permalink / raw)
  To: kexec; +Cc: horms, linux-riscv, Rui Qi

The --print-ckr-size option was added as a user-visible way for
kdump scripts to obtain the crash kernel reserved size. Its original
contract is to print the same value and unit as the kernel
kexec_crash_size sysfs attribute when Linux exports that attribute.

The current implementation derives the value from
get_crash_kernel_load_range(), but that helper describes where crash
kernel segments may be loaded. That is not the same as the total crash
kernel reservation.

The two meanings differ on systems with split crash kernel
reservations. A low reservation may be available to the crash kernel
after boot while the crash image itself must still be loaded into the
main/high reservation. Linux reports the total reserved crash kernel
size through /sys/kernel/kexec_crash_size, including split
reservations.

Prefer /sys/kernel/kexec_crash_size when available so
--print-ckr-size follows its original sysfs-aligned semantics. Keep the
existing load-range calculation as a fallback for older kernels.

Signed-off-by: Rui Qi <qirui.001@bytedance.com>
---
 kexec/kexec.c | 27 ++++++++++++++++++++++-----
 1 file changed, 22 insertions(+), 5 deletions(-)

diff --git a/kexec/kexec.c b/kexec/kexec.c
index 58cab57a3ee3..99ec3ff3c373 100644
--- a/kexec/kexec.c
+++ b/kexec/kexec.c
@@ -60,6 +60,7 @@
 
 #define KEXEC_LOADED_PATH "/sys/kernel/kexec_loaded"
 #define KEXEC_CRASH_LOADED_PATH "/sys/kernel/kexec_crash_loaded"
+#define KEXEC_CRASH_SIZE_PATH "/sys/kernel/kexec_crash_size"
 
 unsigned long long mem_min = 0;
 unsigned long long mem_max = ULONG_MAX;
@@ -1495,14 +1496,30 @@ static inline unsigned long get_hotplug_kexec_flag(void)
 static void print_crashkernel_region_size(void)
 {
 	uint64_t start = 0, end = 0;
+	uint64_t size = 0;
+	FILE *fp;
 
-	if (is_crashkernel_mem_reserved() &&
-	    get_crash_kernel_load_range(&start, &end)) {
-		fprintf(stderr, "get_crash_kernel_load_range() failed.\n");
-		return;
+	fp = fopen(KEXEC_CRASH_SIZE_PATH, "r");
+	if (fp) {
+		if (fscanf(fp, "%" SCNu64, &size) == 1) {
+			fclose(fp);
+			printf("%" PRIu64 "\n", size);
+			return;
+		}
+		fclose(fp);
+	}
+
+	if (is_crashkernel_mem_reserved()) {
+		if (get_crash_kernel_load_range(&start, &end)) {
+			fprintf(stderr, "get_crash_kernel_load_range() failed.\n");
+			return;
+		}
+
+		if (start != end)
+			size = end - start + 1;
 	}
 
-	printf("%" PRIu64 "\n", (start != end) ? (end - start + 1) : 0UL);
+	printf("%" PRIu64 "\n", size);
 }
 
 int main(int argc, char *argv[])
-- 
2.52.0

_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH 2/2] RISC-V: Pass all crash kernel ranges to crash kernel
  2026-08-18 12:35 [PATCH 0/2] kexec-tools: Fix split crash kernel reservations Rui Qi
  2026-08-18 12:35 ` [PATCH 1/2] kexec: Print crash kernel reserved size from sysfs Rui Qi
@ 2026-08-18 12:35 ` Rui Qi
  2026-08-24 15:27 ` [PATCH 0/2] kexec-tools: Fix split crash kernel reservations Simon Horman
  2 siblings, 0 replies; 4+ messages in thread
From: Rui Qi @ 2026-08-18 12:35 UTC (permalink / raw)
  To: kexec; +Cc: horms, linux-riscv, Rui Qi

RISC-V kexec-tools records all Crash kernel ranges from /proc/iomem,
but the kexec_load path still writes only get_crash_kernel_load_range()
to linux,usable-memory-range. On systems with split crash kernel
reservations, this hides the low reservation from the crash kernel
after boot.

Keep the crash image segments in the selected load range, since that
is the range where the panic kernel may be loaded. Build
linux,usable-memory-range from all crash kernel ranges instead, placing
the selected load range first and then appending the remaining ranges.

This follows the model already used by arm64 kexec-tools for split
crash kernel reservations: pass linux,usable-memory-range = <BASE1
SIZE1 BASE2 SIZE2> to the crash dump kernel so the main/high range can
hold the crash image while the low range is still advertised to the
crash kernel for use after boot.

This also matches the split-reservation handoff model used by the
kernel kexec_file_load path: the crash kernel image is loaded into the
main range, while low reserved memory is still made available to the
crash kernel after boot.

Tested on riscv64 with a 128 MiB low reservation and a 1760 MiB high
reservation. After a panic, the crash kernel reported both ranges as
System RAM in /proc/iomem and kdump completed successfully.

Signed-off-by: Rui Qi <qirui.001@bytedance.com>
---
 kexec/arch/riscv/crashdump-riscv.c | 14 ++++++++
 kexec/arch/riscv/kexec-riscv.c     | 35 +++++++++++++++++--
 kexec/arch/riscv/kexec-riscv.h     |  1 +
 kexec/dt-ops.c                     | 55 ++++++++++++++++++++++++------
 kexec/dt-ops.h                     |  5 ++-
 5 files changed, 96 insertions(+), 14 deletions(-)

diff --git a/kexec/arch/riscv/crashdump-riscv.c b/kexec/arch/riscv/crashdump-riscv.c
index deb9a49cd48d..8a09fbafd63e 100644
--- a/kexec/arch/riscv/crashdump-riscv.c
+++ b/kexec/arch/riscv/crashdump-riscv.c
@@ -210,3 +210,17 @@ int get_crash_kernel_load_range(uint64_t *start, uint64_t *end)
 
 	return 0;
 }
+
+int get_crash_kernel_ranges(struct memory_range **ranges, int *nr_ranges)
+{
+	if (!crash_mem_ranges.size)
+		kexec_iomem_for_each_line(NULL, iomem_range_callback, NULL);
+
+	if (!crash_mem_ranges.size)
+		return -1;
+
+	*ranges = crash_mem_ranges.ranges;
+	*nr_ranges = crash_mem_ranges.size;
+
+	return 0;
+}
diff --git a/kexec/arch/riscv/kexec-riscv.c b/kexec/arch/riscv/kexec-riscv.c
index 3a13f90ea70c..d357f1b779e5 100644
--- a/kexec/arch/riscv/kexec-riscv.c
+++ b/kexec/arch/riscv/kexec-riscv.c
@@ -111,6 +111,8 @@ int load_extra_segments(struct kexec_info *info, uint64_t kernel_base,
 			uint64_t kernel_size, uint64_t max_addr)
 {
 	struct fdt_image *fdt = arch_options.fdt;
+	struct memory_range *crash_ranges = NULL;
+	struct memory_range *usable_ranges = NULL;
 	char *initrd_buf = NULL;
 	off_t initrd_size = 0;
 	uint64_t initrd_base = 0;
@@ -118,7 +120,10 @@ int load_extra_segments(struct kexec_info *info, uint64_t kernel_base,
 	uint64_t end = 0;
 	uint64_t min_usable = kernel_base + kernel_size;
 	uint64_t max_usable = max_addr;
+	int nr_crash_ranges = 0;
+	int nr_usable_ranges = 0;
 	int ret = 0;
+	int i;
 
 	/* Prepare the device tree */
 	if (info->kexec_flags & KEXEC_ON_CRASH) {
@@ -142,8 +147,34 @@ int load_extra_segments(struct kexec_info *info, uint64_t kernel_base,
 			return ret;
 		}
 
-		ret = dtb_add_range_property(&fdt->buf, &fdt->size, start, end,
-					     "chosen", "linux,usable-memory-range");
+		ret = get_crash_kernel_ranges(&crash_ranges,
+					      &nr_crash_ranges);
+		if (ret) {
+			fprintf(stderr, "Couldn't get crashkernel regions\n");
+			return ret;
+		}
+
+		usable_ranges = xmalloc(nr_crash_ranges *
+					sizeof(*usable_ranges));
+		usable_ranges[nr_usable_ranges].start = start;
+		usable_ranges[nr_usable_ranges].end = end;
+		usable_ranges[nr_usable_ranges].type = RANGE_RAM;
+		nr_usable_ranges++;
+
+		for (i = 0; i < nr_crash_ranges; i++) {
+			if (crash_ranges[i].start == start &&
+			    crash_ranges[i].end == end)
+				continue;
+
+			usable_ranges[nr_usable_ranges++] = crash_ranges[i];
+		}
+
+		ret = dtb_add_range_properties(&fdt->buf, &fdt->size,
+					       usable_ranges,
+					       nr_usable_ranges,
+					       "chosen",
+					       "linux,usable-memory-range");
+		free(usable_ranges);
 		if (ret) {
 			fprintf(stderr, "Couldn't add usable-memory-range to fdt\n");
 			return ret;
diff --git a/kexec/arch/riscv/kexec-riscv.h b/kexec/arch/riscv/kexec-riscv.h
index f487b27c10bd..43b7ce14c374 100644
--- a/kexec/arch/riscv/kexec-riscv.h
+++ b/kexec/arch/riscv/kexec-riscv.h
@@ -32,6 +32,7 @@ struct riscv_opts {
 /* crashdump-riscv.c */
 extern struct memory_range elfcorehdr_mem;
 int load_elfcorehdr(struct kexec_info *info);
+int get_crash_kernel_ranges(struct memory_range **ranges, int *nr_ranges);
 
 /* kexec-riscv.c */
 int prepare_kexec_file_options(struct kexec_info *info);
diff --git a/kexec/dt-ops.c b/kexec/dt-ops.c
index 3e285ab2043b..6a8e598fed17 100644
--- a/kexec/dt-ops.c
+++ b/kexec/dt-ops.c
@@ -250,14 +250,32 @@ void dtb_fill_int_property(void *buf, uint64_t val, uint32_t cells)
 
 int dtb_add_range_property(char **dtb, off_t *dtb_size, uint64_t start, uint64_t end,
 			   const char *parent, const char *name)
+{
+	struct memory_range range;
+
+	range.start = start;
+	range.end = end;
+	range.type = RANGE_RAM;
+
+	return dtb_add_range_properties(dtb, dtb_size, &range, 1, parent, name);
+}
+
+int dtb_add_range_properties(char **dtb, off_t *dtb_size,
+			     const struct memory_range *ranges, int nr_ranges,
+			     const char *parent, const char *name)
 {
 	uint32_t addr_cells = 0;
 	uint32_t size_cells = 0;
 	char *nodepath = NULL;
 	void *prop = NULL;
+	uint32_t *range_prop = NULL;
 	int nodeoffset = 0;
 	int prop_size = 0;
 	int ret = 0;
+	int i;
+
+	if (nr_ranges <= 0)
+		return -EINVAL;
 
 	nodepath = malloc(strlen("/") + strlen(parent) + 1);
 	if (!nodepath) {
@@ -281,22 +299,37 @@ int dtb_add_range_property(char **dtb, off_t *dtb_size, uint64_t start, uint64_t
 	if (ret < 0)
 		return ret;
 
-	/* Can the range fit with the given address/size cells ? */
-	if ((addr_cells == 1) && (start >= (1ULL << 32)))
-		return -EINVAL;
+	for (i = 0; i < nr_ranges; i++) {
+		uint64_t start = ranges[i].start;
+		uint64_t size = ranges[i].end - ranges[i].start + 1;
 
-	if ((size_cells == 1) && ((end - start + 1) >= (1ULL << 32)))
-		return -EINVAL;
+		/* Can the range fit with the given address/size cells ? */
+		if ((addr_cells == 1) && (start >= (1ULL << 32)))
+			return -EINVAL;
+
+		if ((size_cells == 1) && (size >= (1ULL << 32)))
+			return -EINVAL;
+	}
 
-	prop_size = sizeof(uint32_t) * (addr_cells + size_cells);
-	prop = malloc(prop_size);
+	prop_size = sizeof(uint32_t) * (addr_cells + size_cells) * nr_ranges;
+	prop = xmalloc(prop_size);
+	memset(prop, 0, prop_size);
+	range_prop = prop;
 
-	dtb_fill_int_property(prop, start, addr_cells);
-	dtb_fill_int_property((void *)((uint32_t *)prop + addr_cells),
-			      end - start + 1, size_cells);
+	for (i = 0; i < nr_ranges; i++) {
+		dtb_fill_int_property(range_prop, ranges[i].start, addr_cells);
+		range_prop += addr_cells;
+		dtb_fill_int_property(range_prop,
+				      ranges[i].end - ranges[i].start + 1,
+				      size_cells);
+		range_prop += size_cells;
+	}
 
 	/* Add by node path name */
-	return dtb_set_property(dtb, dtb_size, parent, name, prop, prop_size);
+	ret = dtb_set_property(dtb, dtb_size, parent, name, prop, prop_size);
+	free(prop);
+
+	return ret;
 }
 
 /************************\
diff --git a/kexec/dt-ops.h b/kexec/dt-ops.h
index 3014205d8e98..349be3d09493 100644
--- a/kexec/dt-ops.h
+++ b/kexec/dt-ops.h
@@ -14,7 +14,10 @@ int dtb_delete_property(char *dtb, const char *node, const char *prop);
 void dtb_extract_int_property(uint64_t *val, const void *buf, uint32_t cells);
 void dtb_fill_int_property(void *buf, uint64_t val, uint32_t cells);
 int dtb_add_range_property(char **dtb, off_t *dtb_size, uint64_t start, uint64_t end,
-                           const char *node, const char* parent);
+			   const char *parent, const char *name);
+int dtb_add_range_properties(char **dtb, off_t *dtb_size,
+			     const struct memory_range *ranges, int nr_ranges,
+			     const char *parent, const char *name);
 int dtb_get_memory_ranges(char *dtb, struct memory_ranges *mem_ranges,
 			  struct memory_ranges *extra_ranges);
 
-- 
2.52.0

_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH 0/2] kexec-tools: Fix split crash kernel reservations
  2026-08-18 12:35 [PATCH 0/2] kexec-tools: Fix split crash kernel reservations Rui Qi
  2026-08-18 12:35 ` [PATCH 1/2] kexec: Print crash kernel reserved size from sysfs Rui Qi
  2026-08-18 12:35 ` [PATCH 2/2] RISC-V: Pass all crash kernel ranges to crash kernel Rui Qi
@ 2026-08-24 15:27 ` Simon Horman
  2 siblings, 0 replies; 4+ messages in thread
From: Simon Horman @ 2026-08-24 15:27 UTC (permalink / raw)
  To: Rui Qi; +Cc: kexec, linux-riscv

On Tue, Aug 18, 2026 at 08:35:05PM +0800, Rui Qi wrote:
> Hi,
> 
> This series fixes two kexec-tools issues seen with split crash kernel
> reservations.
> 
> The first patch makes --print-ckr-size prefer
> /sys/kernel/kexec_crash_size. This restores the option's original
> user-visible contract: report the same crash kernel reserved size and
> unit as the kernel sysfs attribute when that attribute is available.
> The existing arch load-range based calculation is kept as a fallback for
> older kernels.
> 
> The second patch fixes the RISC-V kexec_load crash path. RISC-V records
> all Crash kernel ranges from /proc/iomem, but it currently writes only
> the selected load range to linux,usable-memory-range. On systems with
> high/low crash kernel reservations, that prevents the crash kernel from
> seeing the low reservation after boot.
> 
> Keep placing the crash image segments in the selected load range, but
> pass all crash kernel ranges to the crash kernel through
> linux,usable-memory-range. This follows the split-reservation handoff
> model already used by arm64 kexec-tools, where
> linux,usable-memory-range = <BASE1 SIZE1 BASE2 SIZE2> advertises both
> high and low crash kernel ranges to the crash dump kernel.
> 
> Tested on riscv64 with:
> 
>   /proc/iomem:
>     f7e00000-ffdfffff       : Crash kernel  (128 MiB low)
>     1f88c00000-1ff6bfffff   : Crash kernel  (1760 MiB high)
> 
>   /sys/kernel/kexec_crash_size:
>     1979711488
> 
> With the patched kexec binary:
> 
>   kexec --print-ckr-size
>     1979711488
> 
>   kexec -c -p ... followed by a panic completed kdump successfully.
>   The crash kernel reported both ranges as System RAM in /proc/iomem:
> 
>     f7e00000-ffdfffff       : System RAM
>     1f88c00000-1ff6bfffff   : System RAM
> 
> The vmcore was saved successfully.
> 
> Rui Qi (2):
>   kexec: Print crash kernel reserved size from sysfs
>   RISC-V: Pass all crash kernel ranges to crash kernel

Thanks, applied.

- RISC-V: Pass all crash kernel ranges to crash kernel
  https://git.kernel.org/pub/scm/utils/kernel/kexec/kexec-tools.git/commit/?id=6b8b27fbe5cc
- kexec: Print crash kernel reserved size from sysfs
  https://git.kernel.org/pub/scm/utils/kernel/kexec/kexec-tools.git/commit/?id=97061549e25f


_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2026-08-24 15:27 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-18 12:35 [PATCH 0/2] kexec-tools: Fix split crash kernel reservations Rui Qi
2026-08-18 12:35 ` [PATCH 1/2] kexec: Print crash kernel reserved size from sysfs Rui Qi
2026-08-18 12:35 ` [PATCH 2/2] RISC-V: Pass all crash kernel ranges to crash kernel Rui Qi
2026-08-24 15:27 ` [PATCH 0/2] kexec-tools: Fix split crash kernel reservations Simon Horman

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox