aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/kvm/priv.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/s390/kvm/priv.c')
-rw-r--r--arch/s390/kvm/priv.c61
1 files changed, 61 insertions, 0 deletions
diff --git a/arch/s390/kvm/priv.c b/arch/s390/kvm/priv.c
index 59200ee275e5..2440602e6df1 100644
--- a/arch/s390/kvm/priv.c
+++ b/arch/s390/kvm/priv.c
@@ -30,6 +30,38 @@
30#include "kvm-s390.h" 30#include "kvm-s390.h"
31#include "trace.h" 31#include "trace.h"
32 32
33/* Handle SCK (SET CLOCK) interception */
34static int handle_set_clock(struct kvm_vcpu *vcpu)
35{
36 struct kvm_vcpu *cpup;
37 s64 hostclk, val;
38 u64 op2;
39 int i;
40
41 if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
42 return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
43
44 op2 = kvm_s390_get_base_disp_s(vcpu);
45 if (op2 & 7) /* Operand must be on a doubleword boundary */
46 return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
47 if (get_guest(vcpu, val, (u64 __user *) op2))
48 return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
49
50 if (store_tod_clock(&hostclk)) {
51 kvm_s390_set_psw_cc(vcpu, 3);
52 return 0;
53 }
54 val = (val - hostclk) & ~0x3fUL;
55
56 mutex_lock(&vcpu->kvm->lock);
57 kvm_for_each_vcpu(i, cpup, vcpu->kvm)
58 cpup->arch.sie_block->epoch = val;
59 mutex_unlock(&vcpu->kvm->lock);
60
61 kvm_s390_set_psw_cc(vcpu, 0);
62 return 0;
63}
64
33static int handle_set_prefix(struct kvm_vcpu *vcpu) 65static int handle_set_prefix(struct kvm_vcpu *vcpu)
34{ 66{
35 u64 operand2; 67 u64 operand2;
@@ -128,6 +160,33 @@ static int handle_skey(struct kvm_vcpu *vcpu)
128 return 0; 160 return 0;
129} 161}
130 162
163static int handle_test_block(struct kvm_vcpu *vcpu)
164{
165 unsigned long hva;
166 gpa_t addr;
167 int reg2;
168
169 if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
170 return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
171
172 kvm_s390_get_regs_rre(vcpu, NULL, &reg2);
173 addr = vcpu->run->s.regs.gprs[reg2] & PAGE_MASK;
174 addr = kvm_s390_real_to_abs(vcpu, addr);
175
176 hva = gfn_to_hva(vcpu->kvm, gpa_to_gfn(addr));
177 if (kvm_is_error_hva(hva))
178 return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
179 /*
180 * We don't expect errors on modern systems, and do not care
181 * about storage keys (yet), so let's just clear the page.
182 */
183 if (clear_user((void __user *)hva, PAGE_SIZE) != 0)
184 return -EFAULT;
185 kvm_s390_set_psw_cc(vcpu, 0);
186 vcpu->run->s.regs.gprs[0] = 0;
187 return 0;
188}
189
131static int handle_tpi(struct kvm_vcpu *vcpu) 190static int handle_tpi(struct kvm_vcpu *vcpu)
132{ 191{
133 struct kvm_s390_interrupt_info *inti; 192 struct kvm_s390_interrupt_info *inti;
@@ -438,12 +497,14 @@ out_exception:
438 497
439static const intercept_handler_t b2_handlers[256] = { 498static const intercept_handler_t b2_handlers[256] = {
440 [0x02] = handle_stidp, 499 [0x02] = handle_stidp,
500 [0x04] = handle_set_clock,
441 [0x10] = handle_set_prefix, 501 [0x10] = handle_set_prefix,
442 [0x11] = handle_store_prefix, 502 [0x11] = handle_store_prefix,
443 [0x12] = handle_store_cpu_address, 503 [0x12] = handle_store_cpu_address,
444 [0x29] = handle_skey, 504 [0x29] = handle_skey,
445 [0x2a] = handle_skey, 505 [0x2a] = handle_skey,
446 [0x2b] = handle_skey, 506 [0x2b] = handle_skey,
507 [0x2c] = handle_test_block,
447 [0x30] = handle_io_inst, 508 [0x30] = handle_io_inst,
448 [0x31] = handle_io_inst, 509 [0x31] = handle_io_inst,
449 [0x32] = handle_io_inst, 510 [0x32] = handle_io_inst,