aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390
diff options
context:
space:
mode:
Diffstat (limited to 'arch/s390')
-rw-r--r--arch/s390/kvm/interrupt.c140
-rw-r--r--arch/s390/kvm/kvm-s390.c36
-rw-r--r--arch/s390/kvm/kvm-s390.h4
3 files changed, 180 insertions, 0 deletions
diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c
index bc0988093c5b..9de47265ef73 100644
--- a/arch/s390/kvm/interrupt.c
+++ b/arch/s390/kvm/interrupt.c
@@ -2123,3 +2123,143 @@ int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e, struct kvm *kvm,
2123{ 2123{
2124 return -EINVAL; 2124 return -EINVAL;
2125} 2125}
2126
2127int kvm_s390_set_irq_state(struct kvm_vcpu *vcpu, void __user *irqstate, int len)
2128{
2129 struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
2130 struct kvm_s390_irq *buf;
2131 int r = 0;
2132 int n;
2133
2134 buf = vmalloc(len);
2135 if (!buf)
2136 return -ENOMEM;
2137
2138 if (copy_from_user((void *) buf, irqstate, len)) {
2139 r = -EFAULT;
2140 goto out_free;
2141 }
2142
2143 /*
2144 * Don't allow setting the interrupt state
2145 * when there are already interrupts pending
2146 */
2147 spin_lock(&li->lock);
2148 if (li->pending_irqs) {
2149 r = -EBUSY;
2150 goto out_unlock;
2151 }
2152
2153 for (n = 0; n < len / sizeof(*buf); n++) {
2154 r = do_inject_vcpu(vcpu, &buf[n]);
2155 if (r)
2156 break;
2157 }
2158
2159out_unlock:
2160 spin_unlock(&li->lock);
2161out_free:
2162 vfree(buf);
2163
2164 return r;
2165}
2166
2167static void store_local_irq(struct kvm_s390_local_interrupt *li,
2168 struct kvm_s390_irq *irq,
2169 unsigned long irq_type)
2170{
2171 switch (irq_type) {
2172 case IRQ_PEND_MCHK_EX:
2173 case IRQ_PEND_MCHK_REP:
2174 irq->type = KVM_S390_MCHK;
2175 irq->u.mchk = li->irq.mchk;
2176 break;
2177 case IRQ_PEND_PROG:
2178 irq->type = KVM_S390_PROGRAM_INT;
2179 irq->u.pgm = li->irq.pgm;
2180 break;
2181 case IRQ_PEND_PFAULT_INIT:
2182 irq->type = KVM_S390_INT_PFAULT_INIT;
2183 irq->u.ext = li->irq.ext;
2184 break;
2185 case IRQ_PEND_EXT_EXTERNAL:
2186 irq->type = KVM_S390_INT_EXTERNAL_CALL;
2187 irq->u.extcall = li->irq.extcall;
2188 break;
2189 case IRQ_PEND_EXT_CLOCK_COMP:
2190 irq->type = KVM_S390_INT_CLOCK_COMP;
2191 break;
2192 case IRQ_PEND_EXT_CPU_TIMER:
2193 irq->type = KVM_S390_INT_CPU_TIMER;
2194 break;
2195 case IRQ_PEND_SIGP_STOP:
2196 irq->type = KVM_S390_SIGP_STOP;
2197 irq->u.stop = li->irq.stop;
2198 break;
2199 case IRQ_PEND_RESTART:
2200 irq->type = KVM_S390_RESTART;
2201 break;
2202 case IRQ_PEND_SET_PREFIX:
2203 irq->type = KVM_S390_SIGP_SET_PREFIX;
2204 irq->u.prefix = li->irq.prefix;
2205 break;
2206 }
2207}
2208
2209int kvm_s390_get_irq_state(struct kvm_vcpu *vcpu, __u8 __user *buf, int len)
2210{
2211 uint8_t sigp_ctrl = vcpu->kvm->arch.sca->cpu[vcpu->vcpu_id].sigp_ctrl;
2212 unsigned long sigp_emerg_pending[BITS_TO_LONGS(KVM_MAX_VCPUS)];
2213 struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
2214 unsigned long pending_irqs;
2215 struct kvm_s390_irq irq;
2216 unsigned long irq_type;
2217 int cpuaddr;
2218 int n = 0;
2219
2220 spin_lock(&li->lock);
2221 pending_irqs = li->pending_irqs;
2222 memcpy(&sigp_emerg_pending, &li->sigp_emerg_pending,
2223 sizeof(sigp_emerg_pending));
2224 spin_unlock(&li->lock);
2225
2226 for_each_set_bit(irq_type, &pending_irqs, IRQ_PEND_COUNT) {
2227 memset(&irq, 0, sizeof(irq));
2228 if (irq_type == IRQ_PEND_EXT_EMERGENCY)
2229 continue;
2230 if (n + sizeof(irq) > len)
2231 return -ENOBUFS;
2232 store_local_irq(&vcpu->arch.local_int, &irq, irq_type);
2233 if (copy_to_user(&buf[n], &irq, sizeof(irq)))
2234 return -EFAULT;
2235 n += sizeof(irq);
2236 }
2237
2238 if (test_bit(IRQ_PEND_EXT_EMERGENCY, &pending_irqs)) {
2239 for_each_set_bit(cpuaddr, sigp_emerg_pending, KVM_MAX_VCPUS) {
2240 memset(&irq, 0, sizeof(irq));
2241 if (n + sizeof(irq) > len)
2242 return -ENOBUFS;
2243 irq.type = KVM_S390_INT_EMERGENCY;
2244 irq.u.emerg.code = cpuaddr;
2245 if (copy_to_user(&buf[n], &irq, sizeof(irq)))
2246 return -EFAULT;
2247 n += sizeof(irq);
2248 }
2249 }
2250
2251 if ((sigp_ctrl & SIGP_CTRL_C) &&
2252 (atomic_read(&vcpu->arch.sie_block->cpuflags) &
2253 CPUSTAT_ECALL_PEND)) {
2254 if (n + sizeof(irq) > len)
2255 return -ENOBUFS;
2256 memset(&irq, 0, sizeof(irq));
2257 irq.type = KVM_S390_INT_EXTERNAL_CALL;
2258 irq.u.extcall.code = sigp_ctrl & SIGP_CTRL_SCN_MASK;
2259 if (copy_to_user(&buf[n], &irq, sizeof(irq)))
2260 return -EFAULT;
2261 n += sizeof(irq);
2262 }
2263
2264 return n;
2265}
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index 8bc25d405edf..3040b14751b8 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -41,6 +41,9 @@
41#include "trace-s390.h" 41#include "trace-s390.h"
42 42
43#define MEM_OP_MAX_SIZE 65536 /* Maximum transfer size for KVM_S390_MEM_OP */ 43#define MEM_OP_MAX_SIZE 65536 /* Maximum transfer size for KVM_S390_MEM_OP */
44#define LOCAL_IRQS 32
45#define VCPU_IRQS_MAX_BUF (sizeof(struct kvm_s390_irq) * \
46 (KVM_MAX_VCPUS + LOCAL_IRQS))
44 47
45#define VCPU_STAT(x) offsetof(struct kvm_vcpu, stat.x), KVM_STAT_VCPU 48#define VCPU_STAT(x) offsetof(struct kvm_vcpu, stat.x), KVM_STAT_VCPU
46 49
@@ -181,6 +184,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
181 case KVM_CAP_S390_USER_SIGP: 184 case KVM_CAP_S390_USER_SIGP:
182 case KVM_CAP_S390_USER_STSI: 185 case KVM_CAP_S390_USER_STSI:
183 case KVM_CAP_S390_SKEYS: 186 case KVM_CAP_S390_SKEYS:
187 case KVM_CAP_S390_IRQ_STATE:
184 r = 1; 188 r = 1;
185 break; 189 break;
186 case KVM_CAP_S390_MEM_OP: 190 case KVM_CAP_S390_MEM_OP:
@@ -2500,6 +2504,38 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
2500 r = -EFAULT; 2504 r = -EFAULT;
2501 break; 2505 break;
2502 } 2506 }
2507 case KVM_S390_SET_IRQ_STATE: {
2508 struct kvm_s390_irq_state irq_state;
2509
2510 r = -EFAULT;
2511 if (copy_from_user(&irq_state, argp, sizeof(irq_state)))
2512 break;
2513 if (irq_state.len > VCPU_IRQS_MAX_BUF ||
2514 irq_state.len == 0 ||
2515 irq_state.len % sizeof(struct kvm_s390_irq) > 0) {
2516 r = -EINVAL;
2517 break;
2518 }
2519 r = kvm_s390_set_irq_state(vcpu,
2520 (void __user *) irq_state.buf,
2521 irq_state.len);
2522 break;
2523 }
2524 case KVM_S390_GET_IRQ_STATE: {
2525 struct kvm_s390_irq_state irq_state;
2526
2527 r = -EFAULT;
2528 if (copy_from_user(&irq_state, argp, sizeof(irq_state)))
2529 break;
2530 if (irq_state.len == 0) {
2531 r = -EINVAL;
2532 break;
2533 }
2534 r = kvm_s390_get_irq_state(vcpu,
2535 (__u8 __user *) irq_state.buf,
2536 irq_state.len);
2537 break;
2538 }
2503 default: 2539 default:
2504 r = -ENOTTY; 2540 r = -ENOTTY;
2505 } 2541 }
diff --git a/arch/s390/kvm/kvm-s390.h b/arch/s390/kvm/kvm-s390.h
index 343644a59392..ca108b90ae56 100644
--- a/arch/s390/kvm/kvm-s390.h
+++ b/arch/s390/kvm/kvm-s390.h
@@ -272,6 +272,10 @@ int kvm_s390_ext_call_pending(struct kvm_vcpu *vcpu);
272extern struct kvm_device_ops kvm_flic_ops; 272extern struct kvm_device_ops kvm_flic_ops;
273int kvm_s390_is_stop_irq_pending(struct kvm_vcpu *vcpu); 273int kvm_s390_is_stop_irq_pending(struct kvm_vcpu *vcpu);
274void kvm_s390_clear_stop_irq(struct kvm_vcpu *vcpu); 274void kvm_s390_clear_stop_irq(struct kvm_vcpu *vcpu);
275int kvm_s390_set_irq_state(struct kvm_vcpu *vcpu,
276 void __user *buf, int len);
277int kvm_s390_get_irq_state(struct kvm_vcpu *vcpu,
278 __u8 __user *buf, int len);
275 279
276/* implemented in guestdbg.c */ 280/* implemented in guestdbg.c */
277void kvm_s390_backup_guest_per_regs(struct kvm_vcpu *vcpu); 281void kvm_s390_backup_guest_per_regs(struct kvm_vcpu *vcpu);