static int handle_store_cpu_address(struct kvm_vcpu *vcpu) { int base2 = vcpu->arch.sie_block->ipb >> 28; int disp2 = ((vcpu->arch.sie_block->ipb & 0x0fff0000) >> 16); u64 useraddr; int rc; vcpu->stat.instruction_stap++; useraddr = disp2; if (base2) useraddr += vcpu->arch.guest_gprs[base2]; if (useraddr & 1) { kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); goto out; } rc = put_guest_u16(vcpu, useraddr, vcpu->vcpu_id); if (rc == -EFAULT) { kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); goto out; } VCPU_EVENT(vcpu, 5, "storing cpu address to %llx", useraddr); out: return 0; }
static int __try_deliver_ckc_interrupt(struct kvm_vcpu *vcpu) { int rc, exception = 0; if (psw_extint_disabled(vcpu)) return 0; if (!(vcpu->arch.sie_block->gcr[0] & 0x800ul)) return 0; rc = put_guest_u16(vcpu, __LC_EXT_INT_CODE, 0x1004); if (rc == -EFAULT) exception = 1; rc = copy_to_guest(vcpu, __LC_EXT_OLD_PSW, &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); if (rc == -EFAULT) exception = 1; rc = copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw, __LC_EXT_NEW_PSW, sizeof(psw_t)); if (rc == -EFAULT) exception = 1; if (exception) { printk("kvm: The guest lowcore is not mapped during interrupt " "delivery, killing userspace\n"); do_exit(SIGKILL); } return 1; }
static int handle_store_cpu_address(struct kvm_vcpu *vcpu) { u64 useraddr; int rc; vcpu->stat.instruction_stap++; useraddr = kvm_s390_get_base_disp_s(vcpu); if (useraddr & 1) { kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); goto out; } rc = put_guest_u16(vcpu, useraddr, vcpu->vcpu_id); if (rc == -EFAULT) { kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); goto out; } VCPU_EVENT(vcpu, 5, "storing cpu address to %llx", useraddr); trace_kvm_s390_handle_stap(vcpu, useraddr); out: return 0; }
static int handle_tpi(struct kvm_vcpu *vcpu) { u64 addr; struct kvm_s390_interrupt_info *inti; int cc; addr = kvm_s390_get_base_disp_s(vcpu); inti = kvm_s390_get_io_int(vcpu->kvm, vcpu->run->s.regs.crs[6], 0); if (inti) { if (addr) { /* * Store the two-word I/O interruption code into the * provided area. */ put_guest_u16(vcpu, addr, inti->io.subchannel_id); put_guest_u16(vcpu, addr + 2, inti->io.subchannel_nr); put_guest_u32(vcpu, addr + 4, inti->io.io_int_parm); } else { /* * Store the three-word I/O interruption code into * the appropriate lowcore area. */ put_guest_u16(vcpu, 184, inti->io.subchannel_id); put_guest_u16(vcpu, 186, inti->io.subchannel_nr); put_guest_u32(vcpu, 188, inti->io.io_int_parm); put_guest_u32(vcpu, 192, inti->io.io_int_word); } cc = 1; } else cc = 0; kfree(inti); /* Set condition code and we're done. */ vcpu->arch.sie_block->gpsw.mask &= ~(3ul << 44); vcpu->arch.sie_block->gpsw.mask |= (cc & 3ul) << 44; return 0; }
static void __do_deliver_interrupt(struct kvm_vcpu *vcpu, struct kvm_s390_interrupt_info *inti) { const unsigned short table[] = { 2, 4, 4, 6 }; int rc, exception = 0; switch (inti->type) { case KVM_S390_INT_EMERGENCY: VCPU_EVENT(vcpu, 4, "%s", "interrupt: sigp emerg"); vcpu->stat.deliver_emergency_signal++; rc = put_guest_u16(vcpu, __LC_EXT_INT_CODE, 0x1201); if (rc == -EFAULT) exception = 1; rc = put_guest_u16(vcpu, __LC_EXT_CPU_ADDR, inti->emerg.code); if (rc == -EFAULT) exception = 1; rc = copy_to_guest(vcpu, __LC_EXT_OLD_PSW, &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); if (rc == -EFAULT) exception = 1; rc = copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw, __LC_EXT_NEW_PSW, sizeof(psw_t)); if (rc == -EFAULT) exception = 1; break; case KVM_S390_INT_EXTERNAL_CALL: VCPU_EVENT(vcpu, 4, "%s", "interrupt: sigp ext call"); vcpu->stat.deliver_external_call++; rc = put_guest_u16(vcpu, __LC_EXT_INT_CODE, 0x1202); if (rc == -EFAULT) exception = 1; rc = put_guest_u16(vcpu, __LC_EXT_CPU_ADDR, inti->extcall.code); if (rc == -EFAULT) exception = 1; rc = copy_to_guest(vcpu, __LC_EXT_OLD_PSW, &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); if (rc == -EFAULT) exception = 1; rc = copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw, __LC_EXT_NEW_PSW, sizeof(psw_t)); if (rc == -EFAULT) exception = 1; break; case KVM_S390_INT_SERVICE: VCPU_EVENT(vcpu, 4, "interrupt: sclp parm:%x", inti->ext.ext_params); vcpu->stat.deliver_service_signal++; rc = put_guest_u16(vcpu, __LC_EXT_INT_CODE, 0x2401); if (rc == -EFAULT) exception = 1; rc = copy_to_guest(vcpu, __LC_EXT_OLD_PSW, &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); if (rc == -EFAULT) exception = 1; rc = copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw, __LC_EXT_NEW_PSW, sizeof(psw_t)); if (rc == -EFAULT) exception = 1; rc = put_guest_u32(vcpu, __LC_EXT_PARAMS, inti->ext.ext_params); if (rc == -EFAULT) exception = 1; break; case KVM_S390_INT_VIRTIO: VCPU_EVENT(vcpu, 4, "interrupt: virtio parm:%x,parm64:%llx", inti->ext.ext_params, inti->ext.ext_params2); vcpu->stat.deliver_virtio_interrupt++; rc = put_guest_u16(vcpu, __LC_EXT_INT_CODE, 0x2603); if (rc == -EFAULT) exception = 1; rc = put_guest_u16(vcpu, __LC_EXT_CPU_ADDR, 0x0d00); if (rc == -EFAULT) exception = 1; rc = copy_to_guest(vcpu, __LC_EXT_OLD_PSW, &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); if (rc == -EFAULT) exception = 1; rc = copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw, __LC_EXT_NEW_PSW, sizeof(psw_t)); if (rc == -EFAULT) exception = 1; rc = put_guest_u32(vcpu, __LC_EXT_PARAMS, inti->ext.ext_params); if (rc == -EFAULT) exception = 1; rc = put_guest_u64(vcpu, __LC_EXT_PARAMS2, inti->ext.ext_params2); if (rc == -EFAULT) exception = 1; break; case KVM_S390_SIGP_STOP: VCPU_EVENT(vcpu, 4, "%s", "interrupt: cpu stop"); vcpu->stat.deliver_stop_signal++; __set_intercept_indicator(vcpu, inti); break; case KVM_S390_SIGP_SET_PREFIX: VCPU_EVENT(vcpu, 4, "interrupt: set prefix to %x", inti->prefix.address); vcpu->stat.deliver_prefix_signal++; kvm_s390_set_prefix(vcpu, inti->prefix.address); break; case KVM_S390_RESTART: VCPU_EVENT(vcpu, 4, "%s", "interrupt: cpu restart"); vcpu->stat.deliver_restart_signal++; rc = copy_to_guest(vcpu, offsetof(struct _lowcore, restart_old_psw), &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); if (rc == -EFAULT) exception = 1; rc = copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw, offsetof(struct _lowcore, restart_psw), sizeof(psw_t)); if (rc == -EFAULT) exception = 1; atomic_clear_mask(CPUSTAT_STOPPED, &vcpu->arch.sie_block->cpuflags); break; case KVM_S390_PROGRAM_INT: VCPU_EVENT(vcpu, 4, "interrupt: pgm check code:%x, ilc:%x", inti->pgm.code, table[vcpu->arch.sie_block->ipa >> 14]); vcpu->stat.deliver_program_int++; rc = put_guest_u16(vcpu, __LC_PGM_INT_CODE, inti->pgm.code); if (rc == -EFAULT) exception = 1; rc = put_guest_u16(vcpu, __LC_PGM_ILC, table[vcpu->arch.sie_block->ipa >> 14]); if (rc == -EFAULT) exception = 1; rc = copy_to_guest(vcpu, __LC_PGM_OLD_PSW, &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); if (rc == -EFAULT) exception = 1; rc = copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw, __LC_PGM_NEW_PSW, sizeof(psw_t)); if (rc == -EFAULT) exception = 1; break; default: BUG(); } if (exception) { printk("kvm: The guest lowcore is not mapped during interrupt " "delivery, killing userspace\n"); do_exit(SIGKILL); } }