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