summaryrefslogtreecommitdiffstats
path: root/sys/amd64
diff options
context:
space:
mode:
authorneel <neel@FreeBSD.org>2012-10-08 23:41:26 +0000
committerneel <neel@FreeBSD.org>2012-10-08 23:41:26 +0000
commitca6e3cf9305492be70c87be05119c96a49cbecf9 (patch)
tree5f264ddf5503d91087975ec28f3c717cad5437e0 /sys/amd64
parent89c25d5adfd486fe792fd1dc30e0929e0d0ce6eb (diff)
downloadFreeBSD-src-ca6e3cf9305492be70c87be05119c96a49cbecf9.zip
FreeBSD-src-ca6e3cf9305492be70c87be05119c96a49cbecf9.tar.gz
Allocate memory pages for the guest from the host's free page queue.
It is no longer necessary to hard-partition the memory between the host and guests at boot time.
Diffstat (limited to 'sys/amd64')
-rw-r--r--sys/amd64/vmm/amd/amdv.c17
-rw-r--r--sys/amd64/vmm/intel/vtd.c50
-rw-r--r--sys/amd64/vmm/io/iommu.c51
-rw-r--r--sys/amd64/vmm/io/iommu.h8
-rw-r--r--sys/amd64/vmm/vmm.c33
-rw-r--r--sys/amd64/vmm/vmm_dev.c18
-rw-r--r--sys/amd64/vmm/vmm_mem.c386
-rw-r--r--sys/amd64/vmm/vmm_mem.h4
8 files changed, 193 insertions, 374 deletions
diff --git a/sys/amd64/vmm/amd/amdv.c b/sys/amd64/vmm/amd/amdv.c
index b50f972..020743f 100644
--- a/sys/amd64/vmm/amd/amdv.c
+++ b/sys/amd64/vmm/amd/amdv.c
@@ -230,6 +230,14 @@ amd_iommu_create_mapping(void *domain, vm_paddr_t gpa, vm_paddr_t hpa,
return (0);
}
+static uint64_t
+amd_iommu_remove_mapping(void *domain, vm_paddr_t gpa, uint64_t len)
+{
+
+ printf("amd_iommu_remove_mapping: not implemented\n");
+ return (0);
+}
+
static void
amd_iommu_add_device(void *domain, int bus, int slot, int func)
{
@@ -244,6 +252,13 @@ amd_iommu_remove_device(void *domain, int bus, int slot, int func)
printf("amd_iommu_remove_device: not implemented\n");
}
+static void
+amd_iommu_invalidate_tlb(void *domain)
+{
+
+ printf("amd_iommu_invalidate_tlb: not implemented\n");
+}
+
struct iommu_ops iommu_ops_amd = {
amd_iommu_init,
amd_iommu_cleanup,
@@ -252,6 +267,8 @@ struct iommu_ops iommu_ops_amd = {
amd_iommu_create_domain,
amd_iommu_destroy_domain,
amd_iommu_create_mapping,
+ amd_iommu_remove_mapping,
amd_iommu_add_device,
amd_iommu_remove_device,
+ amd_iommu_invalidate_tlb,
};
diff --git a/sys/amd64/vmm/intel/vtd.c b/sys/amd64/vmm/intel/vtd.c
index 24495a9..ef0e9bc 100644
--- a/sys/amd64/vmm/intel/vtd.c
+++ b/sys/amd64/vmm/intel/vtd.c
@@ -444,8 +444,12 @@ vtd_remove_device(void *arg, int bus, int slot, int func)
}
}
+#define CREATE_MAPPING 0
+#define REMOVE_MAPPING 1
+
static uint64_t
-vtd_create_mapping(void *arg, vm_paddr_t gpa, vm_paddr_t hpa, uint64_t len)
+vtd_update_mapping(void *arg, vm_paddr_t gpa, vm_paddr_t hpa, uint64_t len,
+ int remove)
{
struct domain *dom;
int i, spshift, ptpshift, ptpindex, nlevels;
@@ -513,16 +517,50 @@ vtd_create_mapping(void *arg, vm_paddr_t gpa, vm_paddr_t hpa, uint64_t len)
panic("gpa 0x%lx and ptpshift %d mismatch", gpa, ptpshift);
/*
- * Create a 'gpa' -> 'hpa' mapping
+ * Update the 'gpa' -> 'hpa' mapping
*/
- ptp[ptpindex] = hpa | VTD_PTE_RD | VTD_PTE_WR;
+ if (remove) {
+ ptp[ptpindex] = 0;
+ } else {
+ ptp[ptpindex] = hpa | VTD_PTE_RD | VTD_PTE_WR;
- if (nlevels > 0)
- ptp[ptpindex] |= VTD_PTE_SUPERPAGE;
+ if (nlevels > 0)
+ ptp[ptpindex] |= VTD_PTE_SUPERPAGE;
+ }
return (1UL << ptpshift);
}
+static uint64_t
+vtd_create_mapping(void *arg, vm_paddr_t gpa, vm_paddr_t hpa, uint64_t len)
+{
+
+ return (vtd_update_mapping(arg, gpa, hpa, len, CREATE_MAPPING));
+}
+
+static uint64_t
+vtd_remove_mapping(void *arg, vm_paddr_t gpa, uint64_t len)
+{
+
+ return (vtd_update_mapping(arg, gpa, 0, len, REMOVE_MAPPING));
+}
+
+static void
+vtd_invalidate_tlb(void *dom)
+{
+ int i;
+ struct vtdmap *vtdmap;
+
+ /*
+ * Invalidate the IOTLB.
+ * XXX use domain-selective invalidation for IOTLB
+ */
+ for (i = 0; i < drhd_num; i++) {
+ vtdmap = vtdmaps[i];
+ vtd_iotlb_global_invalidate(vtdmap);
+ }
+}
+
static void *
vtd_create_domain(vm_paddr_t maxaddr)
{
@@ -632,6 +670,8 @@ struct iommu_ops iommu_ops_intel = {
vtd_create_domain,
vtd_destroy_domain,
vtd_create_mapping,
+ vtd_remove_mapping,
vtd_add_device,
vtd_remove_device,
+ vtd_invalidate_tlb,
};
diff --git a/sys/amd64/vmm/io/iommu.c b/sys/amd64/vmm/io/iommu.c
index baf2447..c8447cc 100644
--- a/sys/amd64/vmm/io/iommu.c
+++ b/sys/amd64/vmm/io/iommu.c
@@ -40,6 +40,7 @@ __FBSDID("$FreeBSD$");
#include <machine/md_var.h>
#include "vmm_util.h"
+#include "vmm_mem.h"
#include "iommu.h"
static boolean_t iommu_avail;
@@ -90,6 +91,16 @@ IOMMU_CREATE_MAPPING(void *domain, vm_paddr_t gpa, vm_paddr_t hpa, uint64_t len)
return (len); /* XXX */
}
+static __inline uint64_t
+IOMMU_REMOVE_MAPPING(void *domain, vm_paddr_t gpa, uint64_t len)
+{
+
+ if (ops != NULL && iommu_avail)
+ return ((*ops->remove_mapping)(domain, gpa, len));
+ else
+ return (len); /* XXX */
+}
+
static __inline void
IOMMU_ADD_DEVICE(void *domain, int bus, int slot, int func)
{
@@ -107,6 +118,14 @@ IOMMU_REMOVE_DEVICE(void *domain, int bus, int slot, int func)
}
static __inline void
+IOMMU_INVALIDATE_TLB(void *domain)
+{
+
+ if (ops != NULL && iommu_avail)
+ (*ops->invalidate_tlb)(domain);
+}
+
+static __inline void
IOMMU_ENABLE(void)
{
@@ -146,13 +165,13 @@ iommu_init(void)
/*
* Create a domain for the devices owned by the host
*/
- maxaddr = ptoa(Maxmem);
+ maxaddr = vmm_mem_maxaddr();
host_domain = IOMMU_CREATE_DOMAIN(maxaddr);
if (host_domain == NULL)
panic("iommu_init: unable to create a host domain");
/*
- * Create 1:1 mappings from '0' to 'Maxmem' for devices assigned to
+ * Create 1:1 mappings from '0' to 'maxaddr' for devices assigned to
* the host
*/
iommu_create_mapping(host_domain, 0, 0, maxaddr);
@@ -216,6 +235,27 @@ iommu_create_mapping(void *dom, vm_paddr_t gpa, vm_paddr_t hpa, size_t len)
}
void
+iommu_remove_mapping(void *dom, vm_paddr_t gpa, size_t len)
+{
+ uint64_t unmapped, remaining;
+
+ remaining = len;
+
+ while (remaining > 0) {
+ unmapped = IOMMU_REMOVE_MAPPING(dom, gpa, remaining);
+ gpa += unmapped;
+ remaining -= unmapped;
+ }
+}
+
+void *
+iommu_host_domain(void)
+{
+
+ return (host_domain);
+}
+
+void
iommu_add_device(void *dom, int bus, int slot, int func)
{
@@ -228,3 +268,10 @@ iommu_remove_device(void *dom, int bus, int slot, int func)
IOMMU_REMOVE_DEVICE(dom, bus, slot, func);
}
+
+void
+iommu_invalidate_tlb(void *domain)
+{
+
+ IOMMU_INVALIDATE_TLB(domain);
+}
diff --git a/sys/amd64/vmm/io/iommu.h b/sys/amd64/vmm/io/iommu.h
index e4f7229..d5c1d6e 100644
--- a/sys/amd64/vmm/io/iommu.h
+++ b/sys/amd64/vmm/io/iommu.h
@@ -37,8 +37,11 @@ typedef void *(*iommu_create_domain_t)(vm_paddr_t maxaddr);
typedef void (*iommu_destroy_domain_t)(void *domain);
typedef uint64_t (*iommu_create_mapping_t)(void *domain, vm_paddr_t gpa,
vm_paddr_t hpa, uint64_t len);
+typedef uint64_t (*iommu_remove_mapping_t)(void *domain, vm_paddr_t gpa,
+ uint64_t len);
typedef void (*iommu_add_device_t)(void *domain, int bus, int slot, int func);
typedef void (*iommu_remove_device_t)(void *dom, int bus, int slot, int func);
+typedef void (*iommu_invalidate_tlb_t)(void *dom);
struct iommu_ops {
iommu_init_func_t init; /* module wide */
@@ -49,8 +52,10 @@ struct iommu_ops {
iommu_create_domain_t create_domain; /* domain-specific */
iommu_destroy_domain_t destroy_domain;
iommu_create_mapping_t create_mapping;
+ iommu_remove_mapping_t remove_mapping;
iommu_add_device_t add_device;
iommu_remove_device_t remove_device;
+ iommu_invalidate_tlb_t invalidate_tlb;
};
extern struct iommu_ops iommu_ops_intel;
@@ -58,10 +63,13 @@ extern struct iommu_ops iommu_ops_amd;
void iommu_init(void);
void iommu_cleanup(void);
+void *iommu_host_domain(void);
void *iommu_create_domain(vm_paddr_t maxaddr);
void iommu_destroy_domain(void *dom);
void iommu_create_mapping(void *dom, vm_paddr_t gpa, vm_paddr_t hpa,
size_t len);
+void iommu_remove_mapping(void *dom, vm_paddr_t gpa, size_t len);
void iommu_add_device(void *dom, int bus, int slot, int func);
void iommu_remove_device(void *dom, int bus, int slot, int func);
+void iommu_invalidate_tlb(void *domain);
#endif
diff --git a/sys/amd64/vmm/vmm.c b/sys/amd64/vmm/vmm.c
index 7bd3f7f..bcd322a 100644
--- a/sys/amd64/vmm/vmm.c
+++ b/sys/amd64/vmm/vmm.c
@@ -280,6 +280,9 @@ vm_free_mem_seg(struct vm *vm, struct vm_memory_segment *seg)
{
size_t len;
vm_paddr_t hpa;
+ void *host_domain;
+
+ host_domain = iommu_host_domain();
len = 0;
while (len < seg->len) {
@@ -289,11 +292,24 @@ vm_free_mem_seg(struct vm *vm, struct vm_memory_segment *seg)
"associated with gpa 0x%016lx", seg->gpa + len);
}
+ /*
+ * Remove the 'gpa' to 'hpa' mapping in VMs domain.
+ * And resurrect the 1:1 mapping for 'hpa' in 'host_domain'.
+ */
+ iommu_remove_mapping(vm->iommu, seg->gpa + len, PAGE_SIZE);
+ iommu_create_mapping(host_domain, hpa, hpa, PAGE_SIZE);
+
vmm_mem_free(hpa, PAGE_SIZE);
len += PAGE_SIZE;
}
+ /*
+ * Invalidate cached translations associated with 'vm->iommu' since
+ * we have now moved some pages from it.
+ */
+ iommu_invalidate_tlb(vm->iommu);
+
bzero(seg, sizeof(struct vm_memory_segment));
}
@@ -371,6 +387,7 @@ vm_malloc(struct vm *vm, vm_paddr_t gpa, size_t len)
int error, available, allocated;
struct vm_memory_segment *seg;
vm_paddr_t g, hpa;
+ void *host_domain;
const boolean_t spok = TRUE; /* superpage mappings are ok */
@@ -405,8 +422,11 @@ vm_malloc(struct vm *vm, vm_paddr_t gpa, size_t len)
if (vm->num_mem_segs >= VM_MAX_MEMORY_SEGMENTS)
return (E2BIG);
+ host_domain = iommu_host_domain();
+
seg = &vm->mem_segs[vm->num_mem_segs];
+ error = 0;
seg->gpa = gpa;
seg->len = 0;
while (seg->len < len) {
@@ -421,16 +441,27 @@ vm_malloc(struct vm *vm, vm_paddr_t gpa, size_t len)
if (error)
break;
+ /*
+ * Remove the 1:1 mapping for 'hpa' from the 'host_domain'.
+ * Add mapping for 'gpa + seg->len' to 'hpa' in the VMs domain.
+ */
+ iommu_remove_mapping(host_domain, hpa, PAGE_SIZE);
iommu_create_mapping(vm->iommu, gpa + seg->len, hpa, PAGE_SIZE);
seg->len += PAGE_SIZE;
}
- if (seg->len != len) {
+ if (error) {
vm_free_mem_seg(vm, seg);
return (error);
}
+ /*
+ * Invalidate cached translations associated with 'host_domain' since
+ * we have now moved some pages from it.
+ */
+ iommu_invalidate_tlb(host_domain);
+
vm->num_mem_segs++;
return (0);
diff --git a/sys/amd64/vmm/vmm_dev.c b/sys/amd64/vmm/vmm_dev.c
index 91edbe8..66f5184 100644
--- a/sys/amd64/vmm/vmm_dev.c
+++ b/sys/amd64/vmm/vmm_dev.c
@@ -471,24 +471,6 @@ sysctl_vmm_create(SYSCTL_HANDLER_ARGS)
SYSCTL_PROC(_hw_vmm, OID_AUTO, create, CTLTYPE_STRING | CTLFLAG_RW,
NULL, 0, sysctl_vmm_create, "A", NULL);
-static int
-sysctl_vmm_mem_total(SYSCTL_HANDLER_ARGS)
-{
- size_t val = vmm_mem_get_mem_total();
- return sysctl_handle_long(oidp, &val, 0, req);
-}
-SYSCTL_PROC(_hw_vmm, OID_AUTO, mem_total, CTLTYPE_LONG | CTLFLAG_RD,
- 0, 0, sysctl_vmm_mem_total, "LU", "Amount of Total memory");
-
-static int
-sysctl_vmm_mem_free(SYSCTL_HANDLER_ARGS)
-{
- size_t val = vmm_mem_get_mem_free();
- return sysctl_handle_long(oidp, &val, 0, req);
-}
-SYSCTL_PROC(_hw_vmm, OID_AUTO, mem_free, CTLTYPE_LONG | CTLFLAG_RD,
- 0, 0, sysctl_vmm_mem_free, "LU", "Amount of Free memory");
-
void
vmmdev_init(void)
{
diff --git a/sys/amd64/vmm/vmm_mem.c b/sys/amd64/vmm/vmm_mem.c
index eb05b9d..8745339 100644
--- a/sys/amd64/vmm/vmm_mem.c
+++ b/sys/amd64/vmm/vmm_mem.c
@@ -36,9 +36,12 @@ __FBSDID("$FreeBSD$");
#include <sys/systm.h>
#include <sys/malloc.h>
#include <sys/kernel.h>
+#include <sys/sysctl.h>
#include <vm/vm.h>
#include <vm/pmap.h>
+#include <vm/vm_page.h>
+#include <vm/vm_pageout.h>
#include <machine/md_var.h>
#include <machine/metadata.h>
@@ -49,265 +52,21 @@ __FBSDID("$FreeBSD$");
#include "vmm_util.h"
#include "vmm_mem.h"
-static MALLOC_DEFINE(M_VMM_MEM, "vmm memory", "vmm memory");
+SYSCTL_DECL(_hw_vmm);
-#define MB (1024 * 1024)
-#define GB (1024 * MB)
-
-#define VMM_MEM_MAXSEGS 64
-
-/* protected by vmm_mem_mtx */
-static struct {
- vm_paddr_t base;
- vm_size_t length;
-} vmm_mem_avail[VMM_MEM_MAXSEGS];
-
-static int vmm_mem_nsegs;
-size_t vmm_mem_total_bytes;
-
-static vm_paddr_t maxaddr;
-
-static struct mtx vmm_mem_mtx;
-
-/*
- * Steal any memory that was deliberately hidden from FreeBSD either by
- * the use of MAXMEM kernel config option or the hw.physmem loader tunable.
- */
-static int
-vmm_mem_steal_memory(void)
-{
- int nsegs;
- caddr_t kmdp;
- uint32_t smapsize;
- uint64_t base, length;
- struct bios_smap *smapbase, *smap, *smapend;
-
- /*
- * Borrowed from hammer_time() and getmemsize() in machdep.c
- */
- kmdp = preload_search_by_type("elf kernel");
- if (kmdp == NULL)
- kmdp = preload_search_by_type("elf64 kernel");
-
- smapbase = (struct bios_smap *)preload_search_info(kmdp,
- MODINFO_METADATA | MODINFOMD_SMAP);
- if (smapbase == NULL)
- panic("No BIOS smap info from loader!");
-
- smapsize = *((uint32_t *)smapbase - 1);
- smapend = (struct bios_smap *)((uintptr_t)smapbase + smapsize);
-
- vmm_mem_total_bytes = 0;
- nsegs = 0;
- for (smap = smapbase; smap < smapend; smap++) {
- /*
- * XXX
- * Assuming non-overlapping, monotonically increasing
- * memory segments.
- */
- if (smap->type != SMAP_TYPE_MEMORY)
- continue;
- if (smap->length == 0)
- break;
-
- base = roundup(smap->base, NBPDR);
- length = rounddown(smap->length, NBPDR);
-
- /* Skip this segment if FreeBSD is using all of it. */
- if (base + length <= ptoa(Maxmem))
- continue;
-
- /*
- * If FreeBSD is using part of this segment then adjust
- * 'base' and 'length' accordingly.
- */
- if (base < ptoa(Maxmem)) {
- uint64_t used;
- used = roundup(ptoa(Maxmem), NBPDR) - base;
- base += used;
- length -= used;
- }
-
- if (length == 0)
- continue;
-
- vmm_mem_avail[nsegs].base = base;
- vmm_mem_avail[nsegs].length = length;
- vmm_mem_total_bytes += length;
-
- if (base + length > maxaddr)
- maxaddr = base + length;
-
- if (0 && bootverbose) {
- printf("vmm_mem_populate: index %d, base 0x%0lx, "
- "length %ld\n",
- nsegs, vmm_mem_avail[nsegs].base,
- vmm_mem_avail[nsegs].length);
- }
-
- nsegs++;
- if (nsegs >= VMM_MEM_MAXSEGS) {
- printf("vmm_mem_populate: maximum number of vmm memory "
- "segments reached!\n");
- return (ENOSPC);
- }
- }
-
- vmm_mem_nsegs = nsegs;
-
- return (0);
-}
+static u_long pages_allocated;
+SYSCTL_ULONG(_hw_vmm, OID_AUTO, pages_allocated, CTLFLAG_RD,
+ &pages_allocated, 0, "4KB pages allocated");
static void
-vmm_mem_direct_map(vm_paddr_t start, vm_paddr_t end)
+update_pages_allocated(int howmany)
{
- vm_paddr_t addr, remaining;
- int pdpi, pdi, superpage_size;
- pml4_entry_t *pml4p;
- pdp_entry_t *pdp;
- pd_entry_t *pd;
- uint64_t page_attr_bits;
-
- if (end >= NBPML4)
- panic("Cannot map memory beyond %ldGB", NBPML4 / GB);
-
- if (vmm_supports_1G_pages())
- superpage_size = NBPDP;
- else
- superpage_size = NBPDR;
-
- /*
- * Get the page directory pointer page that contains the direct
- * map address mappings.
- */
- pml4p = kernel_pmap->pm_pml4;
- pdp = (pdp_entry_t *)PHYS_TO_DMAP(pml4p[DMPML4I] & ~PAGE_MASK);
-
- page_attr_bits = PG_RW | PG_V | PG_PS | PG_G;
- addr = start;
- while (addr < end) {
- remaining = end - addr;
- pdpi = addr / NBPDP;
- if (superpage_size == NBPDP &&
- remaining >= NBPDP &&
- addr % NBPDP == 0) {
- /*
- * If there isn't a mapping for this address then
- * create one but if there is one already make sure
- * it matches what we expect it to be.
- */
- if (pdp[pdpi] == 0) {
- pdp[pdpi] = addr | page_attr_bits;
- if (0 && bootverbose) {
- printf("vmm_mem_populate: mapping "
- "0x%lx with 1GB page at "
- "pdpi %d\n", addr, pdpi);
- }
- } else {
- pdp_entry_t pdpe = pdp[pdpi];
- if ((pdpe & ~PAGE_MASK) != addr ||
- (pdpe & page_attr_bits) != page_attr_bits) {
- panic("An invalid mapping 0x%016lx "
- "already exists for 0x%016lx\n",
- pdpe, addr);
- }
- }
- addr += NBPDP;
- } else {
- if (remaining < NBPDR) {
- panic("vmm_mem_populate: remaining (%ld) must "
- "be greater than NBPDR (%d)\n",
- remaining, NBPDR);
- }
- if (pdp[pdpi] == 0) {
- /*
- * XXX we lose this memory forever because
- * we do not keep track of the virtual address
- * that would be required to free this page.
- */
- pd = malloc(PAGE_SIZE, M_VMM_MEM,
- M_WAITOK | M_ZERO);
- if ((uintptr_t)pd & PAGE_MASK) {
- panic("vmm_mem_populate: page directory"
- "page not aligned on %d "
- "boundary\n", PAGE_SIZE);
- }
- pdp[pdpi] = vtophys(pd);
- pdp[pdpi] |= PG_RW | PG_V | PG_U;
- if (0 && bootverbose) {
- printf("Creating page directory "
- "at pdp index %d for 0x%016lx\n",
- pdpi, addr);
- }
- }
- pdi = (addr % NBPDP) / NBPDR;
- pd = (pd_entry_t *)PHYS_TO_DMAP(pdp[pdpi] & ~PAGE_MASK);
-
- /*
- * Create a new mapping if one doesn't already exist
- * or validate it if it does.
- */
- if (pd[pdi] == 0) {
- pd[pdi] = addr | page_attr_bits;
- if (0 && bootverbose) {
- printf("vmm_mem_populate: mapping "
- "0x%lx with 2MB page at "
- "pdpi %d, pdi %d\n",
- addr, pdpi, pdi);
- }
- } else {
- pd_entry_t pde = pd[pdi];
- if ((pde & ~PAGE_MASK) != addr ||
- (pde & page_attr_bits) != page_attr_bits) {
- panic("An invalid mapping 0x%016lx "
- "already exists for 0x%016lx\n",
- pde, addr);
- }
- }
- addr += NBPDR;
- }
- }
-}
-
-static int
-vmm_mem_populate(void)
-{
- int seg, error;
- vm_paddr_t start, end;
-
- /* populate the vmm_mem_avail[] array */
- error = vmm_mem_steal_memory();
- if (error)
- return (error);
-
- /*
- * Now map the memory that was hidden from FreeBSD in
- * the direct map VA space.
- */
- for (seg = 0; seg < vmm_mem_nsegs; seg++) {
- start = vmm_mem_avail[seg].base;
- end = start + vmm_mem_avail[seg].length;
- if ((start & PDRMASK) != 0 || (end & PDRMASK) != 0) {
- panic("start (0x%016lx) and end (0x%016lx) must be "
- "aligned on a %dMB boundary\n",
- start, end, NBPDR / MB);
- }
- vmm_mem_direct_map(start, end);
- }
-
- return (0);
+ pages_allocated += howmany; /* XXX locking? */
}
int
vmm_mem_init(void)
{
- int error;
-
- mtx_init(&vmm_mem_mtx, "vmm_mem_mtx", NULL, MTX_DEF);
-
- error = vmm_mem_populate();
- if (error)
- return (error);
return (0);
}
@@ -315,122 +74,61 @@ vmm_mem_init(void)
vm_paddr_t
vmm_mem_alloc(size_t size)
{
- int i;
- vm_paddr_t addr;
+ int flags;
+ vm_page_t m;
+ vm_paddr_t pa;
- if ((size & PAGE_MASK) != 0) {
- panic("vmm_mem_alloc: size 0x%0lx must be "
- "aligned on a 0x%0x boundary\n", size, PAGE_SIZE);
- }
+ if (size != PAGE_SIZE)
+ panic("vmm_mem_alloc: invalid allocation size %lu", size);
- addr = 0;
+ flags = VM_ALLOC_NORMAL | VM_ALLOC_NOOBJ | VM_ALLOC_WIRED |
+ VM_ALLOC_ZERO;
- mtx_lock(&vmm_mem_mtx);
- for (i = 0; i < vmm_mem_nsegs; i++) {
- if (vmm_mem_avail[i].length >= size) {
- addr = vmm_mem_avail[i].base;
- vmm_mem_avail[i].base += size;
- vmm_mem_avail[i].length -= size;
- /* remove a zero length segment */
- if (vmm_mem_avail[i].length == 0) {
- memmove(&vmm_mem_avail[i],
- &vmm_mem_avail[i + 1],
- (vmm_mem_nsegs - (i + 1)) *
- sizeof(vmm_mem_avail[0]));
- vmm_mem_nsegs--;
- }
+ while (1) {
+ /*
+ * XXX need policy to determine when to back off the allocation
+ */
+ m = vm_page_alloc(NULL, 0, flags);
+ if (m == NULL)
+ VM_WAIT;
+ else
break;
- }
}
- mtx_unlock(&vmm_mem_mtx);
-
- return (addr);
-}
-
-size_t
-vmm_mem_get_mem_total(void)
-{
- return vmm_mem_total_bytes;
-}
-size_t
-vmm_mem_get_mem_free(void)
-{
- size_t length = 0;
- int i;
+ pa = VM_PAGE_TO_PHYS(m);
+
+ if ((m->flags & PG_ZERO) == 0)
+ pagezero((void *)PHYS_TO_DMAP(pa));
- mtx_lock(&vmm_mem_mtx);
- for (i = 0; i < vmm_mem_nsegs; i++) {
- length += vmm_mem_avail[i].length;
- }
- mtx_unlock(&vmm_mem_mtx);
+ update_pages_allocated(1);
- return(length);
+ return (pa);
}
void
vmm_mem_free(vm_paddr_t base, size_t length)
{
- int i;
+ vm_page_t m;
- if ((base & PAGE_MASK) != 0 || (length & PAGE_MASK) != 0) {
- panic("vmm_mem_free: base 0x%0lx and length 0x%0lx must be "
- "aligned on a 0x%0x boundary\n", base, length, PAGE_SIZE);
+ if (base & PAGE_MASK) {
+ panic("vmm_mem_free: base 0x%0lx must be aligned on a "
+ "0x%0x boundary\n", base, PAGE_SIZE);
}
- mtx_lock(&vmm_mem_mtx);
-
- for (i = 0; i < vmm_mem_nsegs; i++) {
- if (vmm_mem_avail[i].base > base)
- break;
- }
-
- if (vmm_mem_nsegs >= VMM_MEM_MAXSEGS)
- panic("vmm_mem_free: cannot free any more segments");
-
- /* Create a new segment at index 'i' */
- memmove(&vmm_mem_avail[i + 1], &vmm_mem_avail[i],
- (vmm_mem_nsegs - i) * sizeof(vmm_mem_avail[0]));
-
- vmm_mem_avail[i].base = base;
- vmm_mem_avail[i].length = length;
+ if (length != PAGE_SIZE)
+ panic("vmm_mem_free: invalid length %lu", length);
- vmm_mem_nsegs++;
+ m = PHYS_TO_VM_PAGE(base);
+ m->wire_count--;
+ vm_page_free(m);
+ atomic_subtract_int(&cnt.v_wire_count, 1);
-coalesce_some_more:
- for (i = 0; i < vmm_mem_nsegs - 1; i++) {
- if (vmm_mem_avail[i].base + vmm_mem_avail[i].length ==
- vmm_mem_avail[i + 1].base) {
- vmm_mem_avail[i].length += vmm_mem_avail[i + 1].length;
- memmove(&vmm_mem_avail[i + 1], &vmm_mem_avail[i + 2],
- (vmm_mem_nsegs - (i + 2)) * sizeof(vmm_mem_avail[0]));
- vmm_mem_nsegs--;
- goto coalesce_some_more;
- }
- }
-
- mtx_unlock(&vmm_mem_mtx);
+ update_pages_allocated(-1);
}
vm_paddr_t
vmm_mem_maxaddr(void)
{
- return (maxaddr);
-}
-
-void
-vmm_mem_dump(void)
-{
- int i;
- vm_paddr_t base;
- vm_size_t length;
-
- mtx_lock(&vmm_mem_mtx);
- for (i = 0; i < vmm_mem_nsegs; i++) {
- base = vmm_mem_avail[i].base;
- length = vmm_mem_avail[i].length;
- printf("%-4d0x%016lx 0x%016lx\n", i, base, base + length);
- }
- mtx_unlock(&vmm_mem_mtx);
+ return (ptoa(Maxmem));
}
diff --git a/sys/amd64/vmm/vmm_mem.h b/sys/amd64/vmm/vmm_mem.h
index a83e9be..7d45c74 100644
--- a/sys/amd64/vmm/vmm_mem.h
+++ b/sys/amd64/vmm/vmm_mem.h
@@ -33,9 +33,5 @@ int vmm_mem_init(void);
vm_paddr_t vmm_mem_alloc(size_t size);
void vmm_mem_free(vm_paddr_t start, size_t size);
vm_paddr_t vmm_mem_maxaddr(void);
-void vmm_mem_dump(void);
-
-size_t vmm_mem_get_mem_total(void);
-size_t vmm_mem_get_mem_free(void);
#endif
OpenPOWER on IntegriCloud