Fix IOCTL_PRIVCMD_MMAPBATCH: don't blindly map requested pages read/write

but use the map's protection bits, as the hypervisor may refuse read/write
mappings for some entries. Now suspend/resume of domUs should work
from a NetBSD dom0, provided that the domU's kernel supports it.

From Jean-Yves Migeon.
This commit is contained in:
bouyer 2008-09-20 20:36:09 +00:00
parent a812f51e37
commit d0d4dde4ac

View File

@ -1,4 +1,4 @@
/* $NetBSD: privcmd.c,v 1.29 2008/08/24 20:35:43 bouyer Exp $ */
/* $NetBSD: privcmd.c,v 1.30 2008/09/20 20:36:09 bouyer Exp $ */
/*-
* Copyright (c) 2004 Christian Limpach.
@ -32,7 +32,7 @@
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: privcmd.c,v 1.29 2008/08/24 20:35:43 bouyer Exp $");
__KERNEL_RCSID(0, "$NetBSD: privcmd.c,v 1.30 2008/09/20 20:36:09 bouyer Exp $");
#include "opt_compat_netbsd.h"
@ -400,6 +400,7 @@ privcmd_ioctl(void *v)
vaddr_t va0, va;
u_long mfn, ma;
struct vm_map *vmm;
struct vm_map_entry *entry;
pmap_t pmap;
vaddr_t trymap;
@ -411,6 +412,13 @@ privcmd_ioctl(void *v)
return EINVAL;
if (((VM_MAXUSER_ADDRESS - va0) >> PGSHIFT) < pmb->num)
return EINVAL;
vm_map_lock_read(vmm);
if (!uvm_map_lookup_entry(vmm, va0, &entry)) {
vm_map_unlock_read(vmm);
return EINVAL;
}
vm_map_unlock_read(vmm);
maddr = kmem_alloc(sizeof(paddr_t) * pmb->num, KM_SLEEP);
if (maddr == NULL)
@ -434,7 +442,7 @@ privcmd_ioctl(void *v)
}
ma = mfn << PGSHIFT;
if (pmap_enter_ma(pmap_kernel(), trymap, ma, 0,
VM_PROT_READ | VM_PROT_WRITE, PMAP_CANFAIL,
entry->protection, PMAP_CANFAIL,
pmb->dom)) {
mfn |= 0xF0000000;
copyout(&mfn, &pmb->arr[i], sizeof(mfn));
@ -557,7 +565,7 @@ privcmd_map_obj(struct vm_map *map, vaddr_t start, paddr_t *maddr,
vm_prot_t prot;
off_t size = ((off_t)npages << PGSHIFT);
vm_map_lock(map);
vm_map_lock_read(map);
/* get protections. This also check for validity of mapping */
if (uvm_map_checkprot(map, start, start + size - 1, VM_PROT_WRITE))
prot = VM_PROT_READ | VM_PROT_WRITE;
@ -567,11 +575,11 @@ privcmd_map_obj(struct vm_map *map, vaddr_t start, paddr_t *maddr,
printf("uvm_map_checkprot 0x%lx -> 0x%lx "
"failed\n",
start, (unsigned long)(start + size - 1));
vm_map_unlock(map);
vm_map_unlock_read(map);
kmem_free(maddr, sizeof(paddr_t) * npages);
return EINVAL;
}
vm_map_unlock(map);
vm_map_unlock_read(map);
/* remove current entries */
uvm_unmap1(map, start, start + size, 0);