diff options
Diffstat (limited to 'sys')
-rw-r--r-- | sys/arch/amd64/amd64/vmm.c | 146 | ||||
-rw-r--r-- | sys/arch/amd64/include/vmmvar.h | 25 |
2 files changed, 135 insertions, 36 deletions
diff --git a/sys/arch/amd64/amd64/vmm.c b/sys/arch/amd64/amd64/vmm.c index 1593aa8b06e..5a46b6fc1a7 100644 --- a/sys/arch/amd64/amd64/vmm.c +++ b/sys/arch/amd64/amd64/vmm.c @@ -1,4 +1,4 @@ -/* $OpenBSD: vmm.c,v 1.44 2016/03/09 07:41:25 mlarkin Exp $ */ +/* $OpenBSD: vmm.c,v 1.45 2016/03/13 13:11:47 stefan Exp $ */ /* * Copyright (c) 2014 Mike Larkin <mlarkin@openbsd.org> * @@ -63,8 +63,10 @@ struct vm { vm_map_t vm_map; uint32_t vm_id; pid_t vm_creator_pid; - uint32_t vm_memory_size; + size_t vm_nmemranges; + size_t vm_memory_size; char vm_name[VMM_MAX_NAME_LEN]; + struct vm_mem_range vm_memranges[VMM_MAX_MEM_RANGES]; struct vcpu_head vm_vcpu_list; uint32_t vm_vcpu_ct; @@ -103,6 +105,7 @@ int vmmioctl(dev_t, u_long, caddr_t, int, struct proc *); int vmmclose(dev_t, int, int, struct proc *); int vmm_start(void); int vmm_stop(void); +size_t vm_create_check_mem_ranges(struct vm_create_params *); int vm_create(struct vm_create_params *, struct proc *); int vm_run(struct vm_run_params *); int vm_terminate(struct vm_terminate_params *); @@ -920,6 +923,67 @@ stop_vmm_on_cpu(struct cpu_info *ci) } /* + * vm_create_check_mem_ranges: + * + * Make sure that the guest physical memory ranges given by the user process + * do not overlap and are in ascending order. + * + * The last physical address may not exceed VMM_MAX_VM_MEM_SIZE. + * + * Return Values: + * The total memory size in MB if the checks were successful + * 0: One of the memory ranges was invalid, or VMM_MAX_VM_MEM_SIZE was + * exceeded + */ +size_t +vm_create_check_mem_ranges(struct vm_create_params *vcp) +{ + int disjunct_range; + size_t i, memsize = 0; + struct vm_mem_range *vmr, *pvmr; + const paddr_t maxgpa = (uint64_t)VMM_MAX_VM_MEM_SIZE * 1024 * 1024; + + if (vcp->vcp_nmemranges == 0 || + vcp->vcp_nmemranges > VMM_MAX_MEM_RANGES) + return (0); + + for (i = 0; i < vcp->vcp_nmemranges; i++) { + vmr = &vcp->vcp_memranges[i]; + + /* Only page-aligned addresses and sizes are permitted */ + if ((vmr->vmr_gpa & PAGE_MASK) || + (vmr->vmr_size & PAGE_MASK) || vmr->vmr_size == 0) + return (0); + + /* Make sure that VMM_MAX_VM_MEM_SIZE is not exceeded */ + if (vmr->vmr_gpa >= maxgpa || + vmr->vmr_size > maxgpa - vmr->vmr_gpa) + return (0); + + /* Specifying ranges within the PCI MMIO space is forbidden */ + disjunct_range = (vmr->vmr_gpa > VMM_PCI_MMIO_BAR_END) || + (vmr->vmr_gpa + vmr->vmr_size <= VMM_PCI_MMIO_BAR_BASE); + if (!disjunct_range) + return (0); + + /* + * Make sure that guest physcal memory ranges do not overlap + * and that they are ascending. + */ + if (i > 0 && pvmr->vmr_gpa + pvmr->vmr_size > vmr->vmr_gpa) + return (0); + + memsize += vmr->vmr_size; + pvmr = vmr; + } + + if (memsize % (1024 * 1024) != 0) + return (0); + memsize /= 1024 * 1024; + return (memsize); +} + +/* * vm_create * * Creates the in-memory VMM structures for the VM defined by 'vcp'. The @@ -935,12 +999,17 @@ int vm_create(struct vm_create_params *vcp, struct proc *p) { int i, ret; + size_t memsize; struct vm *vm; struct vcpu *vcpu; if (!(curcpu()->ci_flags & CPUF_VMM)) return (EINVAL); + memsize = vm_create_check_mem_ranges(vcp); + if (memsize == 0) + return (EINVAL); + /* XXX - support UP only (for now) */ if (vcp->vcp_ncpus != 1) return (EINVAL); @@ -950,7 +1019,10 @@ vm_create(struct vm_create_params *vcp, struct proc *p) rw_init(&vm->vm_vcpu_lock, "vcpulock"); vm->vm_creator_pid = p->p_p->ps_pid; - vm->vm_memory_size = vcp->vcp_memory_size; + vm->vm_nmemranges = vcp->vcp_nmemranges; + memcpy(vm->vm_memranges, vcp->vcp_memranges, + vm->vm_nmemranges * sizeof(vm->vm_memranges[0])); + vm->vm_memory_size = memsize; strncpy(vm->vm_name, vcp->vcp_name, VMM_MAX_NAME_LEN); if (vm_impl_init(vm)) { @@ -1009,10 +1081,11 @@ vm_create(struct vm_create_params *vcp, struct proc *p) int vm_impl_init_vmx(struct vm *vm) { - struct pmap *pmap; - size_t memsize; + int i, ret; + vaddr_t mingpa, maxgpa; vaddr_t startp; - int ret; + struct pmap *pmap; + struct vm_mem_range *vmr; /* If not EPT, nothing to do here */ if (vmm_softc->mode != VMM_MODE_EPT) @@ -1025,14 +1098,15 @@ vm_impl_init_vmx(struct vm *vm) return (ENOMEM); } - startp = 0; - memsize = vm->vm_memory_size * 1024 * 1024; - /* * Create a new UVM map for this VM, and assign it the pmap just * created. */ - vm->vm_map = uvm_map_create(pmap, 0, memsize, + vmr = &vm->vm_memranges[0]; + mingpa = vmr->vmr_gpa; + vmr = &vm->vm_memranges[vm->vm_nmemranges - 1]; + maxgpa = vmr->vmr_gpa + vmr->vmr_size; + vm->vm_map = uvm_map_create(pmap, mingpa, maxgpa, VM_MAP_ISVMSPACE | VM_MAP_PAGEABLE); if (!vm->vm_map) { @@ -1043,18 +1117,23 @@ vm_impl_init_vmx(struct vm *vm) /* Map the new map with an anon */ DPRINTF("vm_impl_init_vmx: created vm_map @ %p\n", vm->vm_map); - ret = uvm_mapanon(vm->vm_map, &startp, memsize, 0, - UVM_MAPFLAG(PROT_READ | PROT_WRITE | PROT_EXEC, - PROT_READ | PROT_WRITE | PROT_EXEC, - MAP_INHERIT_NONE, - MADV_NORMAL, - UVM_FLAG_FIXED | UVM_FLAG_COPYONW)); - if (ret) { - printf("vm_impl_init_vmx: uvm_mapanon failed (%d)\n", ret); - /* uvm_map_deallocate calls pmap_destroy for us */ - uvm_map_deallocate(vm->vm_map); - vm->vm_map = NULL; - return (ENOMEM); + for (i = 0; i < vm->vm_nmemranges; i++) { + vmr = &vm->vm_memranges[i]; + startp = vmr->vmr_gpa; + ret = uvm_mapanon(vm->vm_map, &startp, vmr->vmr_size, 0, + UVM_MAPFLAG(PROT_READ | PROT_WRITE | PROT_EXEC, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_INHERIT_NONE, + MADV_NORMAL, + UVM_FLAG_FIXED | UVM_FLAG_COPYONW)); + if (ret) { + printf("vm_impl_init_vmx: uvm_mapanon failed (%d)\n", + ret); + /* uvm_map_deallocate calls pmap_destroy for us */ + uvm_map_deallocate(vm->vm_map); + vm->vm_map = NULL; + return (ENOMEM); + } } /* Convert the low 512GB of the pmap to EPT */ @@ -3079,18 +3158,31 @@ vmx_handle_exit(struct vcpu *vcpu) int vmm_get_guest_memtype(struct vm *vm, paddr_t gpa) { + int i; + struct vm_mem_range *vmr; if (gpa >= VMM_PCI_MMIO_BAR_BASE && gpa <= VMM_PCI_MMIO_BAR_END) { DPRINTF("guest mmio access @ 0x%llx\n", (uint64_t)gpa); return (VMM_MEM_TYPE_REGULAR); } - if (gpa < vm->vm_memory_size * (1024 * 1024)) - return (VMM_MEM_TYPE_REGULAR); - else { - DPRINTF("guest memtype @ 0x%llx unknown\n", (uint64_t)gpa); - return (VMM_MEM_TYPE_UNKNOWN); + /* XXX Use binary search? */ + for (i = 0; i < vm->vm_nmemranges; i++) { + vmr = &vm->vm_memranges[i]; + + /* + * vm_memranges are ascending. gpa can no longer be in one of + * the memranges + */ + if (gpa < vmr->vmr_gpa) + break; + + if (gpa < vmr->vmr_gpa + vmr->vmr_size) + return (VMM_MEM_TYPE_REGULAR); } + + DPRINTF("guest memtype @ 0x%llx unknown\n", (uint64_t)gpa); + return (VMM_MEM_TYPE_UNKNOWN); } /* diff --git a/sys/arch/amd64/include/vmmvar.h b/sys/arch/amd64/include/vmmvar.h index 3b863df0580..f770968dd8b 100644 --- a/sys/arch/amd64/include/vmmvar.h +++ b/sys/arch/amd64/include/vmmvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: vmmvar.h,v 1.10 2016/03/09 08:06:59 mlarkin Exp $ */ +/* $OpenBSD: vmmvar.h,v 1.11 2016/03/13 13:11:47 stefan Exp $ */ /* * Copyright (c) 2014 Mike Larkin <mlarkin@openbsd.org> * @@ -23,6 +23,7 @@ #define VMM_HV_SIGNATURE "OpenBSDVMM58" +#define VMM_MAX_MEM_RANGES 16 #define VMM_MAX_DISKS_PER_VM 2 #define VMM_MAX_PATH_DISK 128 #define VMM_MAX_NAME_LEN 32 @@ -173,16 +174,22 @@ struct vcpu_init_state { struct vcpu_segment_info vis_tr; }; +struct vm_mem_range { + paddr_t vmr_gpa; + size_t vmr_size; +}; + struct vm_create_params { /* Input parameters to VMM_IOC_CREATE */ - size_t vcp_memory_size; - size_t vcp_ncpus; - size_t vcp_ndisks; - size_t vcp_nnics; - char vcp_disks[VMM_MAX_DISKS_PER_VM][VMM_MAX_PATH_DISK]; - char vcp_name[VMM_MAX_NAME_LEN]; - char vcp_kernel[VMM_MAX_KERNEL_PATH]; - uint8_t vcp_macs[VMM_MAX_NICS_PER_VM][6]; + size_t vcp_nmemranges; + size_t vcp_ncpus; + size_t vcp_ndisks; + size_t vcp_nnics; + struct vm_mem_range vcp_memranges[VMM_MAX_MEM_RANGES]; + char vcp_disks[VMM_MAX_DISKS_PER_VM][VMM_MAX_PATH_DISK]; + char vcp_name[VMM_MAX_NAME_LEN]; + char vcp_kernel[VMM_MAX_KERNEL_PATH]; + uint8_t vcp_macs[VMM_MAX_NICS_PER_VM][6]; /* Output parameter from VMM_IOC_CREATE */ uint32_t vcp_id; |