|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [PATCH 4/7] x86/kexec: Support non-page-aligned kexec segments
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 <klampis@xxxxxxxxxx>
---
xen/common/kimage.c | 34 ++++++++++++++++++++++++++++++----
xen/include/xen/kimage.h | 1 +
2 files changed, 31 insertions(+), 4 deletions(-)
diff --git a/xen/common/kimage.c b/xen/common/kimage.c
index 2c3fd3c3b0..1d872916b9 100644
--- a/xen/common/kimage.c
+++ b/xen/common/kimage.c
@@ -730,12 +730,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 )
{
@@ -745,24 +747,28 @@ 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->buf.h, src_offset,
schunk);
+ if ( dest_offset )
+ memset(dest_va, 0, dest_offset);
+ ret = copy_from_guest_offset(dest_va + dest_offset, segment->buf.h,
+ src_offset, schunk);
memset(dest_va + 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;
@@ -803,6 +809,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 )
{
diff --git a/xen/include/xen/kimage.h b/xen/include/xen/kimage.h
index 258349d774..aab8707cac 100644
--- a/xen/include/xen/kimage.h
+++ b/xen/include/xen/kimage.h
@@ -26,6 +26,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
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |