diff options
author | Neel Natu <neel@FreeBSD.org> | 2014-05-26 18:21:08 +0000 |
---|---|---|
committer | Neel Natu <neel@FreeBSD.org> | 2014-05-26 18:21:08 +0000 |
commit | 6303b65d355a1d40a1b7a6de3f4988f9f8ee1723 (patch) | |
tree | 316c82162a97b1c9aca15282244c57611168efe6 /lib/libvmmapi | |
parent | 4eb12144c05517b36ad17b2bcfe231ce1439443e (diff) | |
download | src-6303b65d355a1d40a1b7a6de3f4988f9f8ee1723.tar.gz src-6303b65d355a1d40a1b7a6de3f4988f9f8ee1723.zip |
Fix issue with restarting an "insb/insw/insl" instruction because of a page
fault on the destination buffer.
Prior to this change a page fault would be detected in vm_copyout(). This
was done after the I/O port access was done. If the I/O port access had
side-effects (e.g. reading the uart FIFO) then restarting the instruction
would result in incorrect behavior.
Fix this by validating the guest linear address before doing the I/O port
emulation. If the validation results in a page fault exception being injected
into the guest then the instruction can now be restarted without any
side-effects.
Notes
Notes:
svn path=/head/; revision=266708
Diffstat (limited to 'lib/libvmmapi')
-rw-r--r-- | lib/libvmmapi/vmmapi.c | 76 | ||||
-rw-r--r-- | lib/libvmmapi/vmmapi.h | 16 |
2 files changed, 60 insertions, 32 deletions
diff --git a/lib/libvmmapi/vmmapi.c b/lib/libvmmapi/vmmapi.c index 45fffcf4827a..ba2904c68856 100644 --- a/lib/libvmmapi/vmmapi.c +++ b/lib/libvmmapi/vmmapi.c @@ -33,6 +33,7 @@ __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> @@ -940,7 +941,7 @@ vm_get_hpet_capabilities(struct vmctx *ctx, uint32_t *capabilities) } static int -vm_gla2gpa(struct vmctx *ctx, int vcpu, struct vm_guest_paging *paging, +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; @@ -965,18 +966,20 @@ vm_gla2gpa(struct vmctx *ctx, int vcpu, struct vm_guest_paging *paging, #endif int -vm_copyin(struct vmctx *ctx, int vcpu, struct vm_guest_paging *paging, - uint64_t gla, void *vp, size_t len) +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) { - char *dst; - const char *src; uint64_t gpa; - int error, fault, n, off; + int error, fault, i, n, off; + + for (i = 0; i < iovcnt; i++) { + iov[i].iov_base = 0; + iov[i].iov_len = 0; + } - dst = vp; while (len) { - error = vm_gla2gpa(ctx, vcpu, paging, gla, PROT_READ, - &fault, &gpa); + assert(iovcnt > 0); + error = gla2gpa(ctx, vcpu, paging, gla, prot, &fault, &gpa); if (error) return (-1); if (fault) @@ -984,42 +987,59 @@ vm_copyin(struct vmctx *ctx, int vcpu, struct vm_guest_paging *paging, off = gpa & PAGE_MASK; n = min(len, PAGE_SIZE - off); - src = vm_map_gpa(ctx, gpa, n); - bcopy(src, dst, n); + + iov->iov_base = (void *)gpa; + iov->iov_len = n; + iov++; + iovcnt--; gla += n; - dst += n; len -= n; } return (0); } -int -vm_copyout(struct vmctx *ctx, int vcpu, struct vm_guest_paging *paging, - const void *vp, uint64_t gla, size_t len) +void +vm_copyin(struct vmctx *ctx, int vcpu, struct iovec *iov, void *vp, size_t len) { - uint64_t gpa; + 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; - int error, fault, n, off; + char *dst; + uint64_t gpa; + size_t n; src = vp; while (len) { - error = vm_gla2gpa(ctx, vcpu, paging, gla, PROT_WRITE, - &fault, &gpa); - if (error) - return (-1); - if (fault) - return (1); - - off = gpa & PAGE_MASK; - n = min(len, PAGE_SIZE - off); + 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); - gla += n; + iov++; src += n; len -= n; } - return (0); } diff --git a/lib/libvmmapi/vmmapi.h b/lib/libvmmapi/vmmapi.h index cad41c89ba0e..bab41da7a1a8 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,10 +110,17 @@ 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); -int vm_copyin(struct vmctx *ctx, int vcpu, struct vm_guest_paging *paging, - uint64_t gla_src, void *dst, size_t len); -int vm_copyout(struct vmctx *ctx, int vcpu, struct vm_guest_paging *paging, - const void *src, uint64_t gla_dst, size_t len); +/* + * 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); |