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 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 @@ -52,6 +54,9 @@ 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/arm64/include/vmm_dev.h b/sys/arm64/include/vmm_dev.h --- a/sys/arm64/include/vmm_dev.h +++ b/sys/arm64/include/vmm_dev.h @@ -27,6 +27,8 @@ #ifndef _VMM_DEV_H_ #define _VMM_DEV_H_ +#include + #include struct vm_memmap { @@ -48,6 +50,9 @@ 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/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 @@ -279,7 +279,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; diff --git a/sys/dev/vmm/vmm_mem.h b/sys/dev/vmm/vmm_mem.h --- a/sys/dev/vmm/vmm_mem.h +++ b/sys/dev/vmm/vmm_mem.h @@ -8,6 +8,27 @@ #ifndef _DEV_VMM_MEM_H_ #define _DEV_VMM_MEM_H_ +/* 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_MAX_MEMSEGS VM_MEMSEG_END +#define VM_MAX_MEMMAPS (VM_MAX_MEMSEGS * 2) + #ifdef _KERNEL #include @@ -31,9 +52,6 @@ int flags; }; -#define VM_MAX_MEMSEGS 4 -#define VM_MAX_MEMMAPS 8 - struct vm_mem { struct vm_mem_map mem_maps[VM_MAX_MEMMAPS]; struct vm_mem_seg mem_segs[VM_MAX_MEMSEGS]; @@ -55,7 +73,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 *ds_mask, size_t mask_size, bool sysmem); void vm_free_memseg(struct vm *vm, int ident); /* diff --git a/sys/dev/vmm/vmm_mem.c b/sys/dev/vmm/vmm_mem.c --- a/sys/dev/vmm/vmm_mem.c +++ b/sys/dev/vmm/vmm_mem.c @@ -9,6 +9,7 @@ #include #include #include +#include #include @@ -156,11 +157,15 @@ } 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_domainset; struct vm_mem *mem; struct vm_mem_seg *seg; + domainset_t *mask; vm_object_t obj; + int error; mem = vm_mem(vm); vm_assert_memseg_xlocked(vm); @@ -179,14 +184,41 @@ 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_domainset = domainset_create(&domain); + if (obj_domainset == NULL) { + error = EINVAL; + goto out; + } + } obj = vm_object_allocate(OBJT_SWAP, len >> PAGE_SHIFT); if (obj == NULL) return (ENOMEM); seg->len = len; seg->object = obj; + if (ds_policy != DOMAINSET_POLICY_INVALID) + seg->object->domain.dr_policy = obj_domainset; seg->sysmem = sysmem; - return (0); +out: + free(mask, M_TEMP); + return (error); } int diff --git a/sys/riscv/include/vmm_dev.h b/sys/riscv/include/vmm_dev.h --- a/sys/riscv/include/vmm_dev.h +++ b/sys/riscv/include/vmm_dev.h @@ -34,6 +34,8 @@ #ifndef _VMM_DEV_H_ #define _VMM_DEV_H_ +#include + #include struct vm_memmap { @@ -55,6 +57,9 @@ 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]; };