mirror of
https://github.com/opnsense/src.git
synced 2026-06-09 08:43:19 -04:00
xen: introduce a per-arch scratch mapping ranges
The current approach is to create foreign mappings in any unpopulated address on the memory map. This however can cause issues, as late-loaded drivers could then found their MMIO region has been stolen to be used as foreign mapping scratch space (due to the Xen drivers having started first). Add a local resource manager to the xenpv bus driver, architectures can add suitable resources to that resource manager at boot in order to be used in preference of the generic MMIO resource allocator. No functional change, as the introduced scratch mapping range is not yet populated. Sponsored by: Cloud Software Group MFC after: 1 week Reviewed by: Elliott Mitchell <ehem+freebsd@m5p.com> Differential revision: https://reviews.freebsd.org/D46122
This commit is contained in:
parent
7cb65be96d
commit
baa006f342
2 changed files with 76 additions and 6 deletions
|
|
@ -65,6 +65,16 @@
|
|||
#define LOW_MEM_LIMIT 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Memory ranges available for creating external mappings (foreign or grant
|
||||
* pages for example).
|
||||
*/
|
||||
static struct rman unpopulated_mem = {
|
||||
.rm_end = ~0,
|
||||
.rm_type = RMAN_ARRAY,
|
||||
.rm_descr = "Xen scratch memory",
|
||||
};
|
||||
|
||||
static void
|
||||
xenpv_identify(driver_t *driver, device_t parent)
|
||||
{
|
||||
|
|
@ -91,10 +101,25 @@ xenpv_probe(device_t dev)
|
|||
return (BUS_PROBE_NOWILDCARD);
|
||||
}
|
||||
|
||||
/* Dummy init for arches that don't have a specific implementation. */
|
||||
int __weak_symbol
|
||||
xen_arch_init_physmem(device_t dev, struct rman *mem)
|
||||
{
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
xenpv_attach(device_t dev)
|
||||
{
|
||||
int error;
|
||||
int error = rman_init(&unpopulated_mem);
|
||||
|
||||
if (error != 0)
|
||||
return (error);
|
||||
|
||||
error = xen_arch_init_physmem(dev, &unpopulated_mem);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
|
||||
/*
|
||||
* Let our child drivers identify any child devices that they
|
||||
|
|
@ -110,6 +135,14 @@ xenpv_attach(device_t dev)
|
|||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
release_unpopulated_mem(device_t dev, struct resource *res)
|
||||
{
|
||||
|
||||
return (rman_is_region_manager(res, &unpopulated_mem) ?
|
||||
rman_release_resource(res) : bus_release_resource(dev, res));
|
||||
}
|
||||
|
||||
static struct resource *
|
||||
xenpv_alloc_physmem(device_t dev, device_t child, int *res_id, size_t size)
|
||||
{
|
||||
|
|
@ -117,17 +150,48 @@ xenpv_alloc_physmem(device_t dev, device_t child, int *res_id, size_t size)
|
|||
vm_paddr_t phys_addr;
|
||||
void *virt_addr;
|
||||
int error;
|
||||
const unsigned int flags = RF_ACTIVE | RF_UNMAPPED |
|
||||
RF_ALIGNMENT_LOG2(PAGE_SHIFT);
|
||||
|
||||
res = bus_alloc_resource(child, SYS_RES_MEMORY, res_id, LOW_MEM_LIMIT,
|
||||
~0, size, RF_ACTIVE | RF_UNMAPPED);
|
||||
if (res == NULL)
|
||||
KASSERT((size & PAGE_MASK) == 0, ("unaligned size requested"));
|
||||
size = round_page(size);
|
||||
|
||||
/* Attempt to allocate from arch resource manager. */
|
||||
res = rman_reserve_resource(&unpopulated_mem, 0, ~0, size, flags,
|
||||
child);
|
||||
if (res != NULL) {
|
||||
rman_set_rid(res, *res_id);
|
||||
rman_set_type(res, SYS_RES_MEMORY);
|
||||
} else {
|
||||
static bool warned = false;
|
||||
|
||||
/* Fallback to generic MMIO allocator. */
|
||||
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, flags);
|
||||
}
|
||||
|
||||
if (res == NULL) {
|
||||
device_printf(dev,
|
||||
"failed to allocate Xen unpopulated memory\n");
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
phys_addr = rman_get_start(res);
|
||||
error = vm_phys_fictitious_reg_range(phys_addr, phys_addr + size,
|
||||
VM_MEMATTR_XEN);
|
||||
if (error) {
|
||||
bus_release_resource(child, SYS_RES_MEMORY, *res_id, res);
|
||||
int error = release_unpopulated_mem(child, res);
|
||||
|
||||
if (error != 0)
|
||||
device_printf(dev, "failed to release resource: %d\n",
|
||||
error);
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
virt_addr = pmap_mapdev_attr(phys_addr, size, VM_MEMATTR_XEN);
|
||||
|
|
@ -150,7 +214,8 @@ xenpv_free_physmem(device_t dev, device_t child, int res_id, struct resource *re
|
|||
|
||||
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 (release_unpopulated_mem(child, res));
|
||||
}
|
||||
|
||||
static device_method_t xenpv_methods[] = {
|
||||
|
|
|
|||
|
|
@ -39,6 +39,8 @@
|
|||
#include <contrib/xen/xen.h>
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
#include <sys/rman.h>
|
||||
|
||||
#include <xen/hvm.h>
|
||||
#include <contrib/xen/event_channel.h>
|
||||
|
||||
|
|
@ -158,6 +160,9 @@ void xc_printf(const char *, ...) __printflike(1, 2);
|
|||
*/
|
||||
void xen_emergency_print(const char *str, size_t size);
|
||||
|
||||
/* Arch-specific helper to init scratch mapping space. */
|
||||
int xen_arch_init_physmem(device_t dev, struct rman *mem);
|
||||
|
||||
#ifndef xen_mb
|
||||
#define xen_mb() mb()
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Reference in a new issue