Blame view

arch/s390/kvm/sigp.c 9.74 KB
5288fbf0e   Christian Borntraeger   KVM: s390: interp...
1
2
3
  /*
   * sigp.c - handlinge interprocessor communication
   *
9ace903d1   Christian Ehrhardt   KVM: s390: infras...
4
   * Copyright IBM Corp. 2008,2009
5288fbf0e   Christian Borntraeger   KVM: s390: interp...
5
6
7
8
9
10
11
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License (version 2 only)
   * as published by the Free Software Foundation.
   *
   *    Author(s): Carsten Otte <cotte@de.ibm.com>
   *               Christian Borntraeger <borntraeger@de.ibm.com>
9ace903d1   Christian Ehrhardt   KVM: s390: infras...
12
   *               Christian Ehrhardt <ehrhardt@de.ibm.com>
5288fbf0e   Christian Borntraeger   KVM: s390: interp...
13
14
15
16
   */
  
  #include <linux/kvm.h>
  #include <linux/kvm_host.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
17
  #include <linux/slab.h>
5288fbf0e   Christian Borntraeger   KVM: s390: interp...
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
  #include "gaccess.h"
  #include "kvm-s390.h"
  
  /* sigp order codes */
  #define SIGP_SENSE             0x01
  #define SIGP_EXTERNAL_CALL     0x02
  #define SIGP_EMERGENCY         0x03
  #define SIGP_START             0x04
  #define SIGP_STOP              0x05
  #define SIGP_RESTART           0x06
  #define SIGP_STOP_STORE_STATUS 0x09
  #define SIGP_INITIAL_CPU_RESET 0x0b
  #define SIGP_CPU_RESET         0x0c
  #define SIGP_SET_PREFIX        0x0d
  #define SIGP_STORE_STATUS_ADDR 0x0e
  #define SIGP_SET_ARCH          0x12
bd59d3a44   Cornelia Huck   KVM: s390: handle...
34
  #define SIGP_SENSE_RUNNING     0x15
5288fbf0e   Christian Borntraeger   KVM: s390: interp...
35
36
37
  
  /* cpu status bits */
  #define SIGP_STAT_EQUIPMENT_CHECK   0x80000000UL
bd59d3a44   Cornelia Huck   KVM: s390: handle...
38
  #define SIGP_STAT_NOT_RUNNING	    0x00000400UL
5288fbf0e   Christian Borntraeger   KVM: s390: interp...
39
40
41
42
43
44
45
46
47
  #define SIGP_STAT_INCORRECT_STATE   0x00000200UL
  #define SIGP_STAT_INVALID_PARAMETER 0x00000100UL
  #define SIGP_STAT_EXT_CALL_PENDING  0x00000080UL
  #define SIGP_STAT_STOPPED           0x00000040UL
  #define SIGP_STAT_OPERATOR_INTERV   0x00000020UL
  #define SIGP_STAT_CHECK_STOP        0x00000010UL
  #define SIGP_STAT_INOPERATIVE       0x00000004UL
  #define SIGP_STAT_INVALID_ORDER     0x00000002UL
  #define SIGP_STAT_RECEIVER_CHECK    0x00000001UL
0096369da   Martin Schwidefsky   KVM: s390: Change...
48
49
  static int __sigp_sense(struct kvm_vcpu *vcpu, u16 cpu_addr,
  			unsigned long *reg)
5288fbf0e   Christian Borntraeger   KVM: s390: interp...
50
  {
180c12fb2   Christian Borntraeger   KVM: s390: rename...
51
  	struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int;
5288fbf0e   Christian Borntraeger   KVM: s390: interp...
52
53
54
55
  	int rc;
  
  	if (cpu_addr >= KVM_MAX_VCPUS)
  		return 3; /* not operational */
b037a4f34   Christian Borntraeger   KVM: s390: optimi...
56
  	spin_lock(&fi->lock);
5288fbf0e   Christian Borntraeger   KVM: s390: interp...
57
58
  	if (fi->local_int[cpu_addr] == NULL)
  		rc = 3; /* not operational */
9e6dabeff   Cornelia Huck   KVM: s390: Fix RU...
59
60
  	else if (!(atomic_read(fi->local_int[cpu_addr]->cpuflags)
  		  & CPUSTAT_STOPPED)) {
5288fbf0e   Christian Borntraeger   KVM: s390: interp...
61
62
63
64
65
66
67
  		*reg &= 0xffffffff00000000UL;
  		rc = 1; /* status stored */
  	} else {
  		*reg &= 0xffffffff00000000UL;
  		*reg |= SIGP_STAT_STOPPED;
  		rc = 1; /* status stored */
  	}
b037a4f34   Christian Borntraeger   KVM: s390: optimi...
68
  	spin_unlock(&fi->lock);
5288fbf0e   Christian Borntraeger   KVM: s390: interp...
69
70
71
72
73
74
75
  
  	VCPU_EVENT(vcpu, 4, "sensed status of cpu %x rc %x", cpu_addr, rc);
  	return rc;
  }
  
  static int __sigp_emergency(struct kvm_vcpu *vcpu, u16 cpu_addr)
  {
180c12fb2   Christian Borntraeger   KVM: s390: rename...
76
77
78
  	struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int;
  	struct kvm_s390_local_interrupt *li;
  	struct kvm_s390_interrupt_info *inti;
5288fbf0e   Christian Borntraeger   KVM: s390: interp...
79
80
81
82
83
84
85
86
87
88
  	int rc;
  
  	if (cpu_addr >= KVM_MAX_VCPUS)
  		return 3; /* not operational */
  
  	inti = kzalloc(sizeof(*inti), GFP_KERNEL);
  	if (!inti)
  		return -ENOMEM;
  
  	inti->type = KVM_S390_INT_EMERGENCY;
7697e71f7   Christian Ehrhardt   KVM: s390: implem...
89
  	inti->emerg.code = vcpu->vcpu_id;
5288fbf0e   Christian Borntraeger   KVM: s390: interp...
90

b037a4f34   Christian Borntraeger   KVM: s390: optimi...
91
  	spin_lock(&fi->lock);
5288fbf0e   Christian Borntraeger   KVM: s390: interp...
92
93
94
95
96
97
98
99
100
101
102
103
104
105
  	li = fi->local_int[cpu_addr];
  	if (li == NULL) {
  		rc = 3; /* not operational */
  		kfree(inti);
  		goto unlock;
  	}
  	spin_lock_bh(&li->lock);
  	list_add_tail(&inti->list, &li->list);
  	atomic_set(&li->active, 1);
  	atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags);
  	if (waitqueue_active(&li->wq))
  		wake_up_interruptible(&li->wq);
  	spin_unlock_bh(&li->lock);
  	rc = 0; /* order accepted */
7697e71f7   Christian Ehrhardt   KVM: s390: implem...
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
  	VCPU_EVENT(vcpu, 4, "sent sigp emerg to cpu %x", cpu_addr);
  unlock:
  	spin_unlock(&fi->lock);
  	return rc;
  }
  
  static int __sigp_external_call(struct kvm_vcpu *vcpu, u16 cpu_addr)
  {
  	struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int;
  	struct kvm_s390_local_interrupt *li;
  	struct kvm_s390_interrupt_info *inti;
  	int rc;
  
  	if (cpu_addr >= KVM_MAX_VCPUS)
  		return 3; /* not operational */
  
  	inti = kzalloc(sizeof(*inti), GFP_KERNEL);
  	if (!inti)
  		return -ENOMEM;
  
  	inti->type = KVM_S390_INT_EXTERNAL_CALL;
  	inti->extcall.code = vcpu->vcpu_id;
  
  	spin_lock(&fi->lock);
  	li = fi->local_int[cpu_addr];
  	if (li == NULL) {
  		rc = 3; /* not operational */
  		kfree(inti);
  		goto unlock;
  	}
  	spin_lock_bh(&li->lock);
  	list_add_tail(&inti->list, &li->list);
  	atomic_set(&li->active, 1);
  	atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags);
  	if (waitqueue_active(&li->wq))
  		wake_up_interruptible(&li->wq);
  	spin_unlock_bh(&li->lock);
  	rc = 0; /* order accepted */
  	VCPU_EVENT(vcpu, 4, "sent sigp ext call to cpu %x", cpu_addr);
5288fbf0e   Christian Borntraeger   KVM: s390: interp...
145
  unlock:
b037a4f34   Christian Borntraeger   KVM: s390: optimi...
146
  	spin_unlock(&fi->lock);
5288fbf0e   Christian Borntraeger   KVM: s390: interp...
147
148
  	return rc;
  }
9ace903d1   Christian Ehrhardt   KVM: s390: infras...
149
  static int __inject_sigp_stop(struct kvm_s390_local_interrupt *li, int action)
5288fbf0e   Christian Borntraeger   KVM: s390: interp...
150
  {
180c12fb2   Christian Borntraeger   KVM: s390: rename...
151
  	struct kvm_s390_interrupt_info *inti;
5288fbf0e   Christian Borntraeger   KVM: s390: interp...
152

9940fa80c   Julia Lawall   [S390] arch/s390/...
153
  	inti = kzalloc(sizeof(*inti), GFP_ATOMIC);
5288fbf0e   Christian Borntraeger   KVM: s390: interp...
154
155
  	if (!inti)
  		return -ENOMEM;
5288fbf0e   Christian Borntraeger   KVM: s390: interp...
156
  	inti->type = KVM_S390_SIGP_STOP;
5288fbf0e   Christian Borntraeger   KVM: s390: interp...
157
158
159
160
  	spin_lock_bh(&li->lock);
  	list_add_tail(&inti->list, &li->list);
  	atomic_set(&li->active, 1);
  	atomic_set_mask(CPUSTAT_STOP_INT, li->cpuflags);
9ace903d1   Christian Ehrhardt   KVM: s390: infras...
161
  	li->action_bits |= action;
5288fbf0e   Christian Borntraeger   KVM: s390: interp...
162
163
164
  	if (waitqueue_active(&li->wq))
  		wake_up_interruptible(&li->wq);
  	spin_unlock_bh(&li->lock);
9ace903d1   Christian Ehrhardt   KVM: s390: infras...
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
  
  	return 0; /* order accepted */
  }
  
  static int __sigp_stop(struct kvm_vcpu *vcpu, u16 cpu_addr, int action)
  {
  	struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int;
  	struct kvm_s390_local_interrupt *li;
  	int rc;
  
  	if (cpu_addr >= KVM_MAX_VCPUS)
  		return 3; /* not operational */
  
  	spin_lock(&fi->lock);
  	li = fi->local_int[cpu_addr];
  	if (li == NULL) {
  		rc = 3; /* not operational */
  		goto unlock;
  	}
  
  	rc = __inject_sigp_stop(li, action);
5288fbf0e   Christian Borntraeger   KVM: s390: interp...
186
  unlock:
b037a4f34   Christian Borntraeger   KVM: s390: optimi...
187
  	spin_unlock(&fi->lock);
5288fbf0e   Christian Borntraeger   KVM: s390: interp...
188
189
190
  	VCPU_EVENT(vcpu, 4, "sent sigp stop to cpu %x", cpu_addr);
  	return rc;
  }
9ace903d1   Christian Ehrhardt   KVM: s390: infras...
191
192
193
194
195
  int kvm_s390_inject_sigp_stop(struct kvm_vcpu *vcpu, int action)
  {
  	struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
  	return __inject_sigp_stop(li, action);
  }
5288fbf0e   Christian Borntraeger   KVM: s390: interp...
196
197
198
199
200
201
  static int __sigp_set_arch(struct kvm_vcpu *vcpu, u32 parameter)
  {
  	int rc;
  
  	switch (parameter & 0xff) {
  	case 0:
5288fbf0e   Christian Borntraeger   KVM: s390: interp...
202
203
204
205
206
207
208
  		rc = 3; /* not operational */
  		break;
  	case 1:
  	case 2:
  		rc = 0; /* order accepted */
  		break;
  	default:
b8e660b83   Heiko Carstens   [S390] Replace EN...
209
  		rc = -EOPNOTSUPP;
5288fbf0e   Christian Borntraeger   KVM: s390: interp...
210
211
212
213
214
  	}
  	return rc;
  }
  
  static int __sigp_set_prefix(struct kvm_vcpu *vcpu, u16 cpu_addr, u32 address,
0096369da   Martin Schwidefsky   KVM: s390: Change...
215
  			     unsigned long *reg)
5288fbf0e   Christian Borntraeger   KVM: s390: interp...
216
  {
180c12fb2   Christian Borntraeger   KVM: s390: rename...
217
  	struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int;
53cb780ad   Roel Kluin   [S390] KVM: Read ...
218
  	struct kvm_s390_local_interrupt *li = NULL;
180c12fb2   Christian Borntraeger   KVM: s390: rename...
219
  	struct kvm_s390_interrupt_info *inti;
5288fbf0e   Christian Borntraeger   KVM: s390: interp...
220
221
222
223
224
  	int rc;
  	u8 tmp;
  
  	/* make sure that the new value is valid memory */
  	address = address & 0x7fffe000u;
092670cd9   Carsten Otte   [S390] Use gmap t...
225
226
  	if (copy_from_guest_absolute(vcpu, &tmp, address, 1) ||
  	   copy_from_guest_absolute(vcpu, &tmp, address + PAGE_SIZE, 1)) {
5288fbf0e   Christian Borntraeger   KVM: s390: interp...
227
228
229
230
231
232
233
  		*reg |= SIGP_STAT_INVALID_PARAMETER;
  		return 1; /* invalid parameter */
  	}
  
  	inti = kzalloc(sizeof(*inti), GFP_KERNEL);
  	if (!inti)
  		return 2; /* busy */
b037a4f34   Christian Borntraeger   KVM: s390: optimi...
234
  	spin_lock(&fi->lock);
53cb780ad   Roel Kluin   [S390] KVM: Read ...
235
236
  	if (cpu_addr < KVM_MAX_VCPUS)
  		li = fi->local_int[cpu_addr];
5288fbf0e   Christian Borntraeger   KVM: s390: interp...
237

53cb780ad   Roel Kluin   [S390] KVM: Read ...
238
  	if (li == NULL) {
5288fbf0e   Christian Borntraeger   KVM: s390: interp...
239
240
241
242
243
244
245
246
  		rc = 1; /* incorrect state */
  		*reg &= SIGP_STAT_INCORRECT_STATE;
  		kfree(inti);
  		goto out_fi;
  	}
  
  	spin_lock_bh(&li->lock);
  	/* cpu must be in stopped state */
9e6dabeff   Cornelia Huck   KVM: s390: Fix RU...
247
  	if (!(atomic_read(li->cpuflags) & CPUSTAT_STOPPED)) {
5288fbf0e   Christian Borntraeger   KVM: s390: interp...
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
  		rc = 1; /* incorrect state */
  		*reg &= SIGP_STAT_INCORRECT_STATE;
  		kfree(inti);
  		goto out_li;
  	}
  
  	inti->type = KVM_S390_SIGP_SET_PREFIX;
  	inti->prefix.address = address;
  
  	list_add_tail(&inti->list, &li->list);
  	atomic_set(&li->active, 1);
  	if (waitqueue_active(&li->wq))
  		wake_up_interruptible(&li->wq);
  	rc = 0; /* order accepted */
  
  	VCPU_EVENT(vcpu, 4, "set prefix of cpu %02x to %x", cpu_addr, address);
  out_li:
  	spin_unlock_bh(&li->lock);
  out_fi:
b037a4f34   Christian Borntraeger   KVM: s390: optimi...
267
  	spin_unlock(&fi->lock);
5288fbf0e   Christian Borntraeger   KVM: s390: interp...
268
269
  	return rc;
  }
bd59d3a44   Cornelia Huck   KVM: s390: handle...
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
  static int __sigp_sense_running(struct kvm_vcpu *vcpu, u16 cpu_addr,
  				unsigned long *reg)
  {
  	int rc;
  	struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int;
  
  	if (cpu_addr >= KVM_MAX_VCPUS)
  		return 3; /* not operational */
  
  	spin_lock(&fi->lock);
  	if (fi->local_int[cpu_addr] == NULL)
  		rc = 3; /* not operational */
  	else {
  		if (atomic_read(fi->local_int[cpu_addr]->cpuflags)
  		    & CPUSTAT_RUNNING) {
  			/* running */
  			rc = 1;
  		} else {
  			/* not running */
  			*reg &= 0xffffffff00000000UL;
  			*reg |= SIGP_STAT_NOT_RUNNING;
  			rc = 0;
  		}
  	}
  	spin_unlock(&fi->lock);
  
  	VCPU_EVENT(vcpu, 4, "sensed running status of cpu %x rc %x", cpu_addr,
  		   rc);
  
  	return rc;
  }
5288fbf0e   Christian Borntraeger   KVM: s390: interp...
301
302
303
304
305
306
307
308
309
310
  int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu)
  {
  	int r1 = (vcpu->arch.sie_block->ipa & 0x00f0) >> 4;
  	int r3 = vcpu->arch.sie_block->ipa & 0x000f;
  	int base2 = vcpu->arch.sie_block->ipb >> 28;
  	int disp2 = ((vcpu->arch.sie_block->ipb & 0x0fff0000) >> 16);
  	u32 parameter;
  	u16 cpu_addr = vcpu->arch.guest_gprs[r3];
  	u8 order_code;
  	int rc;
3eb77d511   Christian Borntraeger   KVM: s390: Fix pr...
311
312
313
314
  	/* sigp in userspace can exit */
  	if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
  		return kvm_s390_inject_program_int(vcpu,
  						   PGM_PRIVILEGED_OPERATION);
5288fbf0e   Christian Borntraeger   KVM: s390: interp...
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
  	order_code = disp2;
  	if (base2)
  		order_code += vcpu->arch.guest_gprs[base2];
  
  	if (r1 % 2)
  		parameter = vcpu->arch.guest_gprs[r1];
  	else
  		parameter = vcpu->arch.guest_gprs[r1 + 1];
  
  	switch (order_code) {
  	case SIGP_SENSE:
  		vcpu->stat.instruction_sigp_sense++;
  		rc = __sigp_sense(vcpu, cpu_addr,
  				  &vcpu->arch.guest_gprs[r1]);
  		break;
7697e71f7   Christian Ehrhardt   KVM: s390: implem...
330
331
332
333
  	case SIGP_EXTERNAL_CALL:
  		vcpu->stat.instruction_sigp_external_call++;
  		rc = __sigp_external_call(vcpu, cpu_addr);
  		break;
5288fbf0e   Christian Borntraeger   KVM: s390: interp...
334
335
336
337
338
339
  	case SIGP_EMERGENCY:
  		vcpu->stat.instruction_sigp_emergency++;
  		rc = __sigp_emergency(vcpu, cpu_addr);
  		break;
  	case SIGP_STOP:
  		vcpu->stat.instruction_sigp_stop++;
9ace903d1   Christian Ehrhardt   KVM: s390: infras...
340
  		rc = __sigp_stop(vcpu, cpu_addr, ACTION_STOP_ON_STOP);
5288fbf0e   Christian Borntraeger   KVM: s390: interp...
341
342
343
  		break;
  	case SIGP_STOP_STORE_STATUS:
  		vcpu->stat.instruction_sigp_stop++;
9ace903d1   Christian Ehrhardt   KVM: s390: infras...
344
  		rc = __sigp_stop(vcpu, cpu_addr, ACTION_STORE_ON_STOP);
5288fbf0e   Christian Borntraeger   KVM: s390: interp...
345
346
347
348
349
350
351
352
353
354
  		break;
  	case SIGP_SET_ARCH:
  		vcpu->stat.instruction_sigp_arch++;
  		rc = __sigp_set_arch(vcpu, parameter);
  		break;
  	case SIGP_SET_PREFIX:
  		vcpu->stat.instruction_sigp_prefix++;
  		rc = __sigp_set_prefix(vcpu, cpu_addr, parameter,
  				       &vcpu->arch.guest_gprs[r1]);
  		break;
bd59d3a44   Cornelia Huck   KVM: s390: handle...
355
356
357
358
359
  	case SIGP_SENSE_RUNNING:
  		vcpu->stat.instruction_sigp_sense_running++;
  		rc = __sigp_sense_running(vcpu, cpu_addr,
  					  &vcpu->arch.guest_gprs[r1]);
  		break;
5288fbf0e   Christian Borntraeger   KVM: s390: interp...
360
361
362
363
  	case SIGP_RESTART:
  		vcpu->stat.instruction_sigp_restart++;
  		/* user space must know about restart */
  	default:
b8e660b83   Heiko Carstens   [S390] Replace EN...
364
  		return -EOPNOTSUPP;
5288fbf0e   Christian Borntraeger   KVM: s390: interp...
365
366
367
368
369
370
371
372
373
  	}
  
  	if (rc < 0)
  		return rc;
  
  	vcpu->arch.sie_block->gpsw.mask &= ~(3ul << 44);
  	vcpu->arch.sie_block->gpsw.mask |= (rc & 3ul) << 44;
  	return 0;
  }