2015-07-08 13:19:48 +02:00
/*
* kvm nested virtualization support for s390x
*
* Copyright IBM Corp . 2016
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License ( version 2 only )
* as published by the Free Software Foundation .
*
* Author ( s ) : David Hildenbrand < dahi @ linux . vnet . ibm . com >
*/
# include <linux/vmalloc.h>
# include <linux/kvm_host.h>
# include <linux/bug.h>
# include <linux/list.h>
# include <linux/bitmap.h>
2017-02-02 19:15:33 +01:00
# include <linux/sched/signal.h>
2015-07-08 13:19:48 +02:00
# include <asm/gmap.h>
# include <asm/mmu_context.h>
# include <asm/sclp.h>
# include <asm/nmi.h>
2015-11-26 14:11:19 +01:00
# include <asm/dis.h>
2015-07-08 13:19:48 +02:00
# include "kvm-s390.h"
# include "gaccess.h"
struct vsie_page {
struct kvm_s390_sie_block scb_s ; /* 0x0000 */
/* the pinned originial scb */
struct kvm_s390_sie_block * scb_o ; /* 0x0200 */
/* the shadow gmap in use by the vsie_page */
struct gmap * gmap ; /* 0x0208 */
2015-07-08 13:25:31 +02:00
/* address of the last reported fault to guest2 */
unsigned long fault_addr ; /* 0x0210 */
__u8 reserved [ 0x0700 - 0x0218 ] ; /* 0x0218 */
2015-11-26 13:11:42 +01:00
struct kvm_s390_crypto_cb crycb ; /* 0x0700 */
2015-11-26 14:11:19 +01:00
__u8 fac [ S390_ARCH_FAC_LIST_SIZE_BYTE ] ; /* 0x0800 */
2015-07-08 13:19:48 +02:00
} __packed ;
/* trigger a validity icpt for the given scb */
static int set_validity_icpt ( struct kvm_s390_sie_block * scb ,
__u16 reason_code )
{
scb - > ipa = 0x1000 ;
scb - > ipb = ( ( __u32 ) reason_code ) < < 16 ;
scb - > icptcode = ICPT_VALIDITY ;
return 1 ;
}
/* mark the prefix as unmapped, this will block the VSIE */
static void prefix_unmapped ( struct vsie_page * vsie_page )
{
atomic_or ( PROG_REQUEST , & vsie_page - > scb_s . prog20 ) ;
}
/* mark the prefix as unmapped and wait until the VSIE has been left */
static void prefix_unmapped_sync ( struct vsie_page * vsie_page )
{
prefix_unmapped ( vsie_page ) ;
if ( vsie_page - > scb_s . prog0c & PROG_IN_SIE )
atomic_or ( CPUSTAT_STOP_INT , & vsie_page - > scb_s . cpuflags ) ;
while ( vsie_page - > scb_s . prog0c & PROG_IN_SIE )
cpu_relax ( ) ;
}
/* mark the prefix as mapped, this will allow the VSIE to run */
static void prefix_mapped ( struct vsie_page * vsie_page )
{
atomic_andnot ( PROG_REQUEST , & vsie_page - > scb_s . prog20 ) ;
}
2016-04-22 13:50:09 +02:00
/* test if the prefix is mapped into the gmap shadow */
static int prefix_is_mapped ( struct vsie_page * vsie_page )
{
return ! ( atomic_read ( & vsie_page - > scb_s . prog20 ) & PROG_REQUEST ) ;
}
2015-07-08 13:19:48 +02:00
/* copy the updated intervention request bits into the shadow scb */
static void update_intervention_requests ( struct vsie_page * vsie_page )
{
const int bits = CPUSTAT_STOP_INT | CPUSTAT_IO_INT | CPUSTAT_EXT_INT ;
int cpuflags ;
cpuflags = atomic_read ( & vsie_page - > scb_o - > cpuflags ) ;
atomic_andnot ( bits , & vsie_page - > scb_s . cpuflags ) ;
atomic_or ( cpuflags & bits , & vsie_page - > scb_s . cpuflags ) ;
}
/* shadow (filter and validate) the cpuflags */
static int prepare_cpuflags ( struct kvm_vcpu * vcpu , struct vsie_page * vsie_page )
{
struct kvm_s390_sie_block * scb_s = & vsie_page - > scb_s ;
struct kvm_s390_sie_block * scb_o = vsie_page - > scb_o ;
int newflags , cpuflags = atomic_read ( & scb_o - > cpuflags ) ;
/* we don't allow ESA/390 guests */
if ( ! ( cpuflags & CPUSTAT_ZARCH ) )
return set_validity_icpt ( scb_s , 0x0001U ) ;
if ( cpuflags & ( CPUSTAT_RRF | CPUSTAT_MCDS ) )
return set_validity_icpt ( scb_s , 0x0001U ) ;
else if ( cpuflags & ( CPUSTAT_SLSV | CPUSTAT_SLSR ) )
return set_validity_icpt ( scb_s , 0x0007U ) ;
/* intervention requests will be set later */
newflags = CPUSTAT_ZARCH ;
2016-02-12 12:24:20 +01:00
if ( cpuflags & CPUSTAT_GED & & test_kvm_facility ( vcpu - > kvm , 8 ) )
newflags | = CPUSTAT_GED ;
if ( cpuflags & CPUSTAT_GED2 & & test_kvm_facility ( vcpu - > kvm , 78 ) ) {
if ( cpuflags & CPUSTAT_GED )
return set_validity_icpt ( scb_s , 0x0001U ) ;
newflags | = CPUSTAT_GED2 ;
}
2015-11-24 16:32:35 +01:00
if ( test_kvm_cpu_feat ( vcpu - > kvm , KVM_S390_VM_CPU_FEAT_GPERE ) )
newflags | = cpuflags & CPUSTAT_P ;
2015-11-24 16:41:33 +01:00
if ( test_kvm_cpu_feat ( vcpu - > kvm , KVM_S390_VM_CPU_FEAT_GSLS ) )
newflags | = cpuflags & CPUSTAT_SM ;
2015-11-24 16:56:23 +01:00
if ( test_kvm_cpu_feat ( vcpu - > kvm , KVM_S390_VM_CPU_FEAT_IBS ) )
newflags | = cpuflags & CPUSTAT_IBS ;
2015-07-08 13:19:48 +02:00
atomic_set ( & scb_s - > cpuflags , newflags ) ;
return 0 ;
}
2015-11-26 13:11:42 +01:00
/*
* Create a shadow copy of the crycb block and setup key wrapping , if
* requested for guest 3 and enabled for guest 2.
*
* We only accept format - 1 ( no AP in g2 ) , but convert it into format - 2
* There is nothing to do for format - 0.
*
* Returns : - 0 if shadowed or nothing to do
* - > 0 if control has to be given to guest 2
*/
static int shadow_crycb ( struct kvm_vcpu * vcpu , struct vsie_page * vsie_page )
{
struct kvm_s390_sie_block * scb_s = & vsie_page - > scb_s ;
struct kvm_s390_sie_block * scb_o = vsie_page - > scb_o ;
u32 crycb_addr = scb_o - > crycbd & 0x7ffffff8U ;
unsigned long * b1 , * b2 ;
u8 ecb3_flags ;
scb_s - > crycbd = 0 ;
if ( ! ( scb_o - > crycbd & vcpu - > arch . sie_block - > crycbd & CRYCB_FORMAT1 ) )
return 0 ;
/* format-1 is supported with message-security-assist extension 3 */
if ( ! test_kvm_facility ( vcpu - > kvm , 76 ) )
return 0 ;
/* we may only allow it if enabled for guest 2 */
ecb3_flags = scb_o - > ecb3 & vcpu - > arch . sie_block - > ecb3 &
( ECB3_AES | ECB3_DEA ) ;
if ( ! ecb3_flags )
return 0 ;
if ( ( crycb_addr & PAGE_MASK ) ! = ( ( crycb_addr + 128 ) & PAGE_MASK ) )
return set_validity_icpt ( scb_s , 0x003CU ) ;
else if ( ! crycb_addr )
return set_validity_icpt ( scb_s , 0x0039U ) ;
/* copy only the wrapping keys */
if ( read_guest_real ( vcpu , crycb_addr + 72 , & vsie_page - > crycb , 56 ) )
return set_validity_icpt ( scb_s , 0x0035U ) ;
scb_s - > ecb3 | = ecb3_flags ;
scb_s - > crycbd = ( ( __u32 ) ( __u64 ) & vsie_page - > crycb ) | CRYCB_FORMAT1 |
CRYCB_FORMAT2 ;
/* xor both blocks in one run */
b1 = ( unsigned long * ) vsie_page - > crycb . dea_wrapping_key_mask ;
b2 = ( unsigned long * )
vcpu - > kvm - > arch . crypto . crycb - > dea_wrapping_key_mask ;
/* as 56%8 == 0, bitmap_xor won't overwrite any data */
bitmap_xor ( b1 , b1 , b2 , BITS_PER_BYTE * 56 ) ;
return 0 ;
}
2016-02-19 10:11:24 +01:00
/* shadow (round up/down) the ibc to avoid validity icpt */
static void prepare_ibc ( struct kvm_vcpu * vcpu , struct vsie_page * vsie_page )
{
struct kvm_s390_sie_block * scb_s = & vsie_page - > scb_s ;
struct kvm_s390_sie_block * scb_o = vsie_page - > scb_o ;
__u64 min_ibc = ( sclp . ibc > > 16 ) & 0x0fffU ;
scb_s - > ibc = 0 ;
/* ibc installed in g2 and requested for g3 */
if ( vcpu - > kvm - > arch . model . ibc & & ( scb_o - > ibc & 0x0fffU ) ) {
scb_s - > ibc = scb_o - > ibc & 0x0fffU ;
/* takte care of the minimum ibc level of the machine */
if ( scb_s - > ibc < min_ibc )
scb_s - > ibc = min_ibc ;
/* take care of the maximum ibc level set for the guest */
if ( scb_s - > ibc > vcpu - > kvm - > arch . model . ibc )
scb_s - > ibc = vcpu - > kvm - > arch . model . ibc ;
}
}
2015-07-08 13:19:48 +02:00
/* unshadow the scb, copying parameters back to the real scb */
static void unshadow_scb ( struct kvm_vcpu * vcpu , struct vsie_page * vsie_page )
{
struct kvm_s390_sie_block * scb_s = & vsie_page - > scb_s ;
struct kvm_s390_sie_block * scb_o = vsie_page - > scb_o ;
/* interception */
scb_o - > icptcode = scb_s - > icptcode ;
scb_o - > icptstatus = scb_s - > icptstatus ;
scb_o - > ipa = scb_s - > ipa ;
scb_o - > ipb = scb_s - > ipb ;
scb_o - > gbea = scb_s - > gbea ;
/* timer */
scb_o - > cputm = scb_s - > cputm ;
scb_o - > ckc = scb_s - > ckc ;
scb_o - > todpr = scb_s - > todpr ;
/* guest state */
scb_o - > gpsw = scb_s - > gpsw ;
scb_o - > gg14 = scb_s - > gg14 ;
scb_o - > gg15 = scb_s - > gg15 ;
memcpy ( scb_o - > gcr , scb_s - > gcr , 128 ) ;
scb_o - > pp = scb_s - > pp ;
/* interrupt intercept */
switch ( scb_s - > icptcode ) {
case ICPT_PROGI :
case ICPT_INSTPROGI :
case ICPT_EXTINT :
memcpy ( ( void * ) ( ( u64 ) scb_o + 0xc0 ) ,
( void * ) ( ( u64 ) scb_s + 0xc0 ) , 0xf0 - 0xc0 ) ;
break ;
case ICPT_PARTEXEC :
/* MVPG only */
memcpy ( ( void * ) ( ( u64 ) scb_o + 0xc0 ) ,
( void * ) ( ( u64 ) scb_s + 0xc0 ) , 0xd0 - 0xc0 ) ;
break ;
}
if ( scb_s - > ihcpu ! = 0xffffU )
scb_o - > ihcpu = scb_s - > ihcpu ;
}
/*
* Setup the shadow scb by copying and checking the relevant parts of the g2
* provided scb .
*
* Returns : - 0 if the scb has been shadowed
* - > 0 if control has to be given to guest 2
*/
static int shadow_scb ( struct kvm_vcpu * vcpu , struct vsie_page * vsie_page )
{
struct kvm_s390_sie_block * scb_o = vsie_page - > scb_o ;
struct kvm_s390_sie_block * scb_s = & vsie_page - > scb_s ;
2017-03-13 11:48:28 +01:00
bool had_tx = scb_s - > ecb & ECB_TE ;
2015-11-24 16:41:33 +01:00
unsigned long new_mso = 0 ;
2015-07-08 13:19:48 +02:00
int rc ;
/* make sure we don't have any leftovers when reusing the scb */
scb_s - > icptcode = 0 ;
scb_s - > eca = 0 ;
scb_s - > ecb = 0 ;
scb_s - > ecb2 = 0 ;
scb_s - > ecb3 = 0 ;
scb_s - > ecd = 0 ;
2015-11-26 14:11:19 +01:00
scb_s - > fac = 0 ;
2015-07-08 13:19:48 +02:00
rc = prepare_cpuflags ( vcpu , vsie_page ) ;
if ( rc )
goto out ;
/* timer */
scb_s - > cputm = scb_o - > cputm ;
scb_s - > ckc = scb_o - > ckc ;
scb_s - > todpr = scb_o - > todpr ;
scb_s - > epoch = scb_o - > epoch ;
/* guest state */
scb_s - > gpsw = scb_o - > gpsw ;
scb_s - > gg14 = scb_o - > gg14 ;
scb_s - > gg15 = scb_o - > gg15 ;
memcpy ( scb_s - > gcr , scb_o - > gcr , 128 ) ;
scb_s - > pp = scb_o - > pp ;
/* interception / execution handling */
scb_s - > gbea = scb_o - > gbea ;
scb_s - > lctl = scb_o - > lctl ;
scb_s - > svcc = scb_o - > svcc ;
scb_s - > ictl = scb_o - > ictl ;
/*
* SKEY handling functions can ' t deal with false setting of PTE invalid
* bits . Therefore we cannot provide interpretation and would later
* have to provide own emulation handlers .
*/
scb_s - > ictl | = ICTL_ISKE | ICTL_SSKE | ICTL_RRBE ;
scb_s - > icpua = scb_o - > icpua ;
2015-11-24 16:41:33 +01:00
if ( ! ( atomic_read ( & scb_s - > cpuflags ) & CPUSTAT_SM ) )
new_mso = scb_o - > mso & 0xfffffffffff00000UL ;
2016-04-22 13:50:09 +02:00
/* if the hva of the prefix changes, we have to remap the prefix */
if ( scb_s - > mso ! = new_mso | | scb_s - > prefix ! = scb_o - > prefix )
prefix_unmapped ( vsie_page ) ;
2015-07-08 13:19:48 +02:00
/* SIE will do mso/msl validity and exception checks for us */
scb_s - > msl = scb_o - > msl & 0xfffffffffff00000UL ;
2016-04-22 13:50:09 +02:00
scb_s - > mso = new_mso ;
2015-07-08 13:19:48 +02:00
scb_s - > prefix = scb_o - > prefix ;
/* We have to definetly flush the tlb if this scb never ran */
if ( scb_s - > ihcpu ! = 0xffffU )
scb_s - > ihcpu = scb_o - > ihcpu ;
/* MVPG and Protection Exception Interpretation are always available */
2017-03-13 11:48:28 +01:00
scb_s - > eca | = scb_o - > eca & ( ECA_MVPGI | ECA_PROTEXCI ) ;
2015-11-27 12:34:28 +01:00
/* Host-protection-interruption introduced with ESOP */
if ( test_kvm_cpu_feat ( vcpu - > kvm , KVM_S390_VM_CPU_FEAT_ESOP ) )
2017-03-13 11:48:28 +01:00
scb_s - > ecb | = scb_o - > ecb & ECB_HOSTPROTINT ;
2015-11-25 11:13:32 +01:00
/* transactional execution */
if ( test_kvm_facility ( vcpu - > kvm , 73 ) ) {
/* remap the prefix is tx is toggled on */
2017-03-13 11:48:28 +01:00
if ( ( scb_o - > ecb & ECB_TE ) & & ! had_tx )
2015-11-25 11:13:32 +01:00
prefix_unmapped ( vsie_page ) ;
2017-03-13 11:48:28 +01:00
scb_s - > ecb | = scb_o - > ecb & ECB_TE ;
2015-11-25 11:13:32 +01:00
}
2015-11-25 11:08:32 +01:00
/* SIMD */
if ( test_kvm_facility ( vcpu - > kvm , 129 ) ) {
2017-03-13 11:48:28 +01:00
scb_s - > eca | = scb_o - > eca & ECA_VX ;
scb_s - > ecd | = scb_o - > ecd & ECD_HOSTREGMGMT ;
2015-11-25 11:08:32 +01:00
}
2016-01-26 12:51:06 +01:00
/* Run-time-Instrumentation */
if ( test_kvm_facility ( vcpu - > kvm , 64 ) )
2017-03-13 11:48:28 +01:00
scb_s - > ecb3 | = scb_o - > ecb3 & ECB3_RI ;
2016-08-04 09:57:36 +02:00
/* Instruction Execution Prevention */
if ( test_kvm_facility ( vcpu - > kvm , 130 ) )
2017-03-13 11:48:28 +01:00
scb_s - > ecb2 | = scb_o - > ecb2 & ECB2_IEP ;
2016-11-29 07:17:55 +01:00
/* Guarded Storage */
if ( test_kvm_facility ( vcpu - > kvm , 133 ) ) {
scb_s - > ecb | = scb_o - > ecb & ECB_GS ;
scb_s - > ecd | = scb_o - > ecd & ECD_HOSTREGMGMT ;
}
2015-11-25 09:59:49 +01:00
if ( test_kvm_cpu_feat ( vcpu - > kvm , KVM_S390_VM_CPU_FEAT_SIIF ) )
2017-03-13 11:48:28 +01:00
scb_s - > eca | = scb_o - > eca & ECA_SII ;
2015-11-24 16:53:51 +01:00
if ( test_kvm_cpu_feat ( vcpu - > kvm , KVM_S390_VM_CPU_FEAT_IB ) )
2017-03-13 11:48:28 +01:00
scb_s - > eca | = scb_o - > eca & ECA_IB ;
2015-11-24 16:54:37 +01:00
if ( test_kvm_cpu_feat ( vcpu - > kvm , KVM_S390_VM_CPU_FEAT_CEI ) )
2017-03-13 11:48:28 +01:00
scb_s - > eca | = scb_o - > eca & ECA_CEI ;
2015-07-08 13:19:48 +02:00
2016-02-19 10:11:24 +01:00
prepare_ibc ( vcpu , vsie_page ) ;
2015-11-26 13:11:42 +01:00
rc = shadow_crycb ( vcpu , vsie_page ) ;
2015-07-08 13:19:48 +02:00
out :
if ( rc )
unshadow_scb ( vcpu , vsie_page ) ;
return rc ;
}
void kvm_s390_vsie_gmap_notifier ( struct gmap * gmap , unsigned long start ,
unsigned long end )
{
struct kvm * kvm = gmap - > private ;
struct vsie_page * cur ;
unsigned long prefix ;
struct page * page ;
int i ;
if ( ! gmap_is_shadow ( gmap ) )
return ;
if ( start > = 1UL < < 31 )
/* We are only interested in prefix pages */
return ;
/*
* Only new shadow blocks are added to the list during runtime ,
* therefore we can safely reference them all the time .
*/
for ( i = 0 ; i < kvm - > arch . vsie . page_count ; i + + ) {
page = READ_ONCE ( kvm - > arch . vsie . pages [ i ] ) ;
if ( ! page )
continue ;
cur = page_to_virt ( page ) ;
if ( READ_ONCE ( cur - > gmap ) ! = gmap )
continue ;
prefix = cur - > scb_s . prefix < < GUEST_PREFIX_SHIFT ;
/* with mso/msl, the prefix lies at an offset */
prefix + = cur - > scb_s . mso ;
2015-11-25 11:13:32 +01:00
if ( prefix < = end & & start < = prefix + 2 * PAGE_SIZE - 1 )
2015-07-08 13:19:48 +02:00
prefix_unmapped_sync ( cur ) ;
}
}
/*
2015-11-25 11:13:32 +01:00
* Map the first prefix page and if tx is enabled also the second prefix page .
2015-07-08 13:19:48 +02:00
*
* The prefix will be protected , a gmap notifier will inform about unmaps .
* The shadow scb must not be executed until the prefix is remapped , this is
* guaranteed by properly handling PROG_REQUEST .
*
* Returns : - 0 on if successfully mapped or already mapped
* - > 0 if control has to be given to guest 2
* - - EAGAIN if the caller can retry immediately
* - - ENOMEM if out of memory
*/
static int map_prefix ( struct kvm_vcpu * vcpu , struct vsie_page * vsie_page )
{
struct kvm_s390_sie_block * scb_s = & vsie_page - > scb_s ;
u64 prefix = scb_s - > prefix < < GUEST_PREFIX_SHIFT ;
int rc ;
2016-04-22 13:50:09 +02:00
if ( prefix_is_mapped ( vsie_page ) )
return 0 ;
2015-07-08 13:19:48 +02:00
/* mark it as mapped so we can catch any concurrent unmappers */
prefix_mapped ( vsie_page ) ;
/* with mso/msl, the prefix lies at offset *mso* */
prefix + = scb_s - > mso ;
rc = kvm_s390_shadow_fault ( vcpu , vsie_page - > gmap , prefix ) ;
2017-03-13 11:48:28 +01:00
if ( ! rc & & ( scb_s - > ecb & ECB_TE ) )
2015-11-25 11:13:32 +01:00
rc = kvm_s390_shadow_fault ( vcpu , vsie_page - > gmap ,
prefix + PAGE_SIZE ) ;
2015-07-08 13:19:48 +02:00
/*
* We don ' t have to mprotect , we will be called for all unshadows .
* SIE will detect if protection applies and trigger a validity .
*/
if ( rc )
prefix_unmapped ( vsie_page ) ;
if ( rc > 0 | | rc = = - EFAULT )
rc = set_validity_icpt ( scb_s , 0x0037U ) ;
return rc ;
}
/*
* Pin the guest page given by gpa and set hpa to the pinned host address .
* Will always be pinned writable .
*
* Returns : - 0 on success
* - - EINVAL if the gpa is not valid guest storage
* - - ENOMEM if out of memory
*/
static int pin_guest_page ( struct kvm * kvm , gpa_t gpa , hpa_t * hpa )
{
struct page * page ;
hva_t hva ;
int rc ;
hva = gfn_to_hva ( kvm , gpa_to_gfn ( gpa ) ) ;
if ( kvm_is_error_hva ( hva ) )
return - EINVAL ;
rc = get_user_pages_fast ( hva , 1 , 1 , & page ) ;
if ( rc < 0 )
return rc ;
else if ( rc ! = 1 )
return - ENOMEM ;
* hpa = ( hpa_t ) page_to_virt ( page ) + ( gpa & ~ PAGE_MASK ) ;
return 0 ;
}
/* Unpins a page previously pinned via pin_guest_page, marking it as dirty. */
static void unpin_guest_page ( struct kvm * kvm , gpa_t gpa , hpa_t hpa )
{
struct page * page ;
page = virt_to_page ( hpa ) ;
set_page_dirty_lock ( page ) ;
put_page ( page ) ;
/* mark the page always as dirty for migration */
mark_page_dirty ( kvm , gpa_to_gfn ( gpa ) ) ;
}
/* unpin all blocks previously pinned by pin_blocks(), marking them dirty */
static void unpin_blocks ( struct kvm_vcpu * vcpu , struct vsie_page * vsie_page )
{
struct kvm_s390_sie_block * scb_o = vsie_page - > scb_o ;
struct kvm_s390_sie_block * scb_s = & vsie_page - > scb_s ;
hpa_t hpa ;
gpa_t gpa ;
hpa = ( u64 ) scb_s - > scaoh < < 32 | scb_s - > scaol ;
if ( hpa ) {
gpa = scb_o - > scaol & ~ 0xfUL ;
2015-11-25 11:02:26 +01:00
if ( test_kvm_cpu_feat ( vcpu - > kvm , KVM_S390_VM_CPU_FEAT_64BSCAO ) )
gpa | = ( u64 ) scb_o - > scaoh < < 32 ;
2015-07-08 13:19:48 +02:00
unpin_guest_page ( vcpu - > kvm , gpa , hpa ) ;
scb_s - > scaol = 0 ;
scb_s - > scaoh = 0 ;
}
2015-11-25 11:13:32 +01:00
hpa = scb_s - > itdba ;
if ( hpa ) {
gpa = scb_o - > itdba & ~ 0xffUL ;
unpin_guest_page ( vcpu - > kvm , gpa , hpa ) ;
scb_s - > itdba = 0 ;
}
2015-11-25 11:08:32 +01:00
hpa = scb_s - > gvrd ;
if ( hpa ) {
gpa = scb_o - > gvrd & ~ 0x1ffUL ;
unpin_guest_page ( vcpu - > kvm , gpa , hpa ) ;
scb_s - > gvrd = 0 ;
}
2016-01-26 12:51:06 +01:00
hpa = scb_s - > riccbd ;
if ( hpa ) {
gpa = scb_o - > riccbd & ~ 0x3fUL ;
unpin_guest_page ( vcpu - > kvm , gpa , hpa ) ;
scb_s - > riccbd = 0 ;
}
2016-11-29 07:17:55 +01:00
hpa = scb_s - > sdnxo ;
if ( hpa ) {
gpa = scb_o - > sdnxo ;
unpin_guest_page ( vcpu - > kvm , gpa , hpa ) ;
scb_s - > sdnxo = 0 ;
}
2015-07-08 13:19:48 +02:00
}
/*
* Instead of shadowing some blocks , we can simply forward them because the
* addresses in the scb are 64 bit long .
*
* This works as long as the data lies in one page . If blocks ever exceed one
* page , we have to fall back to shadowing .
*
* As we reuse the sca , the vcpu pointers contained in it are invalid . We must
* therefore not enable any facilities that access these pointers ( e . g . SIGPIF ) .
*
* Returns : - 0 if all blocks were pinned .
* - > 0 if control has to be given to guest 2
* - - ENOMEM if out of memory
*/
static int pin_blocks ( struct kvm_vcpu * vcpu , struct vsie_page * vsie_page )
{
struct kvm_s390_sie_block * scb_o = vsie_page - > scb_o ;
struct kvm_s390_sie_block * scb_s = & vsie_page - > scb_s ;
hpa_t hpa ;
gpa_t gpa ;
int rc = 0 ;
gpa = scb_o - > scaol & ~ 0xfUL ;
2015-11-25 11:02:26 +01:00
if ( test_kvm_cpu_feat ( vcpu - > kvm , KVM_S390_VM_CPU_FEAT_64BSCAO ) )
gpa | = ( u64 ) scb_o - > scaoh < < 32 ;
2015-07-08 13:19:48 +02:00
if ( gpa ) {
if ( ! ( gpa & ~ 0x1fffUL ) )
rc = set_validity_icpt ( scb_s , 0x0038U ) ;
else if ( ( gpa & ~ 0x1fffUL ) = = kvm_s390_get_prefix ( vcpu ) )
rc = set_validity_icpt ( scb_s , 0x0011U ) ;
else if ( ( gpa & PAGE_MASK ) ! =
( ( gpa + sizeof ( struct bsca_block ) - 1 ) & PAGE_MASK ) )
rc = set_validity_icpt ( scb_s , 0x003bU ) ;
if ( ! rc ) {
rc = pin_guest_page ( vcpu - > kvm , gpa , & hpa ) ;
if ( rc = = - EINVAL )
rc = set_validity_icpt ( scb_s , 0x0034U ) ;
}
if ( rc )
goto unpin ;
scb_s - > scaoh = ( u32 ) ( ( u64 ) hpa > > 32 ) ;
scb_s - > scaol = ( u32 ) ( u64 ) hpa ;
}
2015-11-25 11:13:32 +01:00
gpa = scb_o - > itdba & ~ 0xffUL ;
2017-03-13 11:48:28 +01:00
if ( gpa & & ( scb_s - > ecb & ECB_TE ) ) {
2015-11-25 11:13:32 +01:00
if ( ! ( gpa & ~ 0x1fffU ) ) {
rc = set_validity_icpt ( scb_s , 0x0080U ) ;
goto unpin ;
}
/* 256 bytes cannot cross page boundaries */
rc = pin_guest_page ( vcpu - > kvm , gpa , & hpa ) ;
if ( rc = = - EINVAL )
rc = set_validity_icpt ( scb_s , 0x0080U ) ;
if ( rc )
goto unpin ;
scb_s - > itdba = hpa ;
}
2015-11-25 11:08:32 +01:00
gpa = scb_o - > gvrd & ~ 0x1ffUL ;
2017-03-13 11:48:28 +01:00
if ( gpa & & ( scb_s - > eca & ECA_VX ) & & ! ( scb_s - > ecd & ECD_HOSTREGMGMT ) ) {
2015-11-25 11:08:32 +01:00
if ( ! ( gpa & ~ 0x1fffUL ) ) {
rc = set_validity_icpt ( scb_s , 0x1310U ) ;
goto unpin ;
}
/*
* 512 bytes vector registers cannot cross page boundaries
* if this block gets bigger , we have to shadow it .
*/
rc = pin_guest_page ( vcpu - > kvm , gpa , & hpa ) ;
if ( rc = = - EINVAL )
rc = set_validity_icpt ( scb_s , 0x1310U ) ;
if ( rc )
goto unpin ;
scb_s - > gvrd = hpa ;
}
2016-01-26 12:51:06 +01:00
gpa = scb_o - > riccbd & ~ 0x3fUL ;
2017-03-13 11:48:28 +01:00
if ( gpa & & ( scb_s - > ecb3 & ECB3_RI ) ) {
2016-01-26 12:51:06 +01:00
if ( ! ( gpa & ~ 0x1fffUL ) ) {
rc = set_validity_icpt ( scb_s , 0x0043U ) ;
goto unpin ;
}
/* 64 bytes cannot cross page boundaries */
rc = pin_guest_page ( vcpu - > kvm , gpa , & hpa ) ;
if ( rc = = - EINVAL )
rc = set_validity_icpt ( scb_s , 0x0043U ) ;
/* Validity 0x0044 will be checked by SIE */
if ( rc )
goto unpin ;
2016-09-02 12:33:49 +02:00
scb_s - > riccbd = hpa ;
2016-01-26 12:51:06 +01:00
}
2016-11-29 07:17:55 +01:00
if ( ( scb_s - > ecb & ECB_GS ) & & ! ( scb_s - > ecd & ECD_HOSTREGMGMT ) ) {
unsigned long sdnxc ;
gpa = scb_o - > sdnxo & ~ 0xfUL ;
sdnxc = scb_o - > sdnxo & 0xfUL ;
if ( ! gpa | | ! ( gpa & ~ 0x1fffUL ) ) {
rc = set_validity_icpt ( scb_s , 0x10b0U ) ;
goto unpin ;
}
if ( sdnxc < 6 | | sdnxc > 12 ) {
rc = set_validity_icpt ( scb_s , 0x10b1U ) ;
goto unpin ;
}
if ( gpa & ( ( 1 < < sdnxc ) - 1 ) ) {
rc = set_validity_icpt ( scb_s , 0x10b2U ) ;
goto unpin ;
}
/* Due to alignment rules (checked above) this cannot
* cross page boundaries
*/
rc = pin_guest_page ( vcpu - > kvm , gpa , & hpa ) ;
if ( rc = = - EINVAL )
rc = set_validity_icpt ( scb_s , 0x10b0U ) ;
if ( rc )
goto unpin ;
scb_s - > sdnxo = hpa ;
}
2015-07-08 13:19:48 +02:00
return 0 ;
unpin :
unpin_blocks ( vcpu , vsie_page ) ;
return rc ;
}
/* unpin the scb provided by guest 2, marking it as dirty */
static void unpin_scb ( struct kvm_vcpu * vcpu , struct vsie_page * vsie_page ,
gpa_t gpa )
{
hpa_t hpa = ( hpa_t ) vsie_page - > scb_o ;
if ( hpa )
unpin_guest_page ( vcpu - > kvm , gpa , hpa ) ;
vsie_page - > scb_o = NULL ;
}
/*
* Pin the scb at gpa provided by guest 2 at vsie_page - > scb_o .
*
* Returns : - 0 if the scb was pinned .
* - > 0 if control has to be given to guest 2
* - - ENOMEM if out of memory
*/
static int pin_scb ( struct kvm_vcpu * vcpu , struct vsie_page * vsie_page ,
gpa_t gpa )
{
hpa_t hpa ;
int rc ;
rc = pin_guest_page ( vcpu - > kvm , gpa , & hpa ) ;
if ( rc = = - EINVAL ) {
rc = kvm_s390_inject_program_int ( vcpu , PGM_ADDRESSING ) ;
if ( ! rc )
rc = 1 ;
}
if ( ! rc )
vsie_page - > scb_o = ( struct kvm_s390_sie_block * ) hpa ;
return rc ;
}
/*
* Inject a fault into guest 2.
*
* Returns : - > 0 if control has to be given to guest 2
* < 0 if an error occurred during injection .
*/
static int inject_fault ( struct kvm_vcpu * vcpu , __u16 code , __u64 vaddr ,
bool write_flag )
{
struct kvm_s390_pgm_info pgm = {
. code = code ,
. trans_exc_code =
/* 0-51: virtual address */
( vaddr & 0xfffffffffffff000UL ) |
/* 52-53: store / fetch */
( ( ( unsigned int ) ! write_flag ) + 1 ) < < 10 ,
/* 62-63: asce id (alway primary == 0) */
. exc_access_id = 0 , /* always primary */
. op_access_id = 0 , /* not MVPG */
} ;
int rc ;
if ( code = = PGM_PROTECTION )
pgm . trans_exc_code | = 0x4UL ;
rc = kvm_s390_inject_prog_irq ( vcpu , & pgm ) ;
return rc ? rc : 1 ;
}
/*
* Handle a fault during vsie execution on a gmap shadow .
*
* Returns : - 0 if the fault was resolved
* - > 0 if control has to be given to guest 2
* - < 0 if an error occurred
*/
static int handle_fault ( struct kvm_vcpu * vcpu , struct vsie_page * vsie_page )
{
int rc ;
if ( current - > thread . gmap_int_code = = PGM_PROTECTION )
/* we can directly forward all protection exceptions */
return inject_fault ( vcpu , PGM_PROTECTION ,
current - > thread . gmap_addr , 1 ) ;
rc = kvm_s390_shadow_fault ( vcpu , vsie_page - > gmap ,
current - > thread . gmap_addr ) ;
if ( rc > 0 ) {
rc = inject_fault ( vcpu , rc ,
current - > thread . gmap_addr ,
current - > thread . gmap_write_flag ) ;
2015-07-08 13:25:31 +02:00
if ( rc > = 0 )
vsie_page - > fault_addr = current - > thread . gmap_addr ;
2015-07-08 13:19:48 +02:00
}
return rc ;
}
2015-07-08 13:25:31 +02:00
/*
* Retry the previous fault that required guest 2 intervention . This avoids
* one superfluous SIE re - entry and direct exit .
*
* Will ignore any errors . The next SIE fault will do proper fault handling .
*/
static void handle_last_fault ( struct kvm_vcpu * vcpu ,
struct vsie_page * vsie_page )
{
if ( vsie_page - > fault_addr )
kvm_s390_shadow_fault ( vcpu , vsie_page - > gmap ,
vsie_page - > fault_addr ) ;
vsie_page - > fault_addr = 0 ;
}
2015-07-08 13:19:48 +02:00
static inline void clear_vsie_icpt ( struct vsie_page * vsie_page )
{
vsie_page - > scb_s . icptcode = 0 ;
}
2015-11-26 14:11:19 +01:00
/* rewind the psw and clear the vsie icpt, so we can retry execution */
static void retry_vsie_icpt ( struct vsie_page * vsie_page )
{
struct kvm_s390_sie_block * scb_s = & vsie_page - > scb_s ;
int ilen = insn_length ( scb_s - > ipa > > 8 ) ;
/* take care of EXECUTE instructions */
if ( scb_s - > icptstatus & 1 ) {
ilen = ( scb_s - > icptstatus > > 4 ) & 0x6 ;
if ( ! ilen )
ilen = 4 ;
}
scb_s - > gpsw . addr = __rewind_psw ( scb_s - > gpsw , ilen ) ;
clear_vsie_icpt ( vsie_page ) ;
}
/*
* Try to shadow + enable the guest 2 provided facility list .
* Retry instruction execution if enabled for and provided by guest 2.
*
* Returns : - 0 if handled ( retry or guest 2 icpt )
* - > 0 if control has to be given to guest 2
*/
static int handle_stfle ( struct kvm_vcpu * vcpu , struct vsie_page * vsie_page )
{
struct kvm_s390_sie_block * scb_s = & vsie_page - > scb_s ;
__u32 fac = vsie_page - > scb_o - > fac & 0x7ffffff8U ;
if ( fac & & test_kvm_facility ( vcpu - > kvm , 7 ) ) {
retry_vsie_icpt ( vsie_page ) ;
if ( read_guest_real ( vcpu , fac , & vsie_page - > fac ,
sizeof ( vsie_page - > fac ) ) )
return set_validity_icpt ( scb_s , 0x1090U ) ;
scb_s - > fac = ( __u32 ) ( __u64 ) & vsie_page - > fac ;
}
return 0 ;
}
2015-07-08 13:19:48 +02:00
/*
* Run the vsie on a shadow scb and a shadow gmap , without any further
* sanity checks , handling SIE faults .
*
* Returns : - 0 everything went fine
* - > 0 if control has to be given to guest 2
* - < 0 if an error occurred
*/
static int do_vsie_run ( struct kvm_vcpu * vcpu , struct vsie_page * vsie_page )
{
struct kvm_s390_sie_block * scb_s = & vsie_page - > scb_s ;
struct kvm_s390_sie_block * scb_o = vsie_page - > scb_o ;
int rc ;
2015-07-08 13:25:31 +02:00
handle_last_fault ( vcpu , vsie_page ) ;
2015-07-08 13:19:48 +02:00
if ( need_resched ( ) )
schedule ( ) ;
if ( test_cpu_flag ( CIF_MCCK_PENDING ) )
s390_handle_mcck ( ) ;
srcu_read_unlock ( & vcpu - > kvm - > srcu , vcpu - > srcu_idx ) ;
local_irq_disable ( ) ;
2016-06-15 15:18:26 +02:00
guest_enter_irqoff ( ) ;
2015-07-08 13:19:48 +02:00
local_irq_enable ( ) ;
rc = sie64a ( scb_s , vcpu - > run - > s . regs . gprs ) ;
local_irq_disable ( ) ;
2016-06-15 15:18:26 +02:00
guest_exit_irqoff ( ) ;
2015-07-08 13:19:48 +02:00
local_irq_enable ( ) ;
vcpu - > srcu_idx = srcu_read_lock ( & vcpu - > kvm - > srcu ) ;
if ( rc > 0 )
rc = 0 ; /* we could still have an icpt */
else if ( rc = = - EFAULT )
return handle_fault ( vcpu , vsie_page ) ;
switch ( scb_s - > icptcode ) {
2015-11-26 14:11:19 +01:00
case ICPT_INST :
if ( scb_s - > ipa = = 0xb2b0 )
rc = handle_stfle ( vcpu , vsie_page ) ;
break ;
2015-07-08 13:19:48 +02:00
case ICPT_STOP :
/* stop not requested by g2 - must have been a kick */
if ( ! ( atomic_read ( & scb_o - > cpuflags ) & CPUSTAT_STOP_INT ) )
clear_vsie_icpt ( vsie_page ) ;
break ;
case ICPT_VALIDITY :
if ( ( scb_s - > ipa & 0xf000 ) ! = 0xf000 )
scb_s - > ipa + = 0x1000 ;
break ;
}
return rc ;
}
static void release_gmap_shadow ( struct vsie_page * vsie_page )
{
if ( vsie_page - > gmap )
gmap_put ( vsie_page - > gmap ) ;
WRITE_ONCE ( vsie_page - > gmap , NULL ) ;
2016-04-22 13:50:09 +02:00
prefix_unmapped ( vsie_page ) ;
2015-07-08 13:19:48 +02:00
}
static int acquire_gmap_shadow ( struct kvm_vcpu * vcpu ,
struct vsie_page * vsie_page )
{
unsigned long asce ;
union ctlreg0 cr0 ;
struct gmap * gmap ;
int edat ;
asce = vcpu - > arch . sie_block - > gcr [ 1 ] ;
cr0 . val = vcpu - > arch . sie_block - > gcr [ 0 ] ;
edat = cr0 . edat & & test_kvm_facility ( vcpu - > kvm , 8 ) ;
edat + = edat & & test_kvm_facility ( vcpu - > kvm , 78 ) ;
2016-04-22 13:50:09 +02:00
/*
* ASCE or EDAT could have changed since last icpt , or the gmap
* we ' re holding has been unshadowed . If the gmap is still valid ,
* we can safely reuse it .
*/
if ( vsie_page - > gmap & & gmap_shadow_valid ( vsie_page - > gmap , asce , edat ) )
return 0 ;
/* release the old shadow - if any, and mark the prefix as unmapped */
release_gmap_shadow ( vsie_page ) ;
2015-07-08 13:19:48 +02:00
gmap = gmap_shadow ( vcpu - > arch . gmap , asce , edat ) ;
if ( IS_ERR ( gmap ) )
return PTR_ERR ( gmap ) ;
gmap - > private = vcpu - > kvm ;
WRITE_ONCE ( vsie_page - > gmap , gmap ) ;
return 0 ;
}
2016-05-27 22:03:52 +02:00
/*
* Register the shadow scb at the VCPU , e . g . for kicking out of vsie .
*/
static void register_shadow_scb ( struct kvm_vcpu * vcpu ,
struct vsie_page * vsie_page )
{
2015-10-29 10:30:36 +01:00
struct kvm_s390_sie_block * scb_s = & vsie_page - > scb_s ;
2016-05-27 22:03:52 +02:00
WRITE_ONCE ( vcpu - > arch . vsie_block , & vsie_page - > scb_s ) ;
2015-07-07 20:39:35 +02:00
/*
* External calls have to lead to a kick of the vcpu and
* therefore the vsie - > Simulate Wait state .
*/
atomic_or ( CPUSTAT_WAIT , & vcpu - > arch . sie_block - > cpuflags ) ;
2015-10-29 10:30:36 +01:00
/*
* We have to adjust the g3 epoch by the g2 epoch . The epoch will
* automatically be adjusted on tod clock changes via kvm_sync_clock .
*/
preempt_disable ( ) ;
scb_s - > epoch + = vcpu - > kvm - > arch . epoch ;
preempt_enable ( ) ;
2016-05-27 22:03:52 +02:00
}
/*
* Unregister a shadow scb from a VCPU .
*/
static void unregister_shadow_scb ( struct kvm_vcpu * vcpu )
{
2015-07-07 20:39:35 +02:00
atomic_andnot ( CPUSTAT_WAIT , & vcpu - > arch . sie_block - > cpuflags ) ;
2016-05-27 22:03:52 +02:00
WRITE_ONCE ( vcpu - > arch . vsie_block , NULL ) ;
}
2015-07-08 13:19:48 +02:00
/*
* Run the vsie on a shadowed scb , managing the gmap shadow , handling
* prefix pages and faults .
*
* Returns : - 0 if no errors occurred
* - > 0 if control has to be given to guest 2
* - - ENOMEM if out of memory
*/
static int vsie_run ( struct kvm_vcpu * vcpu , struct vsie_page * vsie_page )
{
struct kvm_s390_sie_block * scb_s = & vsie_page - > scb_s ;
int rc = 0 ;
while ( 1 ) {
rc = acquire_gmap_shadow ( vcpu , vsie_page ) ;
if ( ! rc )
rc = map_prefix ( vcpu , vsie_page ) ;
if ( ! rc ) {
gmap_enable ( vsie_page - > gmap ) ;
update_intervention_requests ( vsie_page ) ;
rc = do_vsie_run ( vcpu , vsie_page ) ;
gmap_enable ( vcpu - > arch . gmap ) ;
}
2016-05-27 22:03:52 +02:00
atomic_andnot ( PROG_BLOCK_SIE , & scb_s - > prog20 ) ;
2015-07-08 13:19:48 +02:00
if ( rc = = - EAGAIN )
rc = 0 ;
if ( rc | | scb_s - > icptcode | | signal_pending ( current ) | |
kvm_s390_vcpu_has_irq ( vcpu , 0 ) )
break ;
2017-01-02 08:51:02 +01:00
}
2015-07-08 13:19:48 +02:00
if ( rc = = - EFAULT ) {
/*
* Addressing exceptions are always presentes as intercepts .
* As addressing exceptions are suppressing and our guest 3 PSW
* points at the responsible instruction , we have to
* forward the PSW and set the ilc . If we can ' t read guest 3
* instruction , we can use an arbitrary ilc . Let ' s always use
* ilen = 4 for now , so we can avoid reading in guest 3 virtual
* memory . ( we could also fake the shadow so the hardware
* handles it ) .
*/
scb_s - > icptcode = ICPT_PROGI ;
scb_s - > iprcc = PGM_ADDRESSING ;
scb_s - > pgmilc = 4 ;
scb_s - > gpsw . addr = __rewind_psw ( scb_s - > gpsw , 4 ) ;
}
return rc ;
}
/*
* Get or create a vsie page for a scb address .
*
* Returns : - address of a vsie page ( cached or new one )
* - NULL if the same scb address is already used by another VCPU
* - ERR_PTR ( - ENOMEM ) if out of memory
*/
static struct vsie_page * get_vsie_page ( struct kvm * kvm , unsigned long addr )
{
struct vsie_page * vsie_page ;
struct page * page ;
int nr_vcpus ;
rcu_read_lock ( ) ;
page = radix_tree_lookup ( & kvm - > arch . vsie . addr_to_page , addr > > 9 ) ;
rcu_read_unlock ( ) ;
if ( page ) {
if ( page_ref_inc_return ( page ) = = 2 )
return page_to_virt ( page ) ;
page_ref_dec ( page ) ;
}
/*
* We want at least # online_vcpus shadows , so every VCPU can execute
* the VSIE in parallel .
*/
nr_vcpus = atomic_read ( & kvm - > online_vcpus ) ;
mutex_lock ( & kvm - > arch . vsie . mutex ) ;
if ( kvm - > arch . vsie . page_count < nr_vcpus ) {
2015-11-26 14:11:19 +01:00
page = alloc_page ( GFP_KERNEL | __GFP_ZERO | GFP_DMA ) ;
2015-07-08 13:19:48 +02:00
if ( ! page ) {
mutex_unlock ( & kvm - > arch . vsie . mutex ) ;
return ERR_PTR ( - ENOMEM ) ;
}
page_ref_inc ( page ) ;
kvm - > arch . vsie . pages [ kvm - > arch . vsie . page_count ] = page ;
kvm - > arch . vsie . page_count + + ;
} else {
/* reuse an existing entry that belongs to nobody */
while ( true ) {
page = kvm - > arch . vsie . pages [ kvm - > arch . vsie . next ] ;
if ( page_ref_inc_return ( page ) = = 2 )
break ;
page_ref_dec ( page ) ;
kvm - > arch . vsie . next + + ;
kvm - > arch . vsie . next % = nr_vcpus ;
}
radix_tree_delete ( & kvm - > arch . vsie . addr_to_page , page - > index > > 9 ) ;
}
page - > index = addr ;
/* double use of the same address */
if ( radix_tree_insert ( & kvm - > arch . vsie . addr_to_page , addr > > 9 , page ) ) {
page_ref_dec ( page ) ;
mutex_unlock ( & kvm - > arch . vsie . mutex ) ;
return NULL ;
}
mutex_unlock ( & kvm - > arch . vsie . mutex ) ;
vsie_page = page_to_virt ( page ) ;
memset ( & vsie_page - > scb_s , 0 , sizeof ( struct kvm_s390_sie_block ) ) ;
2016-04-22 13:50:09 +02:00
release_gmap_shadow ( vsie_page ) ;
2015-07-08 13:25:31 +02:00
vsie_page - > fault_addr = 0 ;
2015-07-08 13:19:48 +02:00
vsie_page - > scb_s . ihcpu = 0xffffU ;
return vsie_page ;
}
/* put a vsie page acquired via get_vsie_page */
static void put_vsie_page ( struct kvm * kvm , struct vsie_page * vsie_page )
{
struct page * page = pfn_to_page ( __pa ( vsie_page ) > > PAGE_SHIFT ) ;
page_ref_dec ( page ) ;
}
int kvm_s390_handle_vsie ( struct kvm_vcpu * vcpu )
{
struct vsie_page * vsie_page ;
unsigned long scb_addr ;
int rc ;
vcpu - > stat . instruction_sie + + ;
if ( ! test_kvm_cpu_feat ( vcpu - > kvm , KVM_S390_VM_CPU_FEAT_SIEF2 ) )
return - EOPNOTSUPP ;
if ( vcpu - > arch . sie_block - > gpsw . mask & PSW_MASK_PSTATE )
return kvm_s390_inject_program_int ( vcpu , PGM_PRIVILEGED_OP ) ;
BUILD_BUG_ON ( sizeof ( struct vsie_page ) ! = 4096 ) ;
scb_addr = kvm_s390_get_base_disp_s ( vcpu , NULL ) ;
/* 512 byte alignment */
if ( unlikely ( scb_addr & 0x1ffUL ) )
return kvm_s390_inject_program_int ( vcpu , PGM_SPECIFICATION ) ;
if ( signal_pending ( current ) | | kvm_s390_vcpu_has_irq ( vcpu , 0 ) )
return 0 ;
vsie_page = get_vsie_page ( vcpu - > kvm , scb_addr ) ;
if ( IS_ERR ( vsie_page ) )
return PTR_ERR ( vsie_page ) ;
else if ( ! vsie_page )
/* double use of sie control block - simply do nothing */
return 0 ;
rc = pin_scb ( vcpu , vsie_page , scb_addr ) ;
if ( rc )
goto out_put ;
rc = shadow_scb ( vcpu , vsie_page ) ;
if ( rc )
goto out_unpin_scb ;
rc = pin_blocks ( vcpu , vsie_page ) ;
if ( rc )
goto out_unshadow ;
2016-05-27 22:03:52 +02:00
register_shadow_scb ( vcpu , vsie_page ) ;
2015-07-08 13:19:48 +02:00
rc = vsie_run ( vcpu , vsie_page ) ;
2016-05-27 22:03:52 +02:00
unregister_shadow_scb ( vcpu ) ;
2015-07-08 13:19:48 +02:00
unpin_blocks ( vcpu , vsie_page ) ;
out_unshadow :
unshadow_scb ( vcpu , vsie_page ) ;
out_unpin_scb :
unpin_scb ( vcpu , vsie_page , scb_addr ) ;
out_put :
put_vsie_page ( vcpu - > kvm , vsie_page ) ;
return rc < 0 ? rc : 0 ;
}
/* Init the vsie data structures. To be called when a vm is initialized. */
void kvm_s390_vsie_init ( struct kvm * kvm )
{
mutex_init ( & kvm - > arch . vsie . mutex ) ;
INIT_RADIX_TREE ( & kvm - > arch . vsie . addr_to_page , GFP_KERNEL ) ;
}
/* Destroy the vsie data structures. To be called when a vm is destroyed. */
void kvm_s390_vsie_destroy ( struct kvm * kvm )
{
2016-04-22 13:50:09 +02:00
struct vsie_page * vsie_page ;
2015-07-08 13:19:48 +02:00
struct page * page ;
int i ;
mutex_lock ( & kvm - > arch . vsie . mutex ) ;
for ( i = 0 ; i < kvm - > arch . vsie . page_count ; i + + ) {
page = kvm - > arch . vsie . pages [ i ] ;
kvm - > arch . vsie . pages [ i ] = NULL ;
2016-04-22 13:50:09 +02:00
vsie_page = page_to_virt ( page ) ;
release_gmap_shadow ( vsie_page ) ;
2015-07-08 13:19:48 +02:00
/* free the radix tree entry */
radix_tree_delete ( & kvm - > arch . vsie . addr_to_page , page - > index > > 9 ) ;
__free_page ( page ) ;
}
kvm - > arch . vsie . page_count = 0 ;
mutex_unlock ( & kvm - > arch . vsie . mutex ) ;
}
2016-05-27 22:03:52 +02:00
void kvm_s390_vsie_kick ( struct kvm_vcpu * vcpu )
{
struct kvm_s390_sie_block * scb = READ_ONCE ( vcpu - > arch . vsie_block ) ;
/*
* Even if the VCPU lets go of the shadow sie block reference , it is
* still valid in the cache . So we can safely kick it .
*/
if ( scb ) {
atomic_or ( PROG_BLOCK_SIE , & scb - > prog20 ) ;
if ( scb - > prog0c & PROG_IN_SIE )
atomic_or ( CPUSTAT_STOP_INT , & scb - > cpuflags ) ;
}
}