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 68baa006f3SRoger Pau Monné /* 69baa006f3SRoger Pau Monné * Memory ranges available for creating external mappings (foreign or grant 70baa006f3SRoger Pau Monné * pages for example). 71baa006f3SRoger Pau Monné */ 72baa006f3SRoger Pau Monné static struct rman unpopulated_mem = { 73baa006f3SRoger Pau Monné .rm_end = ~0, 74baa006f3SRoger Pau Monné .rm_type = RMAN_ARRAY, 75baa006f3SRoger Pau Monné .rm_descr = "Xen scratch memory", 76baa006f3SRoger Pau Monné }; 77baa006f3SRoger 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 104baa006f3SRoger Pau Monné /* Dummy init for arches that don't have a specific implementation. */ 105baa006f3SRoger Pau Monné int __weak_symbol 106baa006f3SRoger Pau Monné xen_arch_init_physmem(device_t dev, struct rman *mem) 107baa006f3SRoger Pau Monné { 108baa006f3SRoger Pau Monné 109baa006f3SRoger Pau Monné return (0); 110baa006f3SRoger Pau Monné } 111baa006f3SRoger Pau Monné 112a48f7ba4SJulien Grall static int 113a48f7ba4SJulien Grall xenpv_attach(device_t dev) 114a48f7ba4SJulien Grall { 115baa006f3SRoger Pau Monné int error = rman_init(&unpopulated_mem); 116baa006f3SRoger Pau Monné 117baa006f3SRoger Pau Monné if (error != 0) 118baa006f3SRoger Pau Monné return (error); 119baa006f3SRoger Pau Monné 120baa006f3SRoger Pau Monné error = xen_arch_init_physmem(dev, &unpopulated_mem); 121baa006f3SRoger Pau Monné if (error != 0) 122baa006f3SRoger 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 */ 129723da5d9SJohn Baldwin bus_identify_children(dev); 130*18250ec6SJohn Baldwin bus_attach_children(dev); 131a48f7ba4SJulien Grall 132*18250ec6SJohn Baldwin return (0); 133a48f7ba4SJulien Grall } 134a48f7ba4SJulien Grall 135baa006f3SRoger Pau Monné static int 136baa006f3SRoger Pau Monné release_unpopulated_mem(device_t dev, struct resource *res) 137baa006f3SRoger Pau Monné { 138baa006f3SRoger Pau Monné 139baa006f3SRoger Pau Monné return (rman_is_region_manager(res, &unpopulated_mem) ? 140baa006f3SRoger Pau Monné rman_release_resource(res) : bus_release_resource(dev, res)); 141baa006f3SRoger Pau Monné } 142baa006f3SRoger Pau Monné 143a48f7ba4SJulien Grall static struct resource * 144a48f7ba4SJulien Grall xenpv_alloc_physmem(device_t dev, device_t child, int *res_id, size_t size) 145a48f7ba4SJulien Grall { 146a48f7ba4SJulien Grall struct resource *res; 147a48f7ba4SJulien Grall vm_paddr_t phys_addr; 148f4c6843eSRoger Pau Monné void *virt_addr; 149a48f7ba4SJulien Grall int error; 150baa006f3SRoger Pau Monné const unsigned int flags = RF_ACTIVE | RF_UNMAPPED | 151baa006f3SRoger Pau Monné RF_ALIGNMENT_LOG2(PAGE_SHIFT); 152a48f7ba4SJulien Grall 153baa006f3SRoger Pau Monné KASSERT((size & PAGE_MASK) == 0, ("unaligned size requested")); 154baa006f3SRoger Pau Monné size = round_page(size); 155baa006f3SRoger Pau Monné 156baa006f3SRoger Pau Monné /* Attempt to allocate from arch resource manager. */ 157baa006f3SRoger Pau Monné res = rman_reserve_resource(&unpopulated_mem, 0, ~0, size, flags, 158baa006f3SRoger Pau Monné child); 159baa006f3SRoger Pau Monné if (res != NULL) { 160baa006f3SRoger Pau Monné rman_set_rid(res, *res_id); 161baa006f3SRoger Pau Monné rman_set_type(res, SYS_RES_MEMORY); 162baa006f3SRoger Pau Monné } else { 163baa006f3SRoger Pau Monné static bool warned = false; 164baa006f3SRoger Pau Monné 165baa006f3SRoger Pau Monné /* Fallback to generic MMIO allocator. */ 166baa006f3SRoger Pau Monné if (__predict_false(!warned)) { 167baa006f3SRoger Pau Monné warned = true; 168baa006f3SRoger Pau Monné device_printf(dev, 169baa006f3SRoger Pau Monné "unable to allocate from arch specific routine, " 170baa006f3SRoger Pau Monné "fall back to unused memory areas\n"); 171baa006f3SRoger Pau Monné } 172baa006f3SRoger Pau Monné res = bus_alloc_resource(child, SYS_RES_MEMORY, res_id, 173baa006f3SRoger Pau Monné LOW_MEM_LIMIT, ~0, size, flags); 174baa006f3SRoger Pau Monné } 175baa006f3SRoger Pau Monné 176baa006f3SRoger Pau Monné if (res == NULL) { 177baa006f3SRoger Pau Monné device_printf(dev, 178baa006f3SRoger Pau Monné "failed to allocate Xen unpopulated memory\n"); 179a48f7ba4SJulien Grall return (NULL); 180baa006f3SRoger Pau Monné } 181a48f7ba4SJulien Grall 182a48f7ba4SJulien Grall phys_addr = rman_get_start(res); 183a48f7ba4SJulien Grall error = vm_phys_fictitious_reg_range(phys_addr, phys_addr + size, 184b6ff9345SElliott Mitchell VM_MEMATTR_XEN); 185a48f7ba4SJulien Grall if (error) { 186baa006f3SRoger Pau Monné int error = release_unpopulated_mem(child, res); 187baa006f3SRoger Pau Monné 188baa006f3SRoger Pau Monné if (error != 0) 189baa006f3SRoger Pau Monné device_printf(dev, "failed to release resource: %d\n", 190baa006f3SRoger Pau Monné error); 191baa006f3SRoger Pau Monné 192a48f7ba4SJulien Grall return (NULL); 193a48f7ba4SJulien Grall } 194f4c6843eSRoger Pau Monné virt_addr = pmap_mapdev_attr(phys_addr, size, VM_MEMATTR_XEN); 195f4c6843eSRoger Pau Monné KASSERT(virt_addr != NULL, ("Failed to create linear mappings")); 196f4c6843eSRoger Pau Monné rman_set_virtual(res, virt_addr); 197a48f7ba4SJulien Grall 198a48f7ba4SJulien Grall return (res); 199a48f7ba4SJulien Grall } 200a48f7ba4SJulien Grall 201a48f7ba4SJulien Grall static int 202a48f7ba4SJulien Grall xenpv_free_physmem(device_t dev, device_t child, int res_id, struct resource *res) 203a48f7ba4SJulien Grall { 204a48f7ba4SJulien Grall vm_paddr_t phys_addr; 2057ae99f80SJohn Baldwin void *virt_addr; 206a48f7ba4SJulien Grall size_t size; 207a48f7ba4SJulien Grall 208a48f7ba4SJulien Grall phys_addr = rman_get_start(res); 209a48f7ba4SJulien Grall size = rman_get_size(res); 2107ae99f80SJohn Baldwin virt_addr = rman_get_virtual(res); 211a48f7ba4SJulien Grall 212f4c6843eSRoger Pau Monné pmap_unmapdev(virt_addr, size); 213a48f7ba4SJulien Grall vm_phys_fictitious_unreg_range(phys_addr, phys_addr + size); 214baa006f3SRoger Pau Monné 215baa006f3SRoger Pau Monné return (release_unpopulated_mem(child, res)); 216a48f7ba4SJulien Grall } 217a48f7ba4SJulien Grall 218a48f7ba4SJulien Grall static device_method_t xenpv_methods[] = { 219a48f7ba4SJulien Grall /* Device interface */ 220a48f7ba4SJulien Grall DEVMETHOD(device_identify, xenpv_identify), 221a48f7ba4SJulien Grall DEVMETHOD(device_probe, xenpv_probe), 222a48f7ba4SJulien Grall DEVMETHOD(device_attach, xenpv_attach), 223a48f7ba4SJulien Grall DEVMETHOD(device_suspend, bus_generic_suspend), 224a48f7ba4SJulien Grall DEVMETHOD(device_resume, bus_generic_resume), 225a48f7ba4SJulien Grall 226a48f7ba4SJulien Grall /* Bus interface */ 227a48f7ba4SJulien Grall DEVMETHOD(bus_add_child, bus_generic_add_child), 228a48f7ba4SJulien Grall DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), 229a48f7ba4SJulien Grall DEVMETHOD(bus_release_resource, bus_generic_release_resource), 230a48f7ba4SJulien Grall DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 231a48f7ba4SJulien Grall DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 232a48f7ba4SJulien Grall 233a48f7ba4SJulien Grall /* Interface to allocate memory for foreign mappings */ 234a48f7ba4SJulien Grall DEVMETHOD(xenmem_alloc, xenpv_alloc_physmem), 235a48f7ba4SJulien Grall DEVMETHOD(xenmem_free, xenpv_free_physmem), 236a48f7ba4SJulien Grall 237a48f7ba4SJulien Grall DEVMETHOD_END 238a48f7ba4SJulien Grall }; 239a48f7ba4SJulien Grall 240a48f7ba4SJulien Grall static driver_t xenpv_driver = { 241a48f7ba4SJulien Grall "xenpv", 242a48f7ba4SJulien Grall xenpv_methods, 243a48f7ba4SJulien Grall 0, 244a48f7ba4SJulien Grall }; 245a48f7ba4SJulien Grall 246f929eb1eSJohn Baldwin DRIVER_MODULE(xenpv, nexus, xenpv_driver, 0, 0); 247a48f7ba4SJulien Grall 248a48f7ba4SJulien Grall struct resource * 249a48f7ba4SJulien Grall xenmem_alloc(device_t dev, int *res_id, size_t size) 250a48f7ba4SJulien Grall { 251a48f7ba4SJulien Grall device_t parent; 252a48f7ba4SJulien Grall 253a48f7ba4SJulien Grall parent = device_get_parent(dev); 254a48f7ba4SJulien Grall if (parent == NULL) 255a48f7ba4SJulien Grall return (NULL); 256a48f7ba4SJulien Grall return (XENMEM_ALLOC(parent, dev, res_id, size)); 257a48f7ba4SJulien Grall } 258a48f7ba4SJulien Grall 259a48f7ba4SJulien Grall int 260a48f7ba4SJulien Grall xenmem_free(device_t dev, int res_id, struct resource *res) 261a48f7ba4SJulien Grall { 262a48f7ba4SJulien Grall device_t parent; 263a48f7ba4SJulien Grall 264a48f7ba4SJulien Grall parent = device_get_parent(dev); 265a48f7ba4SJulien Grall if (parent == NULL) 266a48f7ba4SJulien Grall return (ENXIO); 267a48f7ba4SJulien Grall return (XENMEM_FREE(parent, dev, res_id, res)); 268a48f7ba4SJulien Grall } 269