summaryrefslogtreecommitdiff
path: root/arch/s390/kvm
diff options
context:
space:
mode:
authorHeiko Carstens <heiko.carstens@de.ibm.com>2014-01-01 16:55:48 +0100
committerChristian Borntraeger <borntraeger@de.ibm.com>2014-04-22 13:24:44 +0200
commit4799b557c9aa3a7b540121f2bece719f22229a21 (patch)
tree4943ddcf8d63c84b60999bcaa8dd916f388eff4f /arch/s390/kvm
parentef23e7790e148041d159c1f710bee2b7b2f0d8cd (diff)
KVM: s390: convert handle_tpi()
Convert handle_tpi() to new guest access functions. The code now sets up a structure which is copied with a single call to guest space instead of issuing several separate guest access calls. This is necessary since the to be copied data may cross a page boundary. If a protection exception happens while accessing any of the pages, the instruction is suppressed and may not have modified any memory contents. Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com> Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
Diffstat (limited to 'arch/s390/kvm')
-rw-r--r--arch/s390/kvm/priv.c28
1 files changed, 17 insertions, 11 deletions
diff --git a/arch/s390/kvm/priv.c b/arch/s390/kvm/priv.c
index 5abfd531a8f1..4f6bc165d79b 100644
--- a/arch/s390/kvm/priv.c
+++ b/arch/s390/kvm/priv.c
@@ -224,9 +224,12 @@ static int handle_test_block(struct kvm_vcpu *vcpu)
static int handle_tpi(struct kvm_vcpu *vcpu)
{
struct kvm_s390_interrupt_info *inti;
+ unsigned long len;
+ u32 tpi_data[3];
+ int cc, rc;
u64 addr;
- int cc;
+ rc = 0;
addr = kvm_s390_get_base_disp_s(vcpu);
if (addr & 3)
return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
@@ -235,30 +238,33 @@ static int handle_tpi(struct kvm_vcpu *vcpu)
if (!inti)
goto no_interrupt;
cc = 1;
+ tpi_data[0] = inti->io.subchannel_id << 16 | inti->io.subchannel_nr;
+ tpi_data[1] = inti->io.io_int_parm;
+ tpi_data[2] = inti->io.io_int_word;
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);
+ len = sizeof(tpi_data) - 4;
+ rc = write_guest(vcpu, addr, &tpi_data, len);
+ if (rc)
+ return kvm_s390_inject_prog_cond(vcpu, rc);
} 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);
+ len = sizeof(tpi_data);
+ if (write_guest_lc(vcpu, __LC_SUBCHANNEL_ID, &tpi_data, len))
+ rc = -EFAULT;
}
kfree(inti);
no_interrupt:
/* Set condition code and we're done. */
- kvm_s390_set_psw_cc(vcpu, cc);
- return 0;
+ if (!rc)
+ kvm_s390_set_psw_cc(vcpu, cc);
+ return rc ? -EFAULT : 0;
}
static int handle_tsch(struct kvm_vcpu *vcpu)