1a48f7ba4SJulien Grall /* 2a48f7ba4SJulien Grall * Copyright (c) 2014 Roger Pau Monné <roger.pau@citrix.com> 3a48f7ba4SJulien Grall * All rights reserved. 4a48f7ba4SJulien Grall * 5a48f7ba4SJulien Grall * Redistribution and use in source and binary forms, with or without 6a48f7ba4SJulien Grall * modification, are permitted provided that the following conditions 7a48f7ba4SJulien Grall * are met: 8a48f7ba4SJulien Grall * 1. Redistributions of source code must retain the above copyright 9a48f7ba4SJulien Grall * notice, this list of conditions and the following disclaimer. 10a48f7ba4SJulien Grall * 2. Redistributions in binary form must reproduce the above copyright 11a48f7ba4SJulien Grall * notice, this list of conditions and the following disclaimer in the 12a48f7ba4SJulien Grall * documentation and/or other materials provided with the distribution. 13a48f7ba4SJulien Grall * 14a48f7ba4SJulien Grall * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS AS IS'' AND 15a48f7ba4SJulien Grall * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16a48f7ba4SJulien Grall * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17a48f7ba4SJulien Grall * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18a48f7ba4SJulien Grall * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19a48f7ba4SJulien Grall * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20a48f7ba4SJulien Grall * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21a48f7ba4SJulien Grall * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22a48f7ba4SJulien Grall * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23a48f7ba4SJulien Grall * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24a48f7ba4SJulien Grall * SUCH DAMAGE. 25a48f7ba4SJulien Grall */ 26a48f7ba4SJulien Grall 27a48f7ba4SJulien Grall #include <sys/param.h> 28a48f7ba4SJulien Grall #include <sys/systm.h> 29a48f7ba4SJulien Grall #include <sys/bus.h> 30a48f7ba4SJulien Grall #include <sys/kernel.h> 31a48f7ba4SJulien Grall #include <sys/module.h> 32a48f7ba4SJulien Grall #include <sys/pcpu.h> 33a48f7ba4SJulien Grall #include <sys/rman.h> 34a48f7ba4SJulien Grall #include <sys/smp.h> 35a48f7ba4SJulien Grall #include <sys/limits.h> 36a48f7ba4SJulien Grall #include <sys/vmmeter.h> 37a48f7ba4SJulien Grall 38a48f7ba4SJulien Grall #include <vm/vm.h> 39a48f7ba4SJulien Grall #include <vm/vm_page.h> 40a48f7ba4SJulien Grall #include <vm/vm_param.h> 41a48f7ba4SJulien Grall #include <vm/vm_phys.h> 42a48f7ba4SJulien Grall 43a48f7ba4SJulien Grall #include <xen/xen-os.h> 44a48f7ba4SJulien Grall #include <xen/gnttab.h> 45a48f7ba4SJulien Grall 46a48f7ba4SJulien Grall #include "xenmem_if.h" 47a48f7ba4SJulien Grall 48a48f7ba4SJulien Grall /* 49a48f7ba4SJulien Grall * Allocate unused physical memory above 4GB in order to map memory 50a48f7ba4SJulien Grall * from foreign domains. We use memory starting at 4GB in order to 51a48f7ba4SJulien Grall * prevent clashes with MMIO/ACPI regions. 52a48f7ba4SJulien Grall * 53a48f7ba4SJulien Grall * Since this is not possible on i386 just use any available memory 54a48f7ba4SJulien Grall * chunk above 1MB and hope we don't clash with anything else. 55e627e25dSElliott Mitchell * 56e627e25dSElliott Mitchell * Other architectures better document MMIO regions and drivers more 57e627e25dSElliott Mitchell * reliably reserve them. As such, allow using any unpopulated memory 58e627e25dSElliott Mitchell * region. 59a48f7ba4SJulien Grall */ 60a48f7ba4SJulien Grall #ifdef __amd64__ 61a48f7ba4SJulien Grall #define LOW_MEM_LIMIT 0x100000000ul 62a48f7ba4SJulien Grall #elif defined(__i386__) 63a48f7ba4SJulien Grall #define LOW_MEM_LIMIT 0x100000ul 64a48f7ba4SJulien Grall #else 65e627e25dSElliott Mitchell #define LOW_MEM_LIMIT 0 66a48f7ba4SJulien Grall #endif 67a48f7ba4SJulien Grall 68*baa006f3SRoger Pau Monné /* 69*baa006f3SRoger Pau Monné * Memory ranges available for creating external mappings (foreign or grant 70*baa006f3SRoger Pau Monné * pages for example). 71*baa006f3SRoger Pau Monné */ 72*baa006f3SRoger Pau Monné static struct rman unpopulated_mem = { 73*baa006f3SRoger Pau Monné .rm_end = ~0, 74*baa006f3SRoger Pau Monné .rm_type = RMAN_ARRAY, 75*baa006f3SRoger Pau Monné .rm_descr = "Xen scratch memory", 76*baa006f3SRoger Pau Monné }; 77*baa006f3SRoger Pau Monné 78a48f7ba4SJulien Grall static void 79a48f7ba4SJulien Grall xenpv_identify(driver_t *driver, device_t parent) 80a48f7ba4SJulien Grall { 81a48f7ba4SJulien Grall if (!xen_domain()) 82a48f7ba4SJulien Grall return; 83a48f7ba4SJulien Grall 84a48f7ba4SJulien Grall /* Make sure there's only one xenpv device. */ 85651a887fSJohn Baldwin if (devclass_get_device(devclass_find(driver->name), 0)) 86a48f7ba4SJulien Grall return; 87a48f7ba4SJulien Grall 88a48f7ba4SJulien Grall /* 89a48f7ba4SJulien Grall * The xenpv bus should be the last to attach in order 90a48f7ba4SJulien Grall * to properly detect if an ISA bus has already been added. 91a48f7ba4SJulien Grall */ 92651a887fSJohn Baldwin if (BUS_ADD_CHILD(parent, UINT_MAX, driver->name, 0) == NULL) 93a48f7ba4SJulien Grall panic("Unable to attach xenpv bus."); 94a48f7ba4SJulien Grall } 95a48f7ba4SJulien Grall 96a48f7ba4SJulien Grall static int 97a48f7ba4SJulien Grall xenpv_probe(device_t dev) 98a48f7ba4SJulien Grall { 99a48f7ba4SJulien Grall 100a48f7ba4SJulien Grall device_set_desc(dev, "Xen PV bus"); 101a48f7ba4SJulien Grall return (BUS_PROBE_NOWILDCARD); 102a48f7ba4SJulien Grall } 103a48f7ba4SJulien Grall 104*baa006f3SRoger Pau Monné /* Dummy init for arches that don't have a specific implementation. */ 105*baa006f3SRoger Pau Monné int __weak_symbol 106*baa006f3SRoger Pau Monné xen_arch_init_physmem(device_t dev, struct rman *mem) 107*baa006f3SRoger Pau Monné { 108*baa006f3SRoger Pau Monné 109*baa006f3SRoger Pau Monné return (0); 110*baa006f3SRoger Pau Monné } 111*baa006f3SRoger Pau Monné 112a48f7ba4SJulien Grall static int 113a48f7ba4SJulien Grall xenpv_attach(device_t dev) 114a48f7ba4SJulien Grall { 115*baa006f3SRoger Pau Monné int error = rman_init(&unpopulated_mem); 116*baa006f3SRoger Pau Monné 117*baa006f3SRoger Pau Monné if (error != 0) 118*baa006f3SRoger Pau Monné return (error); 119*baa006f3SRoger Pau Monné 120*baa006f3SRoger Pau Monné error = xen_arch_init_physmem(dev, &unpopulated_mem); 121*baa006f3SRoger Pau Monné if (error != 0) 122*baa006f3SRoger Pau Monné return (error); 123a48f7ba4SJulien Grall 124a48f7ba4SJulien Grall /* 125a48f7ba4SJulien Grall * Let our child drivers identify any child devices that they 126a48f7ba4SJulien Grall * can find. Once that is done attach any devices that we 127a48f7ba4SJulien Grall * found. 128a48f7ba4SJulien Grall */ 129a48f7ba4SJulien Grall error = bus_generic_probe(dev); 130a48f7ba4SJulien Grall if (error) 131a48f7ba4SJulien Grall return (error); 132a48f7ba4SJulien Grall 133a48f7ba4SJulien Grall error = bus_generic_attach(dev); 134a48f7ba4SJulien Grall 135a48f7ba4SJulien Grall return (error); 136a48f7ba4SJulien Grall } 137a48f7ba4SJulien Grall 138*baa006f3SRoger Pau Monné static int 139*baa006f3SRoger Pau Monné release_unpopulated_mem(device_t dev, struct resource *res) 140*baa006f3SRoger Pau Monné { 141*baa006f3SRoger Pau Monné 142*baa006f3SRoger Pau Monné return (rman_is_region_manager(res, &unpopulated_mem) ? 143*baa006f3SRoger Pau Monné rman_release_resource(res) : bus_release_resource(dev, res)); 144*baa006f3SRoger Pau Monné } 145*baa006f3SRoger Pau Monné 146a48f7ba4SJulien Grall static struct resource * 147a48f7ba4SJulien Grall xenpv_alloc_physmem(device_t dev, device_t child, int *res_id, size_t size) 148a48f7ba4SJulien Grall { 149a48f7ba4SJulien Grall struct resource *res; 150a48f7ba4SJulien Grall vm_paddr_t phys_addr; 151f4c6843eSRoger Pau Monné void *virt_addr; 152a48f7ba4SJulien Grall int error; 153*baa006f3SRoger Pau Monné const unsigned int flags = RF_ACTIVE | RF_UNMAPPED | 154*baa006f3SRoger Pau Monné RF_ALIGNMENT_LOG2(PAGE_SHIFT); 155a48f7ba4SJulien Grall 156*baa006f3SRoger Pau Monné KASSERT((size & PAGE_MASK) == 0, ("unaligned size requested")); 157*baa006f3SRoger Pau Monné size = round_page(size); 158*baa006f3SRoger Pau Monné 159*baa006f3SRoger Pau Monné /* Attempt to allocate from arch resource manager. */ 160*baa006f3SRoger Pau Monné res = rman_reserve_resource(&unpopulated_mem, 0, ~0, size, flags, 161*baa006f3SRoger Pau Monné child); 162*baa006f3SRoger Pau Monné if (res != NULL) { 163*baa006f3SRoger Pau Monné rman_set_rid(res, *res_id); 164*baa006f3SRoger Pau Monné rman_set_type(res, SYS_RES_MEMORY); 165*baa006f3SRoger Pau Monné } else { 166*baa006f3SRoger Pau Monné static bool warned = false; 167*baa006f3SRoger Pau Monné 168*baa006f3SRoger Pau Monné /* Fallback to generic MMIO allocator. */ 169*baa006f3SRoger Pau Monné if (__predict_false(!warned)) { 170*baa006f3SRoger Pau Monné warned = true; 171*baa006f3SRoger Pau Monné device_printf(dev, 172*baa006f3SRoger Pau Monné "unable to allocate from arch specific routine, " 173*baa006f3SRoger Pau Monné "fall back to unused memory areas\n"); 174*baa006f3SRoger Pau Monné } 175*baa006f3SRoger Pau Monné res = bus_alloc_resource(child, SYS_RES_MEMORY, res_id, 176*baa006f3SRoger Pau Monné LOW_MEM_LIMIT, ~0, size, flags); 177*baa006f3SRoger Pau Monné } 178*baa006f3SRoger Pau Monné 179*baa006f3SRoger Pau Monné if (res == NULL) { 180*baa006f3SRoger Pau Monné device_printf(dev, 181*baa006f3SRoger Pau Monné "failed to allocate Xen unpopulated memory\n"); 182a48f7ba4SJulien Grall return (NULL); 183*baa006f3SRoger Pau Monné } 184a48f7ba4SJulien Grall 185a48f7ba4SJulien Grall phys_addr = rman_get_start(res); 186a48f7ba4SJulien Grall error = vm_phys_fictitious_reg_range(phys_addr, phys_addr + size, 187b6ff9345SElliott Mitchell VM_MEMATTR_XEN); 188a48f7ba4SJulien Grall if (error) { 189*baa006f3SRoger Pau Monné int error = release_unpopulated_mem(child, res); 190*baa006f3SRoger Pau Monné 191*baa006f3SRoger Pau Monné if (error != 0) 192*baa006f3SRoger Pau Monné device_printf(dev, "failed to release resource: %d\n", 193*baa006f3SRoger Pau Monné error); 194*baa006f3SRoger Pau Monné 195a48f7ba4SJulien Grall return (NULL); 196a48f7ba4SJulien Grall } 197f4c6843eSRoger Pau Monné virt_addr = pmap_mapdev_attr(phys_addr, size, VM_MEMATTR_XEN); 198f4c6843eSRoger Pau Monné KASSERT(virt_addr != NULL, ("Failed to create linear mappings")); 199f4c6843eSRoger Pau Monné rman_set_virtual(res, virt_addr); 200a48f7ba4SJulien Grall 201a48f7ba4SJulien Grall return (res); 202a48f7ba4SJulien Grall } 203a48f7ba4SJulien Grall 204a48f7ba4SJulien Grall static int 205a48f7ba4SJulien Grall xenpv_free_physmem(device_t dev, device_t child, int res_id, struct resource *res) 206a48f7ba4SJulien Grall { 207a48f7ba4SJulien Grall vm_paddr_t phys_addr; 2087ae99f80SJohn Baldwin void *virt_addr; 209a48f7ba4SJulien Grall size_t size; 210a48f7ba4SJulien Grall 211a48f7ba4SJulien Grall phys_addr = rman_get_start(res); 212a48f7ba4SJulien Grall size = rman_get_size(res); 2137ae99f80SJohn Baldwin virt_addr = rman_get_virtual(res); 214a48f7ba4SJulien Grall 215f4c6843eSRoger Pau Monné pmap_unmapdev(virt_addr, size); 216a48f7ba4SJulien Grall vm_phys_fictitious_unreg_range(phys_addr, phys_addr + size); 217*baa006f3SRoger Pau Monné 218*baa006f3SRoger Pau Monné return (release_unpopulated_mem(child, res)); 219a48f7ba4SJulien Grall } 220a48f7ba4SJulien Grall 221a48f7ba4SJulien Grall static device_method_t xenpv_methods[] = { 222a48f7ba4SJulien Grall /* Device interface */ 223a48f7ba4SJulien Grall DEVMETHOD(device_identify, xenpv_identify), 224a48f7ba4SJulien Grall DEVMETHOD(device_probe, xenpv_probe), 225a48f7ba4SJulien Grall DEVMETHOD(device_attach, xenpv_attach), 226a48f7ba4SJulien Grall DEVMETHOD(device_suspend, bus_generic_suspend), 227a48f7ba4SJulien Grall DEVMETHOD(device_resume, bus_generic_resume), 228a48f7ba4SJulien Grall 229a48f7ba4SJulien Grall /* Bus interface */ 230a48f7ba4SJulien Grall DEVMETHOD(bus_add_child, bus_generic_add_child), 231a48f7ba4SJulien Grall DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), 232a48f7ba4SJulien Grall DEVMETHOD(bus_release_resource, bus_generic_release_resource), 233a48f7ba4SJulien Grall DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 234a48f7ba4SJulien Grall DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 235a48f7ba4SJulien Grall 236a48f7ba4SJulien Grall /* Interface to allocate memory for foreign mappings */ 237a48f7ba4SJulien Grall DEVMETHOD(xenmem_alloc, xenpv_alloc_physmem), 238a48f7ba4SJulien Grall DEVMETHOD(xenmem_free, xenpv_free_physmem), 239a48f7ba4SJulien Grall 240a48f7ba4SJulien Grall DEVMETHOD_END 241a48f7ba4SJulien Grall }; 242a48f7ba4SJulien Grall 243a48f7ba4SJulien Grall static driver_t xenpv_driver = { 244a48f7ba4SJulien Grall "xenpv", 245a48f7ba4SJulien Grall xenpv_methods, 246a48f7ba4SJulien Grall 0, 247a48f7ba4SJulien Grall }; 248a48f7ba4SJulien Grall 249f929eb1eSJohn Baldwin DRIVER_MODULE(xenpv, nexus, xenpv_driver, 0, 0); 250a48f7ba4SJulien Grall 251a48f7ba4SJulien Grall struct resource * 252a48f7ba4SJulien Grall xenmem_alloc(device_t dev, int *res_id, size_t size) 253a48f7ba4SJulien Grall { 254a48f7ba4SJulien Grall device_t parent; 255a48f7ba4SJulien Grall 256a48f7ba4SJulien Grall parent = device_get_parent(dev); 257a48f7ba4SJulien Grall if (parent == NULL) 258a48f7ba4SJulien Grall return (NULL); 259a48f7ba4SJulien Grall return (XENMEM_ALLOC(parent, dev, res_id, size)); 260a48f7ba4SJulien Grall } 261a48f7ba4SJulien Grall 262a48f7ba4SJulien Grall int 263a48f7ba4SJulien Grall xenmem_free(device_t dev, int res_id, struct resource *res) 264a48f7ba4SJulien Grall { 265a48f7ba4SJulien Grall device_t parent; 266a48f7ba4SJulien Grall 267a48f7ba4SJulien Grall parent = device_get_parent(dev); 268a48f7ba4SJulien Grall if (parent == NULL) 269a48f7ba4SJulien Grall return (ENXIO); 270a48f7ba4SJulien Grall return (XENMEM_FREE(parent, dev, res_id, res)); 271a48f7ba4SJulien Grall } 272