Checksum verification is needed 1. for crash kernels. In a crash, we can't be sure the kernel is intact. 2. if we're worried about relocating the kernel into a region used by some DMA that wasn't properly cancelled.
If KHO is enabled then relocations will happen to KHO scratch, which is free from DMA regions. If we used CMA to allocate segments then relocations are not going to happen at all. Therefore, we can safely disable checksum verification in both of those cases. Instead of adding a new variable to purgatory, just skip adding regions and save the default value of SHA256 hash. Saves ~250ms on my 4.0 GHz CPU. This is an important saving for the live-update project. Signed-off-by: Michal Clapinski <[email protected]> --- v2: - also skip checksum verification if KHO is enabled - small fixes from reviews My original idea was to do 2 changes: 1. Skip checksum if all segments are CMA. 2. If KHO is enabled, allocate the kernel inside kho_scratch using CMA. This way we could skip both relocations and checksum verification when KHO is enabled. But I realized that step 2 might not be possible on warm boots. I have no idea how to fix that (except weird ideas like 2 kho_scratches that we swap on every warm boot), so I decided to just skip checksum verification when KHO is enabled. This unfortunately means relocations will still happen. --- kernel/kexec_file.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/kernel/kexec_file.c b/kernel/kexec_file.c index 2bfbb2d144e6..db25a14692ab 100644 --- a/kernel/kexec_file.c +++ b/kernel/kexec_file.c @@ -27,6 +27,7 @@ #include <linux/syscalls.h> #include <linux/vmalloc.h> #include <linux/dma-map-ops.h> +#include <linux/kexec_handover.h> #include "kexec_internal.h" #ifdef CONFIG_KEXEC_SIG @@ -798,6 +799,16 @@ int kexec_add_buffer(struct kexec_buf *kbuf) return 0; } +static bool kexec_only_cma_segments(struct kimage *image) +{ + for (int i = 0; i < image->nr_segments; i++) { + if (!image->segment_cma[i]) + return false; + } + + return true; +} + /* Calculate and store the digest of segments */ static int kexec_calculate_store_digests(struct kimage *image) { @@ -822,6 +833,21 @@ static int kexec_calculate_store_digests(struct kimage *image) sha256_init(&sctx); + /* + * If KHO is enabled, the destinations are located in KHO scratch. + * KHO scratch can only contain early boot allocations and movable + * allocations. That means there is no risk of memory corruption by + * uncancelled DMA. + * + * If all segments were loaded into contiguous memory, there will be no + * relocations at all, so also no risk no corruption. + */ + if (image->type != KEXEC_TYPE_CRASH && + (kho_is_enabled() || kexec_only_cma_segments(image))) { + pr_debug("disabling checksum verification in purgatory\n"); + goto skip_checksum; + } + for (j = i = 0; i < image->nr_segments; i++) { struct kexec_segment *ksegment; @@ -867,6 +893,7 @@ static int kexec_calculate_store_digests(struct kimage *image) j++; } +skip_checksum: sha256_final(&sctx, digest); ret = kexec_purgatory_get_set_symbol(image, "purgatory_sha_regions", -- 2.54.0.929.g9b7fa37559-goog
