aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/kvm/kvm-s390.c
diff options
context:
space:
mode:
authorCarsten Otte <cotte@de.ibm.com>2008-03-25 13:47:26 -0400
committerAvi Kivity <avi@qumranet.com>2008-04-27 05:00:44 -0400
commitba5c1e9b6ceebdc39343cc03eb39f077abd3c571 (patch)
treeab07e763ad7d9aad2ef189def5537e73a50c7503 /arch/s390/kvm/kvm-s390.c
parent8f2abe6a1e525e878bdf58f68ccd146d543fde84 (diff)
KVM: s390: interrupt subsystem, cpu timer, waitpsw
This patch contains the s390 interrupt subsystem (similar to in kernel apic) including timer interrupts (similar to in-kernel-pit) and enabled wait (similar to in kernel hlt). In order to achieve that, this patch also introduces intercept handling for instruction intercepts, and it implements load control instructions. This patch introduces an ioctl KVM_S390_INTERRUPT which is valid for both the vm file descriptors and the vcpu file descriptors. In case this ioctl is issued against a vm file descriptor, the interrupt is considered floating. Floating interrupts may be delivered to any virtual cpu in the configuration. The following interrupts are supported: SIGP STOP - interprocessor signal that stops a remote cpu SIGP SET PREFIX - interprocessor signal that sets the prefix register of a (stopped) remote cpu INT EMERGENCY - interprocessor interrupt, usually used to signal need_reshed and for smp_call_function() in the guest. PROGRAM INT - exception during program execution such as page fault, illegal instruction and friends RESTART - interprocessor signal that starts a stopped cpu INT VIRTIO - floating interrupt for virtio signalisation INT SERVICE - floating interrupt for signalisations from the system service processor struct kvm_s390_interrupt, which is submitted as ioctl parameter when injecting an interrupt, also carrys parameter data for interrupts along with the interrupt type. Interrupts on s390 usually have a state that represents the current operation, or identifies which device has caused the interruption on s390. kvm_s390_handle_wait() does handle waitpsw in two flavors: in case of a disabled wait (that is, disabled for interrupts), we exit to userspace. In case of an enabled wait we set up a timer that equals the cpu clock comparator value and sleep on a wait queue. [christian: change virtio interrupt to 0x2603] Acked-by: Martin Schwidefsky <schwidefsky@de.ibm.com> Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com> Signed-off-by: Carsten Otte <cotte@de.ibm.com> Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com> Signed-off-by: Avi Kivity <avi@qumranet.com>
Diffstat (limited to 'arch/s390/kvm/kvm-s390.c')
-rw-r--r--arch/s390/kvm/kvm-s390.c48
1 files changed, 46 insertions, 2 deletions
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index a906499214bb..5e3473c9a639 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -20,6 +20,7 @@
20#include <linux/kvm_host.h> 20#include <linux/kvm_host.h>
21#include <linux/module.h> 21#include <linux/module.h>
22#include <linux/slab.h> 22#include <linux/slab.h>
23#include <linux/timer.h>
23#include <asm/lowcore.h> 24#include <asm/lowcore.h>
24#include <asm/pgtable.h> 25#include <asm/pgtable.h>
25 26
@@ -34,6 +35,19 @@ struct kvm_stats_debugfs_item debugfs_entries[] = {
34 { "exit_stop_request", VCPU_STAT(exit_stop_request) }, 35 { "exit_stop_request", VCPU_STAT(exit_stop_request) },
35 { "exit_external_request", VCPU_STAT(exit_external_request) }, 36 { "exit_external_request", VCPU_STAT(exit_external_request) },
36 { "exit_external_interrupt", VCPU_STAT(exit_external_interrupt) }, 37 { "exit_external_interrupt", VCPU_STAT(exit_external_interrupt) },
38 { "exit_instruction", VCPU_STAT(exit_instruction) },
39 { "exit_program_interruption", VCPU_STAT(exit_program_interruption) },
40 { "exit_instr_and_program_int", VCPU_STAT(exit_instr_and_program) },
41 { "instruction_lctg", VCPU_STAT(instruction_lctg) },
42 { "instruction_lctl", VCPU_STAT(instruction_lctl) },
43 { "deliver_emergency_signal", VCPU_STAT(deliver_emergency_signal) },
44 { "deliver_service_signal", VCPU_STAT(deliver_service_signal) },
45 { "deliver_virtio_interrupt", VCPU_STAT(deliver_virtio_interrupt) },
46 { "deliver_stop_signal", VCPU_STAT(deliver_stop_signal) },
47 { "deliver_prefix_signal", VCPU_STAT(deliver_prefix_signal) },
48 { "deliver_restart_signal", VCPU_STAT(deliver_restart_signal) },
49 { "deliver_program_interruption", VCPU_STAT(deliver_program_int) },
50 { "exit_wait_state", VCPU_STAT(exit_wait_state) },
37 { NULL } 51 { NULL }
38}; 52};
39 53
@@ -106,6 +120,15 @@ long kvm_arch_vm_ioctl(struct file *filp,
106 int r; 120 int r;
107 121
108 switch (ioctl) { 122 switch (ioctl) {
123 case KVM_S390_INTERRUPT: {
124 struct kvm_s390_interrupt s390int;
125
126 r = -EFAULT;
127 if (copy_from_user(&s390int, argp, sizeof(s390int)))
128 break;
129 r = kvm_s390_inject_vm(kvm, &s390int);
130 break;
131 }
109 default: 132 default:
110 r = -EINVAL; 133 r = -EINVAL;
111 } 134 }
@@ -138,6 +161,9 @@ struct kvm *kvm_arch_create_vm(void)
138 if (!kvm->arch.dbf) 161 if (!kvm->arch.dbf)
139 goto out_nodbf; 162 goto out_nodbf;
140 163
164 spin_lock_init(&kvm->arch.float_int.lock);
165 INIT_LIST_HEAD(&kvm->arch.float_int.list);
166
141 debug_register_view(kvm->arch.dbf, &debug_sprintf_view); 167 debug_register_view(kvm->arch.dbf, &debug_sprintf_view);
142 VM_EVENT(kvm, 3, "%s", "vm created"); 168 VM_EVENT(kvm, 3, "%s", "vm created");
143 169
@@ -218,7 +244,8 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
218 vcpu->arch.sie_block->gmsor = 0x000000000000; 244 vcpu->arch.sie_block->gmsor = 0x000000000000;
219 vcpu->arch.sie_block->ecb = 2; 245 vcpu->arch.sie_block->ecb = 2;
220 vcpu->arch.sie_block->eca = 0xC1002001U; 246 vcpu->arch.sie_block->eca = 0xC1002001U;
221 247 setup_timer(&vcpu->arch.ckc_timer, kvm_s390_idle_wakeup,
248 (unsigned long) vcpu);
222 return 0; 249 return 0;
223} 250}
224 251
@@ -243,6 +270,14 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm,
243 vcpu->arch.sie_block->scaoh = (__u32)(((__u64)kvm->arch.sca) >> 32); 270 vcpu->arch.sie_block->scaoh = (__u32)(((__u64)kvm->arch.sca) >> 32);
244 vcpu->arch.sie_block->scaol = (__u32)(__u64)kvm->arch.sca; 271 vcpu->arch.sie_block->scaol = (__u32)(__u64)kvm->arch.sca;
245 272
273 spin_lock_init(&vcpu->arch.local_int.lock);
274 INIT_LIST_HEAD(&vcpu->arch.local_int.list);
275 vcpu->arch.local_int.float_int = &kvm->arch.float_int;
276 spin_lock_bh(&kvm->arch.float_int.lock);
277 kvm->arch.float_int.local_int[id] = &vcpu->arch.local_int;
278 init_waitqueue_head(&vcpu->arch.local_int.wq);
279 spin_unlock_bh(&kvm->arch.float_int.lock);
280
246 rc = kvm_vcpu_init(vcpu, kvm, id); 281 rc = kvm_vcpu_init(vcpu, kvm, id);
247 if (rc) 282 if (rc)
248 goto out_free_cpu; 283 goto out_free_cpu;
@@ -395,6 +430,8 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
395 430
396 atomic_set_mask(CPUSTAT_RUNNING, &vcpu->arch.sie_block->cpuflags); 431 atomic_set_mask(CPUSTAT_RUNNING, &vcpu->arch.sie_block->cpuflags);
397 432
433 BUG_ON(vcpu->kvm->arch.float_int.local_int[vcpu->vcpu_id] == NULL);
434
398 switch (kvm_run->exit_reason) { 435 switch (kvm_run->exit_reason) {
399 case KVM_EXIT_S390_SIEIC: 436 case KVM_EXIT_S390_SIEIC:
400 vcpu->arch.sie_block->gpsw.mask = kvm_run->s390_sieic.mask; 437 vcpu->arch.sie_block->gpsw.mask = kvm_run->s390_sieic.mask;
@@ -410,8 +447,8 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
410 might_sleep(); 447 might_sleep();
411 448
412 do { 449 do {
450 kvm_s390_deliver_pending_interrupts(vcpu);
413 __vcpu_run(vcpu); 451 __vcpu_run(vcpu);
414
415 rc = kvm_handle_sie_intercept(vcpu); 452 rc = kvm_handle_sie_intercept(vcpu);
416 } while (!signal_pending(current) && !rc); 453 } while (!signal_pending(current) && !rc);
417 454
@@ -538,6 +575,13 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
538 void __user *argp = (void __user *)arg; 575 void __user *argp = (void __user *)arg;
539 576
540 switch (ioctl) { 577 switch (ioctl) {
578 case KVM_S390_INTERRUPT: {
579 struct kvm_s390_interrupt s390int;
580
581 if (copy_from_user(&s390int, argp, sizeof(s390int)))
582 return -EFAULT;
583 return kvm_s390_inject_vcpu(vcpu, &s390int);
584 }
541 case KVM_S390_STORE_STATUS: 585 case KVM_S390_STORE_STATUS:
542 return kvm_s390_vcpu_store_status(vcpu, arg); 586 return kvm_s390_vcpu_store_status(vcpu, arg);
543 case KVM_S390_SET_INITIAL_PSW: { 587 case KVM_S390_SET_INITIAL_PSW: {