diff options
| author | Mark Brown <broonie@kernel.org> | 2026-09-30 13:31:28 +0100 |
|---|---|---|
| committer | Mark Brown <broonie@kernel.org> | 2026-09-30 13:31:28 +0100 |
| commit | 702c3cf3d279d701e1596cc90b71893b339bec56 (patch) | |
| tree | b2517826f695ae0f7384ae8f9f94ab232744e0ef /kernel | |
| parent | 24bf019cbe7e44d1e933480933b8410886bf4c60 (diff) | |
| parent | 9d0b028715b007188a61ce70b9656ead84a2b3ef (diff) | |
| download | linux-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.c | 10 | ||||
| -rw-r--r-- | kernel/kexec_file.c | 22 |
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; |
