diff options
Diffstat (limited to 'lib/libvmmapi')
-rw-r--r-- | lib/libvmmapi/vmmapi.c | 106 | ||||
-rw-r--r-- | lib/libvmmapi/vmmapi.h | 13 |
2 files changed, 119 insertions, 0 deletions
diff --git a/lib/libvmmapi/vmmapi.c b/lib/libvmmapi/vmmapi.c index 5e630f8..ba2904c 100644 --- a/lib/libvmmapi/vmmapi.c +++ b/lib/libvmmapi/vmmapi.c @@ -33,8 +33,10 @@ __FBSDID("$FreeBSD$"); #include <sys/sysctl.h> #include <sys/ioctl.h> #include <sys/mman.h> +#include <sys/_iovec.h> #include <machine/specialreg.h> +#include <machine/param.h> #include <stdio.h> #include <stdlib.h> @@ -937,3 +939,107 @@ vm_get_hpet_capabilities(struct vmctx *ctx, uint32_t *capabilities) *capabilities = cap.capabilities; return (error); } + +static int +gla2gpa(struct vmctx *ctx, int vcpu, struct vm_guest_paging *paging, + uint64_t gla, int prot, int *fault, uint64_t *gpa) +{ + struct vm_gla2gpa gg; + int error; + + bzero(&gg, sizeof(struct vm_gla2gpa)); + gg.vcpuid = vcpu; + gg.prot = prot; + gg.gla = gla; + gg.paging = *paging; + + error = ioctl(ctx->fd, VM_GLA2GPA, &gg); + if (error == 0) { + *fault = gg.fault; + *gpa = gg.gpa; + } + return (error); +} + +#ifndef min +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +int +vm_gla2gpa(struct vmctx *ctx, int vcpu, struct vm_guest_paging *paging, + uint64_t gla, size_t len, int prot, struct iovec *iov, int iovcnt) +{ + uint64_t gpa; + int error, fault, i, n, off; + + for (i = 0; i < iovcnt; i++) { + iov[i].iov_base = 0; + iov[i].iov_len = 0; + } + + while (len) { + assert(iovcnt > 0); + error = gla2gpa(ctx, vcpu, paging, gla, prot, &fault, &gpa); + if (error) + return (-1); + if (fault) + return (1); + + off = gpa & PAGE_MASK; + n = min(len, PAGE_SIZE - off); + + iov->iov_base = (void *)gpa; + iov->iov_len = n; + iov++; + iovcnt--; + + gla += n; + len -= n; + } + return (0); +} + +void +vm_copyin(struct vmctx *ctx, int vcpu, struct iovec *iov, void *vp, size_t len) +{ + const char *src; + char *dst; + uint64_t gpa; + size_t n; + + dst = vp; + while (len) { + assert(iov->iov_len); + gpa = (uint64_t)iov->iov_base; + n = min(len, iov->iov_len); + src = vm_map_gpa(ctx, gpa, n); + bcopy(src, dst, n); + + iov++; + dst += n; + len -= n; + } +} + +void +vm_copyout(struct vmctx *ctx, int vcpu, const void *vp, struct iovec *iov, + size_t len) +{ + const char *src; + char *dst; + uint64_t gpa; + size_t n; + + src = vp; + while (len) { + assert(iov->iov_len); + gpa = (uint64_t)iov->iov_base; + n = min(len, iov->iov_len); + dst = vm_map_gpa(ctx, gpa, n); + bcopy(src, dst, n); + + iov++; + src += n; + len -= n; + } +} diff --git a/lib/libvmmapi/vmmapi.h b/lib/libvmmapi/vmmapi.h index 88e9947..bab41da 100644 --- a/lib/libvmmapi/vmmapi.h +++ b/lib/libvmmapi/vmmapi.h @@ -29,6 +29,7 @@ #ifndef _VMMAPI_H_ #define _VMMAPI_H_ +struct iovec; struct vmctx; enum x2apic_state; @@ -109,6 +110,18 @@ int vm_set_x2apic_state(struct vmctx *ctx, int vcpu, enum x2apic_state s); int vm_get_hpet_capabilities(struct vmctx *ctx, uint32_t *capabilities); +/* + * Translate the GLA range [gla,gla+len) into GPA segments in 'iov'. + * The 'iovcnt' should be big enough to accomodate all GPA segments. + * Returns 0 on success, 1 on a guest fault condition and -1 otherwise. + */ +int vm_gla2gpa(struct vmctx *ctx, int vcpu, struct vm_guest_paging *paging, + uint64_t gla, size_t len, int prot, struct iovec *iov, int iovcnt); +void vm_copyin(struct vmctx *ctx, int vcpu, struct iovec *guest_iov, + void *host_dst, size_t len); +void vm_copyout(struct vmctx *ctx, int vcpu, const void *host_src, + struct iovec *guest_iov, size_t len); + /* Reset vcpu register state */ int vcpu_reset(struct vmctx *ctx, int vcpu); |