return r;
 }
 
+static int handle_encls_einit(struct kvm_vcpu *vcpu)
+{
+       unsigned long sig_hva, secs_hva, token_hva, rflags;
+       struct vcpu_vmx *vmx = to_vmx(vcpu);
+       gva_t sig_gva, secs_gva, token_gva;
+       gpa_t sig_gpa, secs_gpa, token_gpa;
+       int ret, trapnr;
+
+       if (sgx_get_encls_gva(vcpu, kvm_rbx_read(vcpu), 1808, 4096, &sig_gva) ||
+           sgx_get_encls_gva(vcpu, kvm_rcx_read(vcpu), 4096, 4096, &secs_gva) ||
+           sgx_get_encls_gva(vcpu, kvm_rdx_read(vcpu), 304, 512, &token_gva))
+               return 1;
+
+       /*
+        * Translate the SIGSTRUCT, SECS and TOKEN pointers from GVA to GPA.
+        * Resume the guest on failure to inject a #PF.
+        */
+       if (sgx_gva_to_gpa(vcpu, sig_gva, false, &sig_gpa) ||
+           sgx_gva_to_gpa(vcpu, secs_gva, true, &secs_gpa) ||
+           sgx_gva_to_gpa(vcpu, token_gva, false, &token_gpa))
+               return 1;
+
+       /*
+        * ...and then to HVA.  The order of accesses isn't architectural, i.e.
+        * KVM doesn't have to fully process one address at a time.  Exit to
+        * userspace if a GPA is invalid.  Note, all structures are aligned and
+        * cannot split pages.
+        */
+       if (sgx_gpa_to_hva(vcpu, sig_gpa, &sig_hva) ||
+           sgx_gpa_to_hva(vcpu, secs_gpa, &secs_hva) ||
+           sgx_gpa_to_hva(vcpu, token_gpa, &token_hva))
+               return 0;
+
+       ret = sgx_virt_einit((void __user *)sig_hva, (void __user *)token_hva,
+                            (void __user *)secs_hva,
+                            vmx->msr_ia32_sgxlepubkeyhash, &trapnr);
+
+       if (ret == -EFAULT)
+               return sgx_inject_fault(vcpu, secs_gva, trapnr);
+
+       /*
+        * sgx_virt_einit() returns -EINVAL when access_ok() fails on @sig_hva,
+        * @token_hva or @secs_hva. This should never happen as KVM checks host
+        * addresses at memslot creation. sgx_virt_einit() has already warned
+        * in this case, so just return.
+        */
+       if (ret < 0)
+               return ret;
+
+       rflags = vmx_get_rflags(vcpu) & ~(X86_EFLAGS_CF | X86_EFLAGS_PF |
+                                         X86_EFLAGS_AF | X86_EFLAGS_SF |
+                                         X86_EFLAGS_OF);
+       if (ret)
+               rflags |= X86_EFLAGS_ZF;
+       else
+               rflags &= ~X86_EFLAGS_ZF;
+       vmx_set_rflags(vcpu, rflags);
+
+       kvm_rax_write(vcpu, ret);
+       return kvm_skip_emulated_instruction(vcpu);
+}
+
 static inline bool encls_leaf_enabled_in_guest(struct kvm_vcpu *vcpu, u32 leaf)
 {
        if (!enable_sgx || !guest_cpuid_has(vcpu, X86_FEATURE_SGX))
        } else {
                if (leaf == ECREATE)
                        return handle_encls_ecreate(vcpu);
+               if (leaf == EINIT)
+                       return handle_encls_einit(vcpu);
                WARN(1, "KVM: unexpected exit on ENCLS[%u]", leaf);
                vcpu->run->exit_reason = KVM_EXIT_UNKNOWN;
                vcpu->run->hw.hardware_exit_reason = EXIT_REASON_ENCLS;