2 * handling diagnose instructions
4 * Copyright IBM Corp. 2008, 2011
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)
8 * as published by the Free Software Foundation.
10 * Author(s): Carsten Otte <cotte@de.ibm.com>
11 * Christian Borntraeger <borntraeger@de.ibm.com>
14 #include <linux/kvm.h>
15 #include <linux/kvm_host.h>
16 #include <asm/pgalloc.h>
17 #include <asm/virtio-ccw.h>
20 #include "trace-s390.h"
23 static int diag_release_pages(struct kvm_vcpu
*vcpu
)
25 unsigned long start
, end
;
26 unsigned long prefix
= kvm_s390_get_prefix(vcpu
);
28 start
= vcpu
->run
->s
.regs
.gprs
[(vcpu
->arch
.sie_block
->ipa
& 0xf0) >> 4];
29 end
= vcpu
->run
->s
.regs
.gprs
[vcpu
->arch
.sie_block
->ipa
& 0xf] + 4096;
31 if (start
& ~PAGE_MASK
|| end
& ~PAGE_MASK
|| start
> end
32 || start
< 2 * PAGE_SIZE
)
33 return kvm_s390_inject_program_int(vcpu
, PGM_SPECIFICATION
);
35 VCPU_EVENT(vcpu
, 5, "diag release pages %lX %lX", start
, end
);
36 vcpu
->stat
.diagnose_10
++;
38 /* we checked for start > end above */
39 if (end
< prefix
|| start
>= prefix
+ 2 * PAGE_SIZE
) {
40 gmap_discard(start
, end
, vcpu
->arch
.gmap
);
43 gmap_discard(start
, prefix
, vcpu
->arch
.gmap
);
45 gmap_discard(prefix
+ 2 * PAGE_SIZE
,
46 end
, vcpu
->arch
.gmap
);
51 static int __diag_page_ref_service(struct kvm_vcpu
*vcpu
)
65 u16 rx
= (vcpu
->arch
.sie_block
->ipa
& 0xf0) >> 4;
66 u16 ry
= (vcpu
->arch
.sie_block
->ipa
& 0x0f);
68 if (vcpu
->run
->s
.regs
.gprs
[rx
] & 7)
69 return kvm_s390_inject_program_int(vcpu
, PGM_SPECIFICATION
);
70 rc
= read_guest(vcpu
, vcpu
->run
->s
.regs
.gprs
[rx
], &parm
, sizeof(parm
));
72 return kvm_s390_inject_prog_cond(vcpu
, rc
);
73 if (parm
.parm_version
!= 2 || parm
.parm_len
< 5 || parm
.code
!= 0x258)
74 return kvm_s390_inject_program_int(vcpu
, PGM_SPECIFICATION
);
76 switch (parm
.subcode
) {
78 if (vcpu
->arch
.pfault_token
!= KVM_S390_PFAULT_TOKEN_INVALID
) {
80 * If the pagefault handshake is already activated,
81 * the token must not be changed. We have to return
82 * decimal 8 instead, as mandated in SC24-6084.
84 vcpu
->run
->s
.regs
.gprs
[ry
] = 8;
88 if ((parm
.compare_mask
& parm
.select_mask
) != parm
.compare_mask
||
89 parm
.token_addr
& 7 || parm
.zarch
!= 0x8000000000000000ULL
)
90 return kvm_s390_inject_program_int(vcpu
, PGM_SPECIFICATION
);
92 if (kvm_is_error_gpa(vcpu
->kvm
, parm
.token_addr
))
93 return kvm_s390_inject_program_int(vcpu
, PGM_ADDRESSING
);
95 vcpu
->arch
.pfault_token
= parm
.token_addr
;
96 vcpu
->arch
.pfault_select
= parm
.select_mask
;
97 vcpu
->arch
.pfault_compare
= parm
.compare_mask
;
98 vcpu
->run
->s
.regs
.gprs
[ry
] = 0;
103 * Specification allows to let already pending tokens survive
104 * the cancel, therefore to reduce code complexity, we assume
105 * all outstanding tokens are already pending.
107 if (parm
.token_addr
|| parm
.select_mask
||
108 parm
.compare_mask
|| parm
.zarch
)
109 return kvm_s390_inject_program_int(vcpu
, PGM_SPECIFICATION
);
111 vcpu
->run
->s
.regs
.gprs
[ry
] = 0;
113 * If the pfault handling was not established or is already
114 * canceled SC24-6084 requests to return decimal 4.
116 if (vcpu
->arch
.pfault_token
== KVM_S390_PFAULT_TOKEN_INVALID
)
117 vcpu
->run
->s
.regs
.gprs
[ry
] = 4;
119 vcpu
->arch
.pfault_token
= KVM_S390_PFAULT_TOKEN_INVALID
;
131 static int __diag_time_slice_end(struct kvm_vcpu
*vcpu
)
133 VCPU_EVENT(vcpu
, 5, "%s", "diag time slice end");
134 vcpu
->stat
.diagnose_44
++;
135 kvm_vcpu_on_spin(vcpu
);
139 static int __diag_time_slice_end_directed(struct kvm_vcpu
*vcpu
)
141 struct kvm
*kvm
= vcpu
->kvm
;
142 struct kvm_vcpu
*tcpu
;
146 tid
= vcpu
->run
->s
.regs
.gprs
[(vcpu
->arch
.sie_block
->ipa
& 0xf0) >> 4];
147 vcpu
->stat
.diagnose_9c
++;
148 VCPU_EVENT(vcpu
, 5, "diag time slice end directed to %d", tid
);
150 if (tid
== vcpu
->vcpu_id
)
153 kvm_for_each_vcpu(i
, tcpu
, kvm
)
154 if (tcpu
->vcpu_id
== tid
) {
155 kvm_vcpu_yield_to(tcpu
);
162 static int __diag_ipl_functions(struct kvm_vcpu
*vcpu
)
164 unsigned int reg
= vcpu
->arch
.sie_block
->ipa
& 0xf;
165 unsigned long subcode
= vcpu
->run
->s
.regs
.gprs
[reg
] & 0xffff;
167 VCPU_EVENT(vcpu
, 5, "diag ipl functions, subcode %lx", subcode
);
170 vcpu
->run
->s390_reset_flags
= KVM_S390_RESET_CLEAR
;
173 vcpu
->run
->s390_reset_flags
= 0;
179 if (!kvm_s390_user_cpu_state_ctrl(vcpu
->kvm
))
180 kvm_s390_vcpu_stop(vcpu
);
181 vcpu
->run
->s390_reset_flags
|= KVM_S390_RESET_SUBSYSTEM
;
182 vcpu
->run
->s390_reset_flags
|= KVM_S390_RESET_IPL
;
183 vcpu
->run
->s390_reset_flags
|= KVM_S390_RESET_CPU_INIT
;
184 vcpu
->run
->exit_reason
= KVM_EXIT_S390_RESET
;
185 VCPU_EVENT(vcpu
, 3, "requesting userspace resets %llx",
186 vcpu
->run
->s390_reset_flags
);
187 trace_kvm_s390_request_resets(vcpu
->run
->s390_reset_flags
);
191 static int __diag_virtio_hypercall(struct kvm_vcpu
*vcpu
)
195 /* No virtio-ccw notification? Get out quickly. */
196 if (!vcpu
->kvm
->arch
.css_support
||
197 (vcpu
->run
->s
.regs
.gprs
[1] != KVM_S390_VIRTIO_CCW_NOTIFY
))
201 * The layout is as follows:
202 * - gpr 2 contains the subchannel id (passed as addr)
203 * - gpr 3 contains the virtqueue index (passed as datamatch)
204 * - gpr 4 contains the index on the bus (optionally)
206 ret
= kvm_io_bus_write_cookie(vcpu
->kvm
, KVM_VIRTIO_CCW_NOTIFY_BUS
,
207 vcpu
->run
->s
.regs
.gprs
[2] & 0xffffffff,
208 8, &vcpu
->run
->s
.regs
.gprs
[3],
209 vcpu
->run
->s
.regs
.gprs
[4]);
212 * Return cookie in gpr 2, but don't overwrite the register if the
213 * diagnose will be handled by userspace.
215 if (ret
!= -EOPNOTSUPP
)
216 vcpu
->run
->s
.regs
.gprs
[2] = ret
;
217 /* kvm_io_bus_write_cookie returns -EOPNOTSUPP if it found no match. */
218 return ret
< 0 ? ret
: 0;
221 int kvm_s390_handle_diag(struct kvm_vcpu
*vcpu
)
223 int code
= kvm_s390_get_base_disp_rs(vcpu
) & 0xffff;
225 if (vcpu
->arch
.sie_block
->gpsw
.mask
& PSW_MASK_PSTATE
)
226 return kvm_s390_inject_program_int(vcpu
, PGM_PRIVILEGED_OP
);
228 trace_kvm_s390_handle_diag(vcpu
, code
);
231 return diag_release_pages(vcpu
);
233 return __diag_time_slice_end(vcpu
);
235 return __diag_time_slice_end_directed(vcpu
);
237 return __diag_page_ref_service(vcpu
);
239 return __diag_ipl_functions(vcpu
);
241 return __diag_virtio_hypercall(vcpu
);