aboutsummaryrefslogtreecommitdiffstats
path: root/main/grub/0012-xen-Get-memory-map-from-hypervisor-for-PVH.patch
blob: cdab0c08bfe1ce2b4f61ce7dc6f760725902c25c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
From 4acff24f747e43c3f9bb0551c7d09114355c7d3a Mon Sep 17 00:00:00 2001
From: Juergen Gross <jgross@suse.com>
Date: Fri, 7 Dec 2018 13:11:40 +0100
Subject: [PATCH 12/20] xen: Get memory map from hypervisor for PVH

Retrieve the memory map from the hypervisor and normalize it to contain
no overlapping entries and to be sorted by address.

Signed-off-by: Juergen Gross <jgross@suse.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
Tested-by: Hans van Kranenburg <hans@knorrie.org>
(cherry picked from commit 2b7a21afd319b829941a928f5763e017d1cc2951)
---
 grub-core/kern/i386/xen/pvh.c | 94 +++++++++++++++++++++++++++++++++++
 1 file changed, 94 insertions(+)

diff --git a/grub-core/kern/i386/xen/pvh.c b/grub-core/kern/i386/xen/pvh.c
index a2554fb1d..2b68ac333 100644
--- a/grub-core/kern/i386/xen/pvh.c
+++ b/grub-core/kern/i386/xen/pvh.c
@@ -24,7 +24,12 @@
 #include <grub/i386/io.h>
 #include <grub/xen.h>
 #include <xen/hvm/start_info.h>
+#include <grub/i386/linux.h>
 #include <grub/machine/kernel.h>
+#include <grub/machine/memory.h>
+#include <xen/memory.h>
+
+#define XEN_MEMORY_MAP_SIZE   128
 
 grub_uint64_t grub_rsdp_addr;
 
@@ -32,6 +37,8 @@ static char hypercall_page[GRUB_XEN_PAGE_SIZE]
   __attribute__ ((aligned (GRUB_XEN_PAGE_SIZE)));
 
 static grub_uint32_t xen_cpuid_base;
+static struct grub_e820_mmap_entry map[XEN_MEMORY_MAP_SIZE];
+static unsigned int nr_map_entries;
 
 static void
 grub_xen_cons_msg (const char *msg)
@@ -104,11 +111,98 @@ grub_xen_hypercall (grub_uint32_t callno, grub_uint32_t a0,
   return res;
 }
 
+static void
+grub_xen_sort_mmap (void)
+{
+  grub_uint64_t from, to;
+  unsigned int i;
+  struct grub_e820_mmap_entry tmp;
+
+  /* Align map entries to page boundaries. */
+  for (i = 0; i < nr_map_entries; i++)
+    {
+      from = map[i].addr;
+      to = from + map[i].len;
+      if (map[i].type == GRUB_MEMORY_AVAILABLE)
+	{
+	  from = ALIGN_UP (from, GRUB_XEN_PAGE_SIZE);
+	  to = ALIGN_DOWN (to, GRUB_XEN_PAGE_SIZE);
+	}
+      else
+	{
+	  from = ALIGN_DOWN (from, GRUB_XEN_PAGE_SIZE);
+	  to = ALIGN_UP (to, GRUB_XEN_PAGE_SIZE);
+	}
+      map[i].addr = from;
+      map[i].len = to - from;
+    }
+
+ again:
+  /* Sort entries by start address. */
+  for (i = 1; i < nr_map_entries; i++)
+    {
+      if (map[i].addr >= map[i - 1].addr)
+	continue;
+      tmp = map[i];
+      map[i] = map[i - 1];
+      map[i - 1] = tmp;
+      i = 0;
+    }
+
+  /* Detect overlapping areas. */
+  for (i = 1; i < nr_map_entries; i++)
+    {
+      if (map[i].addr >= map[i - 1].addr + map[i - 1].len)
+	continue;
+      tmp = map[i - 1];
+      map[i - 1].len = map[i].addr - map[i - 1].addr;
+      if (map[i].addr + map[i].len >= tmp.addr + tmp.len)
+	continue;
+      if (nr_map_entries < ARRAY_SIZE (map))
+	{
+	  map[nr_map_entries].addr = map[i].addr + map[i].len;
+	  map[nr_map_entries].len = tmp.addr + tmp.len - map[nr_map_entries].addr;
+	  map[nr_map_entries].type = tmp.type;
+	  nr_map_entries++;
+	  goto again;
+	}
+    }
+
+  /* Merge adjacent entries. */
+  for (i = 1; i < nr_map_entries; i++)
+    {
+      if (map[i].type == map[i - 1].type &&
+	  map[i].addr == map[i - 1].addr + map[i - 1].len)
+	{
+	  map[i - 1].len += map[i].len;
+	  map[i] = map[nr_map_entries - 1];
+	  nr_map_entries--;
+	  goto again;
+	}
+    }
+}
+
+static void
+grub_xen_get_mmap (void)
+{
+  struct xen_memory_map memmap;
+
+  memmap.nr_entries = ARRAY_SIZE (map);
+  set_xen_guest_handle (memmap.buffer, map);
+  if (grub_xen_hypercall (__HYPERVISOR_memory_op, XENMEM_memory_map,
+			  (grub_uint32_t) (&memmap), 0, 0, 0, 0))
+    grub_xen_panic ("Could not get memory map from Xen!\n");
+  nr_map_entries = memmap.nr_entries;
+
+  grub_xen_sort_mmap ();
+}
+
 void
 grub_xen_setup_pvh (void)
 {
   grub_xen_cpuid_base ();
   grub_xen_setup_hypercall_page ();
+  grub_xen_get_mmap ();
 }
 
 grub_err_t
-- 
2.21.0