svn commit: r330032 - in head: lib/libvmmapi sys/amd64/include sys/amd64/vmm
John Baldwin
jhb at FreeBSD.org
Mon Feb 26 19:19:06 UTC 2018
Author: jhb
Date: Mon Feb 26 19:19:05 2018
New Revision: 330032
URL: https://svnweb.freebsd.org/changeset/base/330032
Log:
Add a new variant of the GLA2GPA ioctl for use by the debug server.
Unlike the existing GLA2GPA ioctl, GLA2GPA_NOFAULT does not modify
the guest. In particular, it does not inject any faults or modify
PTEs in the guest when performing an address space translation.
This is used by bhyve's debug server to read and write memory for
the remote debugger.
Reviewed by: grehan
MFC after: 1 month
Differential Revision: https://reviews.freebsd.org/D14075
Modified:
head/lib/libvmmapi/vmmapi.c
head/lib/libvmmapi/vmmapi.h
head/sys/amd64/include/vmm_dev.h
head/sys/amd64/include/vmm_instruction_emul.h
head/sys/amd64/vmm/vmm_dev.c
head/sys/amd64/vmm/vmm_instruction_emul.c
Modified: head/lib/libvmmapi/vmmapi.c
==============================================================================
--- head/lib/libvmmapi/vmmapi.c Mon Feb 26 19:08:27 2018 (r330031)
+++ head/lib/libvmmapi/vmmapi.c Mon Feb 26 19:19:05 2018 (r330032)
@@ -1233,6 +1233,27 @@ vm_gla2gpa(struct vmctx *ctx, int vcpu, struct vm_gues
return (error);
}
+int
+vm_gla2gpa_nofault(struct vmctx *ctx, int vcpu, struct vm_guest_paging *paging,
+ uint64_t gla, int prot, uint64_t *gpa, int *fault)
+{
+ 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_NOFAULT, &gg);
+ if (error == 0) {
+ *fault = gg.fault;
+ *gpa = gg.gpa;
+ }
+ return (error);
+}
+
#ifndef min
#define min(a,b) (((a) < (b)) ? (a) : (b))
#endif
@@ -1479,6 +1500,7 @@ vm_get_ioctls(size_t *len)
VM_PPTDEV_MSIX, VM_INJECT_NMI, VM_STATS, VM_STAT_DESC,
VM_SET_X2APIC_STATE, VM_GET_X2APIC_STATE,
VM_GET_HPET_CAPABILITIES, VM_GET_GPA_PMAP, VM_GLA2GPA,
+ VM_GLA2GPA_NOFAULT,
VM_ACTIVATE_CPU, VM_GET_CPUS, VM_SET_INTINFO, VM_GET_INTINFO,
VM_RTC_WRITE, VM_RTC_READ, VM_RTC_SETTIME, VM_RTC_GETTIME,
VM_RESTART_INSTRUCTION };
Modified: head/lib/libvmmapi/vmmapi.h
==============================================================================
--- head/lib/libvmmapi/vmmapi.h Mon Feb 26 19:08:27 2018 (r330031)
+++ head/lib/libvmmapi/vmmapi.h Mon Feb 26 19:19:05 2018 (r330032)
@@ -113,6 +113,9 @@ void *vm_map_gpa(struct vmctx *ctx, vm_paddr_t gaddr,
int vm_get_gpa_pmap(struct vmctx *, uint64_t gpa, uint64_t *pte, int *num);
int vm_gla2gpa(struct vmctx *, int vcpuid, struct vm_guest_paging *paging,
uint64_t gla, int prot, uint64_t *gpa, int *fault);
+int vm_gla2gpa_nofault(struct vmctx *, int vcpuid,
+ struct vm_guest_paging *paging, uint64_t gla, int prot,
+ uint64_t *gpa, int *fault);
uint32_t vm_get_lowmem_limit(struct vmctx *ctx);
void vm_set_lowmem_limit(struct vmctx *ctx, uint32_t limit);
void vm_set_memflags(struct vmctx *ctx, int flags);
Modified: head/sys/amd64/include/vmm_dev.h
==============================================================================
--- head/sys/amd64/include/vmm_dev.h Mon Feb 26 19:08:27 2018 (r330031)
+++ head/sys/amd64/include/vmm_dev.h Mon Feb 26 19:19:05 2018 (r330032)
@@ -243,6 +243,7 @@ enum {
IOCNUM_GET_MEMSEG = 15,
IOCNUM_MMAP_MEMSEG = 16,
IOCNUM_MMAP_GETNEXT = 17,
+ IOCNUM_GLA2GPA_NOFAULT = 18,
/* register/state accessors */
IOCNUM_SET_REGISTER = 20,
@@ -379,6 +380,8 @@ enum {
_IOWR('v', IOCNUM_GET_GPA_PMAP, struct vm_gpa_pte)
#define VM_GLA2GPA \
_IOWR('v', IOCNUM_GLA2GPA, struct vm_gla2gpa)
+#define VM_GLA2GPA_NOFAULT \
+ _IOWR('v', IOCNUM_GLA2GPA_NOFAULT, struct vm_gla2gpa)
#define VM_ACTIVATE_CPU \
_IOW('v', IOCNUM_ACTIVATE_CPU, struct vm_activate_cpu)
#define VM_GET_CPUS \
Modified: head/sys/amd64/include/vmm_instruction_emul.h
==============================================================================
--- head/sys/amd64/include/vmm_instruction_emul.h Mon Feb 26 19:08:27 2018 (r330031)
+++ head/sys/amd64/include/vmm_instruction_emul.h Mon Feb 26 19:19:05 2018 (r330032)
@@ -97,6 +97,13 @@ int vmm_fetch_instruction(struct vm *vm, int cpuid,
int vm_gla2gpa(struct vm *vm, int vcpuid, struct vm_guest_paging *paging,
uint64_t gla, int prot, uint64_t *gpa, int *is_fault);
+/*
+ * Like vm_gla2gpa, but no exceptions are injected into the guest and
+ * PTEs are not changed.
+ */
+int vm_gla2gpa_nofault(struct vm *vm, int vcpuid, struct vm_guest_paging *paging,
+ uint64_t gla, int prot, uint64_t *gpa, int *is_fault);
+
void vie_init(struct vie *vie, const char *inst_bytes, int inst_length);
/*
Modified: head/sys/amd64/vmm/vmm_dev.c
==============================================================================
--- head/sys/amd64/vmm/vmm_dev.c Mon Feb 26 19:08:27 2018 (r330031)
+++ head/sys/amd64/vmm/vmm_dev.c Mon Feb 26 19:19:05 2018 (r330032)
@@ -375,6 +375,7 @@ vmmdev_ioctl(struct cdev *cdev, u_long cmd, caddr_t da
case VM_PPTDEV_MSIX:
case VM_SET_X2APIC_STATE:
case VM_GLA2GPA:
+ case VM_GLA2GPA_NOFAULT:
case VM_ACTIVATE_CPU:
case VM_SET_INTINFO:
case VM_GET_INTINFO:
@@ -665,6 +666,13 @@ vmmdev_ioctl(struct cdev *cdev, u_long cmd, caddr_t da
("%s: vm_gla2gpa unknown error %d", __func__, error));
break;
}
+ case VM_GLA2GPA_NOFAULT:
+ gg = (struct vm_gla2gpa *)data;
+ error = vm_gla2gpa_nofault(sc->vm, gg->vcpuid, &gg->paging,
+ gg->gla, gg->prot, &gg->gpa, &gg->fault);
+ KASSERT(error == 0 || error == EFAULT,
+ ("%s: vm_gla2gpa unknown error %d", __func__, error));
+ break;
case VM_ACTIVATE_CPU:
vac = (struct vm_activate_cpu *)data;
error = vm_activate_cpu(sc->vm, vac->vcpuid);
Modified: head/sys/amd64/vmm/vmm_instruction_emul.c
==============================================================================
--- head/sys/amd64/vmm/vmm_instruction_emul.c Mon Feb 26 19:08:27 2018 (r330031)
+++ head/sys/amd64/vmm/vmm_instruction_emul.c Mon Feb 26 19:19:05 2018 (r330032)
@@ -1718,9 +1718,9 @@ ptp_hold(struct vm *vm, int vcpu, vm_paddr_t ptpphys,
return (ptr);
}
-int
-vm_gla2gpa(struct vm *vm, int vcpuid, struct vm_guest_paging *paging,
- uint64_t gla, int prot, uint64_t *gpa, int *guest_fault)
+static int
+_vm_gla2gpa(struct vm *vm, int vcpuid, struct vm_guest_paging *paging,
+ uint64_t gla, int prot, uint64_t *gpa, int *guest_fault, bool check_only)
{
int nlevels, pfcode, ptpshift, ptpindex, retval, usermode, writable;
u_int retries;
@@ -1746,7 +1746,8 @@ restart:
* XXX assuming a non-stack reference otherwise a stack fault
* should be generated.
*/
- vm_inject_gp(vm, vcpuid);
+ if (!check_only)
+ vm_inject_gp(vm, vcpuid);
goto fault;
}
@@ -1776,9 +1777,11 @@ restart:
if ((pte32 & PG_V) == 0 ||
(usermode && (pte32 & PG_U) == 0) ||
(writable && (pte32 & PG_RW) == 0)) {
- pfcode = pf_error_code(usermode, prot, 0,
- pte32);
- vm_inject_pf(vm, vcpuid, pfcode, gla);
+ if (!check_only) {
+ pfcode = pf_error_code(usermode, prot, 0,
+ pte32);
+ vm_inject_pf(vm, vcpuid, pfcode, gla);
+ }
goto fault;
}
@@ -1789,7 +1792,7 @@ restart:
* is only set at the last level providing the guest
* physical address.
*/
- if ((pte32 & PG_A) == 0) {
+ if (!check_only && (pte32 & PG_A) == 0) {
if (atomic_cmpset_32(&ptpbase32[ptpindex],
pte32, pte32 | PG_A) == 0) {
goto restart;
@@ -1804,7 +1807,7 @@ restart:
}
/* Set the dirty bit in the page table entry if necessary */
- if (writable && (pte32 & PG_M) == 0) {
+ if (!check_only && writable && (pte32 & PG_M) == 0) {
if (atomic_cmpset_32(&ptpbase32[ptpindex],
pte32, pte32 | PG_M) == 0) {
goto restart;
@@ -1831,8 +1834,10 @@ restart:
pte = ptpbase[ptpindex];
if ((pte & PG_V) == 0) {
- pfcode = pf_error_code(usermode, prot, 0, pte);
- vm_inject_pf(vm, vcpuid, pfcode, gla);
+ if (!check_only) {
+ pfcode = pf_error_code(usermode, prot, 0, pte);
+ vm_inject_pf(vm, vcpuid, pfcode, gla);
+ }
goto fault;
}
@@ -1858,13 +1863,15 @@ restart:
if ((pte & PG_V) == 0 ||
(usermode && (pte & PG_U) == 0) ||
(writable && (pte & PG_RW) == 0)) {
- pfcode = pf_error_code(usermode, prot, 0, pte);
- vm_inject_pf(vm, vcpuid, pfcode, gla);
+ if (!check_only) {
+ pfcode = pf_error_code(usermode, prot, 0, pte);
+ vm_inject_pf(vm, vcpuid, pfcode, gla);
+ }
goto fault;
}
/* Set the accessed bit in the page table entry */
- if ((pte & PG_A) == 0) {
+ if (!check_only && (pte & PG_A) == 0) {
if (atomic_cmpset_64(&ptpbase[ptpindex],
pte, pte | PG_A) == 0) {
goto restart;
@@ -1873,8 +1880,11 @@ restart:
if (nlevels > 0 && (pte & PG_PS) != 0) {
if (pgsize > 1 * GB) {
- pfcode = pf_error_code(usermode, prot, 1, pte);
- vm_inject_pf(vm, vcpuid, pfcode, gla);
+ if (!check_only) {
+ pfcode = pf_error_code(usermode, prot, 1,
+ pte);
+ vm_inject_pf(vm, vcpuid, pfcode, gla);
+ }
goto fault;
}
break;
@@ -1884,7 +1894,7 @@ restart:
}
/* Set the dirty bit in the page table entry if necessary */
- if (writable && (pte & PG_M) == 0) {
+ if (!check_only && writable && (pte & PG_M) == 0) {
if (atomic_cmpset_64(&ptpbase[ptpindex], pte, pte | PG_M) == 0)
goto restart;
}
@@ -1903,6 +1913,24 @@ error:
fault:
*guest_fault = 1;
goto done;
+}
+
+int
+vm_gla2gpa(struct vm *vm, int vcpuid, struct vm_guest_paging *paging,
+ uint64_t gla, int prot, uint64_t *gpa, int *guest_fault)
+{
+
+ return (_vm_gla2gpa(vm, vcpuid, paging, gla, prot, gpa, guest_fault,
+ false));
+}
+
+int
+vm_gla2gpa_nofault(struct vm *vm, int vcpuid, struct vm_guest_paging *paging,
+ uint64_t gla, int prot, uint64_t *gpa, int *guest_fault)
+{
+
+ return (_vm_gla2gpa(vm, vcpuid, paging, gla, prot, gpa, guest_fault,
+ true));
}
int
More information about the svn-src-all
mailing list