Author: jhb
Date: Thu Feb 22 00:39:25 2018
New Revision: 329768
URL: https://svnweb.freebsd.org/changeset/base/329768

Log:
  Add two new ioctls to bhyve for batch register fetch/store operations.
  
  These are a convenience for bhyve's debug server to use a single
  ioctl for 'g' and 'G' rather than a loop of individual get/set
  ioctl requests.
  
  Reviewed by:  grehan
  MFC after:    2 months
  Differential Revision:        https://reviews.freebsd.org/D14074

Modified:
  head/lib/libvmmapi/vmmapi.c
  head/lib/libvmmapi/vmmapi.h
  head/sys/amd64/include/vmm_dev.h
  head/sys/amd64/vmm/vmm_dev.c

Modified: head/lib/libvmmapi/vmmapi.c
==============================================================================
--- head/lib/libvmmapi/vmmapi.c Thu Feb 22 00:36:12 2018        (r329767)
+++ head/lib/libvmmapi/vmmapi.c Thu Feb 22 00:39:25 2018        (r329768)
@@ -588,6 +588,40 @@ vm_get_register(struct vmctx *ctx, int vcpu, int reg, 
 }
 
 int
+vm_set_register_set(struct vmctx *ctx, int vcpu, unsigned int count,
+    const int *regnums, uint64_t *regvals)
+{
+       int error;
+       struct vm_register_set vmregset;
+
+       bzero(&vmregset, sizeof(vmregset));
+       vmregset.cpuid = vcpu;
+       vmregset.count = count;
+       vmregset.regnums = regnums;
+       vmregset.regvals = regvals;
+
+       error = ioctl(ctx->fd, VM_SET_REGISTER_SET, &vmregset);
+       return (error);
+}
+
+int
+vm_get_register_set(struct vmctx *ctx, int vcpu, unsigned int count,
+    const int *regnums, uint64_t *regvals)
+{
+       int error;
+       struct vm_register_set vmregset;
+
+       bzero(&vmregset, sizeof(vmregset));
+       vmregset.cpuid = vcpu;
+       vmregset.count = count;
+       vmregset.regnums = regnums;
+       vmregset.regvals = regvals;
+
+       error = ioctl(ctx->fd, VM_GET_REGISTER_SET, &vmregset);
+       return (error);
+}
+
+int
 vm_run(struct vmctx *ctx, int vcpu, struct vm_exit *vmexit)
 {
        int error;
@@ -1435,6 +1469,7 @@ vm_get_ioctls(size_t *len)
            VM_ALLOC_MEMSEG, VM_GET_MEMSEG, VM_MMAP_MEMSEG, VM_MMAP_MEMSEG,
            VM_MMAP_GETNEXT, VM_SET_REGISTER, VM_GET_REGISTER,
            VM_SET_SEGMENT_DESCRIPTOR, VM_GET_SEGMENT_DESCRIPTOR,
+           VM_SET_REGISTER_SET, VM_GET_REGISTER_SET,
            VM_INJECT_EXCEPTION, VM_LAPIC_IRQ, VM_LAPIC_LOCAL_IRQ,
            VM_LAPIC_MSI, VM_IOAPIC_ASSERT_IRQ, VM_IOAPIC_DEASSERT_IRQ,
            VM_IOAPIC_PULSE_IRQ, VM_IOAPIC_PINCOUNT, VM_ISA_ASSERT_IRQ,

Modified: head/lib/libvmmapi/vmmapi.h
==============================================================================
--- head/lib/libvmmapi/vmmapi.h Thu Feb 22 00:36:12 2018        (r329767)
+++ head/lib/libvmmapi/vmmapi.h Thu Feb 22 00:39:25 2018        (r329768)
@@ -127,6 +127,10 @@ int        vm_get_seg_desc(struct vmctx *ctx, int vcpu, 
int r
                        struct seg_desc *seg_desc);
 int    vm_set_register(struct vmctx *ctx, int vcpu, int reg, uint64_t val);
 int    vm_get_register(struct vmctx *ctx, int vcpu, int reg, uint64_t *retval);
+int    vm_set_register_set(struct vmctx *ctx, int vcpu, unsigned int count,
+    const int *regnums, uint64_t *regvals);
+int    vm_get_register_set(struct vmctx *ctx, int vcpu, unsigned int count,
+    const int *regnums, uint64_t *regvals);
 int    vm_run(struct vmctx *ctx, int vcpu, struct vm_exit *ret_vmexit);
 int    vm_suspend(struct vmctx *ctx, enum vm_suspend_how how);
 int    vm_reinit(struct vmctx *ctx);

Modified: head/sys/amd64/include/vmm_dev.h
==============================================================================
--- head/sys/amd64/include/vmm_dev.h    Thu Feb 22 00:36:12 2018        
(r329767)
+++ head/sys/amd64/include/vmm_dev.h    Thu Feb 22 00:39:25 2018        
(r329768)
@@ -66,6 +66,13 @@ struct vm_seg_desc {                 /* data or code segment 
*/
        struct seg_desc desc;
 };
 
+struct vm_register_set {
+       int             cpuid;
+       unsigned int    count;
+       const int       *regnums;       /* enum vm_reg_name */
+       uint64_t        *regvals;
+};
+
 struct vm_run {
        int             cpuid;
        struct vm_exit  vm_exit;
@@ -242,6 +249,8 @@ enum {
        IOCNUM_GET_REGISTER = 21,
        IOCNUM_SET_SEGMENT_DESCRIPTOR = 22,
        IOCNUM_GET_SEGMENT_DESCRIPTOR = 23,
+       IOCNUM_SET_REGISTER_SET = 24,
+       IOCNUM_GET_REGISTER_SET = 25,
 
        /* interrupt injection */
        IOCNUM_GET_INTINFO = 28,
@@ -312,6 +321,10 @@ enum {
        _IOW('v', IOCNUM_SET_SEGMENT_DESCRIPTOR, struct vm_seg_desc)
 #define        VM_GET_SEGMENT_DESCRIPTOR \
        _IOWR('v', IOCNUM_GET_SEGMENT_DESCRIPTOR, struct vm_seg_desc)
+#define        VM_SET_REGISTER_SET \
+       _IOW('v', IOCNUM_SET_REGISTER_SET, struct vm_register_set)
+#define        VM_GET_REGISTER_SET \
+       _IOWR('v', IOCNUM_GET_REGISTER_SET, struct vm_register_set)
 #define        VM_INJECT_EXCEPTION     \
        _IOW('v', IOCNUM_INJECT_EXCEPTION, struct vm_exception)
 #define        VM_LAPIC_IRQ            \

Modified: head/sys/amd64/vmm/vmm_dev.c
==============================================================================
--- head/sys/amd64/vmm/vmm_dev.c        Thu Feb 22 00:36:12 2018        
(r329767)
+++ head/sys/amd64/vmm/vmm_dev.c        Thu Feb 22 00:39:25 2018        
(r329768)
@@ -282,6 +282,36 @@ done:
 }
 
 static int
+vm_get_register_set(struct vm *vm, int vcpu, unsigned int count, int *regnum,
+    uint64_t *regval)
+{
+       int error, i;
+
+       error = 0;
+       for (i = 0; i < count; i++) {
+               error = vm_get_register(vm, vcpu, regnum[i], &regval[i]);
+               if (error)
+                       break;
+       }
+       return (error);
+}
+
+static int
+vm_set_register_set(struct vm *vm, int vcpu, unsigned int count, int *regnum,
+    uint64_t *regval)
+{
+       int error, i;
+
+       error = 0;
+       for (i = 0; i < count; i++) {
+               error = vm_set_register(vm, vcpu, regnum[i], regval[i]);
+               if (error)
+                       break;
+       }
+       return (error);
+}
+
+static int
 vmmdev_ioctl(struct cdev *cdev, u_long cmd, caddr_t data, int fflag,
             struct thread *td)
 {
@@ -290,6 +320,7 @@ vmmdev_ioctl(struct cdev *cdev, u_long cmd, caddr_t da
        struct vmmdev_softc *sc;
        struct vm_register *vmreg;
        struct vm_seg_desc *vmsegdesc;
+       struct vm_register_set *vmregset;
        struct vm_run *vmrun;
        struct vm_exception *vmexc;
        struct vm_lapic_irq *vmirq;
@@ -315,6 +346,8 @@ vmmdev_ioctl(struct cdev *cdev, u_long cmd, caddr_t da
        struct vm_rtc_time *rtctime;
        struct vm_rtc_data *rtcdata;
        struct vm_memmap *mm;
+       uint64_t *regvals;
+       int *regnums;
 
        sc = vmmdev_lookup2(cdev);
        if (sc == NULL)
@@ -333,6 +366,8 @@ vmmdev_ioctl(struct cdev *cdev, u_long cmd, caddr_t da
        case VM_SET_REGISTER:
        case VM_GET_SEGMENT_DESCRIPTOR:
        case VM_SET_SEGMENT_DESCRIPTOR:
+       case VM_GET_REGISTER_SET:
+       case VM_SET_REGISTER_SET:
        case VM_INJECT_EXCEPTION:
        case VM_GET_CAPABILITY:
        case VM_SET_CAPABILITY:
@@ -545,6 +580,48 @@ vmmdev_ioctl(struct cdev *cdev, u_long cmd, caddr_t da
                error = vm_get_seg_desc(sc->vm, vmsegdesc->cpuid,
                                        vmsegdesc->regnum,
                                        &vmsegdesc->desc);
+               break;
+       case VM_GET_REGISTER_SET:
+               vmregset = (struct vm_register_set *)data;
+               if (vmregset->count > VM_REG_LAST) {
+                       error = EINVAL;
+                       break;
+               }
+               regvals = malloc(sizeof(regvals[0]) * vmregset->count, M_VMMDEV,
+                   M_WAITOK);
+               regnums = malloc(sizeof(regnums[0]) * vmregset->count, M_VMMDEV,
+                   M_WAITOK);
+               error = copyin(vmregset->regnums, regnums, sizeof(regnums[0]) *
+                   vmregset->count);
+               if (error == 0)
+                       error = vm_get_register_set(sc->vm, vmregset->cpuid,
+                           vmregset->count, regnums, regvals);
+               if (error == 0)
+                       error = copyout(regvals, vmregset->regvals,
+                           sizeof(regvals[0]) * vmregset->count);
+               free(regvals, M_VMMDEV);
+               free(regnums, M_VMMDEV);
+               break;
+       case VM_SET_REGISTER_SET:
+               vmregset = (struct vm_register_set *)data;
+               if (vmregset->count > VM_REG_LAST) {
+                       error = EINVAL;
+                       break;
+               }
+               regvals = malloc(sizeof(regvals[0]) * vmregset->count, M_VMMDEV,
+                   M_WAITOK);
+               regnums = malloc(sizeof(regnums[0]) * vmregset->count, M_VMMDEV,
+                   M_WAITOK);
+               error = copyin(vmregset->regnums, regnums, sizeof(regnums[0]) *
+                   vmregset->count);
+               if (error == 0)
+                       error = copyin(vmregset->regvals, regvals,
+                           sizeof(regvals[0]) * vmregset->count);
+               if (error == 0)
+                       error = vm_set_register_set(sc->vm, vmregset->cpuid,
+                           vmregset->count, regnums, regvals);
+               free(regvals, M_VMMDEV);
+               free(regnums, M_VMMDEV);
                break;
        case VM_GET_CAPABILITY:
                vmcap = (struct vm_capability *)data;
_______________________________________________
[email protected] mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "[email protected]"

Reply via email to