summaryrefslogtreecommitdiffstats
path: root/lib/libvmmapi
diff options
context:
space:
mode:
authorneel <neel@FreeBSD.org>2014-05-26 18:21:08 +0000
committerneel <neel@FreeBSD.org>2014-05-26 18:21:08 +0000
commit31a1b31ef24ac304045a63d17285a1a04c060152 (patch)
tree316c82162a97b1c9aca15282244c57611168efe6 /lib/libvmmapi
parent3f99e5891e97262c2542ce665b68b34a02613075 (diff)
downloadFreeBSD-src-31a1b31ef24ac304045a63d17285a1a04c060152.zip
FreeBSD-src-31a1b31ef24ac304045a63d17285a1a04c060152.tar.gz
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.
Diffstat (limited to 'lib/libvmmapi')
-rw-r--r--lib/libvmmapi/vmmapi.c76
-rw-r--r--lib/libvmmapi/vmmapi.h16
2 files changed, 60 insertions, 32 deletions
diff --git a/lib/libvmmapi/vmmapi.c b/lib/libvmmapi/vmmapi.c
index 45fffcf..ba2904c 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 cad41c8..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,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);
OpenPOWER on IntegriCloud