Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1961d276 authored by Avi Kivity's avatar Avi Kivity
Browse files

KVM: Add guest mode signal mask



Allow a special signal mask to be used while executing in guest mode.  This
allows signals to be used to interrupt a vcpu without requiring signal
delivery to a userspace handler, which is quite expensive.  Userspace still
receives -EINTR and can get the signal via sigwait().

Signed-off-by: default avatarAvi Kivity <avi@qumranet.com>
parent 6722c51c
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -277,6 +277,9 @@ struct kvm_vcpu {
	gpa_t mmio_phys_addr;
	int pio_pending;

	int sigset_active;
	sigset_t sigset;

	struct {
		int active;
		u8 save_iopl;
+41 −0
Original line number Diff line number Diff line
@@ -1591,9 +1591,13 @@ static void complete_pio(struct kvm_vcpu *vcpu)
static int kvm_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
{
	int r;
	sigset_t sigsaved;

	vcpu_load(vcpu);

	if (vcpu->sigset_active)
		sigprocmask(SIG_SETMASK, &vcpu->sigset, &sigsaved);

	/* re-sync apic's tpr */
	vcpu->cr8 = kvm_run->cr8;

@@ -1616,6 +1620,9 @@ static int kvm_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)

	r = kvm_arch_ops->run(vcpu, kvm_run);

	if (vcpu->sigset_active)
		sigprocmask(SIG_SETMASK, &sigsaved, NULL);

	vcpu_put(vcpu);
	return r;
}
@@ -2142,6 +2149,17 @@ static int kvm_vcpu_ioctl_set_cpuid(struct kvm_vcpu *vcpu,
	return r;
}

static int kvm_vcpu_ioctl_set_sigmask(struct kvm_vcpu *vcpu, sigset_t *sigset)
{
	if (sigset) {
		sigdelsetmask(sigset, sigmask(SIGKILL)|sigmask(SIGSTOP));
		vcpu->sigset_active = 1;
		vcpu->sigset = *sigset;
	} else
		vcpu->sigset_active = 0;
	return 0;
}

static long kvm_vcpu_ioctl(struct file *filp,
			   unsigned int ioctl, unsigned long arg)
{
@@ -2260,6 +2278,29 @@ static long kvm_vcpu_ioctl(struct file *filp,
			goto out;
		break;
	}
	case KVM_SET_SIGNAL_MASK: {
		struct kvm_signal_mask __user *sigmask_arg = argp;
		struct kvm_signal_mask kvm_sigmask;
		sigset_t sigset, *p;

		p = NULL;
		if (argp) {
			r = -EFAULT;
			if (copy_from_user(&kvm_sigmask, argp,
					   sizeof kvm_sigmask))
				goto out;
			r = -EINVAL;
			if (kvm_sigmask.len != sizeof sigset)
				goto out;
			r = -EFAULT;
			if (copy_from_user(&sigset, sigmask_arg->sigset,
					   sizeof sigset))
				goto out;
			p = &sigset;
		}
		r = kvm_vcpu_ioctl_set_sigmask(vcpu, &sigset);
		break;
	}
	default:
		;
	}
+7 −0
Original line number Diff line number Diff line
@@ -234,6 +234,12 @@ struct kvm_cpuid {
	struct kvm_cpuid_entry entries[0];
};

/* for KVM_SET_SIGNAL_MASK */
struct kvm_signal_mask {
	__u32 len;
	__u8  sigset[0];
};

#define KVMIO 0xAE

/*
@@ -273,5 +279,6 @@ struct kvm_cpuid {
#define KVM_GET_MSRS              _IOWR(KVMIO, 0x88, struct kvm_msrs)
#define KVM_SET_MSRS              _IOW(KVMIO,  0x89, struct kvm_msrs)
#define KVM_SET_CPUID             _IOW(KVMIO,  0x8a, struct kvm_cpuid)
#define KVM_SET_SIGNAL_MASK       _IOW(KVMIO,  0x8b, struct kvm_signal_mask)

#endif