|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [PATCH 5/7] x86/kexec: Implement new EFI load types
From: Ross Lagerwall <ross.lagerwall@xxxxxxxxxx>
Add new EFI load type for kexec. This load type is suitable for use when Secure
Boot is enabled.
When this load type is used, the caller should not pass purgatory as one of
the kexec segments. Instead, Xen will prepare any glue code needed internally.
Signed-off-by: Ross Lagerwall <ross.lagerwall@xxxxxxxxxx>
Signed-off-by: Gerald Elder-Vass <gerald.elder-vass@xxxxxxxxx>
Signed-off-by: Kevin Lampis <klampis@xxxxxxxxxx>
---
xen/arch/x86/include/asm/bzimage.h | 5 ++
xen/common/kexec.c | 9 +++
xen/common/kimage.c | 123 +++++++++++++++++++++--------
xen/include/public/kexec.h | 11 ++-
xen/include/xen/kimage.h | 2 +
5 files changed, 115 insertions(+), 35 deletions(-)
diff --git a/xen/arch/x86/include/asm/bzimage.h
b/xen/arch/x86/include/asm/bzimage.h
index 8c54b21d06..ed61f9446a 100644
--- a/xen/arch/x86/include/asm/bzimage.h
+++ b/xen/arch/x86/include/asm/bzimage.h
@@ -47,4 +47,9 @@ struct __packed bzimage_header {
uint32_t payload_length;
};
+static inline uint64_t kernel_alignment_offset(void)
+{
+ return offsetof(struct bzimage_header, kernel_alignment);
+}
+
#endif /* __X86_BZIMAGE_H__ */
diff --git a/xen/common/kexec.c b/xen/common/kexec.c
index 00346fe616..1ae4c069c1 100644
--- a/xen/common/kexec.c
+++ b/xen/common/kexec.c
@@ -750,6 +750,7 @@ static int kexec_load_get_bits(int type, int *base, int
*bit)
*bit = KEXEC_FLAG_DEFAULT_POS;
break;
case KEXEC_TYPE_CRASH:
+ case KEXEC_TYPE_CRASH_EFI:
*base = KEXEC_IMAGE_CRASH_BASE;
*bit = KEXEC_FLAG_CRASH_POS;
break;
@@ -848,6 +849,7 @@ static int kexec_exec(XEN_GUEST_HANDLE_PARAM(void) uarg)
ret = continue_hypercall_on_cpu(0, kexec_reboot, image);
break;
case KEXEC_TYPE_CRASH:
+ case KEXEC_TYPE_CRASH_EFI:
kexec_crash(CRASHREASON_KEXECCMD); /* Does not return */
break;
}
@@ -1147,6 +1149,13 @@ static int kexec_load(XEN_GUEST_HANDLE_PARAM(void) uarg)
if ( ret )
return ret;
+ if ( load.type == KEXEC_TYPE_CRASH_EFI )
+ {
+ ret = kimage_efi_setup(kimage, load.parameters);
+ if ( ret )
+ return ret;
+ }
+
ret = kexec_load_slot(kimage);
if ( ret < 0 )
goto error;
diff --git a/xen/common/kimage.c b/xen/common/kimage.c
index 1d872916b9..9b49455e8e 100644
--- a/xen/common/kimage.c
+++ b/xen/common/kimage.c
@@ -22,6 +22,7 @@
#include <xen/kimage.h>
#include <xen/sha2.h>
+#include <asm/bzimage.h>
#include <asm/page.h>
#define KIMAGE_SHA256_REGIONS 16
@@ -109,29 +110,6 @@ static int do_kimage_alloc(struct kexec_image **rimage,
paddr_t entry,
INIT_PAGE_LIST_HEAD(&image->dest_pages);
INIT_PAGE_LIST_HEAD(&image->unusable_pages);
- /*
- * Verify we have good destination addresses. The caller is
- * responsible for making certain we don't attempt to load the new
- * image into invalid or reserved areas of RAM. This just
- * verifies it is an address we can use.
- *
- * Since the kernel does everything in page size chunks ensure the
- * destination addresses are page aligned. Too many special cases
- * crop of when we don't do this. The most insidious is getting
- * overlapping destination addresses simply because addresses are
- * changed to page size granularity.
- */
- result = -EADDRNOTAVAIL;
- for ( i = 0; i < nr_segments; i++ )
- {
- paddr_t mstart, mend;
-
- mstart = image->segments[i].dest_maddr;
- mend = mstart + image->segments[i].dest_size;
- if ( (mstart & ~PAGE_MASK) || (mend & ~PAGE_MASK) )
- goto out;
- }
-
/*
* Verify our destination addresses do not overlap. If we allowed
* overlapping destination addresses through very weird things can
@@ -217,17 +195,13 @@ static int kimage_normal_alloc(struct kexec_image
**rimage, paddr_t entry,
KEXEC_TYPE_DEFAULT);
}
-static int kimage_crash_alloc(struct kexec_image **rimage, paddr_t entry,
- unsigned long nr_segments,
- struct kimage_segment *segments)
+static int do_kimage_crash_alloc(struct kexec_image **rimage, paddr_t entry,
+ unsigned long nr_segments,
+ struct kimage_segment *segments,
+ uint8_t type)
{
unsigned long i;
- /* Verify we have a valid entry point */
- if ( (entry < kexec_crash_area.start)
- || (entry > kexec_crash_area.start + kexec_crash_area.size))
- return -EADDRNOTAVAIL;
-
/*
* Verify we have good destination addresses. Normally
* the caller is responsible for making certain we don't
@@ -253,8 +227,28 @@ static int kimage_crash_alloc(struct kexec_image **rimage,
paddr_t entry,
}
/* Allocate and initialize a controlling structure. */
- return do_kimage_alloc(rimage, entry, nr_segments, segments,
- KEXEC_TYPE_CRASH);
+ return do_kimage_alloc(rimage, entry, nr_segments, segments, type);
+}
+
+static int kimage_crash_alloc(struct kexec_image **rimage, paddr_t entry,
+ unsigned long nr_segments,
+ struct kimage_segment *segments)
+{
+ /* Verify we have a valid entry point */
+ if ( (entry < kexec_crash_area.start)
+ || (entry > kexec_crash_area.start + kexec_crash_area.size))
+ return -EADDRNOTAVAIL;
+
+ return do_kimage_crash_alloc(rimage, entry, nr_segments, segments,
+ KEXEC_TYPE_CRASH);
+}
+
+static int kimage_crash_alloc_efi(struct kexec_image **rimage, paddr_t entry,
+ unsigned long nr_segments,
+ struct kimage_segment *segments)
+{
+ return do_kimage_crash_alloc(rimage, entry, nr_segments, segments,
+ KEXEC_TYPE_CRASH_EFI);
}
static int kimage_is_destination_range(struct kexec_image *image,
@@ -426,6 +420,7 @@ struct page_info *kimage_alloc_control_page(struct
kexec_image *image,
pages = kimage_alloc_normal_control_page(image, memflags);
break;
case KEXEC_TYPE_CRASH:
+ case KEXEC_TYPE_CRASH_EFI:
pages = kimage_alloc_crash_control_page(image);
break;
}
@@ -788,6 +783,7 @@ static int kimage_load_segment(struct kexec_image *image,
result = kimage_load_normal_segment(image, segment);
break;
case KEXEC_TYPE_CRASH:
+ case KEXEC_TYPE_CRASH_EFI:
result = kimage_load_crash_segment(image, segment);
break;
}
@@ -838,6 +834,10 @@ int kimage_alloc(struct kexec_image **rimage, uint8_t
type, uint16_t arch,
case KEXEC_TYPE_CRASH:
result = kimage_crash_alloc(rimage, entry_maddr, nr_segments, segment);
break;
+ case KEXEC_TYPE_CRASH_EFI:
+ result = kimage_crash_alloc_efi(rimage, entry_maddr,
+ nr_segments, segment);
+ break;
default:
result = -EINVAL;
break;
@@ -1064,6 +1064,63 @@ done:
return ret;
}
+/*
+ * Find the entry point to the new kernel, we need to map the crash region into
+ * memory in order to read the kernel header.
+ */
+#define KERNEL_SEGMENT_IDX 0
+static uint64_t kimage_find_kernel_entry_maddr(struct kexec_image *image)
+{
+ uint64_t alignment_addr;
+ uint32_t alignment;
+ unsigned long dest_mfn;
+ void *dest_va;
+
+ alignment_addr = image->segments[KERNEL_SEGMENT_IDX].dest_maddr +
+ image->segments[KERNEL_SEGMENT_IDX].dest_offset +
+ kernel_alignment_offset();
+
+ dest_mfn = alignment_addr >> PAGE_SHIFT;
+ dest_va = map_domain_page(_mfn(dest_mfn));
+ if ( !dest_va )
+ return -EINVAL;
+
+ alignment = *((uint32_t *) ((uint8_t *) dest_va +
+ PAGE_OFFSET(alignment_addr)));
+
+ unmap_domain_page(dest_va);
+
+ /*
+ * Ensure the kernel alignment is a valid LOAD_PHYSICAL_ADDR,
+ * which ranges from 0x200000 (2MiB) to 0x1000000 (16Mib) on 64-bit systems
+ * as defined in the kernel x86 Kconfig
+ */
+ if ( alignment % 0x200000 != 0 ||
+ alignment < 0x200000 ||
+ alignment > 0x1000000 )
+ return -EINVAL;
+
+ return ROUNDUP(image->segments[KERNEL_SEGMENT_IDX].dest_maddr +
+ image->segments[KERNEL_SEGMENT_IDX].dest_offset,
+ alignment) +
+ 0x200;
+}
+
+int kimage_efi_setup(struct kexec_image *image, uint64_t parameters)
+{
+ int64_t rip;
+
+ rip = kimage_find_kernel_entry_maddr(image);
+
+ if ( rip < 0 )
+ return -EINVAL;
+
+ image->boot_params = parameters;
+ image->entry_maddr = rip;
+
+ return 0;
+}
+
/*
* Local variables:
* mode: C
diff --git a/xen/include/public/kexec.h b/xen/include/public/kexec.h
index 40d79e936b..287255ea6f 100644
--- a/xen/include/public/kexec.h
+++ b/xen/include/public/kexec.h
@@ -58,13 +58,16 @@
* - kexec into a regular kernel, very similar to a standard reboot
* - KEXEC_TYPE_DEFAULT is used to specify this type
* - kexec into a special "crash kernel", aka kexec-on-panic
- * - KEXEC_TYPE_CRASH is used to specify this type
+ * - KEXEC_TYPE_CRASH or KEXEC_TYPE_CRASH_EFI are used to specify this type
+ * - in case of KEXEC_TYPE_CRASH_EFI the first segment will point to full
+ * the kernel to load and entry point will point to boot params
* - parts of our system may be broken at kexec-on-panic time
* - the code should be kept as simple and self-contained as possible
*/
#define KEXEC_TYPE_DEFAULT 0
#define KEXEC_TYPE_CRASH 1
+#define KEXEC_TYPE_CRASH_EFI 3
/* The kexec implementation for Xen allows the user to load two
@@ -195,7 +198,11 @@ typedef struct xen_kexec_load {
XEN_GUEST_HANDLE(xen_kexec_segment_t) h;
uint64_t _pad;
} segments;
- uint64_t entry_maddr; /* image entry point machine address. */
+ /* image entry point machine address or parameters in case of EFI. */
+ union {
+ uint64_t entry_maddr;
+ uint64_t parameters;
+ };
} xen_kexec_load_t;
DEFINE_XEN_GUEST_HANDLE(xen_kexec_load_t);
diff --git a/xen/include/xen/kimage.h b/xen/include/xen/kimage.h
index aab8707cac..ba5d5c2b92 100644
--- a/xen/include/xen/kimage.h
+++ b/xen/include/xen/kimage.h
@@ -51,6 +51,7 @@ struct kexec_image {
paddr_t next_crash_page;
uint8_t digest[SHA2_256_DIGEST_SIZE];
+ uint64_t boot_params;
};
int kimage_alloc(struct kexec_image **rimage, uint8_t type, uint16_t arch,
@@ -69,6 +70,7 @@ int kimage_build_ind(struct kexec_image *image, mfn_t ind_mfn,
int kimage_verify_digest(const struct kexec_image *image);
int kimage_calc_digest(const struct kexec_image *image,
uint8_t digest[SHA2_256_DIGEST_SIZE]);
+int kimage_efi_setup(struct kexec_image *image, uint64_t parameters);
#endif /* __ASSEMBLER__ */
--
2.52.0
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |