18f2abe6aSChristian Borntraeger /* 28f2abe6aSChristian Borntraeger * intercept.c - in-kernel handling for sie intercepts 38f2abe6aSChristian Borntraeger * 48f2abe6aSChristian Borntraeger * Copyright IBM Corp. 2008 58f2abe6aSChristian Borntraeger * 68f2abe6aSChristian Borntraeger * This program is free software; you can redistribute it and/or modify 78f2abe6aSChristian Borntraeger * it under the terms of the GNU General Public License (version 2 only) 88f2abe6aSChristian Borntraeger * as published by the Free Software Foundation. 98f2abe6aSChristian Borntraeger * 108f2abe6aSChristian Borntraeger * Author(s): Carsten Otte <cotte@de.ibm.com> 118f2abe6aSChristian Borntraeger * Christian Borntraeger <borntraeger@de.ibm.com> 128f2abe6aSChristian Borntraeger */ 138f2abe6aSChristian Borntraeger 148f2abe6aSChristian Borntraeger #include <linux/kvm_host.h> 158f2abe6aSChristian Borntraeger #include <linux/errno.h> 168f2abe6aSChristian Borntraeger #include <linux/pagemap.h> 178f2abe6aSChristian Borntraeger 188f2abe6aSChristian Borntraeger #include <asm/kvm_host.h> 198f2abe6aSChristian Borntraeger 208f2abe6aSChristian Borntraeger #include "kvm-s390.h" 21*ba5c1e9bSCarsten Otte #include "gaccess.h" 22*ba5c1e9bSCarsten Otte 23*ba5c1e9bSCarsten Otte static int handle_lctg(struct kvm_vcpu *vcpu) 24*ba5c1e9bSCarsten Otte { 25*ba5c1e9bSCarsten Otte int reg1 = (vcpu->arch.sie_block->ipa & 0x00f0) >> 4; 26*ba5c1e9bSCarsten Otte int reg3 = vcpu->arch.sie_block->ipa & 0x000f; 27*ba5c1e9bSCarsten Otte int base2 = vcpu->arch.sie_block->ipb >> 28; 28*ba5c1e9bSCarsten Otte int disp2 = ((vcpu->arch.sie_block->ipb & 0x0fff0000) >> 16) + 29*ba5c1e9bSCarsten Otte ((vcpu->arch.sie_block->ipb & 0xff00) << 4); 30*ba5c1e9bSCarsten Otte u64 useraddr; 31*ba5c1e9bSCarsten Otte int reg, rc; 32*ba5c1e9bSCarsten Otte 33*ba5c1e9bSCarsten Otte vcpu->stat.instruction_lctg++; 34*ba5c1e9bSCarsten Otte if ((vcpu->arch.sie_block->ipb & 0xff) != 0x2f) 35*ba5c1e9bSCarsten Otte return -ENOTSUPP; 36*ba5c1e9bSCarsten Otte 37*ba5c1e9bSCarsten Otte useraddr = disp2; 38*ba5c1e9bSCarsten Otte if (base2) 39*ba5c1e9bSCarsten Otte useraddr += vcpu->arch.guest_gprs[base2]; 40*ba5c1e9bSCarsten Otte 41*ba5c1e9bSCarsten Otte reg = reg1; 42*ba5c1e9bSCarsten Otte 43*ba5c1e9bSCarsten Otte VCPU_EVENT(vcpu, 5, "lctg r1:%x, r3:%x,b2:%x,d2:%x", reg1, reg3, base2, 44*ba5c1e9bSCarsten Otte disp2); 45*ba5c1e9bSCarsten Otte 46*ba5c1e9bSCarsten Otte do { 47*ba5c1e9bSCarsten Otte rc = get_guest_u64(vcpu, useraddr, 48*ba5c1e9bSCarsten Otte &vcpu->arch.sie_block->gcr[reg]); 49*ba5c1e9bSCarsten Otte if (rc == -EFAULT) { 50*ba5c1e9bSCarsten Otte kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); 51*ba5c1e9bSCarsten Otte break; 52*ba5c1e9bSCarsten Otte } 53*ba5c1e9bSCarsten Otte useraddr += 8; 54*ba5c1e9bSCarsten Otte if (reg == reg3) 55*ba5c1e9bSCarsten Otte break; 56*ba5c1e9bSCarsten Otte reg = (reg + 1) % 16; 57*ba5c1e9bSCarsten Otte } while (1); 58*ba5c1e9bSCarsten Otte return 0; 59*ba5c1e9bSCarsten Otte } 60*ba5c1e9bSCarsten Otte 61*ba5c1e9bSCarsten Otte static int handle_lctl(struct kvm_vcpu *vcpu) 62*ba5c1e9bSCarsten Otte { 63*ba5c1e9bSCarsten Otte int reg1 = (vcpu->arch.sie_block->ipa & 0x00f0) >> 4; 64*ba5c1e9bSCarsten Otte int reg3 = vcpu->arch.sie_block->ipa & 0x000f; 65*ba5c1e9bSCarsten Otte int base2 = vcpu->arch.sie_block->ipb >> 28; 66*ba5c1e9bSCarsten Otte int disp2 = ((vcpu->arch.sie_block->ipb & 0x0fff0000) >> 16); 67*ba5c1e9bSCarsten Otte u64 useraddr; 68*ba5c1e9bSCarsten Otte u32 val = 0; 69*ba5c1e9bSCarsten Otte int reg, rc; 70*ba5c1e9bSCarsten Otte 71*ba5c1e9bSCarsten Otte vcpu->stat.instruction_lctl++; 72*ba5c1e9bSCarsten Otte 73*ba5c1e9bSCarsten Otte useraddr = disp2; 74*ba5c1e9bSCarsten Otte if (base2) 75*ba5c1e9bSCarsten Otte useraddr += vcpu->arch.guest_gprs[base2]; 76*ba5c1e9bSCarsten Otte 77*ba5c1e9bSCarsten Otte VCPU_EVENT(vcpu, 5, "lctl r1:%x, r3:%x,b2:%x,d2:%x", reg1, reg3, base2, 78*ba5c1e9bSCarsten Otte disp2); 79*ba5c1e9bSCarsten Otte 80*ba5c1e9bSCarsten Otte reg = reg1; 81*ba5c1e9bSCarsten Otte do { 82*ba5c1e9bSCarsten Otte rc = get_guest_u32(vcpu, useraddr, &val); 83*ba5c1e9bSCarsten Otte if (rc == -EFAULT) { 84*ba5c1e9bSCarsten Otte kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); 85*ba5c1e9bSCarsten Otte break; 86*ba5c1e9bSCarsten Otte } 87*ba5c1e9bSCarsten Otte vcpu->arch.sie_block->gcr[reg] &= 0xffffffff00000000ul; 88*ba5c1e9bSCarsten Otte vcpu->arch.sie_block->gcr[reg] |= val; 89*ba5c1e9bSCarsten Otte useraddr += 4; 90*ba5c1e9bSCarsten Otte if (reg == reg3) 91*ba5c1e9bSCarsten Otte break; 92*ba5c1e9bSCarsten Otte reg = (reg + 1) % 16; 93*ba5c1e9bSCarsten Otte } while (1); 94*ba5c1e9bSCarsten Otte return 0; 95*ba5c1e9bSCarsten Otte } 96*ba5c1e9bSCarsten Otte 97*ba5c1e9bSCarsten Otte static intercept_handler_t instruction_handlers[256] = { 98*ba5c1e9bSCarsten Otte [0xb7] = handle_lctl, 99*ba5c1e9bSCarsten Otte [0xeb] = handle_lctg, 100*ba5c1e9bSCarsten Otte }; 1018f2abe6aSChristian Borntraeger 1028f2abe6aSChristian Borntraeger static int handle_noop(struct kvm_vcpu *vcpu) 1038f2abe6aSChristian Borntraeger { 1048f2abe6aSChristian Borntraeger switch (vcpu->arch.sie_block->icptcode) { 1058f2abe6aSChristian Borntraeger case 0x10: 1068f2abe6aSChristian Borntraeger vcpu->stat.exit_external_request++; 1078f2abe6aSChristian Borntraeger break; 1088f2abe6aSChristian Borntraeger case 0x14: 1098f2abe6aSChristian Borntraeger vcpu->stat.exit_external_interrupt++; 1108f2abe6aSChristian Borntraeger break; 1118f2abe6aSChristian Borntraeger default: 1128f2abe6aSChristian Borntraeger break; /* nothing */ 1138f2abe6aSChristian Borntraeger } 1148f2abe6aSChristian Borntraeger return 0; 1158f2abe6aSChristian Borntraeger } 1168f2abe6aSChristian Borntraeger 1178f2abe6aSChristian Borntraeger static int handle_stop(struct kvm_vcpu *vcpu) 1188f2abe6aSChristian Borntraeger { 1198f2abe6aSChristian Borntraeger vcpu->stat.exit_stop_request++; 1208f2abe6aSChristian Borntraeger VCPU_EVENT(vcpu, 3, "%s", "cpu stopped"); 1218f2abe6aSChristian Borntraeger atomic_clear_mask(CPUSTAT_RUNNING, &vcpu->arch.sie_block->cpuflags); 1228f2abe6aSChristian Borntraeger return -ENOTSUPP; 1238f2abe6aSChristian Borntraeger } 1248f2abe6aSChristian Borntraeger 1258f2abe6aSChristian Borntraeger static int handle_validity(struct kvm_vcpu *vcpu) 1268f2abe6aSChristian Borntraeger { 1278f2abe6aSChristian Borntraeger int viwhy = vcpu->arch.sie_block->ipb >> 16; 1288f2abe6aSChristian Borntraeger vcpu->stat.exit_validity++; 1298f2abe6aSChristian Borntraeger if (viwhy == 0x37) { 1308f2abe6aSChristian Borntraeger fault_in_pages_writeable((char __user *) 1318f2abe6aSChristian Borntraeger vcpu->kvm->arch.guest_origin + 1328f2abe6aSChristian Borntraeger vcpu->arch.sie_block->prefix, 1338f2abe6aSChristian Borntraeger PAGE_SIZE); 1348f2abe6aSChristian Borntraeger return 0; 1358f2abe6aSChristian Borntraeger } 1368f2abe6aSChristian Borntraeger VCPU_EVENT(vcpu, 2, "unhandled validity intercept code %d", 1378f2abe6aSChristian Borntraeger viwhy); 1388f2abe6aSChristian Borntraeger return -ENOTSUPP; 1398f2abe6aSChristian Borntraeger } 1408f2abe6aSChristian Borntraeger 141*ba5c1e9bSCarsten Otte static int handle_instruction(struct kvm_vcpu *vcpu) 142*ba5c1e9bSCarsten Otte { 143*ba5c1e9bSCarsten Otte intercept_handler_t handler; 144*ba5c1e9bSCarsten Otte 145*ba5c1e9bSCarsten Otte vcpu->stat.exit_instruction++; 146*ba5c1e9bSCarsten Otte handler = instruction_handlers[vcpu->arch.sie_block->ipa >> 8]; 147*ba5c1e9bSCarsten Otte if (handler) 148*ba5c1e9bSCarsten Otte return handler(vcpu); 149*ba5c1e9bSCarsten Otte return -ENOTSUPP; 150*ba5c1e9bSCarsten Otte } 151*ba5c1e9bSCarsten Otte 152*ba5c1e9bSCarsten Otte static int handle_prog(struct kvm_vcpu *vcpu) 153*ba5c1e9bSCarsten Otte { 154*ba5c1e9bSCarsten Otte vcpu->stat.exit_program_interruption++; 155*ba5c1e9bSCarsten Otte return kvm_s390_inject_program_int(vcpu, vcpu->arch.sie_block->iprcc); 156*ba5c1e9bSCarsten Otte } 157*ba5c1e9bSCarsten Otte 158*ba5c1e9bSCarsten Otte static int handle_instruction_and_prog(struct kvm_vcpu *vcpu) 159*ba5c1e9bSCarsten Otte { 160*ba5c1e9bSCarsten Otte int rc, rc2; 161*ba5c1e9bSCarsten Otte 162*ba5c1e9bSCarsten Otte vcpu->stat.exit_instr_and_program++; 163*ba5c1e9bSCarsten Otte rc = handle_instruction(vcpu); 164*ba5c1e9bSCarsten Otte rc2 = handle_prog(vcpu); 165*ba5c1e9bSCarsten Otte 166*ba5c1e9bSCarsten Otte if (rc == -ENOTSUPP) 167*ba5c1e9bSCarsten Otte vcpu->arch.sie_block->icptcode = 0x04; 168*ba5c1e9bSCarsten Otte if (rc) 169*ba5c1e9bSCarsten Otte return rc; 170*ba5c1e9bSCarsten Otte return rc2; 171*ba5c1e9bSCarsten Otte } 172*ba5c1e9bSCarsten Otte 1738f2abe6aSChristian Borntraeger static const intercept_handler_t intercept_funcs[0x48 >> 2] = { 1748f2abe6aSChristian Borntraeger [0x00 >> 2] = handle_noop, 175*ba5c1e9bSCarsten Otte [0x04 >> 2] = handle_instruction, 176*ba5c1e9bSCarsten Otte [0x08 >> 2] = handle_prog, 177*ba5c1e9bSCarsten Otte [0x0C >> 2] = handle_instruction_and_prog, 1788f2abe6aSChristian Borntraeger [0x10 >> 2] = handle_noop, 1798f2abe6aSChristian Borntraeger [0x14 >> 2] = handle_noop, 180*ba5c1e9bSCarsten Otte [0x1C >> 2] = kvm_s390_handle_wait, 1818f2abe6aSChristian Borntraeger [0x20 >> 2] = handle_validity, 1828f2abe6aSChristian Borntraeger [0x28 >> 2] = handle_stop, 1838f2abe6aSChristian Borntraeger }; 1848f2abe6aSChristian Borntraeger 1858f2abe6aSChristian Borntraeger int kvm_handle_sie_intercept(struct kvm_vcpu *vcpu) 1868f2abe6aSChristian Borntraeger { 1878f2abe6aSChristian Borntraeger intercept_handler_t func; 1888f2abe6aSChristian Borntraeger u8 code = vcpu->arch.sie_block->icptcode; 1898f2abe6aSChristian Borntraeger 1908f2abe6aSChristian Borntraeger if (code & 3 || code > 0x48) 1918f2abe6aSChristian Borntraeger return -ENOTSUPP; 1928f2abe6aSChristian Borntraeger func = intercept_funcs[code >> 2]; 1938f2abe6aSChristian Borntraeger if (func) 1948f2abe6aSChristian Borntraeger return func(vcpu); 1958f2abe6aSChristian Borntraeger return -ENOTSUPP; 1968f2abe6aSChristian Borntraeger } 197