Merge branch 'davinci-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[pandora-kernel.git] / arch / s390 / kvm / sigp.c
1 /*
2  * sigp.c - handlinge interprocessor communication
3  *
4  * Copyright IBM Corp. 2008,2009
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License (version 2 only)
8  * as published by the Free Software Foundation.
9  *
10  *    Author(s): Carsten Otte <cotte@de.ibm.com>
11  *               Christian Borntraeger <borntraeger@de.ibm.com>
12  *               Christian Ehrhardt <ehrhardt@de.ibm.com>
13  */
14
15 #include <linux/kvm.h>
16 #include <linux/kvm_host.h>
17 #include "gaccess.h"
18 #include "kvm-s390.h"
19
20 /* sigp order codes */
21 #define SIGP_SENSE             0x01
22 #define SIGP_EXTERNAL_CALL     0x02
23 #define SIGP_EMERGENCY         0x03
24 #define SIGP_START             0x04
25 #define SIGP_STOP              0x05
26 #define SIGP_RESTART           0x06
27 #define SIGP_STOP_STORE_STATUS 0x09
28 #define SIGP_INITIAL_CPU_RESET 0x0b
29 #define SIGP_CPU_RESET         0x0c
30 #define SIGP_SET_PREFIX        0x0d
31 #define SIGP_STORE_STATUS_ADDR 0x0e
32 #define SIGP_SET_ARCH          0x12
33
34 /* cpu status bits */
35 #define SIGP_STAT_EQUIPMENT_CHECK   0x80000000UL
36 #define SIGP_STAT_INCORRECT_STATE   0x00000200UL
37 #define SIGP_STAT_INVALID_PARAMETER 0x00000100UL
38 #define SIGP_STAT_EXT_CALL_PENDING  0x00000080UL
39 #define SIGP_STAT_STOPPED           0x00000040UL
40 #define SIGP_STAT_OPERATOR_INTERV   0x00000020UL
41 #define SIGP_STAT_CHECK_STOP        0x00000010UL
42 #define SIGP_STAT_INOPERATIVE       0x00000004UL
43 #define SIGP_STAT_INVALID_ORDER     0x00000002UL
44 #define SIGP_STAT_RECEIVER_CHECK    0x00000001UL
45
46
47 static int __sigp_sense(struct kvm_vcpu *vcpu, u16 cpu_addr,
48                         unsigned long *reg)
49 {
50         struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int;
51         int rc;
52
53         if (cpu_addr >= KVM_MAX_VCPUS)
54                 return 3; /* not operational */
55
56         spin_lock(&fi->lock);
57         if (fi->local_int[cpu_addr] == NULL)
58                 rc = 3; /* not operational */
59         else if (atomic_read(fi->local_int[cpu_addr]->cpuflags)
60                  & CPUSTAT_RUNNING) {
61                 *reg &= 0xffffffff00000000UL;
62                 rc = 1; /* status stored */
63         } else {
64                 *reg &= 0xffffffff00000000UL;
65                 *reg |= SIGP_STAT_STOPPED;
66                 rc = 1; /* status stored */
67         }
68         spin_unlock(&fi->lock);
69
70         VCPU_EVENT(vcpu, 4, "sensed status of cpu %x rc %x", cpu_addr, rc);
71         return rc;
72 }
73
74 static int __sigp_emergency(struct kvm_vcpu *vcpu, u16 cpu_addr)
75 {
76         struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int;
77         struct kvm_s390_local_interrupt *li;
78         struct kvm_s390_interrupt_info *inti;
79         int rc;
80
81         if (cpu_addr >= KVM_MAX_VCPUS)
82                 return 3; /* not operational */
83
84         inti = kzalloc(sizeof(*inti), GFP_KERNEL);
85         if (!inti)
86                 return -ENOMEM;
87
88         inti->type = KVM_S390_INT_EMERGENCY;
89
90         spin_lock(&fi->lock);
91         li = fi->local_int[cpu_addr];
92         if (li == NULL) {
93                 rc = 3; /* not operational */
94                 kfree(inti);
95                 goto unlock;
96         }
97         spin_lock_bh(&li->lock);
98         list_add_tail(&inti->list, &li->list);
99         atomic_set(&li->active, 1);
100         atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags);
101         if (waitqueue_active(&li->wq))
102                 wake_up_interruptible(&li->wq);
103         spin_unlock_bh(&li->lock);
104         rc = 0; /* order accepted */
105 unlock:
106         spin_unlock(&fi->lock);
107         VCPU_EVENT(vcpu, 4, "sent sigp emerg to cpu %x", cpu_addr);
108         return rc;
109 }
110
111 static int __inject_sigp_stop(struct kvm_s390_local_interrupt *li, int action)
112 {
113         struct kvm_s390_interrupt_info *inti;
114
115         inti = kzalloc(sizeof(*inti), GFP_KERNEL);
116         if (!inti)
117                 return -ENOMEM;
118         inti->type = KVM_S390_SIGP_STOP;
119
120         spin_lock_bh(&li->lock);
121         list_add_tail(&inti->list, &li->list);
122         atomic_set(&li->active, 1);
123         atomic_set_mask(CPUSTAT_STOP_INT, li->cpuflags);
124         li->action_bits |= action;
125         if (waitqueue_active(&li->wq))
126                 wake_up_interruptible(&li->wq);
127         spin_unlock_bh(&li->lock);
128
129         return 0; /* order accepted */
130 }
131
132 static int __sigp_stop(struct kvm_vcpu *vcpu, u16 cpu_addr, int action)
133 {
134         struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int;
135         struct kvm_s390_local_interrupt *li;
136         int rc;
137
138         if (cpu_addr >= KVM_MAX_VCPUS)
139                 return 3; /* not operational */
140
141         spin_lock(&fi->lock);
142         li = fi->local_int[cpu_addr];
143         if (li == NULL) {
144                 rc = 3; /* not operational */
145                 goto unlock;
146         }
147
148         rc = __inject_sigp_stop(li, action);
149
150 unlock:
151         spin_unlock(&fi->lock);
152         VCPU_EVENT(vcpu, 4, "sent sigp stop to cpu %x", cpu_addr);
153         return rc;
154 }
155
156 int kvm_s390_inject_sigp_stop(struct kvm_vcpu *vcpu, int action)
157 {
158         struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
159         return __inject_sigp_stop(li, action);
160 }
161
162 static int __sigp_set_arch(struct kvm_vcpu *vcpu, u32 parameter)
163 {
164         int rc;
165
166         switch (parameter & 0xff) {
167         case 0:
168                 rc = 3; /* not operational */
169                 break;
170         case 1:
171         case 2:
172                 rc = 0; /* order accepted */
173                 break;
174         default:
175                 rc = -EOPNOTSUPP;
176         }
177         return rc;
178 }
179
180 static int __sigp_set_prefix(struct kvm_vcpu *vcpu, u16 cpu_addr, u32 address,
181                              unsigned long *reg)
182 {
183         struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int;
184         struct kvm_s390_local_interrupt *li = NULL;
185         struct kvm_s390_interrupt_info *inti;
186         int rc;
187         u8 tmp;
188
189         /* make sure that the new value is valid memory */
190         address = address & 0x7fffe000u;
191         if ((copy_from_user(&tmp, (void __user *)
192                 (address + vcpu->arch.sie_block->gmsor) , 1)) ||
193            (copy_from_user(&tmp, (void __user *)(address +
194                         vcpu->arch.sie_block->gmsor + PAGE_SIZE), 1))) {
195                 *reg |= SIGP_STAT_INVALID_PARAMETER;
196                 return 1; /* invalid parameter */
197         }
198
199         inti = kzalloc(sizeof(*inti), GFP_KERNEL);
200         if (!inti)
201                 return 2; /* busy */
202
203         spin_lock(&fi->lock);
204         if (cpu_addr < KVM_MAX_VCPUS)
205                 li = fi->local_int[cpu_addr];
206
207         if (li == NULL) {
208                 rc = 1; /* incorrect state */
209                 *reg &= SIGP_STAT_INCORRECT_STATE;
210                 kfree(inti);
211                 goto out_fi;
212         }
213
214         spin_lock_bh(&li->lock);
215         /* cpu must be in stopped state */
216         if (atomic_read(li->cpuflags) & CPUSTAT_RUNNING) {
217                 rc = 1; /* incorrect state */
218                 *reg &= SIGP_STAT_INCORRECT_STATE;
219                 kfree(inti);
220                 goto out_li;
221         }
222
223         inti->type = KVM_S390_SIGP_SET_PREFIX;
224         inti->prefix.address = address;
225
226         list_add_tail(&inti->list, &li->list);
227         atomic_set(&li->active, 1);
228         if (waitqueue_active(&li->wq))
229                 wake_up_interruptible(&li->wq);
230         rc = 0; /* order accepted */
231
232         VCPU_EVENT(vcpu, 4, "set prefix of cpu %02x to %x", cpu_addr, address);
233 out_li:
234         spin_unlock_bh(&li->lock);
235 out_fi:
236         spin_unlock(&fi->lock);
237         return rc;
238 }
239
240 int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu)
241 {
242         int r1 = (vcpu->arch.sie_block->ipa & 0x00f0) >> 4;
243         int r3 = vcpu->arch.sie_block->ipa & 0x000f;
244         int base2 = vcpu->arch.sie_block->ipb >> 28;
245         int disp2 = ((vcpu->arch.sie_block->ipb & 0x0fff0000) >> 16);
246         u32 parameter;
247         u16 cpu_addr = vcpu->arch.guest_gprs[r3];
248         u8 order_code;
249         int rc;
250
251         /* sigp in userspace can exit */
252         if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
253                 return kvm_s390_inject_program_int(vcpu,
254                                                    PGM_PRIVILEGED_OPERATION);
255
256         order_code = disp2;
257         if (base2)
258                 order_code += vcpu->arch.guest_gprs[base2];
259
260         if (r1 % 2)
261                 parameter = vcpu->arch.guest_gprs[r1];
262         else
263                 parameter = vcpu->arch.guest_gprs[r1 + 1];
264
265         switch (order_code) {
266         case SIGP_SENSE:
267                 vcpu->stat.instruction_sigp_sense++;
268                 rc = __sigp_sense(vcpu, cpu_addr,
269                                   &vcpu->arch.guest_gprs[r1]);
270                 break;
271         case SIGP_EMERGENCY:
272                 vcpu->stat.instruction_sigp_emergency++;
273                 rc = __sigp_emergency(vcpu, cpu_addr);
274                 break;
275         case SIGP_STOP:
276                 vcpu->stat.instruction_sigp_stop++;
277                 rc = __sigp_stop(vcpu, cpu_addr, ACTION_STOP_ON_STOP);
278                 break;
279         case SIGP_STOP_STORE_STATUS:
280                 vcpu->stat.instruction_sigp_stop++;
281                 rc = __sigp_stop(vcpu, cpu_addr, ACTION_STORE_ON_STOP);
282                 break;
283         case SIGP_SET_ARCH:
284                 vcpu->stat.instruction_sigp_arch++;
285                 rc = __sigp_set_arch(vcpu, parameter);
286                 break;
287         case SIGP_SET_PREFIX:
288                 vcpu->stat.instruction_sigp_prefix++;
289                 rc = __sigp_set_prefix(vcpu, cpu_addr, parameter,
290                                        &vcpu->arch.guest_gprs[r1]);
291                 break;
292         case SIGP_RESTART:
293                 vcpu->stat.instruction_sigp_restart++;
294                 /* user space must know about restart */
295         default:
296                 return -EOPNOTSUPP;
297         }
298
299         if (rc < 0)
300                 return rc;
301
302         vcpu->arch.sie_block->gpsw.mask &= ~(3ul << 44);
303         vcpu->arch.sie_block->gpsw.mask |= (rc & 3ul) << 44;
304         return 0;
305 }