Skip to content

Commit b3cf852

Browse files
author
Boris Ostrovsky
committed
xen/balloon: Mark unallocated host memory as UNUSABLE
Commit f5775e0 ("x86/xen: discard RAM regions above the maximum reservation") left host memory not assigned to dom0 as available for memory hotplug. Unfortunately this also meant that those regions could be used by others. Specifically, commit fa564ad ("x86/PCI: Enable a 64bit BAR on AMD Family 15h (Models 00-1f, 30-3f, 60-7f)") may try to map those addresses as MMIO. To prevent this mark unallocated host memory as E820_TYPE_UNUSABLE (thus effectively reverting f5775e0) and keep track of that region as a hostmem resource that can be used for the hotplug. Signed-off-by: Boris Ostrovsky <[email protected]> Reviewed-by: Juergen Gross <[email protected]>
1 parent 2cc42ba commit b3cf852

File tree

4 files changed

+144
-13
lines changed

4 files changed

+144
-13
lines changed

arch/x86/xen/enlighten.c

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
1+
#ifdef CONFIG_XEN_BALLOON_MEMORY_HOTPLUG
2+
#include <linux/bootmem.h>
3+
#endif
14
#include <linux/cpu.h>
25
#include <linux/kexec.h>
36

47
#include <xen/features.h>
58
#include <xen/page.h>
9+
#include <xen/interface/memory.h>
610

711
#include <asm/xen/hypercall.h>
812
#include <asm/xen/hypervisor.h>
@@ -331,3 +335,80 @@ void xen_arch_unregister_cpu(int num)
331335
}
332336
EXPORT_SYMBOL(xen_arch_unregister_cpu);
333337
#endif
338+
339+
#ifdef CONFIG_XEN_BALLOON_MEMORY_HOTPLUG
340+
void __init arch_xen_balloon_init(struct resource *hostmem_resource)
341+
{
342+
struct xen_memory_map memmap;
343+
int rc;
344+
unsigned int i, last_guest_ram;
345+
phys_addr_t max_addr = PFN_PHYS(max_pfn);
346+
struct e820_table *xen_e820_table;
347+
const struct e820_entry *entry;
348+
struct resource *res;
349+
350+
if (!xen_initial_domain())
351+
return;
352+
353+
xen_e820_table = kmalloc(sizeof(*xen_e820_table), GFP_KERNEL);
354+
if (!xen_e820_table)
355+
return;
356+
357+
memmap.nr_entries = ARRAY_SIZE(xen_e820_table->entries);
358+
set_xen_guest_handle(memmap.buffer, xen_e820_table->entries);
359+
rc = HYPERVISOR_memory_op(XENMEM_machine_memory_map, &memmap);
360+
if (rc) {
361+
pr_warn("%s: Can't read host e820 (%d)\n", __func__, rc);
362+
goto out;
363+
}
364+
365+
last_guest_ram = 0;
366+
for (i = 0; i < memmap.nr_entries; i++) {
367+
if (xen_e820_table->entries[i].addr >= max_addr)
368+
break;
369+
if (xen_e820_table->entries[i].type == E820_TYPE_RAM)
370+
last_guest_ram = i;
371+
}
372+
373+
entry = &xen_e820_table->entries[last_guest_ram];
374+
if (max_addr >= entry->addr + entry->size)
375+
goto out; /* No unallocated host RAM. */
376+
377+
hostmem_resource->start = max_addr;
378+
hostmem_resource->end = entry->addr + entry->size;
379+
380+
/*
381+
* Mark non-RAM regions between the end of dom0 RAM and end of host RAM
382+
* as unavailable. The rest of that region can be used for hotplug-based
383+
* ballooning.
384+
*/
385+
for (; i < memmap.nr_entries; i++) {
386+
entry = &xen_e820_table->entries[i];
387+
388+
if (entry->type == E820_TYPE_RAM)
389+
continue;
390+
391+
if (entry->addr >= hostmem_resource->end)
392+
break;
393+
394+
res = kzalloc(sizeof(*res), GFP_KERNEL);
395+
if (!res)
396+
goto out;
397+
398+
res->name = "Unavailable host RAM";
399+
res->start = entry->addr;
400+
res->end = (entry->addr + entry->size < hostmem_resource->end) ?
401+
entry->addr + entry->size : hostmem_resource->end;
402+
rc = insert_resource(hostmem_resource, res);
403+
if (rc) {
404+
pr_warn("%s: Can't insert [%llx - %llx) (%d)\n",
405+
__func__, res->start, res->end, rc);
406+
kfree(res);
407+
goto out;
408+
}
409+
}
410+
411+
out:
412+
kfree(xen_e820_table);
413+
}
414+
#endif /* CONFIG_XEN_BALLOON_MEMORY_HOTPLUG */

arch/x86/xen/setup.c

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -807,7 +807,6 @@ char * __init xen_memory_setup(void)
807807
addr = xen_e820_table.entries[0].addr;
808808
size = xen_e820_table.entries[0].size;
809809
while (i < xen_e820_table.nr_entries) {
810-
bool discard = false;
811810

812811
chunk_size = size;
813812
type = xen_e820_table.entries[i].type;
@@ -823,11 +822,10 @@ char * __init xen_memory_setup(void)
823822
xen_add_extra_mem(pfn_s, n_pfns);
824823
xen_max_p2m_pfn = pfn_s + n_pfns;
825824
} else
826-
discard = true;
825+
type = E820_TYPE_UNUSABLE;
827826
}
828827

829-
if (!discard)
830-
xen_align_and_add_e820_region(addr, chunk_size, type);
828+
xen_align_and_add_e820_region(addr, chunk_size, type);
831829

832830
addr += chunk_size;
833831
size -= chunk_size;

drivers/xen/balloon.c

Lines changed: 56 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -257,10 +257,25 @@ static void release_memory_resource(struct resource *resource)
257257
kfree(resource);
258258
}
259259

260+
/*
261+
* Host memory not allocated to dom0. We can use this range for hotplug-based
262+
* ballooning.
263+
*
264+
* It's a type-less resource. Setting IORESOURCE_MEM will make resource
265+
* management algorithms (arch_remove_reservations()) look into guest e820,
266+
* which we don't want.
267+
*/
268+
static struct resource hostmem_resource = {
269+
.name = "Host RAM",
270+
};
271+
272+
void __attribute__((weak)) __init arch_xen_balloon_init(struct resource *res)
273+
{}
274+
260275
static struct resource *additional_memory_resource(phys_addr_t size)
261276
{
262-
struct resource *res;
263-
int ret;
277+
struct resource *res, *res_hostmem;
278+
int ret = -ENOMEM;
264279

265280
res = kzalloc(sizeof(*res), GFP_KERNEL);
266281
if (!res)
@@ -269,13 +284,42 @@ static struct resource *additional_memory_resource(phys_addr_t size)
269284
res->name = "System RAM";
270285
res->flags = IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY;
271286

272-
ret = allocate_resource(&iomem_resource, res,
273-
size, 0, -1,
274-
PAGES_PER_SECTION * PAGE_SIZE, NULL, NULL);
275-
if (ret < 0) {
276-
pr_err("Cannot allocate new System RAM resource\n");
277-
kfree(res);
278-
return NULL;
287+
res_hostmem = kzalloc(sizeof(*res), GFP_KERNEL);
288+
if (res_hostmem) {
289+
/* Try to grab a range from hostmem */
290+
res_hostmem->name = "Host memory";
291+
ret = allocate_resource(&hostmem_resource, res_hostmem,
292+
size, 0, -1,
293+
PAGES_PER_SECTION * PAGE_SIZE, NULL, NULL);
294+
}
295+
296+
if (!ret) {
297+
/*
298+
* Insert this resource into iomem. Because hostmem_resource
299+
* tracks portion of guest e820 marked as UNUSABLE noone else
300+
* should try to use it.
301+
*/
302+
res->start = res_hostmem->start;
303+
res->end = res_hostmem->end;
304+
ret = insert_resource(&iomem_resource, res);
305+
if (ret < 0) {
306+
pr_err("Can't insert iomem_resource [%llx - %llx]\n",
307+
res->start, res->end);
308+
release_memory_resource(res_hostmem);
309+
res_hostmem = NULL;
310+
res->start = res->end = 0;
311+
}
312+
}
313+
314+
if (ret) {
315+
ret = allocate_resource(&iomem_resource, res,
316+
size, 0, -1,
317+
PAGES_PER_SECTION * PAGE_SIZE, NULL, NULL);
318+
if (ret < 0) {
319+
pr_err("Cannot allocate new System RAM resource\n");
320+
kfree(res);
321+
return NULL;
322+
}
279323
}
280324

281325
#ifdef CONFIG_SPARSEMEM
@@ -287,6 +331,7 @@ static struct resource *additional_memory_resource(phys_addr_t size)
287331
pr_err("New System RAM resource outside addressable RAM (%lu > %lu)\n",
288332
pfn, limit);
289333
release_memory_resource(res);
334+
release_memory_resource(res_hostmem);
290335
return NULL;
291336
}
292337
}
@@ -765,6 +810,8 @@ static int __init balloon_init(void)
765810
set_online_page_callback(&xen_online_page);
766811
register_memory_notifier(&xen_memory_nb);
767812
register_sysctl_table(xen_root);
813+
814+
arch_xen_balloon_init(&hostmem_resource);
768815
#endif
769816

770817
#ifdef CONFIG_XEN_PV

include/xen/balloon.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,8 @@ static inline void xen_balloon_init(void)
4343
{
4444
}
4545
#endif
46+
47+
#ifdef CONFIG_XEN_BALLOON_MEMORY_HOTPLUG
48+
struct resource;
49+
void arch_xen_balloon_init(struct resource *hostmem_resource);
50+
#endif

0 commit comments

Comments
 (0)