aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/kvm
diff options
context:
space:
mode:
Diffstat (limited to 'arch/s390/kvm')
-rw-r--r--arch/s390/kvm/diag.c2
-rw-r--r--arch/s390/kvm/intercept.c3
-rw-r--r--arch/s390/kvm/interrupt.c1
-rw-r--r--arch/s390/kvm/kvm-s390.c12
-rw-r--r--arch/s390/kvm/priv.c10
-rw-r--r--arch/s390/kvm/sigp.c45
6 files changed, 63 insertions, 10 deletions
diff --git a/arch/s390/kvm/diag.c b/arch/s390/kvm/diag.c
index 87cedd61be0..8943e82cd4d 100644
--- a/arch/s390/kvm/diag.c
+++ b/arch/s390/kvm/diag.c
@@ -70,7 +70,7 @@ static int __diag_ipl_functions(struct kvm_vcpu *vcpu)
70 return -EOPNOTSUPP; 70 return -EOPNOTSUPP;
71 } 71 }
72 72
73 atomic_clear_mask(CPUSTAT_RUNNING, &vcpu->arch.sie_block->cpuflags); 73 atomic_set_mask(CPUSTAT_STOPPED, &vcpu->arch.sie_block->cpuflags);
74 vcpu->run->s390_reset_flags |= KVM_S390_RESET_SUBSYSTEM; 74 vcpu->run->s390_reset_flags |= KVM_S390_RESET_SUBSYSTEM;
75 vcpu->run->s390_reset_flags |= KVM_S390_RESET_IPL; 75 vcpu->run->s390_reset_flags |= KVM_S390_RESET_IPL;
76 vcpu->run->s390_reset_flags |= KVM_S390_RESET_CPU_INIT; 76 vcpu->run->s390_reset_flags |= KVM_S390_RESET_CPU_INIT;
diff --git a/arch/s390/kvm/intercept.c b/arch/s390/kvm/intercept.c
index c7c51898984..02434543eab 100644
--- a/arch/s390/kvm/intercept.c
+++ b/arch/s390/kvm/intercept.c
@@ -132,7 +132,6 @@ static int handle_stop(struct kvm_vcpu *vcpu)
132 int rc = 0; 132 int rc = 0;
133 133
134 vcpu->stat.exit_stop_request++; 134 vcpu->stat.exit_stop_request++;
135 atomic_clear_mask(CPUSTAT_RUNNING, &vcpu->arch.sie_block->cpuflags);
136 spin_lock_bh(&vcpu->arch.local_int.lock); 135 spin_lock_bh(&vcpu->arch.local_int.lock);
137 if (vcpu->arch.local_int.action_bits & ACTION_STORE_ON_STOP) { 136 if (vcpu->arch.local_int.action_bits & ACTION_STORE_ON_STOP) {
138 vcpu->arch.local_int.action_bits &= ~ACTION_STORE_ON_STOP; 137 vcpu->arch.local_int.action_bits &= ~ACTION_STORE_ON_STOP;
@@ -149,6 +148,8 @@ static int handle_stop(struct kvm_vcpu *vcpu)
149 } 148 }
150 149
151 if (vcpu->arch.local_int.action_bits & ACTION_STOP_ON_STOP) { 150 if (vcpu->arch.local_int.action_bits & ACTION_STOP_ON_STOP) {
151 atomic_set_mask(CPUSTAT_STOPPED,
152 &vcpu->arch.sie_block->cpuflags);
152 vcpu->arch.local_int.action_bits &= ~ACTION_STOP_ON_STOP; 153 vcpu->arch.local_int.action_bits &= ~ACTION_STOP_ON_STOP;
153 VCPU_EVENT(vcpu, 3, "%s", "cpu stopped"); 154 VCPU_EVENT(vcpu, 3, "%s", "cpu stopped");
154 rc = -EOPNOTSUPP; 155 rc = -EOPNOTSUPP;
diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c
index 87c16705b38..278ee009ce6 100644
--- a/arch/s390/kvm/interrupt.c
+++ b/arch/s390/kvm/interrupt.c
@@ -252,6 +252,7 @@ static void __do_deliver_interrupt(struct kvm_vcpu *vcpu,
252 offsetof(struct _lowcore, restart_psw), sizeof(psw_t)); 252 offsetof(struct _lowcore, restart_psw), sizeof(psw_t));
253 if (rc == -EFAULT) 253 if (rc == -EFAULT)
254 exception = 1; 254 exception = 1;
255 atomic_clear_mask(CPUSTAT_STOPPED, &vcpu->arch.sie_block->cpuflags);
255 break; 256 break;
256 257
257 case KVM_S390_PROGRAM_INT: 258 case KVM_S390_PROGRAM_INT:
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index 0bd3bea1e4c..d1c44573245 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -65,6 +65,7 @@ struct kvm_stats_debugfs_item debugfs_entries[] = {
65 { "instruction_stfl", VCPU_STAT(instruction_stfl) }, 65 { "instruction_stfl", VCPU_STAT(instruction_stfl) },
66 { "instruction_tprot", VCPU_STAT(instruction_tprot) }, 66 { "instruction_tprot", VCPU_STAT(instruction_tprot) },
67 { "instruction_sigp_sense", VCPU_STAT(instruction_sigp_sense) }, 67 { "instruction_sigp_sense", VCPU_STAT(instruction_sigp_sense) },
68 { "instruction_sigp_sense_running", VCPU_STAT(instruction_sigp_sense_running) },
68 { "instruction_sigp_external_call", VCPU_STAT(instruction_sigp_external_call) }, 69 { "instruction_sigp_external_call", VCPU_STAT(instruction_sigp_external_call) },
69 { "instruction_sigp_emergency", VCPU_STAT(instruction_sigp_emergency) }, 70 { "instruction_sigp_emergency", VCPU_STAT(instruction_sigp_emergency) },
70 { "instruction_sigp_stop", VCPU_STAT(instruction_sigp_stop) }, 71 { "instruction_sigp_stop", VCPU_STAT(instruction_sigp_stop) },
@@ -127,6 +128,7 @@ int kvm_dev_ioctl_check_extension(long ext)
127 switch (ext) { 128 switch (ext) {
128 case KVM_CAP_S390_PSW: 129 case KVM_CAP_S390_PSW:
129 case KVM_CAP_S390_GMAP: 130 case KVM_CAP_S390_GMAP:
131 case KVM_CAP_SYNC_MMU:
130 r = 1; 132 r = 1;
131 break; 133 break;
132 default: 134 default:
@@ -270,10 +272,12 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
270 restore_fp_regs(&vcpu->arch.guest_fpregs); 272 restore_fp_regs(&vcpu->arch.guest_fpregs);
271 restore_access_regs(vcpu->arch.guest_acrs); 273 restore_access_regs(vcpu->arch.guest_acrs);
272 gmap_enable(vcpu->arch.gmap); 274 gmap_enable(vcpu->arch.gmap);
275 atomic_set_mask(CPUSTAT_RUNNING, &vcpu->arch.sie_block->cpuflags);
273} 276}
274 277
275void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) 278void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
276{ 279{
280 atomic_clear_mask(CPUSTAT_RUNNING, &vcpu->arch.sie_block->cpuflags);
277 gmap_disable(vcpu->arch.gmap); 281 gmap_disable(vcpu->arch.gmap);
278 save_fp_regs(&vcpu->arch.guest_fpregs); 282 save_fp_regs(&vcpu->arch.guest_fpregs);
279 save_access_regs(vcpu->arch.guest_acrs); 283 save_access_regs(vcpu->arch.guest_acrs);
@@ -301,7 +305,9 @@ static void kvm_s390_vcpu_initial_reset(struct kvm_vcpu *vcpu)
301 305
302int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu) 306int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
303{ 307{
304 atomic_set(&vcpu->arch.sie_block->cpuflags, CPUSTAT_ZARCH | CPUSTAT_SM); 308 atomic_set(&vcpu->arch.sie_block->cpuflags, CPUSTAT_ZARCH |
309 CPUSTAT_SM |
310 CPUSTAT_STOPPED);
305 vcpu->arch.sie_block->ecb = 6; 311 vcpu->arch.sie_block->ecb = 6;
306 vcpu->arch.sie_block->eca = 0xC1002001U; 312 vcpu->arch.sie_block->eca = 0xC1002001U;
307 vcpu->arch.sie_block->fac = (int) (long) facilities; 313 vcpu->arch.sie_block->fac = (int) (long) facilities;
@@ -428,7 +434,7 @@ static int kvm_arch_vcpu_ioctl_set_initial_psw(struct kvm_vcpu *vcpu, psw_t psw)
428{ 434{
429 int rc = 0; 435 int rc = 0;
430 436
431 if (atomic_read(&vcpu->arch.sie_block->cpuflags) & CPUSTAT_RUNNING) 437 if (!(atomic_read(&vcpu->arch.sie_block->cpuflags) & CPUSTAT_STOPPED))
432 rc = -EBUSY; 438 rc = -EBUSY;
433 else { 439 else {
434 vcpu->run->psw_mask = psw.mask; 440 vcpu->run->psw_mask = psw.mask;
@@ -501,7 +507,7 @@ rerun_vcpu:
501 if (vcpu->sigset_active) 507 if (vcpu->sigset_active)
502 sigprocmask(SIG_SETMASK, &vcpu->sigset, &sigsaved); 508 sigprocmask(SIG_SETMASK, &vcpu->sigset, &sigsaved);
503 509
504 atomic_set_mask(CPUSTAT_RUNNING, &vcpu->arch.sie_block->cpuflags); 510 atomic_clear_mask(CPUSTAT_STOPPED, &vcpu->arch.sie_block->cpuflags);
505 511
506 BUG_ON(vcpu->kvm->arch.float_int.local_int[vcpu->vcpu_id] == NULL); 512 BUG_ON(vcpu->kvm->arch.float_int.local_int[vcpu->vcpu_id] == NULL);
507 513
diff --git a/arch/s390/kvm/priv.c b/arch/s390/kvm/priv.c
index 39162636108..d0263895992 100644
--- a/arch/s390/kvm/priv.c
+++ b/arch/s390/kvm/priv.c
@@ -336,6 +336,7 @@ static int handle_tprot(struct kvm_vcpu *vcpu)
336 u64 address1 = disp1 + base1 ? vcpu->arch.guest_gprs[base1] : 0; 336 u64 address1 = disp1 + base1 ? vcpu->arch.guest_gprs[base1] : 0;
337 u64 address2 = disp2 + base2 ? vcpu->arch.guest_gprs[base2] : 0; 337 u64 address2 = disp2 + base2 ? vcpu->arch.guest_gprs[base2] : 0;
338 struct vm_area_struct *vma; 338 struct vm_area_struct *vma;
339 unsigned long user_address;
339 340
340 vcpu->stat.instruction_tprot++; 341 vcpu->stat.instruction_tprot++;
341 342
@@ -349,9 +350,14 @@ static int handle_tprot(struct kvm_vcpu *vcpu)
349 return -EOPNOTSUPP; 350 return -EOPNOTSUPP;
350 351
351 352
353 /* we must resolve the address without holding the mmap semaphore.
354 * This is ok since the userspace hypervisor is not supposed to change
355 * the mapping while the guest queries the memory. Otherwise the guest
356 * might crash or get wrong info anyway. */
357 user_address = (unsigned long) __guestaddr_to_user(vcpu, address1);
358
352 down_read(&current->mm->mmap_sem); 359 down_read(&current->mm->mmap_sem);
353 vma = find_vma(current->mm, 360 vma = find_vma(current->mm, user_address);
354 (unsigned long) __guestaddr_to_user(vcpu, address1));
355 if (!vma) { 361 if (!vma) {
356 up_read(&current->mm->mmap_sem); 362 up_read(&current->mm->mmap_sem);
357 return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); 363 return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
diff --git a/arch/s390/kvm/sigp.c b/arch/s390/kvm/sigp.c
index f815118835f..0a7941d74bc 100644
--- a/arch/s390/kvm/sigp.c
+++ b/arch/s390/kvm/sigp.c
@@ -31,9 +31,11 @@
31#define SIGP_SET_PREFIX 0x0d 31#define SIGP_SET_PREFIX 0x0d
32#define SIGP_STORE_STATUS_ADDR 0x0e 32#define SIGP_STORE_STATUS_ADDR 0x0e
33#define SIGP_SET_ARCH 0x12 33#define SIGP_SET_ARCH 0x12
34#define SIGP_SENSE_RUNNING 0x15
34 35
35/* cpu status bits */ 36/* cpu status bits */
36#define SIGP_STAT_EQUIPMENT_CHECK 0x80000000UL 37#define SIGP_STAT_EQUIPMENT_CHECK 0x80000000UL
38#define SIGP_STAT_NOT_RUNNING 0x00000400UL
37#define SIGP_STAT_INCORRECT_STATE 0x00000200UL 39#define SIGP_STAT_INCORRECT_STATE 0x00000200UL
38#define SIGP_STAT_INVALID_PARAMETER 0x00000100UL 40#define SIGP_STAT_INVALID_PARAMETER 0x00000100UL
39#define SIGP_STAT_EXT_CALL_PENDING 0x00000080UL 41#define SIGP_STAT_EXT_CALL_PENDING 0x00000080UL
@@ -57,8 +59,8 @@ static int __sigp_sense(struct kvm_vcpu *vcpu, u16 cpu_addr,
57 spin_lock(&fi->lock); 59 spin_lock(&fi->lock);
58 if (fi->local_int[cpu_addr] == NULL) 60 if (fi->local_int[cpu_addr] == NULL)
59 rc = 3; /* not operational */ 61 rc = 3; /* not operational */
60 else if (atomic_read(fi->local_int[cpu_addr]->cpuflags) 62 else if (!(atomic_read(fi->local_int[cpu_addr]->cpuflags)
61 & CPUSTAT_RUNNING) { 63 & CPUSTAT_STOPPED)) {
62 *reg &= 0xffffffff00000000UL; 64 *reg &= 0xffffffff00000000UL;
63 rc = 1; /* status stored */ 65 rc = 1; /* status stored */
64 } else { 66 } else {
@@ -251,7 +253,7 @@ static int __sigp_set_prefix(struct kvm_vcpu *vcpu, u16 cpu_addr, u32 address,
251 253
252 spin_lock_bh(&li->lock); 254 spin_lock_bh(&li->lock);
253 /* cpu must be in stopped state */ 255 /* cpu must be in stopped state */
254 if (atomic_read(li->cpuflags) & CPUSTAT_RUNNING) { 256 if (!(atomic_read(li->cpuflags) & CPUSTAT_STOPPED)) {
255 rc = 1; /* incorrect state */ 257 rc = 1; /* incorrect state */
256 *reg &= SIGP_STAT_INCORRECT_STATE; 258 *reg &= SIGP_STAT_INCORRECT_STATE;
257 kfree(inti); 259 kfree(inti);
@@ -275,6 +277,38 @@ out_fi:
275 return rc; 277 return rc;
276} 278}
277 279
280static int __sigp_sense_running(struct kvm_vcpu *vcpu, u16 cpu_addr,
281 unsigned long *reg)
282{
283 int rc;
284 struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int;
285
286 if (cpu_addr >= KVM_MAX_VCPUS)
287 return 3; /* not operational */
288
289 spin_lock(&fi->lock);
290 if (fi->local_int[cpu_addr] == NULL)
291 rc = 3; /* not operational */
292 else {
293 if (atomic_read(fi->local_int[cpu_addr]->cpuflags)
294 & CPUSTAT_RUNNING) {
295 /* running */
296 rc = 1;
297 } else {
298 /* not running */
299 *reg &= 0xffffffff00000000UL;
300 *reg |= SIGP_STAT_NOT_RUNNING;
301 rc = 0;
302 }
303 }
304 spin_unlock(&fi->lock);
305
306 VCPU_EVENT(vcpu, 4, "sensed running status of cpu %x rc %x", cpu_addr,
307 rc);
308
309 return rc;
310}
311
278int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu) 312int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu)
279{ 313{
280 int r1 = (vcpu->arch.sie_block->ipa & 0x00f0) >> 4; 314 int r1 = (vcpu->arch.sie_block->ipa & 0x00f0) >> 4;
@@ -331,6 +365,11 @@ int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu)
331 rc = __sigp_set_prefix(vcpu, cpu_addr, parameter, 365 rc = __sigp_set_prefix(vcpu, cpu_addr, parameter,
332 &vcpu->arch.guest_gprs[r1]); 366 &vcpu->arch.guest_gprs[r1]);
333 break; 367 break;
368 case SIGP_SENSE_RUNNING:
369 vcpu->stat.instruction_sigp_sense_running++;
370 rc = __sigp_sense_running(vcpu, cpu_addr,
371 &vcpu->arch.guest_gprs[r1]);
372 break;
334 case SIGP_RESTART: 373 case SIGP_RESTART:
335 vcpu->stat.instruction_sigp_restart++; 374 vcpu->stat.instruction_sigp_restart++;
336 /* user space must know about restart */ 375 /* user space must know about restart */