aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/kvm/priv.c
diff options
context:
space:
mode:
authorCornelia Huck <cornelia.huck@de.ibm.com>2012-12-20 09:32:12 -0500
committerMarcelo Tosatti <mtosatti@redhat.com>2013-01-07 16:53:43 -0500
commitfa6b7fe9928d50444c29b29c8563746c6b0c6299 (patch)
tree0be284cf322eb82eefdb3df2743740e5578ba5c4 /arch/s390/kvm/priv.c
parentd6712df95bcfea597fc3ea2405ec13e8b69a7b8c (diff)
KVM: s390: Add support for channel I/O instructions.
Add a new capability, KVM_CAP_S390_CSS_SUPPORT, which will pass intercepts for channel I/O instructions to userspace. Only I/O instructions interacting with I/O interrupts need to be handled in-kernel: - TEST PENDING INTERRUPTION (tpi) dequeues and stores pending interrupts entirely in-kernel. - TEST SUBCHANNEL (tsch) dequeues pending interrupts in-kernel and exits via KVM_EXIT_S390_TSCH to userspace for subchannel- related processing. Reviewed-by: Marcelo Tosatti <mtosatti@redhat.com> Reviewed-by: Alexander Graf <agraf@suse.de> Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com> Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Diffstat (limited to 'arch/s390/kvm/priv.c')
-rw-r--r--arch/s390/kvm/priv.c91
1 files changed, 87 insertions, 4 deletions
diff --git a/arch/s390/kvm/priv.c b/arch/s390/kvm/priv.c
index 8ad776f87856..0ef9894606e5 100644
--- a/arch/s390/kvm/priv.c
+++ b/arch/s390/kvm/priv.c
@@ -127,15 +127,98 @@ static int handle_skey(struct kvm_vcpu *vcpu)
127 return 0; 127 return 0;
128} 128}
129 129
130static int handle_io_inst(struct kvm_vcpu *vcpu) 130static int handle_tpi(struct kvm_vcpu *vcpu)
131{ 131{
132 VCPU_EVENT(vcpu, 4, "%s", "I/O instruction"); 132 u64 addr;
133 /* condition code 3 */ 133 struct kvm_s390_interrupt_info *inti;
134 int cc;
135
136 addr = kvm_s390_get_base_disp_s(vcpu);
137
138 inti = kvm_s390_get_io_int(vcpu->kvm, vcpu->run->s.regs.crs[6], 0);
139 if (inti) {
140 if (addr) {
141 /*
142 * Store the two-word I/O interruption code into the
143 * provided area.
144 */
145 put_guest_u16(vcpu, addr, inti->io.subchannel_id);
146 put_guest_u16(vcpu, addr + 2, inti->io.subchannel_nr);
147 put_guest_u32(vcpu, addr + 4, inti->io.io_int_parm);
148 } else {
149 /*
150 * Store the three-word I/O interruption code into
151 * the appropriate lowcore area.
152 */
153 put_guest_u16(vcpu, 184, inti->io.subchannel_id);
154 put_guest_u16(vcpu, 186, inti->io.subchannel_nr);
155 put_guest_u32(vcpu, 188, inti->io.io_int_parm);
156 put_guest_u32(vcpu, 192, inti->io.io_int_word);
157 }
158 cc = 1;
159 } else
160 cc = 0;
161 kfree(inti);
162 /* Set condition code and we're done. */
134 vcpu->arch.sie_block->gpsw.mask &= ~(3ul << 44); 163 vcpu->arch.sie_block->gpsw.mask &= ~(3ul << 44);
135 vcpu->arch.sie_block->gpsw.mask |= (3 & 3ul) << 44; 164 vcpu->arch.sie_block->gpsw.mask |= (cc & 3ul) << 44;
136 return 0; 165 return 0;
137} 166}
138 167
168static int handle_tsch(struct kvm_vcpu *vcpu)
169{
170 struct kvm_s390_interrupt_info *inti;
171
172 inti = kvm_s390_get_io_int(vcpu->kvm, 0,
173 vcpu->run->s.regs.gprs[1]);
174
175 /*
176 * Prepare exit to userspace.
177 * We indicate whether we dequeued a pending I/O interrupt
178 * so that userspace can re-inject it if the instruction gets
179 * a program check. While this may re-order the pending I/O
180 * interrupts, this is no problem since the priority is kept
181 * intact.
182 */
183 vcpu->run->exit_reason = KVM_EXIT_S390_TSCH;
184 vcpu->run->s390_tsch.dequeued = !!inti;
185 if (inti) {
186 vcpu->run->s390_tsch.subchannel_id = inti->io.subchannel_id;
187 vcpu->run->s390_tsch.subchannel_nr = inti->io.subchannel_nr;
188 vcpu->run->s390_tsch.io_int_parm = inti->io.io_int_parm;
189 vcpu->run->s390_tsch.io_int_word = inti->io.io_int_word;
190 }
191 vcpu->run->s390_tsch.ipb = vcpu->arch.sie_block->ipb;
192 kfree(inti);
193 return -EREMOTE;
194}
195
196static int handle_io_inst(struct kvm_vcpu *vcpu)
197{
198 VCPU_EVENT(vcpu, 4, "%s", "I/O instruction");
199
200 if (vcpu->kvm->arch.css_support) {
201 /*
202 * Most I/O instructions will be handled by userspace.
203 * Exceptions are tpi and the interrupt portion of tsch.
204 */
205 if (vcpu->arch.sie_block->ipa == 0xb236)
206 return handle_tpi(vcpu);
207 if (vcpu->arch.sie_block->ipa == 0xb235)
208 return handle_tsch(vcpu);
209 /* Handle in userspace. */
210 return -EOPNOTSUPP;
211 } else {
212 /*
213 * Set condition code 3 to stop the guest from issueing channel
214 * I/O instructions.
215 */
216 vcpu->arch.sie_block->gpsw.mask &= ~(3ul << 44);
217 vcpu->arch.sie_block->gpsw.mask |= (3 & 3ul) << 44;
218 return 0;
219 }
220}
221
139static int handle_stfl(struct kvm_vcpu *vcpu) 222static int handle_stfl(struct kvm_vcpu *vcpu)
140{ 223{
141 unsigned int facility_list; 224 unsigned int facility_list;