diff --git a/sys/dev/xen/bus/xenpv.c b/sys/dev/xen/bus/xenpv.c --- a/sys/dev/xen/bus/xenpv.c +++ b/sys/dev/xen/bus/xenpv.c @@ -96,6 +96,10 @@ { int error; + error = xen_arch_init_physmem(dev); + if (error != 0) + return (error); + /* * Let our child drivers identify any child devices that they * can find. Once that is done attach any devices that we @@ -118,8 +122,20 @@ void *virt_addr; int error; - res = bus_alloc_resource(child, SYS_RES_MEMORY, res_id, LOW_MEM_LIMIT, - ~0, size, RF_ACTIVE | RF_UNMAPPED); + res = xen_arch_alloc_physmem(dev, res_id, size); + if (res == NULL) { + static bool warned = false; + + if (__predict_false(!warned)) { + warned = true; + device_printf(dev, + "unable to allocate from arch specific routine, " + "fall back to unused memory areas\n"); + } + res = bus_alloc_resource(child, SYS_RES_MEMORY, res_id, + LOW_MEM_LIMIT, ~0, size, RF_ACTIVE | RF_UNMAPPED); + } + if (res == NULL) return (NULL); @@ -150,7 +166,9 @@ pmap_unmapdev(virt_addr, size); vm_phys_fictitious_unreg_range(phys_addr, phys_addr + size); - return (bus_release_resource(child, SYS_RES_MEMORY, res_id, res)); + + return (xen_arch_free_physmem(dev, res_id, res) ? 0 + : bus_release_resource(child, SYS_RES_MEMORY, res_id, res)); } static device_method_t xenpv_methods[] = { diff --git a/sys/x86/include/xen/xen-os.h b/sys/x86/include/xen/xen-os.h --- a/sys/x86/include/xen/xen-os.h +++ b/sys/x86/include/xen/xen-os.h @@ -97,6 +97,11 @@ /* (Very) early initialization. */ void xen_early_init(void); +/* Arch-specific helpers to deal with scratch mapping space. */ +int xen_arch_init_physmem(device_t dev); +struct resource *xen_arch_alloc_physmem(device_t dev, int *res_id, size_t size); +bool xen_arch_free_physmem(device_t dev, int res_id, struct resource *res); + #endif /* !__ASSEMBLY__ */ #endif /* _MACHINE_X86_XEN_XEN_OS_H_ */ diff --git a/sys/x86/xen/hvm.c b/sys/x86/xen/hvm.c --- a/sys/x86/xen/hvm.c +++ b/sys/x86/xen/hvm.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -47,6 +48,7 @@ #include #include #include +#include #include #include @@ -548,3 +550,105 @@ return (regs[0] & XEN_HVM_CPUID_IOMMU_MAPPINGS); } + +static struct rman mem_rman = { + .rm_end = ~0, + .rm_type = RMAN_ARRAY, + .rm_descr = "Xen unpopulated memory addresses" +}; + +int xen_arch_init_physmem(device_t dev) +{ + static struct bios_smap smap[128]; + struct xen_memory_map memmap = { + .nr_entries = nitems(smap), + }; + unsigned int i; + int error; + + error = rman_init(&mem_rman); + if (error != 0) + return (error); + + if (!xen_initial_domain()) + return (0); + + set_xen_guest_handle(memmap.buffer, smap); + error = HYPERVISOR_memory_op(XENMEM_memory_map, &memmap); + if (error != 0) + return (error); + + /* + * Fill with UNUSABLE regions, as it's always fine to use those for + * foreign mappings, they will never be populated. + */ + for (i = 0; i < memmap.nr_entries; i++) { + vm_paddr_t start, end; + + if (smap[i].type != SMAP_TYPE_ACPI_ERROR) + continue; + + start = round_page(smap[i].base); + end = trunc_page(smap[i].base + smap[i].length - 1); + + if (bootverbose != 0) + device_printf(dev, + "scratch mapping region @ [%#lx, %#lx]\n", + start, end); + + error = rman_manage_region(&mem_rman, start, end); + if (error != 0) + device_printf(dev, + "unable to add scratch region [%#lx, %#lx]: %d\n", + start, end, error); + } + + return (0); +} + +struct resource * +xen_arch_alloc_physmem(device_t dev, int *res_id, size_t size) +{ + struct resource *res; + int error; + + res = rman_reserve_resource(&mem_rman, 0, ~0, size, + RF_ACTIVE | RF_UNMAPPED, dev); + if (res == NULL) + return (NULL); + + rman_set_rid(res, *res_id); + error = bus_activate_resource(dev, SYS_RES_MEMORY, *res_id, res); + if (error != 0) { + device_printf(dev, "unable to activate resource: %d\n", error); + rman_release_resource(res); + return (NULL); + } + + return (res); +} + +bool +xen_arch_free_physmem(device_t dev, int res_id, struct resource *res) +{ + int error; + + if (!rman_is_region_manager(res, &mem_rman)) + return (false); + + if (rman_get_flags(res) & RF_ACTIVE) { + error = bus_deactivate_resource(dev, SYS_RES_MEMORY, res_id, + res); + if (error != 0) { + device_printf(dev, + "unable to deactivate resource: %d\n", error); + return (true); + } + } + + error = rman_release_resource(res); + if (error != 0) + device_printf(dev, "unable to release resource: %d\n", error); + + return (true); +}