diff --git a/sys/amd64/include/vmm.h b/sys/amd64/include/vmm.h --- a/sys/amd64/include/vmm.h +++ b/sys/amd64/include/vmm.h @@ -30,6 +30,7 @@ #define _VMM_H_ #include +#include #include #include @@ -245,7 +246,8 @@ int vm_mmap_memseg(struct vm *vm, vm_paddr_t gpa, int segid, vm_ooffset_t off, size_t len, int prot, int flags); int vm_munmap_memseg(struct vm *vm, vm_paddr_t gpa, size_t len); -int vm_alloc_memseg(struct vm *vm, int ident, size_t len, bool sysmem); +int vm_alloc_memseg(struct vm *vm, int ident, size_t len, int ds_policy, + domainset_t *mask, size_t mask_size, bool sysmem); void vm_free_memseg(struct vm *vm, int ident); int vm_map_mmio(struct vm *vm, vm_paddr_t gpa, size_t len, vm_paddr_t hpa); int vm_unmap_mmio(struct vm *vm, vm_paddr_t gpa, size_t len); diff --git a/sys/amd64/include/vmm_dev.h b/sys/amd64/include/vmm_dev.h --- a/sys/amd64/include/vmm_dev.h +++ b/sys/amd64/include/vmm_dev.h @@ -29,6 +29,8 @@ #ifndef _VMM_DEV_H_ #define _VMM_DEV_H_ +#include + #include #include @@ -47,11 +49,31 @@ vm_paddr_t gpa; size_t len; }; +/* Maximum number of NUMA domains in a guest. */ +#define VM_MAXMEMDOM 8 +#define VM_MAXSYSMEM VM_MAXMEMDOM + +/* + * Identifiers for memory segments. + * Each guest NUMA domain is represented by a single system + * memory segment from [VM_SYSMEM, VM_MAXSYSMEM). + * The remaining identifiers can be used to create devmem segments. + */ +enum { + VM_SYSMEM, + VM_BOOTROM = VM_MAXSYSMEM, + VM_FRAMEBUFFER, + VM_PCIROM, + VM_MEMSEG_END +}; #define VM_MEMSEG_NAME(m) ((m)->name[0] != '\0' ? (m)->name : NULL) struct vm_memseg { int segid; size_t len; + domainset_t *ds_mask; + size_t ds_mask_size; + int ds_policy; char name[VM_MAX_SUFFIXLEN + 1]; }; diff --git a/sys/amd64/vmm/vmm.c b/sys/amd64/vmm/vmm.c --- a/sys/amd64/vmm/vmm.c +++ b/sys/amd64/vmm/vmm.c @@ -44,6 +44,7 @@ #include #include #include +#include #include #include @@ -136,7 +137,7 @@ bool sysmem; struct vm_object *object; }; -#define VM_MAX_MEMSEGS 4 +#define VM_MAX_MEMSEGS VM_MEMSEG_END struct mem_map { vm_paddr_t gpa; @@ -146,7 +147,7 @@ int prot; int flags; }; -#define VM_MAX_MEMMAPS 8 +#define VM_MAX_MEMMAPS (VM_MAX_MEMSEGS * 2) /* * Initialization: @@ -830,10 +831,14 @@ } int -vm_alloc_memseg(struct vm *vm, int ident, size_t len, bool sysmem) +vm_alloc_memseg(struct vm *vm, int ident, size_t len, int ds_policy, + domainset_t *ds_mask, size_t mask_size, bool sysmem) { + struct domainset domain, *obj_ds_policy; struct mem_seg *seg; + domainset_t *mask; vm_object_t obj; + int error; sx_assert(&vm->mem_segs_lock, SX_XLOCKED); @@ -851,14 +856,44 @@ return (EINVAL); } + error = 0; + mask = NULL; + if (ds_policy != DOMAINSET_POLICY_INVALID) { + if (mask_size < sizeof(domainset_t) || + mask_size > DOMAINSET_MAXSIZE / NBBY) + return (ERANGE); + memset(&domain, 0, sizeof(domain)); + mask = malloc(mask_size, M_TEMP, M_WAITOK | M_ZERO); + error = copyin(ds_mask, mask, mask_size); + if (error) + goto out; + error = domainset_populate(&domain, mask, ds_policy, mask_size); + if (error) { + printf("%s: failed to process domain policy" + ", error: %d\n", __func__, error); + goto out; + } + obj_ds_policy = domainset_create(&domain); + if (obj_ds_policy == NULL) { + error = EINVAL; + goto out; + } + } obj = vm_object_allocate(OBJT_SWAP, len >> PAGE_SHIFT); - if (obj == NULL) - return (ENOMEM); - + if (obj == NULL) { + error = ENOMEM; + goto out; + } seg->len = len; seg->object = obj; + if (ds_policy != DOMAINSET_POLICY_INVALID) + seg->object->domain.dr_policy = obj_ds_policy; seg->sysmem = sysmem; - return (0); + +out: + if (mask != NULL) + free(mask, M_TEMP); + return (error); } int diff --git a/sys/dev/vmm/vmm_dev.c b/sys/dev/vmm/vmm_dev.c --- a/sys/dev/vmm/vmm_dev.c +++ b/sys/dev/vmm/vmm_dev.c @@ -276,7 +276,8 @@ goto done; } - error = vm_alloc_memseg(sc->vm, mseg->segid, mseg->len, sysmem); + error = vm_alloc_memseg(sc->vm, mseg->segid, mseg->len, mseg->ds_policy, + mseg->ds_mask, mseg->ds_mask_size, sysmem); if (error) goto done;