2 * in-kernel handling for sie intercepts
4 * Copyright IBM Corp. 2008, 2009
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_host.h>
15 #include <linux/errno.h>
16 #include <linux/pagemap.h>
18 #include <asm/kvm_host.h>
23 #include "trace-s390.h"
26 static const intercept_handler_t instruction_handlers
[256] = {
27 [0x01] = kvm_s390_handle_01
,
28 [0x82] = kvm_s390_handle_lpsw
,
29 [0x83] = kvm_s390_handle_diag
,
30 [0xae] = kvm_s390_handle_sigp
,
31 [0xb2] = kvm_s390_handle_b2
,
32 [0xb7] = kvm_s390_handle_lctl
,
33 [0xb9] = kvm_s390_handle_b9
,
34 [0xe5] = kvm_s390_handle_e5
,
35 [0xeb] = kvm_s390_handle_eb
,
38 static int handle_noop(struct kvm_vcpu
*vcpu
)
40 switch (vcpu
->arch
.sie_block
->icptcode
) {
42 vcpu
->stat
.exit_null
++;
45 vcpu
->stat
.exit_external_request
++;
48 vcpu
->stat
.exit_external_interrupt
++;
56 static int handle_stop(struct kvm_vcpu
*vcpu
)
60 vcpu
->stat
.exit_stop_request
++;
61 spin_lock_bh(&vcpu
->arch
.local_int
.lock
);
63 trace_kvm_s390_stop_request(vcpu
->arch
.local_int
.action_bits
);
65 if (vcpu
->arch
.local_int
.action_bits
& ACTION_RELOADVCPU_ON_STOP
) {
66 vcpu
->arch
.local_int
.action_bits
&= ~ACTION_RELOADVCPU_ON_STOP
;
67 rc
= SIE_INTERCEPT_RERUNVCPU
;
68 vcpu
->run
->exit_reason
= KVM_EXIT_INTR
;
71 if (vcpu
->arch
.local_int
.action_bits
& ACTION_STOP_ON_STOP
) {
72 atomic_set_mask(CPUSTAT_STOPPED
,
73 &vcpu
->arch
.sie_block
->cpuflags
);
74 vcpu
->arch
.local_int
.action_bits
&= ~ACTION_STOP_ON_STOP
;
75 VCPU_EVENT(vcpu
, 3, "%s", "cpu stopped");
79 if (vcpu
->arch
.local_int
.action_bits
& ACTION_STORE_ON_STOP
) {
80 vcpu
->arch
.local_int
.action_bits
&= ~ACTION_STORE_ON_STOP
;
81 /* store status must be called unlocked. Since local_int.lock
82 * only protects local_int.* and not guest memory we can give
84 spin_unlock_bh(&vcpu
->arch
.local_int
.lock
);
85 rc
= kvm_s390_vcpu_store_status(vcpu
,
86 KVM_S390_STORE_STATUS_NOADDR
);
90 spin_unlock_bh(&vcpu
->arch
.local_int
.lock
);
94 static int handle_validity(struct kvm_vcpu
*vcpu
)
96 int viwhy
= vcpu
->arch
.sie_block
->ipb
>> 16;
98 vcpu
->stat
.exit_validity
++;
99 trace_kvm_s390_intercept_validity(vcpu
, viwhy
);
100 WARN_ONCE(true, "kvm: unhandled validity intercept 0x%x\n", viwhy
);
104 static int handle_instruction(struct kvm_vcpu
*vcpu
)
106 intercept_handler_t handler
;
108 vcpu
->stat
.exit_instruction
++;
109 trace_kvm_s390_intercept_instruction(vcpu
,
110 vcpu
->arch
.sie_block
->ipa
,
111 vcpu
->arch
.sie_block
->ipb
);
112 handler
= instruction_handlers
[vcpu
->arch
.sie_block
->ipa
>> 8];
114 return handler(vcpu
);
118 static int handle_prog(struct kvm_vcpu
*vcpu
)
120 vcpu
->stat
.exit_program_interruption
++;
121 trace_kvm_s390_intercept_prog(vcpu
, vcpu
->arch
.sie_block
->iprcc
);
122 return kvm_s390_inject_program_int(vcpu
, vcpu
->arch
.sie_block
->iprcc
);
125 static int handle_instruction_and_prog(struct kvm_vcpu
*vcpu
)
129 vcpu
->stat
.exit_instr_and_program
++;
130 rc
= handle_instruction(vcpu
);
131 rc2
= handle_prog(vcpu
);
133 if (rc
== -EOPNOTSUPP
)
134 vcpu
->arch
.sie_block
->icptcode
= 0x04;
140 static const intercept_handler_t intercept_funcs
[] = {
141 [0x00 >> 2] = handle_noop
,
142 [0x04 >> 2] = handle_instruction
,
143 [0x08 >> 2] = handle_prog
,
144 [0x0C >> 2] = handle_instruction_and_prog
,
145 [0x10 >> 2] = handle_noop
,
146 [0x14 >> 2] = handle_noop
,
147 [0x18 >> 2] = handle_noop
,
148 [0x1C >> 2] = kvm_s390_handle_wait
,
149 [0x20 >> 2] = handle_validity
,
150 [0x28 >> 2] = handle_stop
,
153 int kvm_handle_sie_intercept(struct kvm_vcpu
*vcpu
)
155 intercept_handler_t func
;
156 u8 code
= vcpu
->arch
.sie_block
->icptcode
;
158 if (code
& 3 || (code
>> 2) >= ARRAY_SIZE(intercept_funcs
))
160 func
= intercept_funcs
[code
>> 2];