int kvm_handle_invpcid(struct kvm_vcpu *vcpu, unsigned long type, gva_t gva)
{
	bool pcid_enabled;
	struct x86_exception e;
	struct {
		u64 pcid;
		u64 gla;
	} operand;
	int r;

	r = kvm_read_guest_virt(vcpu, gva, &operand, sizeof(operand), &e);
	if (r != X86EMUL_CONTINUE)
		return kvm_handle_memory_failure(vcpu, r, &e);

	if (operand.pcid >> 12 != 0) {
		kvm_inject_gp(vcpu, 0);
		return 1;
	}

	pcid_enabled = kvm_read_cr4_bits(vcpu, X86_CR4_PCIDE);

	switch (type) {
	case INVPCID_TYPE_INDIV_ADDR:
		if ((!pcid_enabled && (operand.pcid != 0)) ||
		    is_noncanonical_address(operand.gla, vcpu)) {
			kvm_inject_gp(vcpu, 0);
			return 1;
		}
		kvm_mmu_invpcid_gva(vcpu, operand.gla, operand.pcid);
		return kvm_skip_emulated_instruction(vcpu);

	case INVPCID_TYPE_SINGLE_CTXT:
		if (!pcid_enabled && (operand.pcid != 0)) {
			kvm_inject_gp(vcpu, 0);
			return 1;
		}

		kvm_invalidate_pcid(vcpu, operand.pcid);
		return kvm_skip_emulated_instruction(vcpu);

	case INVPCID_TYPE_ALL_NON_GLOBAL:
		/*
		 * Currently, KVM doesn't mark global entries in the shadow
		 * page tables, so a non-global flush just degenerates to a
		 * global flush. If needed, we could optimize this later by
		 * keeping track of global entries in shadow page tables.
		 */

		fallthrough;
	case INVPCID_TYPE_ALL_INCL_GLOBAL:
		kvm_make_request(KVM_REQ_TLB_FLUSH_GUEST, vcpu);
		return kvm_skip_emulated_instruction(vcpu);

	default:
		kvm_inject_gp(vcpu, 0);
		return 1;
	}
}
int kvm_handle_invpcid(struct kvm_vcpu *vcpu, unsigned long type, gva_t gva)
{
	bool pcid_enabled;
	struct x86_exception e;
	struct {
		u64 pcid;
		u64 gla;
	} operand;
	int r;

	r = kvm_read_guest_virt(vcpu, gva, &operand, sizeof(operand), &e);
	if (r != X86EMUL_CONTINUE)
		return kvm_handle_memory_failure(vcpu, r, &e);

	if (operand.pcid >> 12 != 0) {
		kvm_inject_gp(vcpu, 0);
		return 1;
	}

	pcid_enabled = kvm_read_cr4_bits(vcpu, X86_CR4_PCIDE);

	switch (type) {
	case INVPCID_TYPE_INDIV_ADDR:
		if ((!pcid_enabled && (operand.pcid != 0)) ||
		    is_noncanonical_address(operand.gla, vcpu)) {
			kvm_inject_gp(vcpu, 0);
			return 1;
		}
		kvm_mmu_invpcid_gva(vcpu, operand.gla, operand.pcid);
		return kvm_skip_emulated_instruction(vcpu);

	case INVPCID_TYPE_SINGLE_CTXT:
		if (!pcid_enabled && (operand.pcid != 0)) {
			kvm_inject_gp(vcpu, 0);
			return 1;
		}

		kvm_invalidate_pcid(vcpu, operand.pcid);
		return kvm_skip_emulated_instruction(vcpu);

	case INVPCID_TYPE_ALL_NON_GLOBAL:
		 

		fallthrough;
	case INVPCID_TYPE_ALL_INCL_GLOBAL:
		kvm_make_request(KVM_REQ_TLB_FLUSH_GUEST, vcpu);
		return kvm_skip_emulated_instruction(vcpu);

	default:
		kvm_inject_gp(vcpu, 0);
		return 1;
	}
}