aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Ehrhardt <ehrhardt@linux.vnet.ibm.com>2009-05-20 09:34:55 -0400
committerAvi Kivity <avi@redhat.com>2009-09-10 01:32:42 -0400
commit9ace903d171db7dc2fed96e44ac62b6f4c3ccb3d (patch)
tree50668cde71950831339d601a3bfeabe49657770e
parent3032b925f00ba2653f7695d356d6f8284c82038d (diff)
KVM: s390: infrastructure to kick vcpus out of guest state
To ensure vcpu's come out of guest context in certain cases this patch adds a s390 specific way to kick them out of guest context. Currently it kicks them out to rerun the vcpu_run path in the s390 code, but the mechanism itself is expandable and with a new flag we could also add e.g. kicks to userspace etc. Signed-off-by: Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com> Signed-off-by: Avi Kivity <avi@redhat.com>
-rw-r--r--arch/s390/include/asm/kvm_host.h5
-rw-r--r--arch/s390/kvm/intercept.c12
-rw-r--r--arch/s390/kvm/kvm-s390.c5
-rw-r--r--arch/s390/kvm/kvm-s390.h3
-rw-r--r--arch/s390/kvm/sigp.c56
5 files changed, 54 insertions, 27 deletions
diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h
index 1cd02f6073a0..0a784f6f9c90 100644
--- a/arch/s390/include/asm/kvm_host.h
+++ b/arch/s390/include/asm/kvm_host.h
@@ -182,8 +182,9 @@ struct kvm_s390_interrupt_info {
182}; 182};
183 183
184/* for local_interrupt.action_flags */ 184/* for local_interrupt.action_flags */
185#define ACTION_STORE_ON_STOP 1 185#define ACTION_STORE_ON_STOP (1<<0)
186#define ACTION_STOP_ON_STOP 2 186#define ACTION_STOP_ON_STOP (1<<1)
187#define ACTION_RELOADVCPU_ON_STOP (1<<2)
187 188
188struct kvm_s390_local_interrupt { 189struct kvm_s390_local_interrupt {
189 spinlock_t lock; 190 spinlock_t lock;
diff --git a/arch/s390/kvm/intercept.c b/arch/s390/kvm/intercept.c
index 98997ccba501..0732ab4305f4 100644
--- a/arch/s390/kvm/intercept.c
+++ b/arch/s390/kvm/intercept.c
@@ -128,7 +128,7 @@ static int handle_noop(struct kvm_vcpu *vcpu)
128 128
129static int handle_stop(struct kvm_vcpu *vcpu) 129static int handle_stop(struct kvm_vcpu *vcpu)
130{ 130{
131 int rc; 131 int rc = 0;
132 132
133 vcpu->stat.exit_stop_request++; 133 vcpu->stat.exit_stop_request++;
134 atomic_clear_mask(CPUSTAT_RUNNING, &vcpu->arch.sie_block->cpuflags); 134 atomic_clear_mask(CPUSTAT_RUNNING, &vcpu->arch.sie_block->cpuflags);
@@ -141,12 +141,18 @@ static int handle_stop(struct kvm_vcpu *vcpu)
141 rc = -ENOTSUPP; 141 rc = -ENOTSUPP;
142 } 142 }
143 143
144 if (vcpu->arch.local_int.action_bits & ACTION_RELOADVCPU_ON_STOP) {
145 vcpu->arch.local_int.action_bits &= ~ACTION_RELOADVCPU_ON_STOP;
146 rc = SIE_INTERCEPT_RERUNVCPU;
147 vcpu->run->exit_reason = KVM_EXIT_INTR;
148 }
149
144 if (vcpu->arch.local_int.action_bits & ACTION_STOP_ON_STOP) { 150 if (vcpu->arch.local_int.action_bits & ACTION_STOP_ON_STOP) {
145 vcpu->arch.local_int.action_bits &= ~ACTION_STOP_ON_STOP; 151 vcpu->arch.local_int.action_bits &= ~ACTION_STOP_ON_STOP;
146 VCPU_EVENT(vcpu, 3, "%s", "cpu stopped"); 152 VCPU_EVENT(vcpu, 3, "%s", "cpu stopped");
147 rc = -ENOTSUPP; 153 rc = -ENOTSUPP;
148 } else 154 }
149 rc = 0; 155
150 spin_unlock_bh(&vcpu->arch.local_int.lock); 156 spin_unlock_bh(&vcpu->arch.local_int.lock);
151 return rc; 157 return rc;
152} 158}
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index 90d9d1ba258b..1d65f6277166 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -490,6 +490,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
490 490
491 vcpu_load(vcpu); 491 vcpu_load(vcpu);
492 492
493rerun_vcpu:
493 /* verify, that memory has been registered */ 494 /* verify, that memory has been registered */
494 if (!vcpu->kvm->arch.guest_memsize) { 495 if (!vcpu->kvm->arch.guest_memsize) {
495 vcpu_put(vcpu); 496 vcpu_put(vcpu);
@@ -509,6 +510,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
509 vcpu->arch.sie_block->gpsw.addr = kvm_run->s390_sieic.addr; 510 vcpu->arch.sie_block->gpsw.addr = kvm_run->s390_sieic.addr;
510 break; 511 break;
511 case KVM_EXIT_UNKNOWN: 512 case KVM_EXIT_UNKNOWN:
513 case KVM_EXIT_INTR:
512 case KVM_EXIT_S390_RESET: 514 case KVM_EXIT_S390_RESET:
513 break; 515 break;
514 default: 516 default:
@@ -522,6 +524,9 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
522 rc = kvm_handle_sie_intercept(vcpu); 524 rc = kvm_handle_sie_intercept(vcpu);
523 } while (!signal_pending(current) && !rc); 525 } while (!signal_pending(current) && !rc);
524 526
527 if (rc == SIE_INTERCEPT_RERUNVCPU)
528 goto rerun_vcpu;
529
525 if (signal_pending(current) && !rc) 530 if (signal_pending(current) && !rc)
526 rc = -EINTR; 531 rc = -EINTR;
527 532
diff --git a/arch/s390/kvm/kvm-s390.h b/arch/s390/kvm/kvm-s390.h
index 748fee872323..2072cd4a013e 100644
--- a/arch/s390/kvm/kvm-s390.h
+++ b/arch/s390/kvm/kvm-s390.h
@@ -20,6 +20,8 @@
20 20
21typedef int (*intercept_handler_t)(struct kvm_vcpu *vcpu); 21typedef int (*intercept_handler_t)(struct kvm_vcpu *vcpu);
22 22
23/* negativ values are error codes, positive values for internal conditions */
24#define SIE_INTERCEPT_RERUNVCPU (1<<0)
23int kvm_handle_sie_intercept(struct kvm_vcpu *vcpu); 25int kvm_handle_sie_intercept(struct kvm_vcpu *vcpu);
24 26
25#define VM_EVENT(d_kvm, d_loglevel, d_string, d_args...)\ 27#define VM_EVENT(d_kvm, d_loglevel, d_string, d_args...)\
@@ -50,6 +52,7 @@ int kvm_s390_inject_vm(struct kvm *kvm,
50int kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu, 52int kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu,
51 struct kvm_s390_interrupt *s390int); 53 struct kvm_s390_interrupt *s390int);
52int kvm_s390_inject_program_int(struct kvm_vcpu *vcpu, u16 code); 54int kvm_s390_inject_program_int(struct kvm_vcpu *vcpu, u16 code);
55int kvm_s390_inject_sigp_stop(struct kvm_vcpu *vcpu, int action);
53 56
54/* implemented in priv.c */ 57/* implemented in priv.c */
55int kvm_s390_handle_b2(struct kvm_vcpu *vcpu); 58int kvm_s390_handle_b2(struct kvm_vcpu *vcpu);
diff --git a/arch/s390/kvm/sigp.c b/arch/s390/kvm/sigp.c
index 0ef81d6776e9..21897b0f8a36 100644
--- a/arch/s390/kvm/sigp.c
+++ b/arch/s390/kvm/sigp.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * sigp.c - handlinge interprocessor communication 2 * sigp.c - handlinge interprocessor communication
3 * 3 *
4 * Copyright IBM Corp. 2008 4 * Copyright IBM Corp. 2008,2009
5 * 5 *
6 * This program is free software; you can redistribute it and/or modify 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) 7 * it under the terms of the GNU General Public License (version 2 only)
@@ -9,6 +9,7 @@
9 * 9 *
10 * Author(s): Carsten Otte <cotte@de.ibm.com> 10 * Author(s): Carsten Otte <cotte@de.ibm.com>
11 * Christian Borntraeger <borntraeger@de.ibm.com> 11 * Christian Borntraeger <borntraeger@de.ibm.com>
12 * Christian Ehrhardt <ehrhardt@de.ibm.com>
12 */ 13 */
13 14
14#include <linux/kvm.h> 15#include <linux/kvm.h>
@@ -107,46 +108,57 @@ unlock:
107 return rc; 108 return rc;
108} 109}
109 110
110static int __sigp_stop(struct kvm_vcpu *vcpu, u16 cpu_addr, int store) 111static int __inject_sigp_stop(struct kvm_s390_local_interrupt *li, int action)
111{ 112{
112 struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int;
113 struct kvm_s390_local_interrupt *li;
114 struct kvm_s390_interrupt_info *inti; 113 struct kvm_s390_interrupt_info *inti;
115 int rc;
116
117 if (cpu_addr >= KVM_MAX_VCPUS)
118 return 3; /* not operational */
119 114
120 inti = kzalloc(sizeof(*inti), GFP_KERNEL); 115 inti = kzalloc(sizeof(*inti), GFP_KERNEL);
121 if (!inti) 116 if (!inti)
122 return -ENOMEM; 117 return -ENOMEM;
123
124 inti->type = KVM_S390_SIGP_STOP; 118 inti->type = KVM_S390_SIGP_STOP;
125 119
126 spin_lock(&fi->lock);
127 li = fi->local_int[cpu_addr];
128 if (li == NULL) {
129 rc = 3; /* not operational */
130 kfree(inti);
131 goto unlock;
132 }
133 spin_lock_bh(&li->lock); 120 spin_lock_bh(&li->lock);
134 list_add_tail(&inti->list, &li->list); 121 list_add_tail(&inti->list, &li->list);
135 atomic_set(&li->active, 1); 122 atomic_set(&li->active, 1);
136 atomic_set_mask(CPUSTAT_STOP_INT, li->cpuflags); 123 atomic_set_mask(CPUSTAT_STOP_INT, li->cpuflags);
137 if (store) 124 li->action_bits |= action;
138 li->action_bits |= ACTION_STORE_ON_STOP;
139 li->action_bits |= ACTION_STOP_ON_STOP;
140 if (waitqueue_active(&li->wq)) 125 if (waitqueue_active(&li->wq))
141 wake_up_interruptible(&li->wq); 126 wake_up_interruptible(&li->wq);
142 spin_unlock_bh(&li->lock); 127 spin_unlock_bh(&li->lock);
143 rc = 0; /* order accepted */ 128
129 return 0; /* order accepted */
130}
131
132static 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
144unlock: 150unlock:
145 spin_unlock(&fi->lock); 151 spin_unlock(&fi->lock);
146 VCPU_EVENT(vcpu, 4, "sent sigp stop to cpu %x", cpu_addr); 152 VCPU_EVENT(vcpu, 4, "sent sigp stop to cpu %x", cpu_addr);
147 return rc; 153 return rc;
148} 154}
149 155
156int 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
150static int __sigp_set_arch(struct kvm_vcpu *vcpu, u32 parameter) 162static int __sigp_set_arch(struct kvm_vcpu *vcpu, u32 parameter)
151{ 163{
152 int rc; 164 int rc;
@@ -262,11 +274,11 @@ int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu)
262 break; 274 break;
263 case SIGP_STOP: 275 case SIGP_STOP:
264 vcpu->stat.instruction_sigp_stop++; 276 vcpu->stat.instruction_sigp_stop++;
265 rc = __sigp_stop(vcpu, cpu_addr, 0); 277 rc = __sigp_stop(vcpu, cpu_addr, ACTION_STOP_ON_STOP);
266 break; 278 break;
267 case SIGP_STOP_STORE_STATUS: 279 case SIGP_STOP_STORE_STATUS:
268 vcpu->stat.instruction_sigp_stop++; 280 vcpu->stat.instruction_sigp_stop++;
269 rc = __sigp_stop(vcpu, cpu_addr, 1); 281 rc = __sigp_stop(vcpu, cpu_addr, ACTION_STORE_ON_STOP);
270 break; 282 break;
271 case SIGP_SET_ARCH: 283 case SIGP_SET_ARCH:
272 vcpu->stat.instruction_sigp_arch++; 284 vcpu->stat.instruction_sigp_arch++;