vmm: Fix routines which create maps of the guest physical address space
In vm_mmap_memseg(), use vm_map_insert() instead of vm_map_find(). Existing callers expect to map the GPA that they passed, whereas vm_map_find() merely treats the GPA as a hint. Also check for overflow and remove a test for first < 0 since "first" is unsigned. In vmm_mmio_alloc(), return an error number instead of an object pointer, since the sole caller doesn't need the pointer. As in vm_mmap_memseg(), use vm_map_insert() instead of vm_map_find() and validate parameters. This function is not directly reachable via ioctl(), but we ought to be careful anyway. Reviewed by: corvink, kib MFC after: 2 weeks Sponsored by: The FreeBSD Foundation Sponsored by: Klara, Inc. Differential Revision: https://reviews.freebsd.org/D53246
This commit is contained in:
+1
-6
@@ -724,12 +724,7 @@ vm_name(struct vm *vm)
|
||||
int
|
||||
vm_map_mmio(struct vm *vm, vm_paddr_t gpa, size_t len, vm_paddr_t hpa)
|
||||
{
|
||||
vm_object_t obj;
|
||||
|
||||
if ((obj = vmm_mmio_alloc(vm_vmspace(vm), gpa, len, hpa)) == NULL)
|
||||
return (ENOMEM);
|
||||
else
|
||||
return (0);
|
||||
return (vmm_mmio_alloc(vm_vmspace(vm), gpa, len, hpa));
|
||||
}
|
||||
|
||||
int
|
||||
|
||||
@@ -30,10 +30,9 @@
|
||||
#define _VMM_MEM_H_
|
||||
|
||||
struct vmspace;
|
||||
struct vm_object;
|
||||
|
||||
struct vm_object *vmm_mmio_alloc(struct vmspace *, vm_paddr_t gpa, size_t len,
|
||||
vm_paddr_t hpa);
|
||||
int vmm_mmio_alloc(struct vmspace *, vm_paddr_t gpa, size_t len,
|
||||
vm_paddr_t hpa);
|
||||
void vmm_mmio_free(struct vmspace *, vm_paddr_t gpa, size_t size);
|
||||
vm_paddr_t vmm_mem_maxaddr(void);
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#include <vm/vm.h>
|
||||
#include <vm/vm_param.h>
|
||||
#include <vm/pmap.h>
|
||||
#include <vm/vm_extern.h>
|
||||
#include <vm/vm_map.h>
|
||||
#include <vm/vm_object.h>
|
||||
#include <vm/vm_page.h>
|
||||
@@ -45,40 +46,48 @@
|
||||
|
||||
#include "vmm_mem.h"
|
||||
|
||||
vm_object_t
|
||||
int
|
||||
vmm_mmio_alloc(struct vmspace *vmspace, vm_paddr_t gpa, size_t len,
|
||||
vm_paddr_t hpa)
|
||||
vm_paddr_t hpa)
|
||||
{
|
||||
int error;
|
||||
vm_object_t obj;
|
||||
struct sglist *sg;
|
||||
vm_object_t obj;
|
||||
int error;
|
||||
|
||||
if (gpa + len < gpa || hpa + len < hpa || (gpa & PAGE_MASK) != 0 ||
|
||||
(hpa & PAGE_MASK) != 0 || (len & PAGE_MASK) != 0)
|
||||
return (EINVAL);
|
||||
|
||||
sg = sglist_alloc(1, M_WAITOK);
|
||||
error = sglist_append_phys(sg, hpa, len);
|
||||
KASSERT(error == 0, ("error %d appending physaddr to sglist", error));
|
||||
|
||||
obj = vm_pager_allocate(OBJT_SG, sg, len, VM_PROT_RW, 0, NULL);
|
||||
if (obj != NULL) {
|
||||
/*
|
||||
* VT-x ignores the MTRR settings when figuring out the
|
||||
* memory type for translations obtained through EPT.
|
||||
*
|
||||
* Therefore we explicitly force the pages provided by
|
||||
* this object to be mapped as uncacheable.
|
||||
*/
|
||||
VM_OBJECT_WLOCK(obj);
|
||||
error = vm_object_set_memattr(obj, VM_MEMATTR_UNCACHEABLE);
|
||||
VM_OBJECT_WUNLOCK(obj);
|
||||
if (error != KERN_SUCCESS) {
|
||||
panic("vmm_mmio_alloc: vm_object_set_memattr error %d",
|
||||
error);
|
||||
}
|
||||
error = vm_map_find(&vmspace->vm_map, obj, 0, &gpa, len, 0,
|
||||
VMFS_NO_SPACE, VM_PROT_RW, VM_PROT_RW, 0);
|
||||
if (error != KERN_SUCCESS) {
|
||||
vm_object_deallocate(obj);
|
||||
obj = NULL;
|
||||
}
|
||||
if (obj == NULL)
|
||||
return (ENOMEM);
|
||||
|
||||
/*
|
||||
* VT-x ignores the MTRR settings when figuring out the memory type for
|
||||
* translations obtained through EPT.
|
||||
*
|
||||
* Therefore we explicitly force the pages provided by this object to be
|
||||
* mapped as uncacheable.
|
||||
*/
|
||||
VM_OBJECT_WLOCK(obj);
|
||||
error = vm_object_set_memattr(obj, VM_MEMATTR_UNCACHEABLE);
|
||||
VM_OBJECT_WUNLOCK(obj);
|
||||
if (error != KERN_SUCCESS)
|
||||
panic("vmm_mmio_alloc: vm_object_set_memattr error %d", error);
|
||||
|
||||
vm_map_lock(&vmspace->vm_map);
|
||||
error = vm_map_insert(&vmspace->vm_map, obj, 0, gpa, gpa + len,
|
||||
VM_PROT_RW, VM_PROT_RW, 0);
|
||||
vm_map_unlock(&vmspace->vm_map);
|
||||
if (error != KERN_SUCCESS) {
|
||||
error = vm_mmap_to_errno(error);
|
||||
vm_object_deallocate(obj);
|
||||
} else {
|
||||
error = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -94,7 +103,7 @@ vmm_mmio_alloc(struct vmspace *vmspace, vm_paddr_t gpa, size_t len,
|
||||
*/
|
||||
sglist_free(sg);
|
||||
|
||||
return (obj);
|
||||
return (error);
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -279,8 +279,10 @@ vm_mmap_memseg(struct vm *vm, vm_paddr_t gpa, int segid, vm_ooffset_t first,
|
||||
if (seg->object == NULL)
|
||||
return (EINVAL);
|
||||
|
||||
if (first + len < first || gpa + len < gpa)
|
||||
return (EINVAL);
|
||||
last = first + len;
|
||||
if (first < 0 || first >= last || last > seg->len)
|
||||
if (first >= last || last > seg->len)
|
||||
return (EINVAL);
|
||||
|
||||
if ((gpa | first | last) & PAGE_MASK)
|
||||
@@ -298,11 +300,12 @@ vm_mmap_memseg(struct vm *vm, vm_paddr_t gpa, int segid, vm_ooffset_t first,
|
||||
return (ENOSPC);
|
||||
|
||||
vmmap = &mem->mem_vmspace->vm_map;
|
||||
error = vm_map_find(vmmap, seg->object, first, &gpa, len, 0,
|
||||
VMFS_NO_SPACE, prot, prot, 0);
|
||||
vm_map_lock(vmmap);
|
||||
error = vm_map_insert(vmmap, seg->object, first, gpa, gpa + len,
|
||||
prot, prot, 0);
|
||||
vm_map_unlock(vmmap);
|
||||
if (error != KERN_SUCCESS)
|
||||
return (EFAULT);
|
||||
|
||||
return (vm_mmap_to_errno(error));
|
||||
vm_object_reference(seg->object);
|
||||
|
||||
if (flags & VM_MEMMAP_F_WIRED) {
|
||||
|
||||
Reference in New Issue
Block a user