static int handle_tsch(struct kvm_vcpu *vcpu) { struct kvm_s390_interrupt_info *inti; inti = kvm_s390_get_io_int(vcpu->kvm, 0, vcpu->run->s.regs.gprs[1]); /* * Prepare exit to userspace. * We indicate whether we dequeued a pending I/O interrupt * so that userspace can re-inject it if the instruction gets * a program check. While this may re-order the pending I/O * interrupts, this is no problem since the priority is kept * intact. */ vcpu->run->exit_reason = KVM_EXIT_S390_TSCH; vcpu->run->s390_tsch.dequeued = !!inti; if (inti) { vcpu->run->s390_tsch.subchannel_id = inti->io.subchannel_id; vcpu->run->s390_tsch.subchannel_nr = inti->io.subchannel_nr; vcpu->run->s390_tsch.io_int_parm = inti->io.io_int_parm; vcpu->run->s390_tsch.io_int_word = inti->io.io_int_word; } vcpu->run->s390_tsch.ipb = vcpu->arch.sie_block->ipb; kfree(inti); return -EREMOTE; }
static int handle_tpi(struct kvm_vcpu *vcpu) { struct kvm_s390_interrupt_info *inti; u64 addr; int cc; addr = kvm_s390_get_base_disp_s(vcpu); if (addr & 3) return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); cc = 0; inti = kvm_s390_get_io_int(vcpu->kvm, vcpu->run->s.regs.crs[6], 0); if (!inti) goto no_interrupt; cc = 1; if (addr) { /* * Store the two-word I/O interruption code into the * provided area. */ if (put_guest(vcpu, inti->io.subchannel_id, (u16 __user *)addr) || put_guest(vcpu, inti->io.subchannel_nr, (u16 __user *)(addr + 2)) || put_guest(vcpu, inti->io.io_int_parm, (u32 __user *)(addr + 4))) return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); } else { /* * Store the three-word I/O interruption code into * the appropriate lowcore area. */ put_guest(vcpu, inti->io.subchannel_id, (u16 __user *) __LC_SUBCHANNEL_ID); put_guest(vcpu, inti->io.subchannel_nr, (u16 __user *) __LC_SUBCHANNEL_NR); put_guest(vcpu, inti->io.io_int_parm, (u32 __user *) __LC_IO_INT_PARM); put_guest(vcpu, inti->io.io_int_word, (u32 __user *) __LC_IO_INT_WORD); } kfree(inti); no_interrupt: /* 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 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; }