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 | |
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>
-rw-r--r-- | drivers/kvm/kvm.h | 3 | ||||
-rw-r--r-- | drivers/kvm/kvm_main.c | 41 | ||||
-rw-r--r-- | include/linux/kvm.h | 7 |
3 files changed, 51 insertions, 0 deletions
diff --git a/drivers/kvm/kvm.h b/drivers/kvm/kvm.h index be3a0e7ecae4..1c4a581938bf 100644 --- a/drivers/kvm/kvm.h +++ b/drivers/kvm/kvm.h | |||
@@ -277,6 +277,9 @@ struct kvm_vcpu { | |||
277 | gpa_t mmio_phys_addr; | 277 | gpa_t mmio_phys_addr; |
278 | int pio_pending; | 278 | int pio_pending; |
279 | 279 | ||
280 | int sigset_active; | ||
281 | sigset_t sigset; | ||
282 | |||
280 | struct { | 283 | struct { |
281 | int active; | 284 | int active; |
282 | u8 save_iopl; | 285 | u8 save_iopl; |
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 | } |
diff --git a/include/linux/kvm.h b/include/linux/kvm.h index b3af92e7bf5d..c0d10cd8088e 100644 --- a/include/linux/kvm.h +++ b/include/linux/kvm.h | |||
@@ -234,6 +234,12 @@ struct kvm_cpuid { | |||
234 | struct kvm_cpuid_entry entries[0]; | 234 | struct kvm_cpuid_entry entries[0]; |
235 | }; | 235 | }; |
236 | 236 | ||
237 | /* for KVM_SET_SIGNAL_MASK */ | ||
238 | struct kvm_signal_mask { | ||
239 | __u32 len; | ||
240 | __u8 sigset[0]; | ||
241 | }; | ||
242 | |||
237 | #define KVMIO 0xAE | 243 | #define KVMIO 0xAE |
238 | 244 | ||
239 | /* | 245 | /* |
@@ -273,5 +279,6 @@ struct kvm_cpuid { | |||
273 | #define KVM_GET_MSRS _IOWR(KVMIO, 0x88, struct kvm_msrs) | 279 | #define KVM_GET_MSRS _IOWR(KVMIO, 0x88, struct kvm_msrs) |
274 | #define KVM_SET_MSRS _IOW(KVMIO, 0x89, struct kvm_msrs) | 280 | #define KVM_SET_MSRS _IOW(KVMIO, 0x89, struct kvm_msrs) |
275 | #define KVM_SET_CPUID _IOW(KVMIO, 0x8a, struct kvm_cpuid) | 281 | #define KVM_SET_CPUID _IOW(KVMIO, 0x8a, struct kvm_cpuid) |
282 | #define KVM_SET_SIGNAL_MASK _IOW(KVMIO, 0x8b, struct kvm_signal_mask) | ||
276 | 283 | ||
277 | #endif | 284 | #endif |