aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/xen
diff options
context:
space:
mode:
authorDavid Vrabel <david.vrabel@citrix.com>2011-09-28 12:46:36 -0400
committerKonrad Rzeszutek Wilk <konrad.wilk@oracle.com>2011-09-29 11:12:15 -0400
commitf3f436e33b925ead21e3f9b47b1e2aed965511d9 (patch)
tree1911bb6a8f38433e8c685581766a0d2a20ddf03a /arch/x86/xen
parentdc91c728fddc29dfed1ae96f6807216b5f42d3a1 (diff)
xen: release all pages within 1-1 p2m mappings
In xen_memory_setup() all reserved regions and gaps are set to an identity (1-1) p2m mapping. If an available page has a PFN within one of these 1-1 mappings it will become inaccessible (as it MFN is lost) so release them before setting up the mapping. This can make an additional 256 MiB or more of RAM available (depending on the size of the reserved regions in the memory map) if the initial pages overlap with reserved regions. The 1:1 p2m mappings are also extended to cover partial pages. This fixes an issue with (for example) systems with a BIOS that puts the DMI tables in a reserved region that begins on a non-page boundary. Signed-off-by: David Vrabel <david.vrabel@citrix.com> Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Diffstat (limited to 'arch/x86/xen')
-rw-r--r--arch/x86/xen/setup.c117
1 files changed, 42 insertions, 75 deletions
diff --git a/arch/x86/xen/setup.c b/arch/x86/xen/setup.c
index 2ad2fd53bd32..38d0af4fefec 100644
--- a/arch/x86/xen/setup.c
+++ b/arch/x86/xen/setup.c
@@ -83,25 +83,18 @@ static void __init xen_add_extra_mem(u64 start, u64 size)
83 __set_phys_to_machine(pfn, INVALID_P2M_ENTRY); 83 __set_phys_to_machine(pfn, INVALID_P2M_ENTRY);
84} 84}
85 85
86static unsigned long __init xen_release_chunk(phys_addr_t start_addr, 86static unsigned long __init xen_release_chunk(unsigned long start,
87 phys_addr_t end_addr) 87 unsigned long end)
88{ 88{
89 struct xen_memory_reservation reservation = { 89 struct xen_memory_reservation reservation = {
90 .address_bits = 0, 90 .address_bits = 0,
91 .extent_order = 0, 91 .extent_order = 0,
92 .domid = DOMID_SELF 92 .domid = DOMID_SELF
93 }; 93 };
94 unsigned long start, end;
95 unsigned long len = 0; 94 unsigned long len = 0;
96 unsigned long pfn; 95 unsigned long pfn;
97 int ret; 96 int ret;
98 97
99 start = PFN_UP(start_addr);
100 end = PFN_DOWN(end_addr);
101
102 if (end <= start)
103 return 0;
104
105 for(pfn = start; pfn < end; pfn++) { 98 for(pfn = start; pfn < end; pfn++) {
106 unsigned long mfn = pfn_to_mfn(pfn); 99 unsigned long mfn = pfn_to_mfn(pfn);
107 100
@@ -126,72 +119,52 @@ static unsigned long __init xen_release_chunk(phys_addr_t start_addr,
126 return len; 119 return len;
127} 120}
128 121
129static unsigned long __init xen_return_unused_memory( 122static unsigned long __init xen_set_identity_and_release(
130 unsigned long max_pfn, const struct e820entry *map, int nr_map) 123 const struct e820entry *list, size_t map_size, unsigned long nr_pages)
131{ 124{
132 phys_addr_t max_addr = PFN_PHYS(max_pfn); 125 phys_addr_t start = 0;
133 phys_addr_t last_end = ISA_END_ADDRESS;
134 unsigned long released = 0; 126 unsigned long released = 0;
135 int i;
136
137 /* Free any unused memory above the low 1Mbyte. */
138 for (i = 0; i < nr_map && last_end < max_addr; i++) {
139 phys_addr_t end = map[i].addr;
140 end = min(max_addr, end);
141
142 if (last_end < end)
143 released += xen_release_chunk(last_end, end);
144 last_end = max(last_end, map[i].addr + map[i].size);
145 }
146
147 if (last_end < max_addr)
148 released += xen_release_chunk(last_end, max_addr);
149
150 printk(KERN_INFO "released %lu pages of unused memory\n", released);
151 return released;
152}
153
154static unsigned long __init xen_set_identity(const struct e820entry *list,
155 ssize_t map_size)
156{
157 phys_addr_t last = xen_initial_domain() ? 0 : ISA_END_ADDRESS;
158 phys_addr_t start_pci = last;
159 const struct e820entry *entry;
160 unsigned long identity = 0; 127 unsigned long identity = 0;
128 const struct e820entry *entry;
161 int i; 129 int i;
162 130
131 /*
132 * Combine non-RAM regions and gaps until a RAM region (or the
133 * end of the map) is reached, then set the 1:1 map and
134 * release the pages (if available) in those non-RAM regions.
135 *
136 * The combined non-RAM regions are rounded to a whole number
137 * of pages so any partial pages are accessible via the 1:1
138 * mapping. This is needed for some BIOSes that put (for
139 * example) the DMI tables in a reserved region that begins on
140 * a non-page boundary.
141 */
163 for (i = 0, entry = list; i < map_size; i++, entry++) { 142 for (i = 0, entry = list; i < map_size; i++, entry++) {
164 phys_addr_t start = entry->addr; 143 phys_addr_t end = entry->addr + entry->size;
165 phys_addr_t end = start + entry->size;
166 144
167 if (start < last) 145 if (entry->type == E820_RAM || i == map_size - 1) {
168 start = last; 146 unsigned long start_pfn = PFN_DOWN(start);
147 unsigned long end_pfn = PFN_UP(end);
169 148
170 if (end <= start) 149 if (entry->type == E820_RAM)
171 continue; 150 end_pfn = PFN_UP(entry->addr);
172 151
173 /* Skip over the 1MB region. */ 152 if (start_pfn < end_pfn) {
174 if (last > end) 153 if (start_pfn < nr_pages)
175 continue; 154 released += xen_release_chunk(
155 start_pfn, min(end_pfn, nr_pages));
176 156
177 if ((entry->type == E820_RAM) || (entry->type == E820_UNUSABLE)) {
178 if (start > start_pci)
179 identity += set_phys_range_identity( 157 identity += set_phys_range_identity(
180 PFN_UP(start_pci), PFN_DOWN(start)); 158 start_pfn, end_pfn);
181 159 }
182 /* Without saving 'last' we would gooble RAM too 160 start = end;
183 * at the end of the loop. */
184 last = end;
185 start_pci = end;
186 continue;
187 } 161 }
188 start_pci = min(start, start_pci);
189 last = end;
190 } 162 }
191 if (last > start_pci) 163
192 identity += set_phys_range_identity( 164 printk(KERN_INFO "Released %lu pages of unused memory\n", released);
193 PFN_UP(start_pci), PFN_DOWN(last)); 165 printk(KERN_INFO "Set %ld page(s) to 1-1 mapping\n", identity);
194 return identity; 166
167 return released;
195} 168}
196 169
197static unsigned long __init xen_get_max_pages(void) 170static unsigned long __init xen_get_max_pages(void)
@@ -232,7 +205,6 @@ char * __init xen_memory_setup(void)
232 struct xen_memory_map memmap; 205 struct xen_memory_map memmap;
233 unsigned long max_pages; 206 unsigned long max_pages;
234 unsigned long extra_pages = 0; 207 unsigned long extra_pages = 0;
235 unsigned long identity_pages = 0;
236 int i; 208 int i;
237 int op; 209 int op;
238 210
@@ -265,8 +237,13 @@ char * __init xen_memory_setup(void)
265 if (max_pages > max_pfn) 237 if (max_pages > max_pfn)
266 extra_pages += max_pages - max_pfn; 238 extra_pages += max_pages - max_pfn;
267 239
268 xen_released_pages = xen_return_unused_memory(max_pfn, map, 240 /*
269 memmap.nr_entries); 241 * Set P2M for all non-RAM pages and E820 gaps to be identity
242 * type PFNs. Any RAM pages that would be made inaccesible by
243 * this are first released.
244 */
245 xen_released_pages = xen_set_identity_and_release(
246 map, memmap.nr_entries, max_pfn);
270 extra_pages += xen_released_pages; 247 extra_pages += xen_released_pages;
271 248
272 /* 249 /*
@@ -312,10 +289,6 @@ char * __init xen_memory_setup(void)
312 * In domU, the ISA region is normal, usable memory, but we 289 * In domU, the ISA region is normal, usable memory, but we
313 * reserve ISA memory anyway because too many things poke 290 * reserve ISA memory anyway because too many things poke
314 * about in there. 291 * about in there.
315 *
316 * In Dom0, the host E820 information can leave gaps in the
317 * ISA range, which would cause us to release those pages. To
318 * avoid this, we unconditionally reserve them here.
319 */ 292 */
320 e820_add_region(ISA_START_ADDRESS, ISA_END_ADDRESS - ISA_START_ADDRESS, 293 e820_add_region(ISA_START_ADDRESS, ISA_END_ADDRESS - ISA_START_ADDRESS,
321 E820_RESERVED); 294 E820_RESERVED);
@@ -332,12 +305,6 @@ char * __init xen_memory_setup(void)
332 305
333 sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map); 306 sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map);
334 307
335 /*
336 * Set P2M for all non-RAM pages and E820 gaps to be identity
337 * type PFNs.
338 */
339 identity_pages = xen_set_identity(e820.map, e820.nr_map);
340 printk(KERN_INFO "Set %ld page(s) to 1-1 mapping.\n", identity_pages);
341 return "Xen"; 308 return "Xen";
342} 309}
343 310