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
This commit is contained in:
John Baldwin 2018-02-26 19:19:05 +00:00
parent 85ebe1f1cf
commit 5f8754c077
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=330032
6 changed files with 88 additions and 17 deletions

View File

@ -1233,6 +1233,27 @@ vm_gla2gpa(struct vmctx *ctx, int vcpu, struct vm_guest_paging *paging,
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 };

View File

@ -113,6 +113,9 @@ void *vm_map_gpa(struct vmctx *ctx, vm_paddr_t gaddr, size_t len);
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);

View File

@ -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 \

View File

@ -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);
/*

View File

@ -375,6 +375,7 @@ vmmdev_ioctl(struct cdev *cdev, u_long cmd, caddr_t data, int fflag,
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 data, int fflag,
("%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);

View File

@ -1718,9 +1718,9 @@ ptp_hold(struct vm *vm, int vcpu, vm_paddr_t ptpphys, size_t len, void **cookie)
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 @@ vm_gla2gpa(struct vm *vm, int vcpuid, struct vm_guest_paging *paging,
* 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 @@ vm_gla2gpa(struct vm *vm, int vcpuid, struct vm_guest_paging *paging,
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 @@ vm_gla2gpa(struct vm *vm, int vcpuid, struct vm_guest_paging *paging,
* 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 @@ vm_gla2gpa(struct vm *vm, int vcpuid, struct vm_guest_paging *paging,
}
/* 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 @@ vm_gla2gpa(struct vm *vm, int vcpuid, struct vm_guest_paging *paging,
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 @@ vm_gla2gpa(struct vm *vm, int vcpuid, struct vm_guest_paging *paging,
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 @@ vm_gla2gpa(struct vm *vm, int vcpuid, struct vm_guest_paging *paging,
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 @@ vm_gla2gpa(struct vm *vm, int vcpuid, struct vm_guest_paging *paging,
}
/* 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;
}
@ -1905,6 +1915,24 @@ vm_gla2gpa(struct vm *vm, int vcpuid, struct vm_guest_paging *paging,
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
vmm_fetch_instruction(struct vm *vm, int vcpuid, struct vm_guest_paging *paging,
uint64_t rip, int inst_length, struct vie *vie, int *faultptr)