int kvm_vm_ioctl_enable_cap()

in kvm/x86.c [5821:5959]


int kvm_vm_ioctl_enable_cap(struct kvm *kvm,
			    struct kvm_enable_cap *cap)
{
	int r;

	if (cap->flags)
		return -EINVAL;

	switch (cap->cap) {
	case KVM_CAP_DISABLE_QUIRKS:
		kvm->arch.disabled_quirks = cap->args[0];
		r = 0;
		break;
	case KVM_CAP_SPLIT_IRQCHIP: {
		mutex_lock(&kvm->lock);
		r = -EINVAL;
		if (cap->args[0] > MAX_NR_RESERVED_IOAPIC_PINS)
			goto split_irqchip_unlock;
		r = -EEXIST;
		if (irqchip_in_kernel(kvm))
			goto split_irqchip_unlock;
		if (kvm->created_vcpus)
			goto split_irqchip_unlock;
		r = kvm_setup_empty_irq_routing(kvm);
		if (r)
			goto split_irqchip_unlock;
		/* Pairs with irqchip_in_kernel. */
		smp_wmb();
		kvm->arch.irqchip_mode = KVM_IRQCHIP_SPLIT;
		kvm->arch.nr_reserved_ioapic_pins = cap->args[0];
		kvm_request_apicv_update(kvm, true, APICV_INHIBIT_REASON_ABSENT);
		r = 0;
split_irqchip_unlock:
		mutex_unlock(&kvm->lock);
		break;
	}
	case KVM_CAP_X2APIC_API:
		r = -EINVAL;
		if (cap->args[0] & ~KVM_X2APIC_API_VALID_FLAGS)
			break;

		if (cap->args[0] & KVM_X2APIC_API_USE_32BIT_IDS)
			kvm->arch.x2apic_format = true;
		if (cap->args[0] & KVM_X2APIC_API_DISABLE_BROADCAST_QUIRK)
			kvm->arch.x2apic_broadcast_quirk_disabled = true;

		r = 0;
		break;
	case KVM_CAP_X86_DISABLE_EXITS:
		r = -EINVAL;
		if (cap->args[0] & ~KVM_X86_DISABLE_VALID_EXITS)
			break;

		if ((cap->args[0] & KVM_X86_DISABLE_EXITS_MWAIT) &&
			kvm_can_mwait_in_guest())
			kvm->arch.mwait_in_guest = true;
		if (cap->args[0] & KVM_X86_DISABLE_EXITS_HLT)
			kvm->arch.hlt_in_guest = true;
		if (cap->args[0] & KVM_X86_DISABLE_EXITS_PAUSE)
			kvm->arch.pause_in_guest = true;
		if (cap->args[0] & KVM_X86_DISABLE_EXITS_CSTATE)
			kvm->arch.cstate_in_guest = true;
		r = 0;
		break;
	case KVM_CAP_MSR_PLATFORM_INFO:
		kvm->arch.guest_can_read_msr_platform_info = cap->args[0];
		r = 0;
		break;
	case KVM_CAP_EXCEPTION_PAYLOAD:
		kvm->arch.exception_payload_enabled = cap->args[0];
		r = 0;
		break;
	case KVM_CAP_X86_USER_SPACE_MSR:
		kvm->arch.user_space_msr_mask = cap->args[0];
		r = 0;
		break;
	case KVM_CAP_X86_BUS_LOCK_EXIT:
		r = -EINVAL;
		if (cap->args[0] & ~KVM_BUS_LOCK_DETECTION_VALID_MODE)
			break;

		if ((cap->args[0] & KVM_BUS_LOCK_DETECTION_OFF) &&
		    (cap->args[0] & KVM_BUS_LOCK_DETECTION_EXIT))
			break;

		if (kvm_has_bus_lock_exit &&
		    cap->args[0] & KVM_BUS_LOCK_DETECTION_EXIT)
			kvm->arch.bus_lock_detection_enabled = true;
		r = 0;
		break;
#ifdef CONFIG_X86_SGX_KVM
	case KVM_CAP_SGX_ATTRIBUTE: {
		unsigned long allowed_attributes = 0;

		r = sgx_set_attribute(&allowed_attributes, cap->args[0]);
		if (r)
			break;

		/* KVM only supports the PROVISIONKEY privileged attribute. */
		if ((allowed_attributes & SGX_ATTR_PROVISIONKEY) &&
		    !(allowed_attributes & ~SGX_ATTR_PROVISIONKEY))
			kvm->arch.sgx_provisioning_allowed = true;
		else
			r = -EINVAL;
		break;
	}
#endif
	case KVM_CAP_VM_COPY_ENC_CONTEXT_FROM:
		r = -EINVAL;
		if (kvm_x86_ops.vm_copy_enc_context_from)
			r = kvm_x86_ops.vm_copy_enc_context_from(kvm, cap->args[0]);
		return r;
	case KVM_CAP_VM_MOVE_ENC_CONTEXT_FROM:
		r = -EINVAL;
		if (kvm_x86_ops.vm_move_enc_context_from)
			r = kvm_x86_ops.vm_move_enc_context_from(
				kvm, cap->args[0]);
		return r;
	case KVM_CAP_EXIT_HYPERCALL:
		if (cap->args[0] & ~KVM_EXIT_HYPERCALL_VALID_MASK) {
			r = -EINVAL;
			break;
		}
		kvm->arch.hypercall_exit_enabled = cap->args[0];
		r = 0;
		break;
	case KVM_CAP_EXIT_ON_EMULATION_FAILURE:
		r = -EINVAL;
		if (cap->args[0] & ~1)
			break;
		kvm->arch.exit_on_emulation_error = cap->args[0];
		r = 0;
		break;
	default:
		r = -EINVAL;
		break;
	}
	return r;
}