[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH v2 4/7] x86/kexec: Support non-page-aligned kexec segments


  • To: xen-devel@xxxxxxxxxxxxxxxxxxxx
  • From: Kevin Lampis <kevin.lampis@xxxxxxxxxx>
  • Date: Mon, 22 Jun 2026 16:18:30 +0100
  • Arc-authentication-results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=citrix.com; dmarc=pass action=none header.from=citrix.com; dkim=pass header.d=citrix.com; arc=none
  • Arc-message-signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=TAZqxPDz4iGQDAm8r7PVY0zk34ELEqip4hG1SLppqVU=; b=LTkZgBXAxpW4jT1PQ1g/pZTJQbIPgQxXL70xnPM87zq/R4QB4/aDwM1XBP0OQ5YRYutiQOhKn1SjxzgA6m/HPP3Ax3sZmXpAQOR9LuBlc+lMlgHWaF8817nLzszFq3190xYQ7aIW4i16FVq5CkVcXA4Gyrdqdj69JXLUwEyih3mrCDsO+lO85tXxR25+T/gxAlJm1hxXrBzAsUsziV65Y+vAJ1anBROAhvdjU6p0L9wrfW8LTKRKZKLQX3sn7G9ANZO8VRPbBqJAw2kohASNZYGsE7r/wY2HpYCsy50Nez6WIwtDgXPLrSVgfWVPdBBZn6tiL5HPCzgSv1sTc2E6dA==
  • Arc-seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=TTF6kwwvRVX1Xy2dtL9LJ/R/8w5YhbWUyYtQ81S8TYgaKpGkmExAhjxrTeWba8eTFxUJdchAMXmwypXs0NPwEb8ei3YJXUJtiVOZ46L2xUrFe52YE3YoshO7Px0aCnPSjgNYzif8hYH7fFSPLHXgpC9s0uGG6H6n1Rf1jCVWkEP+BKmNevUJWYk4PggtZf2V67cMk+oK6ZpsSEKQXAU0Aqqa7WuHNDR8Drj/2IuTLjvo+/5SyMcDtNCzDKFcWEn7rQAoGFGpougtodWVSVyWJ4M+LZl73s3DOV80C9+m1p1REaFZl2ZnlZiUbEekIz/Di0ICtdihno0jiGijRaQ3cA==
  • Authentication-results: eu.smtp.expurgate.cloud; dkim=pass header.s=selector1 header.d=citrix.com header.i="@citrix.com" header.h="From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck"
  • Authentication-results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=citrix.com;
  • Cc: jbeulich@xxxxxxxx, andrew.cooper3@xxxxxxxxxx, roger.pau@xxxxxxxxxx, ross.lagerwall@xxxxxxxxxx, Kevin Lampis <kevin.lampis@xxxxxxxxxx>
  • Delivery-date: Mon, 22 Jun 2026 15:17:38 +0000
  • List-id: Xen developer discussion <xen-devel.lists.xenproject.org>

From: Ross Lagerwall <ross.lagerwall@xxxxxxxxxx>

With Secure Boot, userspace passes in the entire kernel loaded for
verification purposes. However, the kernel's startup32 function needs to
be aligned (e.g. to 16 MiB) and this results in the start of the segment
not being page-aligned (depending on where the startup32 function lands
in the kernel binary). Relax this restriction in Xen to support this
use case.

Signed-off-by: Ross Lagerwall <ross.lagerwall@xxxxxxxxxx>
Signed-off-by: Kevin Lampis <kevin.lampis@xxxxxxxxxx>
---
Changes in v2:
- Remove error handling around map_domain_page because it doesn't fail
---
 xen/common/kimage.c      | 47 +++++++++++++++++++++++++++++++---------
 xen/include/xen/kimage.h |  1 +
 2 files changed, 38 insertions(+), 10 deletions(-)

diff --git a/xen/common/kimage.c b/xen/common/kimage.c
index dc47306223..d4a695a2bd 100644
--- a/xen/common/kimage.c
+++ b/xen/common/kimage.c
@@ -725,12 +725,14 @@ static int kimage_load_crash_segment(struct kexec_image 
*image,
      */
     paddr_t dest;
     unsigned long sbytes, dbytes;
+    unsigned int dest_offset;
     int ret = 0;
     unsigned long src_offset = 0;
 
     sbytes = segment->buf_size;
     dbytes = segment->dest_size;
     dest = segment->dest_maddr;
+    dest_offset = segment->dest_offset;
 
     while ( dbytes )
     {
@@ -740,24 +742,26 @@ static int kimage_load_crash_segment(struct kexec_image 
*image,
 
         dest_mfn = dest >> PAGE_SHIFT;
 
-        dchunk = PAGE_SIZE;
+        dchunk = PAGE_SIZE - dest_offset;
         schunk = min(dchunk, sbytes);
 
         dest_va = map_domain_page(_mfn(dest_mfn));
-        if ( !dest_va )
-            return -EINVAL;
 
-        ret = copy_from_guest_offset(dest_va, segment->h, src_offset, schunk);
-        memset(dest_va + schunk, 0, dchunk - schunk);
+        if ( dest_offset )
+            memset(dest_va, 0, dest_offset);
+        ret = copy_from_guest_offset(dest_va + dest_offset, segment->h,
+                                     src_offset, schunk);
+        memset(dest_va + dest_offset + schunk, 0, dchunk - schunk);
 
         unmap_domain_page(dest_va);
         if ( ret )
             return -EFAULT;
 
-        dbytes -= dchunk;
+        dbytes -= dchunk + dest_offset;
         sbytes -= schunk;
-        dest += dchunk;
+        dest += dchunk + dest_offset;
         src_offset += schunk;
+        dest_offset = 0;
     }
 
     return 0;
@@ -798,6 +802,26 @@ int kimage_alloc(struct kexec_image **rimage, uint8_t 
type, uint16_t arch,
                  uint32_t nr_segments, struct kimage_segment *segment)
 {
     int result;
+    unsigned int i;
+
+    for ( i = 0; i < nr_segments; i++ )
+    {
+        paddr_t mend;
+
+        /*
+         * Stash the destination offset-in-page for use when copying the
+         * buffer later.
+         */
+        segment[i].dest_offset = PAGE_OFFSET(segment[i].dest_maddr);
+
+        /*
+         * Align down the start address to page size and align up the end
+         * address to page size.
+         */
+        mend = segment[i].dest_maddr + segment[i].dest_size;
+        segment[i].dest_maddr &= PAGE_MASK;
+        segment[i].dest_size = ROUNDUP(mend, PAGE_SIZE) - 
segment[i].dest_maddr;
+    }
 
     switch( type )
     {
@@ -824,9 +848,11 @@ static void kimage_calc_one_digest(struct sha2_256_state 
*ctx,
 {
     paddr_t dest;
     unsigned long sbytes;
+    unsigned int dest_offset;
 
     sbytes = segment->buf_size;
     dest = segment->dest_maddr;
+    dest_offset = segment->dest_offset;
 
     while ( sbytes )
     {
@@ -836,15 +862,16 @@ static void kimage_calc_one_digest(struct sha2_256_state 
*ctx,
 
         dest_mfn = dest >> PAGE_SHIFT;
 
-        dchunk = PAGE_SIZE;
+        dchunk = PAGE_SIZE - dest_offset;
         schunk = min(dchunk, sbytes);
 
         dest_va = map_domain_page(_mfn(dest_mfn));
-        sha2_256_update(ctx, dest_va, schunk);
+        sha2_256_update(ctx, dest_va + dest_offset, schunk);
         unmap_domain_page(dest_va);
 
         sbytes -= schunk;
-        dest += dchunk;
+        dest += dchunk + dest_offset;
+        dest_offset = 0;
     }
 }
 
diff --git a/xen/include/xen/kimage.h b/xen/include/xen/kimage.h
index 0841b6f321..86250f2939 100644
--- a/xen/include/xen/kimage.h
+++ b/xen/include/xen/kimage.h
@@ -23,6 +23,7 @@ struct kimage_segment {
     uint64_t buf_size;
     uint64_t dest_maddr;
     uint64_t dest_size;
+    unsigned int dest_offset;
 };
 
 struct kexec_image {
-- 
2.52.0




 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.