All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] xen: Avoid overlapping segments in low memory
@ 2019-04-28 10:52 David Woodhouse
  2019-05-15  7:40 ` Simon Horman
  0 siblings, 1 reply; 2+ messages in thread
From: David Woodhouse @ 2019-04-28 10:52 UTC (permalink / raw)
  To: kexec


[-- Attachment #1.1: Type: text/plain, Size: 4930 bytes --]

From: David Woodhouse <dwmw@amazon.co.uk>

Unlike Linux which creates a full identity mapping, Xen only maps those
segments which are explicitly requested. Therefore, xen_kexec_load()
silently adds in a segment from zero to 1MiB to ensure that VGA memory
and other things are accessible.

However, this doesn't work when there are already segments to be loaded
under 1MiB, because the overlap causes Xen to reject the kexec_load.

Be more careful and just infill the ranges which are required instead
of naïvely adding a full 0-1MiB segment at the end of the list.

Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>
---
Of course, if kexec didn't choose to put a whole bunch of stuff
gratuitously below 1MiB — especially, if it didn't choose to scribble
over the BIOS Data Area in the zero page — that would be kind of nice
too. qv.

 kexec/kexec-xen.c | 73 +++++++++++++++++++++++++++++++++++------------
 1 file changed, 54 insertions(+), 19 deletions(-)

diff --git a/kexec/kexec-xen.c b/kexec/kexec-xen.c
index 1887390..c326955 100644
--- a/kexec/kexec-xen.c
+++ b/kexec/kexec-xen.c
@@ -64,15 +64,18 @@ int __xc_interface_close(xc_interface *xch)
 }
 #endif /* CONFIG_LIBXENCTRL_DL */
 
+#define IDENTMAP_1MiB (1024 * 1024)
+
 int xen_kexec_load(struct kexec_info *info)
 {
-	uint32_t nr_segments = info->nr_segments;
+	uint32_t nr_segments = info->nr_segments, nr_low_segments = 0;
 	struct kexec_segment *segments = info->segment;
+	uint64_t low_watermark = 0;
 	xc_interface *xch;
 	xc_hypercall_buffer_array_t *array = NULL;
 	uint8_t type;
 	uint8_t arch;
-	xen_kexec_segment_t *xen_segs;
+	xen_kexec_segment_t *xen_segs, *seg;
 	int s;
 	int ret = -1;
 
@@ -80,7 +83,28 @@ int xen_kexec_load(struct kexec_info *info)
 	if (!xch)
 		return -1;
 
-	xen_segs = calloc(nr_segments + 1, sizeof(*xen_segs));
+	/*
+	 * Ensure 0 - 1 MiB is mapped and accessible by the image.
+	 * This allows access to the VGA memory and the region
+	 * purgatory copies in the crash case.
+	 *
+	 * First, count the number of additional segments which will
+	 * need to be added in between the ones in segments[].
+	 *
+	 * The segments are already sorted.
+	 */
+	for (s = 0; s < nr_segments && (uint64_t)segments[s].mem <= IDENTMAP_1MiB; s++) {
+		if ((uint64_t)segments[s].mem > low_watermark)
+			nr_low_segments++;
+
+		low_watermark = (uint64_t)segments[s].mem + segments[s].memsz;
+	}
+	if (low_watermark < IDENTMAP_1MiB)
+		nr_low_segments++;
+
+	low_watermark = 0;
+
+	xen_segs = calloc(nr_segments + nr_low_segments, sizeof(*xen_segs));
 	if (!xen_segs)
 		goto out;
 
@@ -88,32 +112,43 @@ int xen_kexec_load(struct kexec_info *info)
 	if (array == NULL)
 		goto out;
 
+	seg = xen_segs;
 	for (s = 0; s < nr_segments; s++) {
 		DECLARE_HYPERCALL_BUFFER(void, seg_buf);
 
+		if (low_watermark < IDENTMAP_1MiB && (uint64_t)segments[s].mem > low_watermark) {
+			set_xen_guest_handle(seg->buf.h, HYPERCALL_BUFFER_NULL);
+			seg->buf_size = 0;
+			seg->dest_maddr = low_watermark;
+			low_watermark = (uint64_t)segments[s].mem;
+			if (low_watermark > IDENTMAP_1MiB)
+				low_watermark = IDENTMAP_1MiB;
+			seg->dest_size = low_watermark - seg->dest_maddr;
+			seg++;
+		}
+
 		seg_buf = xc_hypercall_buffer_array_alloc(xch, array, s,
 							  seg_buf, segments[s].bufsz);
 		if (seg_buf == NULL)
 			goto out;
 		memcpy(seg_buf, segments[s].buf, segments[s].bufsz);
 
-		set_xen_guest_handle(xen_segs[s].buf.h, seg_buf);
-		xen_segs[s].buf_size = segments[s].bufsz;
-		xen_segs[s].dest_maddr = (uint64_t)segments[s].mem;
-		xen_segs[s].dest_size = segments[s].memsz;
+		set_xen_guest_handle(seg->buf.h, seg_buf);
+		seg->buf_size = segments[s].bufsz;
+		seg->dest_maddr = (uint64_t)segments[s].mem;
+		seg->dest_size = segments[s].memsz;
+		seg++;
+
+		low_watermark = (uint64_t)segments[s].mem + segments[s].memsz;
 	}
 
-	/*
-	 * Ensure 0 - 1 MiB is mapped and accessible by the image.
-	 *
-	 * This allows access to the VGA memory and the region
-	 * purgatory copies in the crash case.
-	 */
-	set_xen_guest_handle(xen_segs[s].buf.h, HYPERCALL_BUFFER_NULL);
-	xen_segs[s].buf_size = 0;
-	xen_segs[s].dest_maddr = 0;
-	xen_segs[s].dest_size = 1 * 1024 * 1024;
-	nr_segments++;
+	if ((uint64_t)low_watermark < IDENTMAP_1MiB) {
+		set_xen_guest_handle(seg->buf.h, HYPERCALL_BUFFER_NULL);
+		seg->buf_size = 0;
+		seg->dest_maddr = low_watermark;
+		seg->dest_size = IDENTMAP_1MiB - low_watermark;
+		seg++;
+	}
 
 	type = (info->kexec_flags & KEXEC_ON_CRASH) ? KEXEC_TYPE_CRASH
 		: KEXEC_TYPE_DEFAULT;
@@ -125,7 +160,7 @@ int xen_kexec_load(struct kexec_info *info)
 #endif
 
 	ret = xc_kexec_load(xch, type, arch, (uint64_t)info->entry,
-			    nr_segments, xen_segs);
+			    nr_segments + nr_low_segments, xen_segs);
 
 out:
 	xc_hypercall_buffer_array_destroy(xch, array);


[-- Attachment #1.2: smime.p7s --]
[-- Type: application/x-pkcs7-signature, Size: 5174 bytes --]

[-- Attachment #2: Type: text/plain, Size: 143 bytes --]

_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec

^ permalink raw reply related	[flat|nested] 2+ messages in thread

* Re: [PATCH] xen: Avoid overlapping segments in low memory
  2019-04-28 10:52 [PATCH] xen: Avoid overlapping segments in low memory David Woodhouse
@ 2019-05-15  7:40 ` Simon Horman
  0 siblings, 0 replies; 2+ messages in thread
From: Simon Horman @ 2019-05-15  7:40 UTC (permalink / raw)
  To: David Woodhouse; +Cc: kexec

On Sun, Apr 28, 2019 at 01:52:12PM +0300, David Woodhouse wrote:
> From: David Woodhouse <dwmw@amazon.co.uk>
> 
> Unlike Linux which creates a full identity mapping, Xen only maps those
> segments which are explicitly requested. Therefore, xen_kexec_load()
> silently adds in a segment from zero to 1MiB to ensure that VGA memory
> and other things are accessible.
> 
> However, this doesn't work when there are already segments to be loaded
> under 1MiB, because the overlap causes Xen to reject the kexec_load.
> 
> Be more careful and just infill the ranges which are required instead
> of naïvely adding a full 0-1MiB segment at the end of the list.
> 
> Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>

Thanks David,

applied.

_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2019-05-15  7:40 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-04-28 10:52 [PATCH] xen: Avoid overlapping segments in low memory David Woodhouse
2019-05-15  7:40 ` Simon Horman

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.