summaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
authorMark Brown <broonie@kernel.org>2026-09-30 13:31:28 +0100
committerMark Brown <broonie@kernel.org>2026-09-30 13:31:28 +0100
commit702c3cf3d279d701e1596cc90b71893b339bec56 (patch)
treeb2517826f695ae0f7384ae8f9f94ab232744e0ef /kernel
parent24bf019cbe7e44d1e933480933b8410886bf4c60 (diff)
parent9d0b028715b007188a61ce70b9656ead84a2b3ef (diff)
downloadlinux-next-702c3cf3d279d701e1596cc90b71893b339bec56.tar.gz
linux-next-702c3cf3d279d701e1596cc90b71893b339bec56.zip
Merge branch 'kexec-next' of https://git.kernel.org/pub/scm/linux/kernel/git/liveupdate/linux.git
Diffstat (limited to 'kernel')
-rw-r--r--kernel/kexec_core.c10
-rw-r--r--kernel/kexec_file.c22
2 files changed, 30 insertions, 2 deletions
diff --git a/kernel/kexec_core.c b/kernel/kexec_core.c
index dc770b9a6d05..7ee8c9f078f6 100644
--- a/kernel/kexec_core.c
+++ b/kernel/kexec_core.c
@@ -213,6 +213,16 @@ int sanity_check_segment_list(struct kimage *image)
#endif
/*
+ * Reject destinations that land on hardware-poisoned memory: the
+ * relocation copy would machine-check on the bad frame.
+ */
+ for (i = 0; i < nr_segments; i++) {
+ if (range_first_hwpoison(image->segment[i].mem,
+ image->segment[i].memsz) != PHYS_ADDR_MAX)
+ return -EHWPOISON;
+ }
+
+ /*
* The destination addresses are searched from system RAM rather than
* being allocated from the buddy allocator, so they are not guaranteed
* to be accepted by the current kernel. Accept the destination
diff --git a/kernel/kexec_file.c b/kernel/kexec_file.c
index c11a815e2235..a8455481f639 100644
--- a/kernel/kexec_file.c
+++ b/kernel/kexec_file.c
@@ -477,6 +477,7 @@ static int locate_mem_hole_top_down(unsigned long start, unsigned long end,
{
struct kimage *image = kbuf->image;
unsigned long temp_start, temp_end;
+ phys_addr_t poison;
temp_end = min(end, kbuf->buf_max);
temp_start = temp_end - kbuf->memsz + 1;
@@ -486,7 +487,9 @@ static int locate_mem_hole_top_down(unsigned long start, unsigned long end,
/* align down start */
temp_start = ALIGN_DOWN(temp_start, kbuf->buf_align);
- if (temp_start < start || temp_start < kbuf->buf_min)
+ /* A candidate above the range means the walk wrapped around */
+ if (temp_start < start || temp_start < kbuf->buf_min ||
+ temp_start > end)
return 0;
temp_end = temp_start + kbuf->memsz - 1;
@@ -506,6 +509,13 @@ static int locate_mem_hole_top_down(unsigned long start, unsigned long end,
continue;
}
+ poison = range_first_hwpoison(temp_start, kbuf->memsz);
+ if (poison != PHYS_ADDR_MAX) {
+ /* we hit a poisoned page */
+ temp_start = poison - kbuf->memsz;
+ continue;
+ }
+
/* We found a suitable memory range */
break;
} while (1);
@@ -522,6 +532,7 @@ static int locate_mem_hole_bottom_up(unsigned long start, unsigned long end,
{
struct kimage *image = kbuf->image;
unsigned long temp_start, temp_end;
+ phys_addr_t poison;
temp_start = max(start, kbuf->buf_min);
@@ -548,6 +559,13 @@ static int locate_mem_hole_bottom_up(unsigned long start, unsigned long end,
continue;
}
+ poison = range_last_hwpoison(temp_start, kbuf->memsz);
+ if (poison != PHYS_ADDR_MAX) {
+ /* we hit a poisoned page */
+ temp_start = poison + PAGE_SIZE;
+ continue;
+ }
+
/* We found a suitable memory range */
break;
} while (1);
@@ -786,7 +804,7 @@ int kexec_add_buffer(struct kexec_buf *kbuf)
kbuf->cma = NULL;
/* Walk the RAM ranges and allocate a suitable range for the buffer */
- ret = arch_kexec_locate_mem_hole(kbuf);
+ ret = kexec_locate_mem_hole(kbuf);
if (ret)
return ret;