diff options
-rw-r--r-- | arch/s390/include/asm/kvm_host.h | 7 | ||||
-rw-r--r-- | arch/s390/kvm/interrupt.c | 30 | ||||
-rw-r--r-- | arch/s390/kvm/kvm-s390.c | 2 | ||||
-rw-r--r-- | arch/s390/kvm/sigp.c | 45 | ||||
-rw-r--r-- | include/linux/kvm.h | 1 |
5 files changed, 84 insertions, 1 deletions
diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h index 00ff00dfb24c..1ca5de07ac36 100644 --- a/arch/s390/include/asm/kvm_host.h +++ b/arch/s390/include/asm/kvm_host.h | |||
@@ -119,6 +119,7 @@ struct kvm_vcpu_stat { | |||
119 | u32 instruction_lctlg; | 119 | u32 instruction_lctlg; |
120 | u32 exit_program_interruption; | 120 | u32 exit_program_interruption; |
121 | u32 exit_instr_and_program; | 121 | u32 exit_instr_and_program; |
122 | u32 deliver_external_call; | ||
122 | u32 deliver_emergency_signal; | 123 | u32 deliver_emergency_signal; |
123 | u32 deliver_service_signal; | 124 | u32 deliver_service_signal; |
124 | u32 deliver_virtio_interrupt; | 125 | u32 deliver_virtio_interrupt; |
@@ -138,6 +139,7 @@ struct kvm_vcpu_stat { | |||
138 | u32 instruction_stfl; | 139 | u32 instruction_stfl; |
139 | u32 instruction_tprot; | 140 | u32 instruction_tprot; |
140 | u32 instruction_sigp_sense; | 141 | u32 instruction_sigp_sense; |
142 | u32 instruction_sigp_external_call; | ||
141 | u32 instruction_sigp_emergency; | 143 | u32 instruction_sigp_emergency; |
142 | u32 instruction_sigp_stop; | 144 | u32 instruction_sigp_stop; |
143 | u32 instruction_sigp_arch; | 145 | u32 instruction_sigp_arch; |
@@ -174,6 +176,10 @@ struct kvm_s390_prefix_info { | |||
174 | __u32 address; | 176 | __u32 address; |
175 | }; | 177 | }; |
176 | 178 | ||
179 | struct kvm_s390_extcall_info { | ||
180 | __u16 code; | ||
181 | }; | ||
182 | |||
177 | struct kvm_s390_emerg_info { | 183 | struct kvm_s390_emerg_info { |
178 | __u16 code; | 184 | __u16 code; |
179 | }; | 185 | }; |
@@ -186,6 +192,7 @@ struct kvm_s390_interrupt_info { | |||
186 | struct kvm_s390_ext_info ext; | 192 | struct kvm_s390_ext_info ext; |
187 | struct kvm_s390_pgm_info pgm; | 193 | struct kvm_s390_pgm_info pgm; |
188 | struct kvm_s390_emerg_info emerg; | 194 | struct kvm_s390_emerg_info emerg; |
195 | struct kvm_s390_extcall_info extcall; | ||
189 | struct kvm_s390_prefix_info prefix; | 196 | struct kvm_s390_prefix_info prefix; |
190 | }; | 197 | }; |
191 | }; | 198 | }; |
diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c index c9aeb4b4d0b8..87c16705b381 100644 --- a/arch/s390/kvm/interrupt.c +++ b/arch/s390/kvm/interrupt.c | |||
@@ -38,6 +38,11 @@ static int __interrupt_is_deliverable(struct kvm_vcpu *vcpu, | |||
38 | struct kvm_s390_interrupt_info *inti) | 38 | struct kvm_s390_interrupt_info *inti) |
39 | { | 39 | { |
40 | switch (inti->type) { | 40 | switch (inti->type) { |
41 | case KVM_S390_INT_EXTERNAL_CALL: | ||
42 | if (psw_extint_disabled(vcpu)) | ||
43 | return 0; | ||
44 | if (vcpu->arch.sie_block->gcr[0] & 0x2000ul) | ||
45 | return 1; | ||
41 | case KVM_S390_INT_EMERGENCY: | 46 | case KVM_S390_INT_EMERGENCY: |
42 | if (psw_extint_disabled(vcpu)) | 47 | if (psw_extint_disabled(vcpu)) |
43 | return 0; | 48 | return 0; |
@@ -98,6 +103,7 @@ static void __set_intercept_indicator(struct kvm_vcpu *vcpu, | |||
98 | struct kvm_s390_interrupt_info *inti) | 103 | struct kvm_s390_interrupt_info *inti) |
99 | { | 104 | { |
100 | switch (inti->type) { | 105 | switch (inti->type) { |
106 | case KVM_S390_INT_EXTERNAL_CALL: | ||
101 | case KVM_S390_INT_EMERGENCY: | 107 | case KVM_S390_INT_EMERGENCY: |
102 | case KVM_S390_INT_SERVICE: | 108 | case KVM_S390_INT_SERVICE: |
103 | case KVM_S390_INT_VIRTIO: | 109 | case KVM_S390_INT_VIRTIO: |
@@ -143,6 +149,28 @@ static void __do_deliver_interrupt(struct kvm_vcpu *vcpu, | |||
143 | exception = 1; | 149 | exception = 1; |
144 | break; | 150 | break; |
145 | 151 | ||
152 | case KVM_S390_INT_EXTERNAL_CALL: | ||
153 | VCPU_EVENT(vcpu, 4, "%s", "interrupt: sigp ext call"); | ||
154 | vcpu->stat.deliver_external_call++; | ||
155 | rc = put_guest_u16(vcpu, __LC_EXT_INT_CODE, 0x1202); | ||
156 | if (rc == -EFAULT) | ||
157 | exception = 1; | ||
158 | |||
159 | rc = put_guest_u16(vcpu, __LC_CPU_ADDRESS, inti->extcall.code); | ||
160 | if (rc == -EFAULT) | ||
161 | exception = 1; | ||
162 | |||
163 | rc = copy_to_guest(vcpu, __LC_EXT_OLD_PSW, | ||
164 | &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); | ||
165 | if (rc == -EFAULT) | ||
166 | exception = 1; | ||
167 | |||
168 | rc = copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw, | ||
169 | __LC_EXT_NEW_PSW, sizeof(psw_t)); | ||
170 | if (rc == -EFAULT) | ||
171 | exception = 1; | ||
172 | break; | ||
173 | |||
146 | case KVM_S390_INT_SERVICE: | 174 | case KVM_S390_INT_SERVICE: |
147 | VCPU_EVENT(vcpu, 4, "interrupt: sclp parm:%x", | 175 | VCPU_EVENT(vcpu, 4, "interrupt: sclp parm:%x", |
148 | inti->ext.ext_params); | 176 | inti->ext.ext_params); |
@@ -522,6 +550,7 @@ int kvm_s390_inject_vm(struct kvm *kvm, | |||
522 | break; | 550 | break; |
523 | case KVM_S390_PROGRAM_INT: | 551 | case KVM_S390_PROGRAM_INT: |
524 | case KVM_S390_SIGP_STOP: | 552 | case KVM_S390_SIGP_STOP: |
553 | case KVM_S390_INT_EXTERNAL_CALL: | ||
525 | case KVM_S390_INT_EMERGENCY: | 554 | case KVM_S390_INT_EMERGENCY: |
526 | default: | 555 | default: |
527 | kfree(inti); | 556 | kfree(inti); |
@@ -581,6 +610,7 @@ int kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu, | |||
581 | break; | 610 | break; |
582 | case KVM_S390_SIGP_STOP: | 611 | case KVM_S390_SIGP_STOP: |
583 | case KVM_S390_RESTART: | 612 | case KVM_S390_RESTART: |
613 | case KVM_S390_INT_EXTERNAL_CALL: | ||
584 | case KVM_S390_INT_EMERGENCY: | 614 | case KVM_S390_INT_EMERGENCY: |
585 | VCPU_EVENT(vcpu, 3, "inject: type %x", s390int->type); | 615 | VCPU_EVENT(vcpu, 3, "inject: type %x", s390int->type); |
586 | inti->type = s390int->type; | 616 | inti->type = s390int->type; |
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index 29635678b5ec..9610ba41b974 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c | |||
@@ -46,6 +46,7 @@ struct kvm_stats_debugfs_item debugfs_entries[] = { | |||
46 | { "instruction_lctlg", VCPU_STAT(instruction_lctlg) }, | 46 | { "instruction_lctlg", VCPU_STAT(instruction_lctlg) }, |
47 | { "instruction_lctl", VCPU_STAT(instruction_lctl) }, | 47 | { "instruction_lctl", VCPU_STAT(instruction_lctl) }, |
48 | { "deliver_emergency_signal", VCPU_STAT(deliver_emergency_signal) }, | 48 | { "deliver_emergency_signal", VCPU_STAT(deliver_emergency_signal) }, |
49 | { "deliver_external_call", VCPU_STAT(deliver_external_call) }, | ||
49 | { "deliver_service_signal", VCPU_STAT(deliver_service_signal) }, | 50 | { "deliver_service_signal", VCPU_STAT(deliver_service_signal) }, |
50 | { "deliver_virtio_interrupt", VCPU_STAT(deliver_virtio_interrupt) }, | 51 | { "deliver_virtio_interrupt", VCPU_STAT(deliver_virtio_interrupt) }, |
51 | { "deliver_stop_signal", VCPU_STAT(deliver_stop_signal) }, | 52 | { "deliver_stop_signal", VCPU_STAT(deliver_stop_signal) }, |
@@ -64,6 +65,7 @@ struct kvm_stats_debugfs_item debugfs_entries[] = { | |||
64 | { "instruction_stfl", VCPU_STAT(instruction_stfl) }, | 65 | { "instruction_stfl", VCPU_STAT(instruction_stfl) }, |
65 | { "instruction_tprot", VCPU_STAT(instruction_tprot) }, | 66 | { "instruction_tprot", VCPU_STAT(instruction_tprot) }, |
66 | { "instruction_sigp_sense", VCPU_STAT(instruction_sigp_sense) }, | 67 | { "instruction_sigp_sense", VCPU_STAT(instruction_sigp_sense) }, |
68 | { "instruction_sigp_external_call", VCPU_STAT(instruction_sigp_external_call) }, | ||
67 | { "instruction_sigp_emergency", VCPU_STAT(instruction_sigp_emergency) }, | 69 | { "instruction_sigp_emergency", VCPU_STAT(instruction_sigp_emergency) }, |
68 | { "instruction_sigp_stop", VCPU_STAT(instruction_sigp_stop) }, | 70 | { "instruction_sigp_stop", VCPU_STAT(instruction_sigp_stop) }, |
69 | { "instruction_sigp_set_arch", VCPU_STAT(instruction_sigp_arch) }, | 71 | { "instruction_sigp_set_arch", VCPU_STAT(instruction_sigp_arch) }, |
diff --git a/arch/s390/kvm/sigp.c b/arch/s390/kvm/sigp.c index d6a50c1fb2e6..f815118835f3 100644 --- a/arch/s390/kvm/sigp.c +++ b/arch/s390/kvm/sigp.c | |||
@@ -87,6 +87,7 @@ static int __sigp_emergency(struct kvm_vcpu *vcpu, u16 cpu_addr) | |||
87 | return -ENOMEM; | 87 | return -ENOMEM; |
88 | 88 | ||
89 | inti->type = KVM_S390_INT_EMERGENCY; | 89 | inti->type = KVM_S390_INT_EMERGENCY; |
90 | inti->emerg.code = vcpu->vcpu_id; | ||
90 | 91 | ||
91 | spin_lock(&fi->lock); | 92 | spin_lock(&fi->lock); |
92 | li = fi->local_int[cpu_addr]; | 93 | li = fi->local_int[cpu_addr]; |
@@ -103,9 +104,47 @@ static int __sigp_emergency(struct kvm_vcpu *vcpu, u16 cpu_addr) | |||
103 | wake_up_interruptible(&li->wq); | 104 | wake_up_interruptible(&li->wq); |
104 | spin_unlock_bh(&li->lock); | 105 | spin_unlock_bh(&li->lock); |
105 | rc = 0; /* order accepted */ | 106 | rc = 0; /* order accepted */ |
107 | VCPU_EVENT(vcpu, 4, "sent sigp emerg to cpu %x", cpu_addr); | ||
108 | unlock: | ||
109 | spin_unlock(&fi->lock); | ||
110 | return rc; | ||
111 | } | ||
112 | |||
113 | static int __sigp_external_call(struct kvm_vcpu *vcpu, u16 cpu_addr) | ||
114 | { | ||
115 | struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int; | ||
116 | struct kvm_s390_local_interrupt *li; | ||
117 | struct kvm_s390_interrupt_info *inti; | ||
118 | int rc; | ||
119 | |||
120 | if (cpu_addr >= KVM_MAX_VCPUS) | ||
121 | return 3; /* not operational */ | ||
122 | |||
123 | inti = kzalloc(sizeof(*inti), GFP_KERNEL); | ||
124 | if (!inti) | ||
125 | return -ENOMEM; | ||
126 | |||
127 | inti->type = KVM_S390_INT_EXTERNAL_CALL; | ||
128 | inti->extcall.code = vcpu->vcpu_id; | ||
129 | |||
130 | spin_lock(&fi->lock); | ||
131 | li = fi->local_int[cpu_addr]; | ||
132 | if (li == NULL) { | ||
133 | rc = 3; /* not operational */ | ||
134 | kfree(inti); | ||
135 | goto unlock; | ||
136 | } | ||
137 | spin_lock_bh(&li->lock); | ||
138 | list_add_tail(&inti->list, &li->list); | ||
139 | atomic_set(&li->active, 1); | ||
140 | atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags); | ||
141 | if (waitqueue_active(&li->wq)) | ||
142 | wake_up_interruptible(&li->wq); | ||
143 | spin_unlock_bh(&li->lock); | ||
144 | rc = 0; /* order accepted */ | ||
145 | VCPU_EVENT(vcpu, 4, "sent sigp ext call to cpu %x", cpu_addr); | ||
106 | unlock: | 146 | unlock: |
107 | spin_unlock(&fi->lock); | 147 | spin_unlock(&fi->lock); |
108 | VCPU_EVENT(vcpu, 4, "sent sigp emerg to cpu %x", cpu_addr); | ||
109 | return rc; | 148 | return rc; |
110 | } | 149 | } |
111 | 150 | ||
@@ -267,6 +306,10 @@ int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu) | |||
267 | rc = __sigp_sense(vcpu, cpu_addr, | 306 | rc = __sigp_sense(vcpu, cpu_addr, |
268 | &vcpu->arch.guest_gprs[r1]); | 307 | &vcpu->arch.guest_gprs[r1]); |
269 | break; | 308 | break; |
309 | case SIGP_EXTERNAL_CALL: | ||
310 | vcpu->stat.instruction_sigp_external_call++; | ||
311 | rc = __sigp_external_call(vcpu, cpu_addr); | ||
312 | break; | ||
270 | case SIGP_EMERGENCY: | 313 | case SIGP_EMERGENCY: |
271 | vcpu->stat.instruction_sigp_emergency++; | 314 | vcpu->stat.instruction_sigp_emergency++; |
272 | rc = __sigp_emergency(vcpu, cpu_addr); | 315 | rc = __sigp_emergency(vcpu, cpu_addr); |
diff --git a/include/linux/kvm.h b/include/linux/kvm.h index 68840544006d..f47fcd30273d 100644 --- a/include/linux/kvm.h +++ b/include/linux/kvm.h | |||
@@ -371,6 +371,7 @@ struct kvm_s390_psw { | |||
371 | #define KVM_S390_INT_VIRTIO 0xffff2603u | 371 | #define KVM_S390_INT_VIRTIO 0xffff2603u |
372 | #define KVM_S390_INT_SERVICE 0xffff2401u | 372 | #define KVM_S390_INT_SERVICE 0xffff2401u |
373 | #define KVM_S390_INT_EMERGENCY 0xffff1201u | 373 | #define KVM_S390_INT_EMERGENCY 0xffff1201u |
374 | #define KVM_S390_INT_EXTERNAL_CALL 0xffff1202u | ||
374 | 375 | ||
375 | struct kvm_s390_interrupt { | 376 | struct kvm_s390_interrupt { |
376 | __u32 type; | 377 | __u32 type; |