2 * intercept.c - in-kernel handling for sie intercepts
4 * Copyright IBM Corp. 2008
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 static int handle_lctlg(struct kvm_vcpu
*vcpu
)
25 int reg1
= (vcpu
->arch
.sie_block
->ipa
& 0x00f0) >> 4;
26 int reg3
= vcpu
->arch
.sie_block
->ipa
& 0x000f;
27 int base2
= vcpu
->arch
.sie_block
->ipb
>> 28;
28 int disp2
= ((vcpu
->arch
.sie_block
->ipb
& 0x0fff0000) >> 16) +
29 ((vcpu
->arch
.sie_block
->ipb
& 0xff00) << 4);
33 vcpu
->stat
.instruction_lctlg
++;
34 if ((vcpu
->arch
.sie_block
->ipb
& 0xff) != 0x2f)
39 useraddr
+= vcpu
->arch
.guest_gprs
[base2
];
42 return kvm_s390_inject_program_int(vcpu
, PGM_SPECIFICATION
);
46 VCPU_EVENT(vcpu
, 5, "lctlg r1:%x, r3:%x,b2:%x,d2:%x", reg1
, reg3
, base2
,
50 rc
= get_guest_u64(vcpu
, useraddr
,
51 &vcpu
->arch
.sie_block
->gcr
[reg
]);
53 kvm_s390_inject_program_int(vcpu
, PGM_ADDRESSING
);
64 static int handle_lctl(struct kvm_vcpu
*vcpu
)
66 int reg1
= (vcpu
->arch
.sie_block
->ipa
& 0x00f0) >> 4;
67 int reg3
= vcpu
->arch
.sie_block
->ipa
& 0x000f;
68 int base2
= vcpu
->arch
.sie_block
->ipb
>> 28;
69 int disp2
= ((vcpu
->arch
.sie_block
->ipb
& 0x0fff0000) >> 16);
74 vcpu
->stat
.instruction_lctl
++;
78 useraddr
+= vcpu
->arch
.guest_gprs
[base2
];
81 return kvm_s390_inject_program_int(vcpu
, PGM_SPECIFICATION
);
83 VCPU_EVENT(vcpu
, 5, "lctl r1:%x, r3:%x,b2:%x,d2:%x", reg1
, reg3
, base2
,
88 rc
= get_guest_u32(vcpu
, useraddr
, &val
);
90 kvm_s390_inject_program_int(vcpu
, PGM_ADDRESSING
);
93 vcpu
->arch
.sie_block
->gcr
[reg
] &= 0xffffffff00000000ul
;
94 vcpu
->arch
.sie_block
->gcr
[reg
] |= val
;
103 static intercept_handler_t instruction_handlers
[256] = {
104 [0x83] = kvm_s390_handle_diag
,
105 [0xae] = kvm_s390_handle_sigp
,
106 [0xb2] = kvm_s390_handle_b2
,
107 [0xb7] = handle_lctl
,
108 [0xeb] = handle_lctlg
,
111 static int handle_noop(struct kvm_vcpu
*vcpu
)
113 switch (vcpu
->arch
.sie_block
->icptcode
) {
115 vcpu
->stat
.exit_null
++;
118 vcpu
->stat
.exit_external_request
++;
121 vcpu
->stat
.exit_external_interrupt
++;
129 static int handle_stop(struct kvm_vcpu
*vcpu
)
133 vcpu
->stat
.exit_stop_request
++;
134 atomic_clear_mask(CPUSTAT_RUNNING
, &vcpu
->arch
.sie_block
->cpuflags
);
135 spin_lock_bh(&vcpu
->arch
.local_int
.lock
);
136 if (vcpu
->arch
.local_int
.action_bits
& ACTION_STORE_ON_STOP
) {
137 vcpu
->arch
.local_int
.action_bits
&= ~ACTION_STORE_ON_STOP
;
138 rc
= __kvm_s390_vcpu_store_status(vcpu
,
139 KVM_S390_STORE_STATUS_NOADDR
);
144 if (vcpu
->arch
.local_int
.action_bits
& ACTION_STOP_ON_STOP
) {
145 vcpu
->arch
.local_int
.action_bits
&= ~ACTION_STOP_ON_STOP
;
146 VCPU_EVENT(vcpu
, 3, "%s", "cpu stopped");
150 spin_unlock_bh(&vcpu
->arch
.local_int
.lock
);
154 static int handle_validity(struct kvm_vcpu
*vcpu
)
156 int viwhy
= vcpu
->arch
.sie_block
->ipb
>> 16;
159 vcpu
->stat
.exit_validity
++;
160 if ((viwhy
== 0x37) && (vcpu
->arch
.sie_block
->prefix
161 <= vcpu
->kvm
->arch
.guest_memsize
- 2*PAGE_SIZE
)){
162 rc
= fault_in_pages_writeable((char __user
*)
163 vcpu
->kvm
->arch
.guest_origin
+
164 vcpu
->arch
.sie_block
->prefix
,
167 /* user will receive sigsegv, exit to user */
173 VCPU_EVENT(vcpu
, 2, "unhandled validity intercept code %d",
178 static int handle_instruction(struct kvm_vcpu
*vcpu
)
180 intercept_handler_t handler
;
182 vcpu
->stat
.exit_instruction
++;
183 handler
= instruction_handlers
[vcpu
->arch
.sie_block
->ipa
>> 8];
185 return handler(vcpu
);
189 static int handle_prog(struct kvm_vcpu
*vcpu
)
191 vcpu
->stat
.exit_program_interruption
++;
192 return kvm_s390_inject_program_int(vcpu
, vcpu
->arch
.sie_block
->iprcc
);
195 static int handle_instruction_and_prog(struct kvm_vcpu
*vcpu
)
199 vcpu
->stat
.exit_instr_and_program
++;
200 rc
= handle_instruction(vcpu
);
201 rc2
= handle_prog(vcpu
);
204 vcpu
->arch
.sie_block
->icptcode
= 0x04;
210 static const intercept_handler_t intercept_funcs
[0x48 >> 2] = {
211 [0x00 >> 2] = handle_noop
,
212 [0x04 >> 2] = handle_instruction
,
213 [0x08 >> 2] = handle_prog
,
214 [0x0C >> 2] = handle_instruction_and_prog
,
215 [0x10 >> 2] = handle_noop
,
216 [0x14 >> 2] = handle_noop
,
217 [0x1C >> 2] = kvm_s390_handle_wait
,
218 [0x20 >> 2] = handle_validity
,
219 [0x28 >> 2] = handle_stop
,
222 int kvm_handle_sie_intercept(struct kvm_vcpu
*vcpu
)
224 intercept_handler_t func
;
225 u8 code
= vcpu
->arch
.sie_block
->icptcode
;
227 if (code
& 3 || code
> 0x48)
229 func
= intercept_funcs
[code
>> 2];