diff options
author | Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com> | 2009-05-20 09:34:55 -0400 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2009-09-10 01:32:42 -0400 |
commit | 9ace903d171db7dc2fed96e44ac62b6f4c3ccb3d (patch) | |
tree | 50668cde71950831339d601a3bfeabe49657770e | |
parent | 3032b925f00ba2653f7695d356d6f8284c82038d (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.h | 5 | ||||
-rw-r--r-- | arch/s390/kvm/intercept.c | 12 | ||||
-rw-r--r-- | arch/s390/kvm/kvm-s390.c | 5 | ||||
-rw-r--r-- | arch/s390/kvm/kvm-s390.h | 3 | ||||
-rw-r--r-- | arch/s390/kvm/sigp.c | 56 |
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 | ||
188 | struct kvm_s390_local_interrupt { | 189 | struct 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 | ||
129 | static int handle_stop(struct kvm_vcpu *vcpu) | 129 | static 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 | ||
493 | rerun_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 | ||
21 | typedef int (*intercept_handler_t)(struct kvm_vcpu *vcpu); | 21 | typedef 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) | ||
23 | int kvm_handle_sie_intercept(struct kvm_vcpu *vcpu); | 25 | int 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, | |||
50 | int kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu, | 52 | int kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu, |
51 | struct kvm_s390_interrupt *s390int); | 53 | struct kvm_s390_interrupt *s390int); |
52 | int kvm_s390_inject_program_int(struct kvm_vcpu *vcpu, u16 code); | 54 | int kvm_s390_inject_program_int(struct kvm_vcpu *vcpu, u16 code); |
55 | int kvm_s390_inject_sigp_stop(struct kvm_vcpu *vcpu, int action); | ||
53 | 56 | ||
54 | /* implemented in priv.c */ | 57 | /* implemented in priv.c */ |
55 | int kvm_s390_handle_b2(struct kvm_vcpu *vcpu); | 58 | int 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 | ||
110 | static int __sigp_stop(struct kvm_vcpu *vcpu, u16 cpu_addr, int store) | 111 | static 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 | |||
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 | |||
144 | unlock: | 150 | unlock: |
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 | ||
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 | |||
150 | static int __sigp_set_arch(struct kvm_vcpu *vcpu, u32 parameter) | 162 | static 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++; |