diff options
author | Avi Kivity <avi@qumranet.com> | 2007-03-05 12:46:05 -0500 |
---|---|---|
committer | Avi Kivity <avi@qumranet.com> | 2007-05-03 03:52:24 -0400 |
commit | 1961d276c877b99f5f16aaf36377c75e0e191c3a (patch) | |
tree | 4ea92fc2821bd0f9013ee567ee2f11c6cc532d79 /drivers/kvm/kvm_main.c | |
parent | 6722c51c51518af9581ab6cd9b6aec93774334a6 (diff) |
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: Avi Kivity <avi@qumranet.com>
Diffstat (limited to 'drivers/kvm/kvm_main.c')
-rw-r--r-- | drivers/kvm/kvm_main.c | 41 |
1 files changed, 41 insertions, 0 deletions
diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c index ac44df551aa8..df85f5f65489 100644 --- a/drivers/kvm/kvm_main.c +++ b/drivers/kvm/kvm_main.c | |||
@@ -1591,9 +1591,13 @@ static void complete_pio(struct kvm_vcpu *vcpu) | |||
1591 | static int kvm_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | 1591 | static int kvm_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) |
1592 | { | 1592 | { |
1593 | int r; | 1593 | int r; |
1594 | sigset_t sigsaved; | ||
1594 | 1595 | ||
1595 | vcpu_load(vcpu); | 1596 | vcpu_load(vcpu); |
1596 | 1597 | ||
1598 | if (vcpu->sigset_active) | ||
1599 | sigprocmask(SIG_SETMASK, &vcpu->sigset, &sigsaved); | ||
1600 | |||
1597 | /* re-sync apic's tpr */ | 1601 | /* re-sync apic's tpr */ |
1598 | vcpu->cr8 = kvm_run->cr8; | 1602 | vcpu->cr8 = kvm_run->cr8; |
1599 | 1603 | ||
@@ -1616,6 +1620,9 @@ static int kvm_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | |||
1616 | 1620 | ||
1617 | r = kvm_arch_ops->run(vcpu, kvm_run); | 1621 | r = kvm_arch_ops->run(vcpu, kvm_run); |
1618 | 1622 | ||
1623 | if (vcpu->sigset_active) | ||
1624 | sigprocmask(SIG_SETMASK, &sigsaved, NULL); | ||
1625 | |||
1619 | vcpu_put(vcpu); | 1626 | vcpu_put(vcpu); |
1620 | return r; | 1627 | return r; |
1621 | } | 1628 | } |
@@ -2142,6 +2149,17 @@ out: | |||
2142 | return r; | 2149 | return r; |
2143 | } | 2150 | } |
2144 | 2151 | ||
2152 | static int kvm_vcpu_ioctl_set_sigmask(struct kvm_vcpu *vcpu, sigset_t *sigset) | ||
2153 | { | ||
2154 | if (sigset) { | ||
2155 | sigdelsetmask(sigset, sigmask(SIGKILL)|sigmask(SIGSTOP)); | ||
2156 | vcpu->sigset_active = 1; | ||
2157 | vcpu->sigset = *sigset; | ||
2158 | } else | ||
2159 | vcpu->sigset_active = 0; | ||
2160 | return 0; | ||
2161 | } | ||
2162 | |||
2145 | static long kvm_vcpu_ioctl(struct file *filp, | 2163 | static long kvm_vcpu_ioctl(struct file *filp, |
2146 | unsigned int ioctl, unsigned long arg) | 2164 | unsigned int ioctl, unsigned long arg) |
2147 | { | 2165 | { |
@@ -2260,6 +2278,29 @@ static long kvm_vcpu_ioctl(struct file *filp, | |||
2260 | goto out; | 2278 | goto out; |
2261 | break; | 2279 | break; |
2262 | } | 2280 | } |
2281 | case KVM_SET_SIGNAL_MASK: { | ||
2282 | struct kvm_signal_mask __user *sigmask_arg = argp; | ||
2283 | struct kvm_signal_mask kvm_sigmask; | ||
2284 | sigset_t sigset, *p; | ||
2285 | |||
2286 | p = NULL; | ||
2287 | if (argp) { | ||
2288 | r = -EFAULT; | ||
2289 | if (copy_from_user(&kvm_sigmask, argp, | ||
2290 | sizeof kvm_sigmask)) | ||
2291 | goto out; | ||
2292 | r = -EINVAL; | ||
2293 | if (kvm_sigmask.len != sizeof sigset) | ||
2294 | goto out; | ||
2295 | r = -EFAULT; | ||
2296 | if (copy_from_user(&sigset, sigmask_arg->sigset, | ||
2297 | sizeof sigset)) | ||
2298 | goto out; | ||
2299 | p = &sigset; | ||
2300 | } | ||
2301 | r = kvm_vcpu_ioctl_set_sigmask(vcpu, &sigset); | ||
2302 | break; | ||
2303 | } | ||
2263 | default: | 2304 | default: |
2264 | ; | 2305 | ; |
2265 | } | 2306 | } |