Commit b3cf8528 authored by Boris Ostrovsky's avatar Boris Ostrovsky

xen/balloon: Mark unallocated host memory as UNUSABLE

Commit f5775e0b ("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 fa564ad9 ("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 f5775e0b) and keep track of that region as
a hostmem resource that can be used for the hotplug.
Signed-off-by: default avatarBoris Ostrovsky <boris.ostrovsky@oracle.com>
Reviewed-by: default avatarJuergen Gross <jgross@suse.com>
parent 2cc42bac
#ifdef CONFIG_XEN_BALLOON_MEMORY_HOTPLUG
#include <linux/bootmem.h>
#endif
#include <linux/cpu.h> #include <linux/cpu.h>
#include <linux/kexec.h> #include <linux/kexec.h>
#include <xen/features.h> #include <xen/features.h>
#include <xen/page.h> #include <xen/page.h>
#include <xen/interface/memory.h>
#include <asm/xen/hypercall.h> #include <asm/xen/hypercall.h>
#include <asm/xen/hypervisor.h> #include <asm/xen/hypervisor.h>
...@@ -331,3 +335,80 @@ void xen_arch_unregister_cpu(int num) ...@@ -331,3 +335,80 @@ void xen_arch_unregister_cpu(int num)
} }
EXPORT_SYMBOL(xen_arch_unregister_cpu); EXPORT_SYMBOL(xen_arch_unregister_cpu);
#endif #endif
#ifdef CONFIG_XEN_BALLOON_MEMORY_HOTPLUG
void __init arch_xen_balloon_init(struct resource *hostmem_resource)
{
struct xen_memory_map memmap;
int rc;
unsigned int i, last_guest_ram;
phys_addr_t max_addr = PFN_PHYS(max_pfn);
struct e820_table *xen_e820_table;
const struct e820_entry *entry;
struct resource *res;
if (!xen_initial_domain())
return;
xen_e820_table = kmalloc(sizeof(*xen_e820_table), GFP_KERNEL);
if (!xen_e820_table)
return;
memmap.nr_entries = ARRAY_SIZE(xen_e820_table->entries);
set_xen_guest_handle(memmap.buffer, xen_e820_table->entries);
rc = HYPERVISOR_memory_op(XENMEM_machine_memory_map, &memmap);
if (rc) {
pr_warn("%s: Can't read host e820 (%d)\n", __func__, rc);
goto out;
}
last_guest_ram = 0;
for (i = 0; i < memmap.nr_entries; i++) {
if (xen_e820_table->entries[i].addr >= max_addr)
break;
if (xen_e820_table->entries[i].type == E820_TYPE_RAM)
last_guest_ram = i;
}
entry = &xen_e820_table->entries[last_guest_ram];
if (max_addr >= entry->addr + entry->size)
goto out; /* No unallocated host RAM. */
hostmem_resource->start = max_addr;
hostmem_resource->end = entry->addr + entry->size;
/*
* Mark non-RAM regions between the end of dom0 RAM and end of host RAM
* as unavailable. The rest of that region can be used for hotplug-based
* ballooning.
*/
for (; i < memmap.nr_entries; i++) {
entry = &xen_e820_table->entries[i];
if (entry->type == E820_TYPE_RAM)
continue;
if (entry->addr >= hostmem_resource->end)
break;
res = kzalloc(sizeof(*res), GFP_KERNEL);
if (!res)
goto out;
res->name = "Unavailable host RAM";
res->start = entry->addr;
res->end = (entry->addr + entry->size < hostmem_resource->end) ?
entry->addr + entry->size : hostmem_resource->end;
rc = insert_resource(hostmem_resource, res);
if (rc) {
pr_warn("%s: Can't insert [%llx - %llx) (%d)\n",
__func__, res->start, res->end, rc);
kfree(res);
goto out;
}
}
out:
kfree(xen_e820_table);
}
#endif /* CONFIG_XEN_BALLOON_MEMORY_HOTPLUG */
...@@ -807,7 +807,6 @@ char * __init xen_memory_setup(void) ...@@ -807,7 +807,6 @@ char * __init xen_memory_setup(void)
addr = xen_e820_table.entries[0].addr; addr = xen_e820_table.entries[0].addr;
size = xen_e820_table.entries[0].size; size = xen_e820_table.entries[0].size;
while (i < xen_e820_table.nr_entries) { while (i < xen_e820_table.nr_entries) {
bool discard = false;
chunk_size = size; chunk_size = size;
type = xen_e820_table.entries[i].type; type = xen_e820_table.entries[i].type;
...@@ -823,10 +822,9 @@ char * __init xen_memory_setup(void) ...@@ -823,10 +822,9 @@ char * __init xen_memory_setup(void)
xen_add_extra_mem(pfn_s, n_pfns); xen_add_extra_mem(pfn_s, n_pfns);
xen_max_p2m_pfn = pfn_s + n_pfns; xen_max_p2m_pfn = pfn_s + n_pfns;
} else } else
discard = true; type = E820_TYPE_UNUSABLE;
} }
if (!discard)
xen_align_and_add_e820_region(addr, chunk_size, type); xen_align_and_add_e820_region(addr, chunk_size, type);
addr += chunk_size; addr += chunk_size;
......
...@@ -257,10 +257,25 @@ static void release_memory_resource(struct resource *resource) ...@@ -257,10 +257,25 @@ static void release_memory_resource(struct resource *resource)
kfree(resource); kfree(resource);
} }
/*
* Host memory not allocated to dom0. We can use this range for hotplug-based
* ballooning.
*
* It's a type-less resource. Setting IORESOURCE_MEM will make resource
* management algorithms (arch_remove_reservations()) look into guest e820,
* which we don't want.
*/
static struct resource hostmem_resource = {
.name = "Host RAM",
};
void __attribute__((weak)) __init arch_xen_balloon_init(struct resource *res)
{}
static struct resource *additional_memory_resource(phys_addr_t size) static struct resource *additional_memory_resource(phys_addr_t size)
{ {
struct resource *res; struct resource *res, *res_hostmem;
int ret; int ret = -ENOMEM;
res = kzalloc(sizeof(*res), GFP_KERNEL); res = kzalloc(sizeof(*res), GFP_KERNEL);
if (!res) if (!res)
...@@ -269,6 +284,34 @@ static struct resource *additional_memory_resource(phys_addr_t size) ...@@ -269,6 +284,34 @@ static struct resource *additional_memory_resource(phys_addr_t size)
res->name = "System RAM"; res->name = "System RAM";
res->flags = IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY; res->flags = IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY;
res_hostmem = kzalloc(sizeof(*res), GFP_KERNEL);
if (res_hostmem) {
/* Try to grab a range from hostmem */
res_hostmem->name = "Host memory";
ret = allocate_resource(&hostmem_resource, res_hostmem,
size, 0, -1,
PAGES_PER_SECTION * PAGE_SIZE, NULL, NULL);
}
if (!ret) {
/*
* Insert this resource into iomem. Because hostmem_resource
* tracks portion of guest e820 marked as UNUSABLE noone else
* should try to use it.
*/
res->start = res_hostmem->start;
res->end = res_hostmem->end;
ret = insert_resource(&iomem_resource, res);
if (ret < 0) {
pr_err("Can't insert iomem_resource [%llx - %llx]\n",
res->start, res->end);
release_memory_resource(res_hostmem);
res_hostmem = NULL;
res->start = res->end = 0;
}
}
if (ret) {
ret = allocate_resource(&iomem_resource, res, ret = allocate_resource(&iomem_resource, res,
size, 0, -1, size, 0, -1,
PAGES_PER_SECTION * PAGE_SIZE, NULL, NULL); PAGES_PER_SECTION * PAGE_SIZE, NULL, NULL);
...@@ -277,6 +320,7 @@ static struct resource *additional_memory_resource(phys_addr_t size) ...@@ -277,6 +320,7 @@ static struct resource *additional_memory_resource(phys_addr_t size)
kfree(res); kfree(res);
return NULL; return NULL;
} }
}
#ifdef CONFIG_SPARSEMEM #ifdef CONFIG_SPARSEMEM
{ {
...@@ -287,6 +331,7 @@ static struct resource *additional_memory_resource(phys_addr_t size) ...@@ -287,6 +331,7 @@ static struct resource *additional_memory_resource(phys_addr_t size)
pr_err("New System RAM resource outside addressable RAM (%lu > %lu)\n", pr_err("New System RAM resource outside addressable RAM (%lu > %lu)\n",
pfn, limit); pfn, limit);
release_memory_resource(res); release_memory_resource(res);
release_memory_resource(res_hostmem);
return NULL; return NULL;
} }
} }
...@@ -765,6 +810,8 @@ static int __init balloon_init(void) ...@@ -765,6 +810,8 @@ static int __init balloon_init(void)
set_online_page_callback(&xen_online_page); set_online_page_callback(&xen_online_page);
register_memory_notifier(&xen_memory_nb); register_memory_notifier(&xen_memory_nb);
register_sysctl_table(xen_root); register_sysctl_table(xen_root);
arch_xen_balloon_init(&hostmem_resource);
#endif #endif
#ifdef CONFIG_XEN_PV #ifdef CONFIG_XEN_PV
......
...@@ -43,3 +43,8 @@ static inline void xen_balloon_init(void) ...@@ -43,3 +43,8 @@ static inline void xen_balloon_init(void)
{ {
} }
#endif #endif
#ifdef CONFIG_XEN_BALLOON_MEMORY_HOTPLUG
struct resource;
void arch_xen_balloon_init(struct resource *hostmem_resource);
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment