On Fri, Feb 07, 2020 at 04:20:16AM +0000, Adam Steen wrote:
> Hi
> 
> Please see the attached patch to add an 'IOCTL handler to sets the access
> protections of the ept'
> 
> vmd(8) does not make use of this change, but solo5, which uses vmm(4) as
> a backend hypervisor. The code calling 'VMM_IOC_MPROTECT_EPT' is
> available here https://github.com/Solo5/solo5/compare/master...adamsteen:wnox
> 
> there are changes to vmd too, but this is just to ensure completeness,
> if mprotect ept is called in the future, we would want the vm to be
> stopped if we get a protection fault.
> 
> I was unsure what todo if called with execute only permissions on a cpu that
> does not support it. I went with add read permissions and logging the
> fact, instead of returning EINVAL.
> 
> Cheers
> Adam
> 

I have been giving Adam feedback on this diff for a while. There are a few
minor comments below, but I think this is ok if someone wants to commit it after
the fixes below are incorporated.

-ml

> ? div
> Index: sys/arch/amd64/amd64/vmm.c
> ===================================================================
> RCS file: /cvs/src/sys/arch/amd64/amd64/vmm.c,v
> retrieving revision 1.258
> diff -u -p -u -p -r1.258 vmm.c
> --- sys/arch/amd64/amd64/vmm.c        31 Jan 2020 01:51:27 -0000      1.258
> +++ sys/arch/amd64/amd64/vmm.c        7 Feb 2020 03:15:16 -0000
> @@ -124,6 +124,7 @@ int vm_get_info(struct vm_info_params *)
>  int vm_resetcpu(struct vm_resetcpu_params *);
>  int vm_intr_pending(struct vm_intr_params *);
>  int vm_rwregs(struct vm_rwregs_params *, int);
> +int vm_mprotect_ept(struct vm_mprotect_ept_params *);
>  int vm_rwvmparams(struct vm_rwvmparams_params *, int);
>  int vm_find(uint32_t, struct vm **);
>  int vcpu_readregs_vmx(struct vcpu *, uint64_t, struct vcpu_reg_state *);
> @@ -186,6 +187,8 @@ int svm_fault_page(struct vcpu *, paddr_
>  int vmx_fault_page(struct vcpu *, paddr_t);
>  int vmx_handle_np_fault(struct vcpu *);
>  int svm_handle_np_fault(struct vcpu *);
> +int vmx_mprotect_ept(vm_map_t, paddr_t, paddr_t, int);
> +pt_entry_t *vmx_pmap_find_pte_ept(pmap_t, paddr_t);
>  int vmm_alloc_vpid(uint16_t *);
>  void vmm_free_vpid(uint16_t);
>  const char *vcpu_state_decode(u_int);
> @@ -493,6 +496,9 @@ vmmioctl(dev_t dev, u_long cmd, caddr_t 
>       case VMM_IOC_WRITEREGS:
>               ret = vm_rwregs((struct vm_rwregs_params *)data, 1);
>               break;
> +     case VMM_IOC_MPROTECT_EPT:
> +             ret = vm_mprotect_ept((struct vm_mprotect_ept_params *)data);
> +             break;
>       case VMM_IOC_READVMPARAMS:
>               ret = vm_rwvmparams((struct vm_rwvmparams_params *)data, 0);
>               break;
> @@ -531,6 +537,7 @@ pledge_ioctl_vmm(struct proc *p, long co
>       case VMM_IOC_INTR:
>       case VMM_IOC_READREGS:
>       case VMM_IOC_WRITEREGS:
> +     case VMM_IOC_MPROTECT_EPT:
>       case VMM_IOC_READVMPARAMS:
>       case VMM_IOC_WRITEVMPARAMS:
>               return (0);
> @@ -806,6 +813,288 @@ vm_rwregs(struct vm_rwregs_params *vrwp,
>  }
>  
>  /*
> + * vm_mprotect_ept
> + *
> + * IOCTL handler to sets the access protections of the ept
> + *
> + * Parameters:
> + *   vmep: decribes the memory for which the protect will be applied..
> + *
> + * Return values:
> + *  0: if successful
> + *  ENOENT: if the VM defined by 'vmep' cannot be found
> + *  EINVAL: if the sgpa or size is not page aligned, the prot is invalid,
> + *          size is too large (512GB), there is wraparound
> + *          (like start = 512GB-1 and end = 512GB-2),
> + *          the address specified is not within the vm's mem range
> + *          or the address lies inside reserved (MMIO) memory
> + */
> +int
> +vm_mprotect_ept(struct vm_mprotect_ept_params *vmep)
> +{
> +     struct vm *vm;
> +     struct vcpu *vcpu;
> +     vaddr_t sgpa;
> +     size_t size;
> +     vm_prot_t prot;
> +     uint64_t msr;
> +     int ret, memtype;
> +
> +     /* If not EPT or RVI, nothing to do here */
> +     if (!(vmm_softc->mode == VMM_MODE_EPT
> +         || vmm_softc->mode == VMM_MODE_RVI))
> +             return (0);
> +
> +     /* Find the desired VM */
> +     rw_enter_read(&vmm_softc->vm_lock);
> +     ret = vm_find(vmep->vmep_vm_id, &vm);
> +     rw_exit_read(&vmm_softc->vm_lock);
> +
> +     /* Not found? exit. */
> +     if (ret != 0) {
> +             DPRINTF("%s: vm id %u not found\n", __func__,
> +                 vmep->vmep_vm_id);
> +             return (ret);
> +     }
> +
> +     rw_enter_read(&vm->vm_vcpu_lock);
> +     SLIST_FOREACH(vcpu, &vm->vm_vcpu_list, vc_vcpu_link) {
> +             if (vcpu->vc_id == vmep->vmep_vcpu_id)
> +                     break;
> +     }
> +     rw_exit_read(&vm->vm_vcpu_lock);
> +
> +     if (vcpu == NULL) {
> +             DPRINTF("%s: vcpu id %u of vm %u not found\n", __func__,
> +                 vmep->vmep_vcpu_id, vmep->vmep_vm_id);
> +             return (ENOENT);
> +     }
> +
> +     if (vcpu->vc_state != VCPU_STATE_STOPPED) {
> +             DPRINTF("%s: mprotect_ept %u on vm %u attempted "
> +                 "while vcpu was in state %u (%s)\n", __func__,
> +                 vmep->vmep_vcpu_id, vmep->vmep_vm_id, vcpu->vc_state,
> +                 vcpu_state_decode(vcpu->vc_state));
> +
> +             return (EBUSY);
> +     }
> +
> +     /* Only proceed if the pmap is in the correct mode */
> +     KASSERT((vmm_softc->mode == VMM_MODE_EPT &&
> +         vm->vm_map->pmap->pm_type == PMAP_TYPE_EPT) ||
> +         (vmm_softc->mode == VMM_MODE_RVI &&
> +          vm->vm_map->pmap->pm_type == PMAP_TYPE_RVI));
> +
> +     sgpa = vmep->vmep_sgpa;
> +     size = vmep->vmep_size;
> +     prot = vmep->vmep_prot;
> +
> +     /* No W^X permissions */
> +     if ((prot & PROT_MASK) != prot &&
> +         (prot & (PROT_WRITE | PROT_EXEC)) == (PROT_WRITE | PROT_EXEC)) {
> +             DPRINTF("%s: No W^X permissions\n", __func__);
> +             return (EINVAL);
> +     }

I would probably reword this to "W+X permission requested".

> +
> +     /* No Write only permissions */
> +     if ((prot & (PROT_READ | PROT_WRITE | PROT_EXEC)) == PROT_WRITE) {
> +             DPRINTF("%s: No Write only permissions\n", __func__);
> +             return (EINVAL);
> +     }
> +
> +     /* No empty permissions */
> +     if (prot == 0) {
> +             DPRINTF("%s: No empty permissions\n", __func__);
> +             return (EINVAL);
> +     }
> +
> +     /* No execute only on EPT CPUs that don't have that capability */
> +     if (vmm_softc->mode == VMM_MODE_EPT) {
> +             msr = rdmsr(IA32_VMX_EPT_VPID_CAP);
> +             if (prot == PROT_EXEC && 
> +                 (msr & IA32_EPT_VPID_CAP_XO_TRANSLATIONS)) {
> +                     printf("%s: Execute only permissions unsupported,"
> +                        " adding read permission\n", __func__);
> +                     /* XXX should this return (EINVAL) */
> +
> +                     prot |= PROT_READ;
> +             }
> +     }
> +
> +     /* Must be page aligned */
> +     if ((sgpa & PAGE_MASK) || (size & PAGE_MASK) || size == 0)
> +             return (EINVAL);
> +
> +     /* size must be less then 512GB */
> +     if (size >= NBPD_L4)
> +             return (EINVAL);
> +     
> +     /* no wraparound */
> +     if (sgpa + size < sgpa)
> +             return (EINVAL);
> +
> +     /*
> +      * Specifying addresses within the PCI MMIO space is forbidden.
> +      * Disallow addresses that start inside the MMIO space:
> +      * [VMM_PCI_MMIO_BAR_BASE .. VMM_PCI_MMIO_BAR_END]
> +      */
> +     if (sgpa >= VMM_PCI_MMIO_BAR_BASE && sgpa <= VMM_PCI_MMIO_BAR_END)
> +             return (EINVAL);
> +
> +     /*
> +      * ... and disallow addresses that end inside the MMIO space:
> +      * (VMM_PCI_MMIO_BAR_BASE .. VMM_PCI_MMIO_BAR_END]
> +      */
> +     if (sgpa + size > VMM_PCI_MMIO_BAR_BASE &&
> +         sgpa + size <= VMM_PCI_MMIO_BAR_END)
> +             return (EINVAL);
> +
> +     memtype = vmm_get_guest_memtype(vm, sgpa);
> +     if (memtype == VMM_MEM_TYPE_UNKNOWN)
> +             return (EINVAL);
> +
> +     if (vmm_softc->mode == VMM_MODE_EPT)
> +             ret = vmx_mprotect_ept(vm->vm_map, sgpa, sgpa + size, prot);
> +     else if (vmm_softc->mode == VMM_MODE_RVI) {
> +             pmap_write_protect(vm->vm_map->pmap, sgpa, sgpa + size, prot);
> +             ret = 0;
> +     } else
> +             return (EINVAL);
> +
> +     return (ret);
> +}
> +
> +/*
> + * vmx_mprotect_ept
> + *
> + * apply the ept protections to the requested pages, faulting the page if

"faulting in"

> + * required.
> + */
> +int
> +vmx_mprotect_ept(vm_map_t vm_map, paddr_t sgpa, paddr_t egpa, int prot)
> +{
> +     struct vmx_invept_descriptor vid;
> +     pmap_t pmap;
> +     pt_entry_t *pte;
> +     paddr_t addr;
> +     int ret = 0;
> +
> +     pmap = vm_map->pmap;
> +
> +     for (addr = sgpa; addr < egpa; addr += PAGE_SIZE) {
> +             pte = vmx_pmap_find_pte_ept(pmap, addr);
> +             if (pte == NULL) {

if (pte & PG_V) == 0

> +                     ret = uvm_fault(vm_map, addr, VM_FAULT_INVALID,
> +                         PROT_READ | PROT_WRITE | PROT_EXEC);
> +                     if (ret)
> +                             printf("%s: uvm_fault returns %d, GPA=0x%llx\n",
> +                                 __func__, ret, (uint64_t)addr);
> +
> +                     pte = vmx_pmap_find_pte_ept(pmap, addr);
> +                     if (pte == NULL)
> +                             return EFAULT;
> +             }
> +
> +             if (prot & PROT_READ)
> +                     *pte |= EPT_R;
> +             else
> +                     *pte &= ~EPT_R;
> +
> +             if (prot & PROT_WRITE)
> +                     *pte |= EPT_W;
> +             else
> +                     *pte &= ~EPT_W;
> +
> +             if (prot & PROT_EXEC)
> +                     *pte |= EPT_X;
> +             else
> +                     *pte &= ~EPT_X;
> +     }
> +
> +     /*
> +      * SDM 3C: 28.3.3.4 Guidelines for Use of the INVEPT Instruction
> +      * the first bullet point seems to say we should call invept.
> +      *
> +      * Software should use the INVEPT instruction with the “single-context”
> +      * INVEPT type after making any of the following changes to an EPT
> +      * paging-structure entry (the INVEPT descriptor should contain an
> +      * EPTP value that references — directly or indirectly
> +      * — the modified EPT paging structure):
> +      * —   Changing any of the privilege bits 2:0 from 1 to 0.
> +      * */
> +     if (pmap->eptp != 0) {
> +             memset(&vid, 0, sizeof(vid));
> +             vid.vid_eptp = pmap->eptp;
> +             DPRINTF("%s: flushing EPT TLB for EPTP 0x%llx\n", __func__,
> +                 vid.vid_eptp);
> +             invept(IA32_VMX_INVEPT_SINGLE_CTX, &vid);
> +     }
> +
> +     return ret;
> +}

The previous block is not technically correct, but it's as good as it will
get until we get the larger "proper INVEPT" diff in that I have stashed in
one of my trees. For now, this is ok. The reason it's not correct as it does
not consider the case where the ioctl is being called on one CPU while the last
CPU to run the VM might be a different one - in that case, we need to send an
EPT flush IPI to the other cpu. Note that this problem exists in vmm(4) today
anyway, even without this diff. Another possible fix for the general problem
would be to flush the EPT TLB on each vmentry, but that would impact performance
in a negative way.

> +
> +/*
> + * vmx_pmap_find_pte_ept
> + *
> + * find the page table entry specified by addr in the pmap supplied.
> + */
> +pt_entry_t *
> +vmx_pmap_find_pte_ept(pmap_t pmap, paddr_t addr)
> +{
> +     int l4idx, l3idx, l2idx, l1idx;
> +     pd_entry_t *pd;
> +     paddr_t pdppa;
> +     pt_entry_t *ptes, *pte;
> +
> +     l4idx = (addr & L4_MASK) >> L4_SHIFT; /* PML4E idx */
> +     l3idx = (addr & L3_MASK) >> L3_SHIFT; /* PDPTE idx */
> +     l2idx = (addr & L2_MASK) >> L2_SHIFT; /* PDE idx */
> +     l1idx = (addr & L1_MASK) >> L1_SHIFT; /* PTE idx */
> +
> +     pd = (pd_entry_t *)pmap->pm_pdir;
> +     if (pd == NULL)
> +             return NULL;
> +
> +     /*
> +      * l4idx should always be 0 since we don't support more than 512GB
> +      * guest physical memory.
> +      */
> +     if (l4idx > 0)
> +             return NULL;
> +
> +     /*
> +      * l3idx should always be < MAXDSIZ/1GB because we don't support more
> +      * than MAXDSIZ guest phys mem.
> +      */
> +     if (l3idx >= MAXDSIZ / ((paddr_t)1024*1024*1024))

Spaces around *s

> +             return NULL;
> +
> +     pdppa = pd[l4idx] & PG_FRAME;
> +     if (pdppa == 0)
> +             return NULL;
> +
> +     ptes = (pt_entry_t *)PMAP_DIRECT_MAP(pdppa);
> +
> +     pdppa = ptes[l3idx] & PG_FRAME;
> +     if (pdppa == 0)
> +             return NULL;
> +
> +     ptes = (pt_entry_t *)PMAP_DIRECT_MAP(pdppa);
> +
> +     pdppa = ptes[l2idx] & PG_FRAME;
> +     if (pdppa == 0)
> +             return NULL;
> +
> +     ptes = (pt_entry_t *)PMAP_DIRECT_MAP(pdppa);
> +
> +     pte = &ptes[l1idx];
> +     if (*pte == 0)
> +             return NULL;
> +
> +     return pte;
> +}
> +
> +/*
>   * vm_find
>   *
>   * Function to find an existing VM by its identifier.
> @@ -5099,19 +5388,35 @@ vmx_get_exit_qualification(uint64_t *exi
>  int
>  vmx_get_guest_faulttype(void)
>  {
> -     uint64_t exit_qualification;
> +     uint64_t exit_qual;
>       uint64_t presentmask = IA32_VMX_EPT_FAULT_WAS_READABLE |
>           IA32_VMX_EPT_FAULT_WAS_WRITABLE | IA32_VMX_EPT_FAULT_WAS_EXECABLE;
> -     uint64_t protmask = IA32_VMX_EPT_FAULT_READ |
> -         IA32_VMX_EPT_FAULT_WRITE | IA32_VMX_EPT_FAULT_EXEC;
> +     vm_prot_t prot, was_prot;
>  
> -     if (vmx_get_exit_qualification(&exit_qualification))
> +     if (vmx_get_exit_qualification(&exit_qual))
>               return (-1);
>  
> -     if ((exit_qualification & presentmask) == 0)
> +     if ((exit_qual & presentmask) == 0)
>               return VM_FAULT_INVALID;
> -     if (exit_qualification & protmask)
> +
> +     was_prot = 0;
> +     if (exit_qual & IA32_VMX_EPT_FAULT_WAS_READABLE)
> +             was_prot |= PROT_READ;
> +     if (exit_qual & IA32_VMX_EPT_FAULT_WAS_WRITABLE)
> +             was_prot |= PROT_WRITE;
> +     if (exit_qual & IA32_VMX_EPT_FAULT_WAS_EXECABLE)
> +             was_prot |= PROT_EXEC;
> +
> +     if (exit_qual & IA32_VMX_EPT_FAULT_READ)
> +             prot = PROT_READ;
> +     else if (exit_qual & IA32_VMX_EPT_FAULT_WRITE)
> +             prot = PROT_WRITE;
> +     else if (exit_qual & IA32_VMX_EPT_FAULT_EXEC)
> +             prot = PROT_EXEC;
> +
> +     if ((was_prot & prot) == 0)
>               return VM_FAULT_PROTECT;
> +
>       return (-1);
>  }
>  
> @@ -5188,6 +5493,9 @@ svm_handle_np_fault(struct vcpu *vcpu)
>   *
>   * Request a new page to be faulted into the UVM map of the VM owning 'vcpu'
>   * at address 'gpa'.
> + *
> + * Returns EAGAIN to indication a protection fault, ie writing to a read only
> + * page.
>   */
>  int
>  vmx_fault_page(struct vcpu *vcpu, paddr_t gpa)
> @@ -5198,6 +5506,11 @@ vmx_fault_page(struct vcpu *vcpu, paddr_
>       if (fault_type == -1) {
>               printf("%s: invalid fault type\n", __func__);
>               return (EINVAL);
> +     }
> +
> +     if (fault_type == VM_FAULT_PROTECT) {
> +             vcpu->vc_exit.vee.vee_fault_type = VEE_FAULT_PROTECT;
> +             return (EAGAIN);
>       }
>  
>       ret = uvm_fault(vcpu->vc_parent->vm_map, gpa, fault_type,
> Index: sys/arch/amd64/include/specialreg.h
> ===================================================================
> RCS file: /cvs/src/sys/arch/amd64/include/specialreg.h,v
> retrieving revision 1.86
> diff -u -p -u -p -r1.86 specialreg.h
> --- sys/arch/amd64/include/specialreg.h       20 Dec 2019 07:49:31 -0000      
> 1.86
> +++ sys/arch/amd64/include/specialreg.h       7 Feb 2020 03:15:17 -0000
> @@ -954,9 +954,10 @@
>  #define IA32_VMX_TRUE_ENTRY_CTLS     0x490
>  #define IA32_VMX_VMFUNC                      0x491
>  
> -#define IA32_EPT_VPID_CAP_PAGE_WALK_4        (1ULL << 6)
> -#define IA32_EPT_VPID_CAP_WB         (1ULL << 14)
> -#define IA32_EPT_VPID_CAP_AD_BITS    (1ULL << 21)
> +#define IA32_EPT_VPID_CAP_XO_TRANSLATIONS    0x0
> +#define IA32_EPT_VPID_CAP_PAGE_WALK_4                (1ULL << 6)
> +#define IA32_EPT_VPID_CAP_WB                 (1ULL << 14)
> +#define IA32_EPT_VPID_CAP_AD_BITS            (1ULL << 21)
>  
>  #define IA32_EPT_PAGING_CACHE_TYPE_UC        0x0
>  #define IA32_EPT_PAGING_CACHE_TYPE_WB        0x6
> Index: sys/arch/amd64/include/vmmvar.h
> ===================================================================
> RCS file: /cvs/src/sys/arch/amd64/include/vmmvar.h,v
> retrieving revision 1.68
> diff -u -p -u -p -r1.68 vmmvar.h
> --- sys/arch/amd64/include/vmmvar.h   22 Jan 2020 03:29:58 -0000      1.68
> +++ sys/arch/amd64/include/vmmvar.h   7 Feb 2020 03:15:17 -0000
> @@ -322,6 +322,10 @@ enum {
>  };
>  
>  enum {
> +     VEE_FAULT_PROTECT
> +};
> +
> +enum {
>       VMM_CPU_MODE_REAL,
>       VMM_CPU_MODE_PROT,
>       VMM_CPU_MODE_PROT32,
> @@ -350,6 +354,12 @@ struct vm_exit_inout {
>       uint16_t                vei_port;       /* port */
>       uint32_t                vei_data;       /* data */
>  };
> +/*
> + *  vm_exit_eptviolation     : describes an EPT VIOLATION exit
> + */
> +struct vm_exit_eptviolation {
> +     uint8_t         vee_fault_type;
> +};
>  
>  /*
>   * struct vcpu_segment_info
> @@ -447,7 +457,8 @@ struct vm_mem_range {
>   */
>  struct vm_exit {
>       union {
> -             struct vm_exit_inout    vei;            /* IN/OUT exit */
> +             struct vm_exit_inout            vei;    /* IN/OUT exit */
> +             struct vm_exit_eptviolation     vee;    /* EPT VIOLATION exit*/
>       };
>  
>       struct vcpu_reg_state           vrs;
> @@ -558,6 +569,15 @@ struct vm_rwregs_params {
>       struct vcpu_reg_state   vrwp_regs;
>  };
>  
> +struct vm_mprotect_ept_params {
> +     /* Input parameters to VMM_IOC_MPROTECT_EPT */
> +     uint32_t                vmep_vm_id;
> +     uint32_t                vmep_vcpu_id;
> +     vaddr_t                 vmep_sgpa;
> +     size_t                  vmep_size;
> +     int                     vmep_prot;
> +};
> +
>  /* IOCTL definitions */
>  #define VMM_IOC_CREATE _IOWR('V', 1, struct vm_create_params) /* Create VM */
>  #define VMM_IOC_RUN _IOWR('V', 2, struct vm_run_params) /* Run VCPU */
> @@ -571,7 +591,8 @@ struct vm_rwregs_params {
>  #define VMM_IOC_READVMPARAMS _IOWR('V', 9, struct vm_rwvmparams_params)
>  /* Set VM params */
>  #define VMM_IOC_WRITEVMPARAMS _IOW('V', 10, struct vm_rwvmparams_params)
> -
> +/* Control the protection of ept pages*/
> +#define VMM_IOC_MPROTECT_EPT _IOW('V', 11, struct vm_mprotect_ept_params)
>  
>  /* CPUID masks */
>  /*
> Index: usr.sbin/vmd/vm.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/vmd/vm.c,v
> retrieving revision 1.54
> diff -u -p -u -p -r1.54 vm.c
> --- usr.sbin/vmd/vm.c 11 Dec 2019 06:45:16 -0000      1.54
> +++ usr.sbin/vmd/vm.c 7 Feb 2020 03:15:23 -0000
> @@ -81,6 +81,7 @@ void init_emulated_hw(struct vmop_create
>  void restore_emulated_hw(struct vm_create_params *, int, int *,
>      int[][VM_MAX_BASE_PER_DISK],int);
>  void vcpu_exit_inout(struct vm_run_params *);
> +int vcpu_exit_eptviolation(struct vm_run_params *);
>  uint8_t vcpu_exit_pci(struct vm_run_params *);
>  int vcpu_pic_intr(uint32_t, uint32_t, uint8_t);
>  int loadfile_bios(FILE *, struct vcpu_reg_state *);
> @@ -1600,6 +1601,38 @@ vcpu_exit_inout(struct vm_run_params *vr
>  }
>  
>  /*
> + * vcpu_exit_eptviolation
> + *
> + * handle an EPT Violation
> + *
> + *
> + * Parameters:
> + *  vrp: vcpu run parameters containing guest state for this exit
> + *
> + * Return values:
> + *  0: no action required
> + *  EAGAIN: a protection fault occured, kill the vm.
> + */
> +int
> +vcpu_exit_eptviolation(struct vm_run_params *vrp)
> +{
> +     struct vm_exit *ve = vrp->vrp_exit;
> +     /*
> +      * vmd may be exiting to vmd to handle a pending interrupt
> +      * but last exit type may have bee VMX_EXIT_EPT_VIOLATION,
> +      * check the fault_type to ensure we really are processing
> +      * a VMX_EXIT_EPT_VIOLATION.
> +      */
> +     if (ve->vee.vee_fault_type == VEE_FAULT_PROTECT) {
> +             log_debug("%s: EPT Violation: rip=0x%llx",
> +                 __progname, vrp->vrp_exit->vrs.vrs_gprs[VCPU_REGS_RIP]);
> +             return (EAGAIN);
> +     }
> +
> +     return (0);
> +}
> +
> +/*
>   * vcpu_exit
>   *
>   * Handle a vcpu exit. This function is called when it is determined that
> @@ -1629,7 +1662,6 @@ vcpu_exit(struct vm_run_params *vrp)
>       case VMX_EXIT_CPUID:
>       case VMX_EXIT_EXTINT:
>       case SVM_VMEXIT_INTR:
> -     case VMX_EXIT_EPT_VIOLATION:
>       case SVM_VMEXIT_NPF:
>       case SVM_VMEXIT_MSR:
>       case SVM_VMEXIT_CPUID:
> @@ -1640,6 +1672,12 @@ vcpu_exit(struct vm_run_params *vrp)
>                * here (and falling through to the default case below results
>                * in more vmd log spam).
>                */
> +             break;
> +     case VMX_EXIT_EPT_VIOLATION:
> +             ret = vcpu_exit_eptviolation(vrp);
> +             if (ret)
> +                     return (ret);
> +
>               break;
>       case VMX_EXIT_IO:
>       case SVM_VMEXIT_IOIO:
> 

Reply via email to