Commit 92ea2b33 authored by Radim Krčmář's avatar Radim Krčmář

Merge tag 'kvm-s390-next-4.16-2' of git://git.kernel.org/pub/scm/linux/kernel/git/kvms390/linux

KVM: s390: Fixes and features for 4.16 part 2

- exitless interrupts for emulated devices (Michael Mueller)
- cleanup of cpuflag handling (David Hildenbrand)
- kvm stat counter improvements (Christian Borntraeger)
- vsie improvements (David Hildenbrand)
- mm cleanup (Janosch Frank)
parents d7231e75 4b9f9525
...@@ -261,6 +261,11 @@ static inline void clear_bit_inv(unsigned long nr, volatile unsigned long *ptr) ...@@ -261,6 +261,11 @@ static inline void clear_bit_inv(unsigned long nr, volatile unsigned long *ptr)
return clear_bit(nr ^ (BITS_PER_LONG - 1), ptr); return clear_bit(nr ^ (BITS_PER_LONG - 1), ptr);
} }
static inline int test_and_clear_bit_inv(unsigned long nr, volatile unsigned long *ptr)
{
return test_and_clear_bit(nr ^ (BITS_PER_LONG - 1), ptr);
}
static inline void __set_bit_inv(unsigned long nr, volatile unsigned long *ptr) static inline void __set_bit_inv(unsigned long nr, volatile unsigned long *ptr)
{ {
return __set_bit(nr ^ (BITS_PER_LONG - 1), ptr); return __set_bit(nr ^ (BITS_PER_LONG - 1), ptr);
......
...@@ -20,7 +20,9 @@ struct css_general_char { ...@@ -20,7 +20,9 @@ struct css_general_char {
u32 aif_tdd : 1; /* bit 56 */ u32 aif_tdd : 1; /* bit 56 */
u32 : 1; u32 : 1;
u32 qebsm : 1; /* bit 58 */ u32 qebsm : 1; /* bit 58 */
u32 : 8; u32 : 2;
u32 aiv : 1; /* bit 61 */
u32 : 5;
u32 aif_osa : 1; /* bit 67 */ u32 aif_osa : 1; /* bit 67 */
u32 : 12; u32 : 12;
u32 eadm_rf : 1; /* bit 80 */ u32 eadm_rf : 1; /* bit 80 */
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
/* /*
* definition for kernel virtual machines on s390 * definition for kernel virtual machines on s390
* *
* Copyright IBM Corp. 2008, 2009 * Copyright IBM Corp. 2008, 2018
* *
* Author(s): Carsten Otte <cotte@de.ibm.com> * Author(s): Carsten Otte <cotte@de.ibm.com>
*/ */
...@@ -183,6 +183,7 @@ struct kvm_s390_sie_block { ...@@ -183,6 +183,7 @@ struct kvm_s390_sie_block {
#define ECA_IB 0x40000000 #define ECA_IB 0x40000000
#define ECA_SIGPI 0x10000000 #define ECA_SIGPI 0x10000000
#define ECA_MVPGI 0x01000000 #define ECA_MVPGI 0x01000000
#define ECA_AIV 0x00200000
#define ECA_VX 0x00020000 #define ECA_VX 0x00020000
#define ECA_PROTEXCI 0x00002000 #define ECA_PROTEXCI 0x00002000
#define ECA_SII 0x00000001 #define ECA_SII 0x00000001
...@@ -227,7 +228,9 @@ struct kvm_s390_sie_block { ...@@ -227,7 +228,9 @@ struct kvm_s390_sie_block {
__u8 epdx; /* 0x0069 */ __u8 epdx; /* 0x0069 */
__u8 reserved6a[2]; /* 0x006a */ __u8 reserved6a[2]; /* 0x006a */
__u32 todpr; /* 0x006c */ __u32 todpr; /* 0x006c */
__u8 reserved70[16]; /* 0x0070 */ #define GISA_FORMAT1 0x00000001
__u32 gd; /* 0x0070 */
__u8 reserved74[12]; /* 0x0074 */
__u64 mso; /* 0x0080 */ __u64 mso; /* 0x0080 */
__u64 msl; /* 0x0088 */ __u64 msl; /* 0x0088 */
psw_t gpsw; /* 0x0090 */ psw_t gpsw; /* 0x0090 */
...@@ -316,18 +319,30 @@ struct kvm_vcpu_stat { ...@@ -316,18 +319,30 @@ struct kvm_vcpu_stat {
u64 deliver_program_int; u64 deliver_program_int;
u64 deliver_io_int; u64 deliver_io_int;
u64 exit_wait_state; u64 exit_wait_state;
u64 instruction_epsw;
u64 instruction_gs;
u64 instruction_io_other;
u64 instruction_lpsw;
u64 instruction_lpswe;
u64 instruction_pfmf; u64 instruction_pfmf;
u64 instruction_ptff;
u64 instruction_sck;
u64 instruction_sckpf;
u64 instruction_stidp; u64 instruction_stidp;
u64 instruction_spx; u64 instruction_spx;
u64 instruction_stpx; u64 instruction_stpx;
u64 instruction_stap; u64 instruction_stap;
u64 instruction_storage_key; u64 instruction_iske;
u64 instruction_ri;
u64 instruction_rrbe;
u64 instruction_sske;
u64 instruction_ipte_interlock; u64 instruction_ipte_interlock;
u64 instruction_stsch;
u64 instruction_chsc;
u64 instruction_stsi; u64 instruction_stsi;
u64 instruction_stfl; u64 instruction_stfl;
u64 instruction_tb;
u64 instruction_tpi;
u64 instruction_tprot; u64 instruction_tprot;
u64 instruction_tsch;
u64 instruction_sie; u64 instruction_sie;
u64 instruction_essa; u64 instruction_essa;
u64 instruction_sthyi; u64 instruction_sthyi;
...@@ -353,6 +368,7 @@ struct kvm_vcpu_stat { ...@@ -353,6 +368,7 @@ struct kvm_vcpu_stat {
u64 diagnose_258; u64 diagnose_258;
u64 diagnose_308; u64 diagnose_308;
u64 diagnose_500; u64 diagnose_500;
u64 diagnose_other;
}; };
#define PGM_OPERATION 0x01 #define PGM_OPERATION 0x01
...@@ -409,35 +425,35 @@ struct kvm_vcpu_stat { ...@@ -409,35 +425,35 @@ struct kvm_vcpu_stat {
#define PGM_PER 0x80 #define PGM_PER 0x80
#define PGM_CRYPTO_OPERATION 0x119 #define PGM_CRYPTO_OPERATION 0x119
/* irq types in order of priority */ /* irq types in ascend order of priorities */
enum irq_types { enum irq_types {
IRQ_PEND_MCHK_EX = 0, IRQ_PEND_SET_PREFIX = 0,
IRQ_PEND_SVC,
IRQ_PEND_PROG,
IRQ_PEND_MCHK_REP,
IRQ_PEND_EXT_IRQ_KEY,
IRQ_PEND_EXT_MALFUNC,
IRQ_PEND_EXT_EMERGENCY,
IRQ_PEND_EXT_EXTERNAL,
IRQ_PEND_EXT_CLOCK_COMP,
IRQ_PEND_EXT_CPU_TIMER,
IRQ_PEND_EXT_TIMING,
IRQ_PEND_EXT_SERVICE,
IRQ_PEND_EXT_HOST,
IRQ_PEND_PFAULT_INIT,
IRQ_PEND_PFAULT_DONE,
IRQ_PEND_VIRTIO,
IRQ_PEND_IO_ISC_0,
IRQ_PEND_IO_ISC_1,
IRQ_PEND_IO_ISC_2,
IRQ_PEND_IO_ISC_3,
IRQ_PEND_IO_ISC_4,
IRQ_PEND_IO_ISC_5,
IRQ_PEND_IO_ISC_6,
IRQ_PEND_IO_ISC_7,
IRQ_PEND_SIGP_STOP,
IRQ_PEND_RESTART, IRQ_PEND_RESTART,
IRQ_PEND_SET_PREFIX, IRQ_PEND_SIGP_STOP,
IRQ_PEND_IO_ISC_7,
IRQ_PEND_IO_ISC_6,
IRQ_PEND_IO_ISC_5,
IRQ_PEND_IO_ISC_4,
IRQ_PEND_IO_ISC_3,
IRQ_PEND_IO_ISC_2,
IRQ_PEND_IO_ISC_1,
IRQ_PEND_IO_ISC_0,
IRQ_PEND_VIRTIO,
IRQ_PEND_PFAULT_DONE,
IRQ_PEND_PFAULT_INIT,
IRQ_PEND_EXT_HOST,
IRQ_PEND_EXT_SERVICE,
IRQ_PEND_EXT_TIMING,
IRQ_PEND_EXT_CPU_TIMER,
IRQ_PEND_EXT_CLOCK_COMP,
IRQ_PEND_EXT_EXTERNAL,
IRQ_PEND_EXT_EMERGENCY,
IRQ_PEND_EXT_MALFUNC,
IRQ_PEND_EXT_IRQ_KEY,
IRQ_PEND_MCHK_REP,
IRQ_PEND_PROG,
IRQ_PEND_SVC,
IRQ_PEND_MCHK_EX,
IRQ_PEND_COUNT IRQ_PEND_COUNT
}; };
...@@ -703,14 +719,50 @@ struct kvm_s390_crypto_cb { ...@@ -703,14 +719,50 @@ struct kvm_s390_crypto_cb {
struct kvm_s390_apcb1 apcb1; /* 0x0080 */ struct kvm_s390_apcb1 apcb1; /* 0x0080 */
}; };
struct kvm_s390_gisa {
union {
struct { /* common to all formats */
u32 next_alert;
u8 ipm;
u8 reserved01[2];
u8 iam;
};
struct { /* format 0 */
u32 next_alert;
u8 ipm;
u8 reserved01;
u8 : 6;
u8 g : 1;
u8 c : 1;
u8 iam;
u8 reserved02[4];
u32 airq_count;
} g0;
struct { /* format 1 */
u32 next_alert;
u8 ipm;
u8 simm;
u8 nimm;
u8 iam;
u8 aism[8];
u8 : 6;
u8 g : 1;
u8 c : 1;
u8 reserved03[11];
u32 airq_count;
} g1;
};
};
/* /*
* sie_page2 has to be allocated as DMA because fac_list and crycb need * sie_page2 has to be allocated as DMA because fac_list, crycb and
* 31bit addresses in the sie control block. * gisa need 31bit addresses in the sie control block.
*/ */
struct sie_page2 { struct sie_page2 {
__u64 fac_list[S390_ARCH_FAC_LIST_SIZE_U64]; /* 0x0000 */ __u64 fac_list[S390_ARCH_FAC_LIST_SIZE_U64]; /* 0x0000 */
struct kvm_s390_crypto_cb crycb; /* 0x0800 */ struct kvm_s390_crypto_cb crycb; /* 0x0800 */
u8 reserved900[0x1000 - 0x900]; /* 0x0900 */ struct kvm_s390_gisa gisa; /* 0x0900 */
u8 reserved920[0x1000 - 0x920]; /* 0x0920 */
}; };
struct kvm_s390_vsie { struct kvm_s390_vsie {
...@@ -757,6 +809,7 @@ struct kvm_arch{ ...@@ -757,6 +809,7 @@ struct kvm_arch{
struct kvm_s390_migration_state *migration_state; struct kvm_s390_migration_state *migration_state;
/* subset of available cpu features enabled by user space */ /* subset of available cpu features enabled by user space */
DECLARE_BITMAP(cpu_feat, KVM_S390_VM_CPU_FEAT_NR_BITS); DECLARE_BITMAP(cpu_feat, KVM_S390_VM_CPU_FEAT_NR_BITS);
struct kvm_s390_gisa *gisa;
}; };
#define KVM_HVA_ERR_BAD (-1UL) #define KVM_HVA_ERR_BAD (-1UL)
......
...@@ -77,6 +77,7 @@ struct sclp_info { ...@@ -77,6 +77,7 @@ struct sclp_info {
unsigned char has_ibs : 1; unsigned char has_ibs : 1;
unsigned char has_skey : 1; unsigned char has_skey : 1;
unsigned char has_kss : 1; unsigned char has_kss : 1;
unsigned char has_gisaf : 1;
unsigned int ibc; unsigned int ibc;
unsigned int mtid; unsigned int mtid;
unsigned int mtid_cp; unsigned int mtid_cp;
......
...@@ -257,6 +257,7 @@ int kvm_s390_handle_diag(struct kvm_vcpu *vcpu) ...@@ -257,6 +257,7 @@ int kvm_s390_handle_diag(struct kvm_vcpu *vcpu)
case 0x500: case 0x500:
return __diag_virtio_hypercall(vcpu); return __diag_virtio_hypercall(vcpu);
default: default:
vcpu->stat.diagnose_other++;
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
} }
...@@ -36,7 +36,7 @@ static int sca_ext_call_pending(struct kvm_vcpu *vcpu, int *src_id) ...@@ -36,7 +36,7 @@ static int sca_ext_call_pending(struct kvm_vcpu *vcpu, int *src_id)
{ {
int c, scn; int c, scn;
if (!(atomic_read(&vcpu->arch.sie_block->cpuflags) & CPUSTAT_ECALL_PEND)) if (!kvm_s390_test_cpuflags(vcpu, CPUSTAT_ECALL_PEND))
return 0; return 0;
BUG_ON(!kvm_s390_use_sca_entries()); BUG_ON(!kvm_s390_use_sca_entries());
...@@ -101,7 +101,7 @@ static int sca_inject_ext_call(struct kvm_vcpu *vcpu, int src_id) ...@@ -101,7 +101,7 @@ static int sca_inject_ext_call(struct kvm_vcpu *vcpu, int src_id)
/* another external call is pending */ /* another external call is pending */
return -EBUSY; return -EBUSY;
} }
atomic_or(CPUSTAT_ECALL_PEND, &vcpu->arch.sie_block->cpuflags); kvm_s390_set_cpuflags(vcpu, CPUSTAT_ECALL_PEND);
return 0; return 0;
} }
...@@ -111,7 +111,7 @@ static void sca_clear_ext_call(struct kvm_vcpu *vcpu) ...@@ -111,7 +111,7 @@ static void sca_clear_ext_call(struct kvm_vcpu *vcpu)
if (!kvm_s390_use_sca_entries()) if (!kvm_s390_use_sca_entries())
return; return;
atomic_andnot(CPUSTAT_ECALL_PEND, &vcpu->arch.sie_block->cpuflags); kvm_s390_clear_cpuflags(vcpu, CPUSTAT_ECALL_PEND);
read_lock(&vcpu->kvm->arch.sca_lock); read_lock(&vcpu->kvm->arch.sca_lock);
if (vcpu->kvm->arch.use_esca) { if (vcpu->kvm->arch.use_esca) {
struct esca_block *sca = vcpu->kvm->arch.sca; struct esca_block *sca = vcpu->kvm->arch.sca;
...@@ -189,8 +189,8 @@ static int cpu_timer_irq_pending(struct kvm_vcpu *vcpu) ...@@ -189,8 +189,8 @@ static int cpu_timer_irq_pending(struct kvm_vcpu *vcpu)
static inline int is_ioirq(unsigned long irq_type) static inline int is_ioirq(unsigned long irq_type)
{ {
return ((irq_type >= IRQ_PEND_IO_ISC_0) && return ((irq_type >= IRQ_PEND_IO_ISC_7) &&
(irq_type <= IRQ_PEND_IO_ISC_7)); (irq_type <= IRQ_PEND_IO_ISC_0));
} }
static uint64_t isc_to_isc_bits(int isc) static uint64_t isc_to_isc_bits(int isc)
...@@ -198,25 +198,59 @@ static uint64_t isc_to_isc_bits(int isc) ...@@ -198,25 +198,59 @@ static uint64_t isc_to_isc_bits(int isc)
return (0x80 >> isc) << 24; return (0x80 >> isc) << 24;
} }
static inline u32 isc_to_int_word(u8 isc)
{
return ((u32)isc << 27) | 0x80000000;
}
static inline u8 int_word_to_isc(u32 int_word) static inline u8 int_word_to_isc(u32 int_word)
{ {
return (int_word & 0x38000000) >> 27; return (int_word & 0x38000000) >> 27;
} }
/*
* To use atomic bitmap functions, we have to provide a bitmap address
* that is u64 aligned. However, the ipm might be u32 aligned.
* Therefore, we logically start the bitmap at the very beginning of the
* struct and fixup the bit number.
*/
#define IPM_BIT_OFFSET (offsetof(struct kvm_s390_gisa, ipm) * BITS_PER_BYTE)
static inline void kvm_s390_gisa_set_ipm_gisc(struct kvm_s390_gisa *gisa, u32 gisc)
{
set_bit_inv(IPM_BIT_OFFSET + gisc, (unsigned long *) gisa);
}
static inline u8 kvm_s390_gisa_get_ipm(struct kvm_s390_gisa *gisa)
{
return READ_ONCE(gisa->ipm);
}
static inline void kvm_s390_gisa_clear_ipm_gisc(struct kvm_s390_gisa *gisa, u32 gisc)
{
clear_bit_inv(IPM_BIT_OFFSET + gisc, (unsigned long *) gisa);
}
static inline int kvm_s390_gisa_tac_ipm_gisc(struct kvm_s390_gisa *gisa, u32 gisc)
{
return test_and_clear_bit_inv(IPM_BIT_OFFSET + gisc, (unsigned long *) gisa);
}
static inline unsigned long pending_irqs(struct kvm_vcpu *vcpu) static inline unsigned long pending_irqs(struct kvm_vcpu *vcpu)
{ {
return vcpu->kvm->arch.float_int.pending_irqs | return vcpu->kvm->arch.float_int.pending_irqs |
vcpu->arch.local_int.pending_irqs; vcpu->arch.local_int.pending_irqs |
kvm_s390_gisa_get_ipm(vcpu->kvm->arch.gisa) << IRQ_PEND_IO_ISC_7;
} }
static inline int isc_to_irq_type(unsigned long isc) static inline int isc_to_irq_type(unsigned long isc)
{ {
return IRQ_PEND_IO_ISC_0 + isc; return IRQ_PEND_IO_ISC_0 - isc;
} }
static inline int irq_type_to_isc(unsigned long irq_type) static inline int irq_type_to_isc(unsigned long irq_type)
{ {
return irq_type - IRQ_PEND_IO_ISC_0; return IRQ_PEND_IO_ISC_0 - irq_type;
} }
static unsigned long disable_iscs(struct kvm_vcpu *vcpu, static unsigned long disable_iscs(struct kvm_vcpu *vcpu,
...@@ -277,20 +311,20 @@ static unsigned long deliverable_irqs(struct kvm_vcpu *vcpu) ...@@ -277,20 +311,20 @@ static unsigned long deliverable_irqs(struct kvm_vcpu *vcpu)
static void __set_cpu_idle(struct kvm_vcpu *vcpu) static void __set_cpu_idle(struct kvm_vcpu *vcpu)
{ {
atomic_or(CPUSTAT_WAIT, &vcpu->arch.sie_block->cpuflags); kvm_s390_set_cpuflags(vcpu, CPUSTAT_WAIT);
set_bit(vcpu->vcpu_id, vcpu->kvm->arch.float_int.idle_mask); set_bit(vcpu->vcpu_id, vcpu->kvm->arch.float_int.idle_mask);
} }
static void __unset_cpu_idle(struct kvm_vcpu *vcpu) static void __unset_cpu_idle(struct kvm_vcpu *vcpu)
{ {
atomic_andnot(CPUSTAT_WAIT, &vcpu->arch.sie_block->cpuflags); kvm_s390_clear_cpuflags(vcpu, CPUSTAT_WAIT);
clear_bit(vcpu->vcpu_id, vcpu->kvm->arch.float_int.idle_mask); clear_bit(vcpu->vcpu_id, vcpu->kvm->arch.float_int.idle_mask);
} }
static void __reset_intercept_indicators(struct kvm_vcpu *vcpu) static void __reset_intercept_indicators(struct kvm_vcpu *vcpu)
{ {
atomic_andnot(CPUSTAT_IO_INT | CPUSTAT_EXT_INT | CPUSTAT_STOP_INT, kvm_s390_clear_cpuflags(vcpu, CPUSTAT_IO_INT | CPUSTAT_EXT_INT |
&vcpu->arch.sie_block->cpuflags); CPUSTAT_STOP_INT);
vcpu->arch.sie_block->lctl = 0x0000; vcpu->arch.sie_block->lctl = 0x0000;
vcpu->arch.sie_block->ictl &= ~(ICTL_LPSW | ICTL_STCTL | ICTL_PINT); vcpu->arch.sie_block->ictl &= ~(ICTL_LPSW | ICTL_STCTL | ICTL_PINT);
...@@ -301,17 +335,12 @@ static void __reset_intercept_indicators(struct kvm_vcpu *vcpu) ...@@ -301,17 +335,12 @@ static void __reset_intercept_indicators(struct kvm_vcpu *vcpu)
} }
} }
static void __set_cpuflag(struct kvm_vcpu *vcpu, u32 flag)
{
atomic_or(flag, &vcpu->arch.sie_block->cpuflags);
}
static void set_intercept_indicators_io(struct kvm_vcpu *vcpu) static void set_intercept_indicators_io(struct kvm_vcpu *vcpu)
{ {
if (!(pending_irqs(vcpu) & IRQ_PEND_IO_MASK)) if (!(pending_irqs(vcpu) & IRQ_PEND_IO_MASK))
return; return;
else if (psw_ioint_disabled(vcpu)) else if (psw_ioint_disabled(vcpu))
__set_cpuflag(vcpu, CPUSTAT_IO_INT); kvm_s390_set_cpuflags(vcpu, CPUSTAT_IO_INT);
else else
vcpu->arch.sie_block->lctl |= LCTL_CR6; vcpu->arch.sie_block->lctl |= LCTL_CR6;
} }
...@@ -321,7 +350,7 @@ static void set_intercept_indicators_ext(struct kvm_vcpu *vcpu) ...@@ -321,7 +350,7 @@ static void set_intercept_indicators_ext(struct kvm_vcpu *vcpu)
if (!(pending_irqs(vcpu) & IRQ_PEND_EXT_MASK)) if (!(pending_irqs(vcpu) & IRQ_PEND_EXT_MASK))
return; return;
if (psw_extint_disabled(vcpu)) if (psw_extint_disabled(vcpu))
__set_cpuflag(vcpu, CPUSTAT_EXT_INT); kvm_s390_set_cpuflags(vcpu, CPUSTAT_EXT_INT);
else else
vcpu->arch.sie_block->lctl |= LCTL_CR0; vcpu->arch.sie_block->lctl |= LCTL_CR0;
} }
...@@ -339,7 +368,7 @@ static void set_intercept_indicators_mchk(struct kvm_vcpu *vcpu) ...@@ -339,7 +368,7 @@ static void set_intercept_indicators_mchk(struct kvm_vcpu *vcpu)
static void set_intercept_indicators_stop(struct kvm_vcpu *vcpu) static void set_intercept_indicators_stop(struct kvm_vcpu *vcpu)
{ {
if (kvm_s390_is_stop_irq_pending(vcpu)) if (kvm_s390_is_stop_irq_pending(vcpu))
__set_cpuflag(vcpu, CPUSTAT_STOP_INT); kvm_s390_set_cpuflags(vcpu, CPUSTAT_STOP_INT);
} }
/* Set interception request for non-deliverable interrupts */ /* Set interception request for non-deliverable interrupts */
...@@ -896,18 +925,38 @@ static int __must_check __deliver_virtio(struct kvm_vcpu *vcpu) ...@@ -896,18 +925,38 @@ static int __must_check __deliver_virtio(struct kvm_vcpu *vcpu)
return rc ? -EFAULT : 0; return rc ? -EFAULT : 0;
} }
static int __do_deliver_io(struct kvm_vcpu *vcpu, struct kvm_s390_io_info *io)
{
int rc;
rc = put_guest_lc(vcpu, io->subchannel_id, (u16 *)__LC_SUBCHANNEL_ID);
rc |= put_guest_lc(vcpu, io->subchannel_nr, (u16 *)__LC_SUBCHANNEL_NR);
rc |= put_guest_lc(vcpu, io->io_int_parm, (u32 *)__LC_IO_INT_PARM);
rc |= put_guest_lc(vcpu, io->io_int_word, (u32 *)__LC_IO_INT_WORD);
rc |= write_guest_lc(vcpu, __LC_IO_OLD_PSW,
&vcpu->arch.sie_block->gpsw,
sizeof(psw_t));
rc |= read_guest_lc(vcpu, __LC_IO_NEW_PSW,
&vcpu->arch.sie_block->gpsw,
sizeof(psw_t));
return rc ? -EFAULT : 0;
}
static int __must_check __deliver_io(struct kvm_vcpu *vcpu, static int __must_check __deliver_io(struct kvm_vcpu *vcpu,
unsigned long irq_type) unsigned long irq_type)
{ {
struct list_head *isc_list; struct list_head *isc_list;
struct kvm_s390_float_interrupt *fi; struct kvm_s390_float_interrupt *fi;
struct kvm_s390_interrupt_info *inti = NULL; struct kvm_s390_interrupt_info *inti = NULL;
struct kvm_s390_io_info io;
u32 isc;
int rc = 0; int rc = 0;
fi = &vcpu->kvm->arch.float_int; fi = &vcpu->kvm->arch.float_int;
spin_lock(&fi->lock); spin_lock(&fi->lock);
isc_list = &fi->lists[irq_type_to_isc(irq_type)]; isc = irq_type_to_isc(irq_type);
isc_list = &fi->lists[isc];
inti = list_first_entry_or_null(isc_list, inti = list_first_entry_or_null(isc_list,
struct kvm_s390_interrupt_info, struct kvm_s390_interrupt_info,
list); list);
...@@ -935,24 +984,31 @@ static int __must_check __deliver_io(struct kvm_vcpu *vcpu, ...@@ -935,24 +984,31 @@ static int __must_check __deliver_io(struct kvm_vcpu *vcpu,
spin_unlock(&fi->lock); spin_unlock(&fi->lock);
if (inti) { if (inti) {
rc = put_guest_lc(vcpu, inti->io.subchannel_id, rc = __do_deliver_io(vcpu, &(inti->io));
(u16 *)__LC_SUBCHANNEL_ID);
rc |= put_guest_lc(vcpu, inti->io.subchannel_nr,
(u16 *)__LC_SUBCHANNEL_NR);
rc |= put_guest_lc(vcpu, inti->io.io_int_parm,
(u32 *)__LC_IO_INT_PARM);
rc |= put_guest_lc(vcpu, inti->io.io_int_word,
(u32 *)__LC_IO_INT_WORD);
rc |= write_guest_lc(vcpu, __LC_IO_OLD_PSW,
&vcpu->arch.sie_block->gpsw,
sizeof(psw_t));
rc |= read_guest_lc(vcpu, __LC_IO_NEW_PSW,
&vcpu->arch.sie_block->gpsw,
sizeof(psw_t));
kfree(inti); kfree(inti);
goto out;
} }
return rc ? -EFAULT : 0; if (vcpu->kvm->arch.gisa &&
kvm_s390_gisa_tac_ipm_gisc(vcpu->kvm->arch.gisa, isc)) {
/*
* in case an adapter interrupt was not delivered
* in SIE context KVM will handle the delivery
*/
VCPU_EVENT(vcpu, 4, "%s isc %u", "deliver: I/O (AI/gisa)", isc);
memset(&io, 0, sizeof(io));
io.io_int_word = isc_to_int_word(isc);
vcpu->stat.deliver_io_int++;
trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id,
KVM_S390_INT_IO(1, 0, 0, 0),
((__u32)io.subchannel_id << 16) |
io.subchannel_nr,
((__u64)io.io_int_parm << 32) |
io.io_int_word);
rc = __do_deliver_io(vcpu, &io);
}
out:
return rc;
} }
typedef int (*deliver_irq_t)(struct kvm_vcpu *vcpu); typedef int (*deliver_irq_t)(struct kvm_vcpu *vcpu);
...@@ -1154,8 +1210,8 @@ int __must_check kvm_s390_deliver_pending_interrupts(struct kvm_vcpu *vcpu) ...@@ -1154,8 +1210,8 @@ int __must_check kvm_s390_deliver_pending_interrupts(struct kvm_vcpu *vcpu)
set_bit(IRQ_PEND_EXT_CPU_TIMER, &li->pending_irqs); set_bit(IRQ_PEND_EXT_CPU_TIMER, &li->pending_irqs);
while ((irqs = deliverable_irqs(vcpu)) && !rc) { while ((irqs = deliverable_irqs(vcpu)) && !rc) {
/* bits are in the order of interrupt priority */ /* bits are in the reverse order of interrupt priority */
irq_type = find_first_bit(&irqs, IRQ_PEND_COUNT); irq_type = find_last_bit(&irqs, IRQ_PEND_COUNT);
if (is_ioirq(irq_type)) { if (is_ioirq(irq_type)) {
rc = __deliver_io(vcpu, irq_type); rc = __deliver_io(vcpu, irq_type);
} else { } else {
...@@ -1227,7 +1283,7 @@ static int __inject_pfault_init(struct kvm_vcpu *vcpu, struct kvm_s390_irq *irq) ...@@ -1227,7 +1283,7 @@ static int __inject_pfault_init(struct kvm_vcpu *vcpu, struct kvm_s390_irq *irq)
li->irq.ext = irq->u.ext; li->irq.ext = irq->u.ext;
set_bit(IRQ_PEND_PFAULT_INIT, &li->pending_irqs); set_bit(IRQ_PEND_PFAULT_INIT, &li->pending_irqs);
__set_cpuflag(vcpu, CPUSTAT_EXT_INT); kvm_s390_set_cpuflags(vcpu, CPUSTAT_EXT_INT);
return 0; return 0;
} }
...@@ -1252,7 +1308,7 @@ static int __inject_extcall(struct kvm_vcpu *vcpu, struct kvm_s390_irq *irq) ...@@ -1252,7 +1308,7 @@ static int __inject_extcall(struct kvm_vcpu *vcpu, struct kvm_s390_irq *irq)
if (test_and_set_bit(IRQ_PEND_EXT_EXTERNAL, &li->pending_irqs)) if (test_and_set_bit(IRQ_PEND_EXT_EXTERNAL, &li->pending_irqs))
return -EBUSY; return -EBUSY;
*extcall = irq->u.extcall; *extcall = irq->u.extcall;
__set_cpuflag(vcpu, CPUSTAT_EXT_INT); kvm_s390_set_cpuflags(vcpu, CPUSTAT_EXT_INT);
return 0; return 0;
} }
...@@ -1296,7 +1352,7 @@ static int __inject_sigp_stop(struct kvm_vcpu *vcpu, struct kvm_s390_irq *irq) ...@@ -1296,7 +1352,7 @@ static int __inject_sigp_stop(struct kvm_vcpu *vcpu, struct kvm_s390_irq *irq)
if (test_and_set_bit(IRQ_PEND_SIGP_STOP, &li->pending_irqs)) if (test_and_set_bit(IRQ_PEND_SIGP_STOP, &li->pending_irqs))
return -EBUSY; return -EBUSY;
stop->flags = irq->u.stop.flags; stop->flags = irq->u.stop.flags;
__set_cpuflag(vcpu, CPUSTAT_STOP_INT); kvm_s390_set_cpuflags(vcpu, CPUSTAT_STOP_INT);
return 0; return 0;
} }
...@@ -1328,7 +1384,7 @@ static int __inject_sigp_emergency(struct kvm_vcpu *vcpu, ...@@ -1328,7 +1384,7 @@ static int __inject_sigp_emergency(struct kvm_vcpu *vcpu,
set_bit(irq->u.emerg.code, li->sigp_emerg_pending); set_bit(irq->u.emerg.code, li->sigp_emerg_pending);
set_bit(IRQ_PEND_EXT_EMERGENCY, &li->pending_irqs); set_bit(IRQ_PEND_EXT_EMERGENCY, &li->pending_irqs);
__set_cpuflag(vcpu, CPUSTAT_EXT_INT); kvm_s390_set_cpuflags(vcpu, CPUSTAT_EXT_INT);
return 0; return 0;
} }
...@@ -1372,7 +1428,7 @@ static int __inject_ckc(struct kvm_vcpu *vcpu) ...@@ -1372,7 +1428,7 @@ static int __inject_ckc(struct kvm_vcpu *vcpu)
0, 0); 0, 0);
set_bit(IRQ_PEND_EXT_CLOCK_COMP, &li->pending_irqs); set_bit(IRQ_PEND_EXT_CLOCK_COMP, &li->pending_irqs);
__set_cpuflag(vcpu, CPUSTAT_EXT_INT); kvm_s390_set_cpuflags(vcpu, CPUSTAT_EXT_INT);
return 0; return 0;
} }
...@@ -1385,7 +1441,7 @@ static int __inject_cpu_timer(struct kvm_vcpu *vcpu) ...@@ -1385,7 +1441,7 @@ static int __inject_cpu_timer(struct kvm_vcpu *vcpu)
0, 0); 0, 0);
set_bit(IRQ_PEND_EXT_CPU_TIMER, &li->pending_irqs); set_bit(IRQ_PEND_EXT_CPU_TIMER, &li->pending_irqs);
__set_cpuflag(vcpu, CPUSTAT_EXT_INT); kvm_s390_set_cpuflags(vcpu, CPUSTAT_EXT_INT);
return 0; return 0;
} }
...@@ -1415,20 +1471,86 @@ static struct kvm_s390_interrupt_info *get_io_int(struct kvm *kvm, ...@@ -1415,20 +1471,86 @@ static struct kvm_s390_interrupt_info *get_io_int(struct kvm *kvm,
return NULL; return NULL;
} }
static struct kvm_s390_interrupt_info *get_top_io_int(struct kvm *kvm,
u64 isc_mask, u32 schid)
{
struct kvm_s390_interrupt_info *inti = NULL;
int isc;
for (isc = 0; isc <= MAX_ISC && !inti; isc++) {
if (isc_mask & isc_to_isc_bits(isc))
inti = get_io_int(kvm, isc, schid);
}
return inti;
}
static int get_top_gisa_isc(struct kvm *kvm, u64 isc_mask, u32 schid)
{
unsigned long active_mask;
int isc;
if (schid)
goto out;
if (!kvm->arch.gisa)
goto out;
active_mask = (isc_mask & kvm_s390_gisa_get_ipm(kvm->arch.gisa) << 24) << 32;
while (active_mask) {
isc = __fls(active_mask) ^ (BITS_PER_LONG - 1);
if (kvm_s390_gisa_tac_ipm_gisc(kvm->arch.gisa, isc))
return isc;
clear_bit_inv(isc, &active_mask);
}
out:
return -EINVAL;
}
/* /*
* Dequeue and return an I/O interrupt matching any of the interruption * Dequeue and return an I/O interrupt matching any of the interruption
* subclasses as designated by the isc mask in cr6 and the schid (if != 0). * subclasses as designated by the isc mask in cr6 and the schid (if != 0).
* Take into account the interrupts pending in the interrupt list and in GISA.
*
* Note that for a guest that does not enable I/O interrupts
* but relies on TPI, a flood of classic interrupts may starve
* out adapter interrupts on the same isc. Linux does not do
* that, and it is possible to work around the issue by configuring
* different iscs for classic and adapter interrupts in the guest,
* but we may want to revisit this in the future.
*/ */
struct kvm_s390_interrupt_info *kvm_s390_get_io_int(struct kvm *kvm, struct kvm_s390_interrupt_info *kvm_s390_get_io_int(struct kvm *kvm,
u64 isc_mask, u32 schid) u64 isc_mask, u32 schid)
{ {
struct kvm_s390_interrupt_info *inti = NULL; struct kvm_s390_interrupt_info *inti, *tmp_inti;
int isc; int isc;
for (isc = 0; isc <= MAX_ISC && !inti; isc++) { inti = get_top_io_int(kvm, isc_mask, schid);
if (isc_mask & isc_to_isc_bits(isc))
inti = get_io_int(kvm, isc, schid); isc = get_top_gisa_isc(kvm, isc_mask, schid);
if (isc < 0)
/* no AI in GISA */
goto out;
if (!inti)
/* AI in GISA but no classical IO int */
goto gisa_out;
/* both types of interrupts present */
if (int_word_to_isc(inti->io.io_int_word) <= isc) {
/* classical IO int with higher priority */
kvm_s390_gisa_set_ipm_gisc(kvm->arch.gisa, isc);
goto out;
} }
gisa_out:
tmp_inti = kzalloc(sizeof(*inti), GFP_KERNEL);
if (tmp_inti) {
tmp_inti->type = KVM_S390_INT_IO(1, 0, 0, 0);
tmp_inti->io.io_int_word = isc_to_int_word(isc);
if (inti)
kvm_s390_reinject_io_int(kvm, inti);
inti = tmp_inti;
} else
kvm_s390_gisa_set_ipm_gisc(kvm->arch.gisa, isc);
out:
return inti; return inti;
} }
...@@ -1516,6 +1638,15 @@ static int __inject_io(struct kvm *kvm, struct kvm_s390_interrupt_info *inti) ...@@ -1516,6 +1638,15 @@ static int __inject_io(struct kvm *kvm, struct kvm_s390_interrupt_info *inti)
struct list_head *list; struct list_head *list;
int isc; int isc;
isc = int_word_to_isc(inti->io.io_int_word);
if (kvm->arch.gisa && inti->type & KVM_S390_INT_IO_AI_MASK) {
VM_EVENT(kvm, 4, "%s isc %1u", "inject: I/O (AI/gisa)", isc);
kvm_s390_gisa_set_ipm_gisc(kvm->arch.gisa, isc);
kfree(inti);
return 0;
}
fi = &kvm->arch.float_int; fi = &kvm->arch.float_int;
spin_lock(&fi->lock); spin_lock(&fi->lock);
if (fi->counters[FIRQ_CNTR_IO] >= KVM_S390_MAX_FLOAT_IRQS) { if (fi->counters[FIRQ_CNTR_IO] >= KVM_S390_MAX_FLOAT_IRQS) {
...@@ -1531,7 +1662,6 @@ static int __inject_io(struct kvm *kvm, struct kvm_s390_interrupt_info *inti) ...@@ -1531,7 +1662,6 @@ static int __inject_io(struct kvm *kvm, struct kvm_s390_interrupt_info *inti)
inti->io.subchannel_id >> 8, inti->io.subchannel_id >> 8,
inti->io.subchannel_id >> 1 & 0x3, inti->io.subchannel_id >> 1 & 0x3,
inti->io.subchannel_nr); inti->io.subchannel_nr);
isc = int_word_to_isc(inti->io.io_int_word);
list = &fi->lists[FIRQ_LIST_IO_ISC_0 + isc]; list = &fi->lists[FIRQ_LIST_IO_ISC_0 + isc];
list_add_tail(&inti->list, list); list_add_tail(&inti->list, list);
set_bit(isc_to_irq_type(isc), &fi->pending_irqs); set_bit(isc_to_irq_type(isc), &fi->pending_irqs);
...@@ -1568,13 +1698,13 @@ static void __floating_irq_kick(struct kvm *kvm, u64 type) ...@@ -1568,13 +1698,13 @@ static void __floating_irq_kick(struct kvm *kvm, u64 type)
/* make the VCPU drop out of the SIE, or wake it up if sleeping */ /* make the VCPU drop out of the SIE, or wake it up if sleeping */
switch (type) { switch (type) {
case KVM_S390_MCHK: case KVM_S390_MCHK:
__set_cpuflag(dst_vcpu, CPUSTAT_STOP_INT); kvm_s390_set_cpuflags(dst_vcpu, CPUSTAT_STOP_INT);
break; break;
case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX: case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX:
__set_cpuflag(dst_vcpu, CPUSTAT_IO_INT); kvm_s390_set_cpuflags(dst_vcpu, CPUSTAT_IO_INT);
break; break;
default: default:
__set_cpuflag(dst_vcpu, CPUSTAT_EXT_INT); kvm_s390_set_cpuflags(dst_vcpu, CPUSTAT_EXT_INT);
break; break;
} }
kvm_s390_vcpu_wakeup(dst_vcpu); kvm_s390_vcpu_wakeup(dst_vcpu);
...@@ -1815,6 +1945,7 @@ void kvm_s390_clear_float_irqs(struct kvm *kvm) ...@@ -1815,6 +1945,7 @@ void kvm_s390_clear_float_irqs(struct kvm *kvm)
for (i = 0; i < FIRQ_MAX_COUNT; i++) for (i = 0; i < FIRQ_MAX_COUNT; i++)
fi->counters[i] = 0; fi->counters[i] = 0;
spin_unlock(&fi->lock); spin_unlock(&fi->lock);
kvm_s390_gisa_clear(kvm);
}; };
static int get_all_floating_irqs(struct kvm *kvm, u8 __user *usrbuf, u64 len) static int get_all_floating_irqs(struct kvm *kvm, u8 __user *usrbuf, u64 len)
...@@ -1842,6 +1973,22 @@ static int get_all_floating_irqs(struct kvm *kvm, u8 __user *usrbuf, u64 len) ...@@ -1842,6 +1973,22 @@ static int get_all_floating_irqs(struct kvm *kvm, u8 __user *usrbuf, u64 len)
max_irqs = len / sizeof(struct kvm_s390_irq); max_irqs = len / sizeof(struct kvm_s390_irq);
if (kvm->arch.gisa &&
kvm_s390_gisa_get_ipm(kvm->arch.gisa)) {
for (i = 0; i <= MAX_ISC; i++) {
if (n == max_irqs) {
/* signal userspace to try again */
ret = -ENOMEM;
goto out_nolock;
}
if (kvm_s390_gisa_tac_ipm_gisc(kvm->arch.gisa, i)) {
irq = (struct kvm_s390_irq *) &buf[n];
irq->type = KVM_S390_INT_IO(1, 0, 0, 0);
irq->u.io.io_int_word = isc_to_int_word(i);
n++;
}
}
}
fi = &kvm->arch.float_int; fi = &kvm->arch.float_int;
spin_lock(&fi->lock); spin_lock(&fi->lock);
for (i = 0; i < FIRQ_LIST_COUNT; i++) { for (i = 0; i < FIRQ_LIST_COUNT; i++) {
...@@ -1880,6 +2027,7 @@ static int get_all_floating_irqs(struct kvm *kvm, u8 __user *usrbuf, u64 len) ...@@ -1880,6 +2027,7 @@ static int get_all_floating_irqs(struct kvm *kvm, u8 __user *usrbuf, u64 len)
out: out:
spin_unlock(&fi->lock); spin_unlock(&fi->lock);
out_nolock:
if (!ret && n > 0) { if (!ret && n > 0) {
if (copy_to_user(usrbuf, buf, sizeof(struct kvm_s390_irq) * n)) if (copy_to_user(usrbuf, buf, sizeof(struct kvm_s390_irq) * n))
ret = -EFAULT; ret = -EFAULT;
...@@ -2240,7 +2388,7 @@ static int kvm_s390_inject_airq(struct kvm *kvm, ...@@ -2240,7 +2388,7 @@ static int kvm_s390_inject_airq(struct kvm *kvm,
struct kvm_s390_interrupt s390int = { struct kvm_s390_interrupt s390int = {
.type = KVM_S390_INT_IO(1, 0, 0, 0), .type = KVM_S390_INT_IO(1, 0, 0, 0),
.parm = 0, .parm = 0,
.parm64 = (adapter->isc << 27) | 0x80000000, .parm64 = isc_to_int_word(adapter->isc),
}; };
int ret = 0; int ret = 0;
...@@ -2682,3 +2830,28 @@ int kvm_s390_get_irq_state(struct kvm_vcpu *vcpu, __u8 __user *buf, int len) ...@@ -2682,3 +2830,28 @@ int kvm_s390_get_irq_state(struct kvm_vcpu *vcpu, __u8 __user *buf, int len)
return n; return n;
} }
void kvm_s390_gisa_clear(struct kvm *kvm)
{
if (kvm->arch.gisa) {
memset(kvm->arch.gisa, 0, sizeof(struct kvm_s390_gisa));
kvm->arch.gisa->next_alert = (u32)(u64)kvm->arch.gisa;
VM_EVENT(kvm, 3, "gisa 0x%pK cleared", kvm->arch.gisa);
}
}
void kvm_s390_gisa_init(struct kvm *kvm)
{
if (css_general_characteristics.aiv) {
kvm->arch.gisa = &kvm->arch.sie_page2->gisa;
VM_EVENT(kvm, 3, "gisa 0x%pK initialized", kvm->arch.gisa);
kvm_s390_gisa_clear(kvm);
}
}
void kvm_s390_gisa_destroy(struct kvm *kvm)
{
if (!kvm->arch.gisa)
return;
kvm->arch.gisa = NULL;
}
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
/* /*
* hosting IBM Z kernel virtual machines (s390x) * hosting IBM Z kernel virtual machines (s390x)
* *
* Copyright IBM Corp. 2008, 2017 * Copyright IBM Corp. 2008, 2018
* *
* Author(s): Carsten Otte <cotte@de.ibm.com> * Author(s): Carsten Otte <cotte@de.ibm.com>
* Christian Borntraeger <borntraeger@de.ibm.com> * Christian Borntraeger <borntraeger@de.ibm.com>
...@@ -87,19 +87,31 @@ struct kvm_stats_debugfs_item debugfs_entries[] = { ...@@ -87,19 +87,31 @@ struct kvm_stats_debugfs_item debugfs_entries[] = {
{ "deliver_restart_signal", VCPU_STAT(deliver_restart_signal) }, { "deliver_restart_signal", VCPU_STAT(deliver_restart_signal) },
{ "deliver_program_interruption", VCPU_STAT(deliver_program_int) }, { "deliver_program_interruption", VCPU_STAT(deliver_program_int) },
{ "exit_wait_state", VCPU_STAT(exit_wait_state) }, { "exit_wait_state", VCPU_STAT(exit_wait_state) },
{ "instruction_epsw", VCPU_STAT(instruction_epsw) },
{ "instruction_gs", VCPU_STAT(instruction_gs) },
{ "instruction_io_other", VCPU_STAT(instruction_io_other) },
{ "instruction_lpsw", VCPU_STAT(instruction_lpsw) },
{ "instruction_lpswe", VCPU_STAT(instruction_lpswe) },
{ "instruction_pfmf", VCPU_STAT(instruction_pfmf) }, { "instruction_pfmf", VCPU_STAT(instruction_pfmf) },
{ "instruction_ptff", VCPU_STAT(instruction_ptff) },
{ "instruction_stidp", VCPU_STAT(instruction_stidp) }, { "instruction_stidp", VCPU_STAT(instruction_stidp) },
{ "instruction_sck", VCPU_STAT(instruction_sck) },
{ "instruction_sckpf", VCPU_STAT(instruction_sckpf) },
{ "instruction_spx", VCPU_STAT(instruction_spx) }, { "instruction_spx", VCPU_STAT(instruction_spx) },
{ "instruction_stpx", VCPU_STAT(instruction_stpx) }, { "instruction_stpx", VCPU_STAT(instruction_stpx) },
{ "instruction_stap", VCPU_STAT(instruction_stap) }, { "instruction_stap", VCPU_STAT(instruction_stap) },
{ "instruction_storage_key", VCPU_STAT(instruction_storage_key) }, { "instruction_iske", VCPU_STAT(instruction_iske) },
{ "instruction_ri", VCPU_STAT(instruction_ri) },
{ "instruction_rrbe", VCPU_STAT(instruction_rrbe) },
{ "instruction_sske", VCPU_STAT(instruction_sske) },
{ "instruction_ipte_interlock", VCPU_STAT(instruction_ipte_interlock) }, { "instruction_ipte_interlock", VCPU_STAT(instruction_ipte_interlock) },
{ "instruction_stsch", VCPU_STAT(instruction_stsch) },
{ "instruction_chsc", VCPU_STAT(instruction_chsc) },
{ "instruction_essa", VCPU_STAT(instruction_essa) }, { "instruction_essa", VCPU_STAT(instruction_essa) },
{ "instruction_stsi", VCPU_STAT(instruction_stsi) }, { "instruction_stsi", VCPU_STAT(instruction_stsi) },
{ "instruction_stfl", VCPU_STAT(instruction_stfl) }, { "instruction_stfl", VCPU_STAT(instruction_stfl) },
{ "instruction_tb", VCPU_STAT(instruction_tb) },
{ "instruction_tpi", VCPU_STAT(instruction_tpi) },
{ "instruction_tprot", VCPU_STAT(instruction_tprot) }, { "instruction_tprot", VCPU_STAT(instruction_tprot) },
{ "instruction_tsch", VCPU_STAT(instruction_tsch) },
{ "instruction_sthyi", VCPU_STAT(instruction_sthyi) }, { "instruction_sthyi", VCPU_STAT(instruction_sthyi) },
{ "instruction_sie", VCPU_STAT(instruction_sie) }, { "instruction_sie", VCPU_STAT(instruction_sie) },
{ "instruction_sigp_sense", VCPU_STAT(instruction_sigp_sense) }, { "instruction_sigp_sense", VCPU_STAT(instruction_sigp_sense) },
...@@ -118,12 +130,13 @@ struct kvm_stats_debugfs_item debugfs_entries[] = { ...@@ -118,12 +130,13 @@ struct kvm_stats_debugfs_item debugfs_entries[] = {
{ "instruction_sigp_cpu_reset", VCPU_STAT(instruction_sigp_cpu_reset) }, { "instruction_sigp_cpu_reset", VCPU_STAT(instruction_sigp_cpu_reset) },
{ "instruction_sigp_init_cpu_reset", VCPU_STAT(instruction_sigp_init_cpu_reset) }, { "instruction_sigp_init_cpu_reset", VCPU_STAT(instruction_sigp_init_cpu_reset) },
{ "instruction_sigp_unknown", VCPU_STAT(instruction_sigp_unknown) }, { "instruction_sigp_unknown", VCPU_STAT(instruction_sigp_unknown) },
{ "diagnose_10", VCPU_STAT(diagnose_10) }, { "instruction_diag_10", VCPU_STAT(diagnose_10) },
{ "diagnose_44", VCPU_STAT(diagnose_44) }, { "instruction_diag_44", VCPU_STAT(diagnose_44) },
{ "diagnose_9c", VCPU_STAT(diagnose_9c) }, { "instruction_diag_9c", VCPU_STAT(diagnose_9c) },
{ "diagnose_258", VCPU_STAT(diagnose_258) }, { "instruction_diag_258", VCPU_STAT(diagnose_258) },
{ "diagnose_308", VCPU_STAT(diagnose_308) }, { "instruction_diag_308", VCPU_STAT(diagnose_308) },
{ "diagnose_500", VCPU_STAT(diagnose_500) }, { "instruction_diag_500", VCPU_STAT(diagnose_500) },
{ "instruction_diag_other", VCPU_STAT(diagnose_other) },
{ NULL } { NULL }
}; };
...@@ -1915,6 +1928,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) ...@@ -1915,6 +1928,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
if (!kvm->arch.dbf) if (!kvm->arch.dbf)
goto out_err; goto out_err;
BUILD_BUG_ON(sizeof(struct sie_page2) != 4096);
kvm->arch.sie_page2 = kvm->arch.sie_page2 =
(struct sie_page2 *) get_zeroed_page(GFP_KERNEL | GFP_DMA); (struct sie_page2 *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
if (!kvm->arch.sie_page2) if (!kvm->arch.sie_page2)
...@@ -1985,6 +1999,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) ...@@ -1985,6 +1999,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
spin_lock_init(&kvm->arch.start_stop_lock); spin_lock_init(&kvm->arch.start_stop_lock);
kvm_s390_vsie_init(kvm); kvm_s390_vsie_init(kvm);
kvm_s390_gisa_init(kvm);
KVM_EVENT(3, "vm 0x%pK created by pid %u", kvm, current->pid); KVM_EVENT(3, "vm 0x%pK created by pid %u", kvm, current->pid);
return 0; return 0;
...@@ -2047,6 +2062,7 @@ void kvm_arch_destroy_vm(struct kvm *kvm) ...@@ -2047,6 +2062,7 @@ void kvm_arch_destroy_vm(struct kvm *kvm)
kvm_free_vcpus(kvm); kvm_free_vcpus(kvm);
sca_dispose(kvm); sca_dispose(kvm);
debug_unregister(kvm->arch.dbf); debug_unregister(kvm->arch.dbf);
kvm_s390_gisa_destroy(kvm);
free_page((unsigned long)kvm->arch.sie_page2); free_page((unsigned long)kvm->arch.sie_page2);
if (!kvm_is_ucontrol(kvm)) if (!kvm_is_ucontrol(kvm))
gmap_remove(kvm->arch.gmap); gmap_remove(kvm->arch.gmap);
...@@ -2316,7 +2332,7 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu) ...@@ -2316,7 +2332,7 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
{ {
gmap_enable(vcpu->arch.enabled_gmap); gmap_enable(vcpu->arch.enabled_gmap);
atomic_or(CPUSTAT_RUNNING, &vcpu->arch.sie_block->cpuflags); kvm_s390_set_cpuflags(vcpu, CPUSTAT_RUNNING);
if (vcpu->arch.cputm_enabled && !is_vcpu_idle(vcpu)) if (vcpu->arch.cputm_enabled && !is_vcpu_idle(vcpu))
__start_cpu_timer_accounting(vcpu); __start_cpu_timer_accounting(vcpu);
vcpu->cpu = cpu; vcpu->cpu = cpu;
...@@ -2327,7 +2343,7 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) ...@@ -2327,7 +2343,7 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
vcpu->cpu = -1; vcpu->cpu = -1;
if (vcpu->arch.cputm_enabled && !is_vcpu_idle(vcpu)) if (vcpu->arch.cputm_enabled && !is_vcpu_idle(vcpu))
__stop_cpu_timer_accounting(vcpu); __stop_cpu_timer_accounting(vcpu);
atomic_andnot(CPUSTAT_RUNNING, &vcpu->arch.sie_block->cpuflags); kvm_s390_clear_cpuflags(vcpu, CPUSTAT_RUNNING);
vcpu->arch.enabled_gmap = gmap_get_enabled(); vcpu->arch.enabled_gmap = gmap_get_enabled();
gmap_disable(vcpu->arch.enabled_gmap); gmap_disable(vcpu->arch.enabled_gmap);
...@@ -2423,9 +2439,9 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu) ...@@ -2423,9 +2439,9 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
CPUSTAT_STOPPED); CPUSTAT_STOPPED);
if (test_kvm_facility(vcpu->kvm, 78)) if (test_kvm_facility(vcpu->kvm, 78))
atomic_or(CPUSTAT_GED2, &vcpu->arch.sie_block->cpuflags); kvm_s390_set_cpuflags(vcpu, CPUSTAT_GED2);
else if (test_kvm_facility(vcpu->kvm, 8)) else if (test_kvm_facility(vcpu->kvm, 8))
atomic_or(CPUSTAT_GED, &vcpu->arch.sie_block->cpuflags); kvm_s390_set_cpuflags(vcpu, CPUSTAT_GED);
kvm_s390_vcpu_setup_model(vcpu); kvm_s390_vcpu_setup_model(vcpu);
...@@ -2457,12 +2473,17 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu) ...@@ -2457,12 +2473,17 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
if (test_kvm_facility(vcpu->kvm, 139)) if (test_kvm_facility(vcpu->kvm, 139))
vcpu->arch.sie_block->ecd |= ECD_MEF; vcpu->arch.sie_block->ecd |= ECD_MEF;
if (vcpu->arch.sie_block->gd) {
vcpu->arch.sie_block->eca |= ECA_AIV;
VCPU_EVENT(vcpu, 3, "AIV gisa format-%u enabled for cpu %03u",
vcpu->arch.sie_block->gd & 0x3, vcpu->vcpu_id);
}
vcpu->arch.sie_block->sdnxo = ((unsigned long) &vcpu->run->s.regs.sdnx) vcpu->arch.sie_block->sdnxo = ((unsigned long) &vcpu->run->s.regs.sdnx)
| SDNXC; | SDNXC;
vcpu->arch.sie_block->riccbd = (unsigned long) &vcpu->run->s.regs.riccb; vcpu->arch.sie_block->riccbd = (unsigned long) &vcpu->run->s.regs.riccb;
if (sclp.has_kss) if (sclp.has_kss)
atomic_or(CPUSTAT_KSS, &vcpu->arch.sie_block->cpuflags); kvm_s390_set_cpuflags(vcpu, CPUSTAT_KSS);
else else
vcpu->arch.sie_block->ictl |= ICTL_ISKE | ICTL_SSKE | ICTL_RRBE; vcpu->arch.sie_block->ictl |= ICTL_ISKE | ICTL_SSKE | ICTL_RRBE;
...@@ -2509,6 +2530,9 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, ...@@ -2509,6 +2530,9 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm,
vcpu->arch.sie_block->icpua = id; vcpu->arch.sie_block->icpua = id;
spin_lock_init(&vcpu->arch.local_int.lock); spin_lock_init(&vcpu->arch.local_int.lock);
vcpu->arch.sie_block->gd = (u32)(u64)kvm->arch.gisa;
if (vcpu->arch.sie_block->gd && sclp.has_gisaf)
vcpu->arch.sie_block->gd |= GISA_FORMAT1;
seqcount_init(&vcpu->arch.cputm_seqcount); seqcount_init(&vcpu->arch.cputm_seqcount);
rc = kvm_vcpu_init(vcpu, kvm, id); rc = kvm_vcpu_init(vcpu, kvm, id);
...@@ -2565,7 +2589,7 @@ static void kvm_s390_vcpu_request_handled(struct kvm_vcpu *vcpu) ...@@ -2565,7 +2589,7 @@ static void kvm_s390_vcpu_request_handled(struct kvm_vcpu *vcpu)
* return immediately. */ * return immediately. */
void exit_sie(struct kvm_vcpu *vcpu) void exit_sie(struct kvm_vcpu *vcpu)
{ {
atomic_or(CPUSTAT_STOP_INT, &vcpu->arch.sie_block->cpuflags); kvm_s390_set_cpuflags(vcpu, CPUSTAT_STOP_INT);
while (vcpu->arch.sie_block->prog0c & PROG_IN_SIE) while (vcpu->arch.sie_block->prog0c & PROG_IN_SIE)
cpu_relax(); cpu_relax();
} }
...@@ -2840,19 +2864,19 @@ int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu, ...@@ -2840,19 +2864,19 @@ int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
if (dbg->control & KVM_GUESTDBG_ENABLE) { if (dbg->control & KVM_GUESTDBG_ENABLE) {
vcpu->guest_debug = dbg->control; vcpu->guest_debug = dbg->control;
/* enforce guest PER */ /* enforce guest PER */
atomic_or(CPUSTAT_P, &vcpu->arch.sie_block->cpuflags); kvm_s390_set_cpuflags(vcpu, CPUSTAT_P);
if (dbg->control & KVM_GUESTDBG_USE_HW_BP) if (dbg->control & KVM_GUESTDBG_USE_HW_BP)
rc = kvm_s390_import_bp_data(vcpu, dbg); rc = kvm_s390_import_bp_data(vcpu, dbg);
} else { } else {
atomic_andnot(CPUSTAT_P, &vcpu->arch.sie_block->cpuflags); kvm_s390_clear_cpuflags(vcpu, CPUSTAT_P);
vcpu->arch.guestdbg.last_bp = 0; vcpu->arch.guestdbg.last_bp = 0;
} }
if (rc) { if (rc) {
vcpu->guest_debug = 0; vcpu->guest_debug = 0;
kvm_s390_clear_bp_data(vcpu); kvm_s390_clear_bp_data(vcpu);
atomic_andnot(CPUSTAT_P, &vcpu->arch.sie_block->cpuflags); kvm_s390_clear_cpuflags(vcpu, CPUSTAT_P);
} }
out: out:
...@@ -2905,7 +2929,7 @@ int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu, ...@@ -2905,7 +2929,7 @@ int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu,
static bool ibs_enabled(struct kvm_vcpu *vcpu) static bool ibs_enabled(struct kvm_vcpu *vcpu)
{ {
return atomic_read(&vcpu->arch.sie_block->cpuflags) & CPUSTAT_IBS; return kvm_s390_test_cpuflags(vcpu, CPUSTAT_IBS);
} }
static int kvm_s390_handle_requests(struct kvm_vcpu *vcpu) static int kvm_s390_handle_requests(struct kvm_vcpu *vcpu)
...@@ -2941,8 +2965,7 @@ static int kvm_s390_handle_requests(struct kvm_vcpu *vcpu) ...@@ -2941,8 +2965,7 @@ static int kvm_s390_handle_requests(struct kvm_vcpu *vcpu)
if (kvm_check_request(KVM_REQ_ENABLE_IBS, vcpu)) { if (kvm_check_request(KVM_REQ_ENABLE_IBS, vcpu)) {
if (!ibs_enabled(vcpu)) { if (!ibs_enabled(vcpu)) {
trace_kvm_s390_enable_disable_ibs(vcpu->vcpu_id, 1); trace_kvm_s390_enable_disable_ibs(vcpu->vcpu_id, 1);
atomic_or(CPUSTAT_IBS, kvm_s390_set_cpuflags(vcpu, CPUSTAT_IBS);
&vcpu->arch.sie_block->cpuflags);
} }
goto retry; goto retry;
} }
...@@ -2950,8 +2973,7 @@ static int kvm_s390_handle_requests(struct kvm_vcpu *vcpu) ...@@ -2950,8 +2973,7 @@ static int kvm_s390_handle_requests(struct kvm_vcpu *vcpu)
if (kvm_check_request(KVM_REQ_DISABLE_IBS, vcpu)) { if (kvm_check_request(KVM_REQ_DISABLE_IBS, vcpu)) {
if (ibs_enabled(vcpu)) { if (ibs_enabled(vcpu)) {
trace_kvm_s390_enable_disable_ibs(vcpu->vcpu_id, 0); trace_kvm_s390_enable_disable_ibs(vcpu->vcpu_id, 0);
atomic_andnot(CPUSTAT_IBS, kvm_s390_clear_cpuflags(vcpu, CPUSTAT_IBS);
&vcpu->arch.sie_block->cpuflags);
} }
goto retry; goto retry;
} }
...@@ -3601,7 +3623,7 @@ void kvm_s390_vcpu_start(struct kvm_vcpu *vcpu) ...@@ -3601,7 +3623,7 @@ void kvm_s390_vcpu_start(struct kvm_vcpu *vcpu)
__disable_ibs_on_all_vcpus(vcpu->kvm); __disable_ibs_on_all_vcpus(vcpu->kvm);
} }
atomic_andnot(CPUSTAT_STOPPED, &vcpu->arch.sie_block->cpuflags); kvm_s390_clear_cpuflags(vcpu, CPUSTAT_STOPPED);
/* /*
* Another VCPU might have used IBS while we were offline. * Another VCPU might have used IBS while we were offline.
* Let's play safe and flush the VCPU at startup. * Let's play safe and flush the VCPU at startup.
...@@ -3627,7 +3649,7 @@ void kvm_s390_vcpu_stop(struct kvm_vcpu *vcpu) ...@@ -3627,7 +3649,7 @@ void kvm_s390_vcpu_stop(struct kvm_vcpu *vcpu)
/* SIGP STOP and SIGP STOP AND STORE STATUS has been fully processed */ /* SIGP STOP and SIGP STOP AND STORE STATUS has been fully processed */
kvm_s390_clear_stop_irq(vcpu); kvm_s390_clear_stop_irq(vcpu);
atomic_or(CPUSTAT_STOPPED, &vcpu->arch.sie_block->cpuflags); kvm_s390_set_cpuflags(vcpu, CPUSTAT_STOPPED);
__disable_ibs_on_vcpu(vcpu); __disable_ibs_on_vcpu(vcpu);
for (i = 0; i < online_vcpus; i++) { for (i = 0; i < online_vcpus; i++) {
......
...@@ -47,9 +47,24 @@ do { \ ...@@ -47,9 +47,24 @@ do { \
d_args); \ d_args); \
} while (0) } while (0)
static inline void kvm_s390_set_cpuflags(struct kvm_vcpu *vcpu, u32 flags)
{
atomic_or(flags, &vcpu->arch.sie_block->cpuflags);
}
static inline void kvm_s390_clear_cpuflags(struct kvm_vcpu *vcpu, u32 flags)
{
atomic_andnot(flags, &vcpu->arch.sie_block->cpuflags);
}
static inline bool kvm_s390_test_cpuflags(struct kvm_vcpu *vcpu, u32 flags)
{
return (atomic_read(&vcpu->arch.sie_block->cpuflags) & flags) == flags;
}
static inline int is_vcpu_stopped(struct kvm_vcpu *vcpu) static inline int is_vcpu_stopped(struct kvm_vcpu *vcpu)
{ {
return atomic_read(&vcpu->arch.sie_block->cpuflags) & CPUSTAT_STOPPED; return kvm_s390_test_cpuflags(vcpu, CPUSTAT_STOPPED);
} }
static inline int is_vcpu_idle(struct kvm_vcpu *vcpu) static inline int is_vcpu_idle(struct kvm_vcpu *vcpu)
...@@ -367,6 +382,9 @@ int kvm_s390_set_irq_state(struct kvm_vcpu *vcpu, ...@@ -367,6 +382,9 @@ int kvm_s390_set_irq_state(struct kvm_vcpu *vcpu,
void __user *buf, int len); void __user *buf, int len);
int kvm_s390_get_irq_state(struct kvm_vcpu *vcpu, int kvm_s390_get_irq_state(struct kvm_vcpu *vcpu,
__u8 __user *buf, int len); __u8 __user *buf, int len);
void kvm_s390_gisa_init(struct kvm *kvm);
void kvm_s390_gisa_clear(struct kvm *kvm);
void kvm_s390_gisa_destroy(struct kvm *kvm);
/* implemented in guestdbg.c */ /* implemented in guestdbg.c */
void kvm_s390_backup_guest_per_regs(struct kvm_vcpu *vcpu); void kvm_s390_backup_guest_per_regs(struct kvm_vcpu *vcpu);
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
/* /*
* handling privileged instructions * handling privileged instructions
* *
* Copyright IBM Corp. 2008, 2013 * Copyright IBM Corp. 2008, 2018
* *
* Author(s): Carsten Otte <cotte@de.ibm.com> * Author(s): Carsten Otte <cotte@de.ibm.com>
* Christian Borntraeger <borntraeger@de.ibm.com> * Christian Borntraeger <borntraeger@de.ibm.com>
...@@ -34,6 +34,8 @@ ...@@ -34,6 +34,8 @@
static int handle_ri(struct kvm_vcpu *vcpu) static int handle_ri(struct kvm_vcpu *vcpu)
{ {
vcpu->stat.instruction_ri++;
if (test_kvm_facility(vcpu->kvm, 64)) { if (test_kvm_facility(vcpu->kvm, 64)) {
VCPU_EVENT(vcpu, 3, "%s", "ENABLE: RI (lazy)"); VCPU_EVENT(vcpu, 3, "%s", "ENABLE: RI (lazy)");
vcpu->arch.sie_block->ecb3 |= ECB3_RI; vcpu->arch.sie_block->ecb3 |= ECB3_RI;
...@@ -53,6 +55,8 @@ int kvm_s390_handle_aa(struct kvm_vcpu *vcpu) ...@@ -53,6 +55,8 @@ int kvm_s390_handle_aa(struct kvm_vcpu *vcpu)
static int handle_gs(struct kvm_vcpu *vcpu) static int handle_gs(struct kvm_vcpu *vcpu)
{ {
vcpu->stat.instruction_gs++;
if (test_kvm_facility(vcpu->kvm, 133)) { if (test_kvm_facility(vcpu->kvm, 133)) {
VCPU_EVENT(vcpu, 3, "%s", "ENABLE: GS (lazy)"); VCPU_EVENT(vcpu, 3, "%s", "ENABLE: GS (lazy)");
preempt_disable(); preempt_disable();
...@@ -85,6 +89,8 @@ static int handle_set_clock(struct kvm_vcpu *vcpu) ...@@ -85,6 +89,8 @@ static int handle_set_clock(struct kvm_vcpu *vcpu)
u8 ar; u8 ar;
u64 op2, val; u64 op2, val;
vcpu->stat.instruction_sck++;
if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP); return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
...@@ -203,14 +209,14 @@ int kvm_s390_skey_check_enable(struct kvm_vcpu *vcpu) ...@@ -203,14 +209,14 @@ int kvm_s390_skey_check_enable(struct kvm_vcpu *vcpu)
trace_kvm_s390_skey_related_inst(vcpu); trace_kvm_s390_skey_related_inst(vcpu);
if (!(sie_block->ictl & (ICTL_ISKE | ICTL_SSKE | ICTL_RRBE)) && if (!(sie_block->ictl & (ICTL_ISKE | ICTL_SSKE | ICTL_RRBE)) &&
!(atomic_read(&sie_block->cpuflags) & CPUSTAT_KSS)) !kvm_s390_test_cpuflags(vcpu, CPUSTAT_KSS))
return rc; return rc;
rc = s390_enable_skey(); rc = s390_enable_skey();
VCPU_EVENT(vcpu, 3, "enabling storage keys for guest: %d", rc); VCPU_EVENT(vcpu, 3, "enabling storage keys for guest: %d", rc);
if (!rc) { if (!rc) {
if (atomic_read(&sie_block->cpuflags) & CPUSTAT_KSS) if (kvm_s390_test_cpuflags(vcpu, CPUSTAT_KSS))
atomic_andnot(CPUSTAT_KSS, &sie_block->cpuflags); kvm_s390_clear_cpuflags(vcpu, CPUSTAT_KSS);
else else
sie_block->ictl &= ~(ICTL_ISKE | ICTL_SSKE | sie_block->ictl &= ~(ICTL_ISKE | ICTL_SSKE |
ICTL_RRBE); ICTL_RRBE);
...@@ -222,7 +228,6 @@ static int try_handle_skey(struct kvm_vcpu *vcpu) ...@@ -222,7 +228,6 @@ static int try_handle_skey(struct kvm_vcpu *vcpu)
{ {
int rc; int rc;
vcpu->stat.instruction_storage_key++;
rc = kvm_s390_skey_check_enable(vcpu); rc = kvm_s390_skey_check_enable(vcpu);
if (rc) if (rc)
return rc; return rc;
...@@ -242,6 +247,8 @@ static int handle_iske(struct kvm_vcpu *vcpu) ...@@ -242,6 +247,8 @@ static int handle_iske(struct kvm_vcpu *vcpu)
int reg1, reg2; int reg1, reg2;
int rc; int rc;
vcpu->stat.instruction_iske++;
if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP); return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
...@@ -274,6 +281,8 @@ static int handle_rrbe(struct kvm_vcpu *vcpu) ...@@ -274,6 +281,8 @@ static int handle_rrbe(struct kvm_vcpu *vcpu)
int reg1, reg2; int reg1, reg2;
int rc; int rc;
vcpu->stat.instruction_rrbe++;
if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP); return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
...@@ -312,6 +321,8 @@ static int handle_sske(struct kvm_vcpu *vcpu) ...@@ -312,6 +321,8 @@ static int handle_sske(struct kvm_vcpu *vcpu)
int reg1, reg2; int reg1, reg2;
int rc; int rc;
vcpu->stat.instruction_sske++;
if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP); return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
...@@ -392,6 +403,8 @@ static int handle_test_block(struct kvm_vcpu *vcpu) ...@@ -392,6 +403,8 @@ static int handle_test_block(struct kvm_vcpu *vcpu)
gpa_t addr; gpa_t addr;
int reg2; int reg2;
vcpu->stat.instruction_tb++;
if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP); return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
...@@ -424,6 +437,8 @@ static int handle_tpi(struct kvm_vcpu *vcpu) ...@@ -424,6 +437,8 @@ static int handle_tpi(struct kvm_vcpu *vcpu)
u64 addr; u64 addr;
u8 ar; u8 ar;
vcpu->stat.instruction_tpi++;
addr = kvm_s390_get_base_disp_s(vcpu, &ar); addr = kvm_s390_get_base_disp_s(vcpu, &ar);
if (addr & 3) if (addr & 3)
return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
...@@ -484,6 +499,8 @@ static int handle_tsch(struct kvm_vcpu *vcpu) ...@@ -484,6 +499,8 @@ static int handle_tsch(struct kvm_vcpu *vcpu)
struct kvm_s390_interrupt_info *inti = NULL; struct kvm_s390_interrupt_info *inti = NULL;
const u64 isc_mask = 0xffUL << 24; /* all iscs set */ const u64 isc_mask = 0xffUL << 24; /* all iscs set */
vcpu->stat.instruction_tsch++;
/* a valid schid has at least one bit set */ /* a valid schid has at least one bit set */
if (vcpu->run->s.regs.gprs[1]) if (vcpu->run->s.regs.gprs[1])
inti = kvm_s390_get_io_int(vcpu->kvm, isc_mask, inti = kvm_s390_get_io_int(vcpu->kvm, isc_mask,
...@@ -527,6 +544,7 @@ static int handle_io_inst(struct kvm_vcpu *vcpu) ...@@ -527,6 +544,7 @@ static int handle_io_inst(struct kvm_vcpu *vcpu)
if (vcpu->arch.sie_block->ipa == 0xb235) if (vcpu->arch.sie_block->ipa == 0xb235)
return handle_tsch(vcpu); return handle_tsch(vcpu);
/* Handle in userspace. */ /* Handle in userspace. */
vcpu->stat.instruction_io_other++;
return -EOPNOTSUPP; return -EOPNOTSUPP;
} else { } else {
/* /*
...@@ -592,6 +610,8 @@ int kvm_s390_handle_lpsw(struct kvm_vcpu *vcpu) ...@@ -592,6 +610,8 @@ int kvm_s390_handle_lpsw(struct kvm_vcpu *vcpu)
int rc; int rc;
u8 ar; u8 ar;
vcpu->stat.instruction_lpsw++;
if (gpsw->mask & PSW_MASK_PSTATE) if (gpsw->mask & PSW_MASK_PSTATE)
return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP); return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
...@@ -619,6 +639,8 @@ static int handle_lpswe(struct kvm_vcpu *vcpu) ...@@ -619,6 +639,8 @@ static int handle_lpswe(struct kvm_vcpu *vcpu)
int rc; int rc;
u8 ar; u8 ar;
vcpu->stat.instruction_lpswe++;
if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP); return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
...@@ -828,6 +850,8 @@ static int handle_epsw(struct kvm_vcpu *vcpu) ...@@ -828,6 +850,8 @@ static int handle_epsw(struct kvm_vcpu *vcpu)
{ {
int reg1, reg2; int reg1, reg2;
vcpu->stat.instruction_epsw++;
kvm_s390_get_regs_rre(vcpu, &reg1, &reg2); kvm_s390_get_regs_rre(vcpu, &reg1, &reg2);
/* This basically extracts the mask half of the psw. */ /* This basically extracts the mask half of the psw. */
...@@ -1332,6 +1356,8 @@ static int handle_sckpf(struct kvm_vcpu *vcpu) ...@@ -1332,6 +1356,8 @@ static int handle_sckpf(struct kvm_vcpu *vcpu)
{ {
u32 value; u32 value;
vcpu->stat.instruction_sckpf++;
if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP); return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
...@@ -1347,6 +1373,8 @@ static int handle_sckpf(struct kvm_vcpu *vcpu) ...@@ -1347,6 +1373,8 @@ static int handle_sckpf(struct kvm_vcpu *vcpu)
static int handle_ptff(struct kvm_vcpu *vcpu) static int handle_ptff(struct kvm_vcpu *vcpu)
{ {
vcpu->stat.instruction_ptff++;
/* we don't emulate any control instructions yet */ /* we don't emulate any control instructions yet */
kvm_s390_set_psw_cc(vcpu, 3); kvm_s390_set_psw_cc(vcpu, 3);
return 0; return 0;
......
...@@ -20,19 +20,18 @@ ...@@ -20,19 +20,18 @@
static int __sigp_sense(struct kvm_vcpu *vcpu, struct kvm_vcpu *dst_vcpu, static int __sigp_sense(struct kvm_vcpu *vcpu, struct kvm_vcpu *dst_vcpu,
u64 *reg) u64 *reg)
{ {
int cpuflags; const bool stopped = kvm_s390_test_cpuflags(dst_vcpu, CPUSTAT_STOPPED);
int rc; int rc;
int ext_call_pending; int ext_call_pending;
cpuflags = atomic_read(&dst_vcpu->arch.sie_block->cpuflags);
ext_call_pending = kvm_s390_ext_call_pending(dst_vcpu); ext_call_pending = kvm_s390_ext_call_pending(dst_vcpu);
if (!(cpuflags & CPUSTAT_STOPPED) && !ext_call_pending) if (!stopped && !ext_call_pending)
rc = SIGP_CC_ORDER_CODE_ACCEPTED; rc = SIGP_CC_ORDER_CODE_ACCEPTED;
else { else {
*reg &= 0xffffffff00000000UL; *reg &= 0xffffffff00000000UL;
if (ext_call_pending) if (ext_call_pending)
*reg |= SIGP_STATUS_EXT_CALL_PENDING; *reg |= SIGP_STATUS_EXT_CALL_PENDING;
if (cpuflags & CPUSTAT_STOPPED) if (stopped)
*reg |= SIGP_STATUS_STOPPED; *reg |= SIGP_STATUS_STOPPED;
rc = SIGP_CC_STATUS_STORED; rc = SIGP_CC_STATUS_STORED;
} }
...@@ -205,11 +204,9 @@ static int __sigp_store_status_at_addr(struct kvm_vcpu *vcpu, ...@@ -205,11 +204,9 @@ static int __sigp_store_status_at_addr(struct kvm_vcpu *vcpu,
struct kvm_vcpu *dst_vcpu, struct kvm_vcpu *dst_vcpu,
u32 addr, u64 *reg) u32 addr, u64 *reg)
{ {
int flags;
int rc; int rc;
flags = atomic_read(&dst_vcpu->arch.sie_block->cpuflags); if (!kvm_s390_test_cpuflags(dst_vcpu, CPUSTAT_STOPPED)) {
if (!(flags & CPUSTAT_STOPPED)) {
*reg &= 0xffffffff00000000UL; *reg &= 0xffffffff00000000UL;
*reg |= SIGP_STATUS_INCORRECT_STATE; *reg |= SIGP_STATUS_INCORRECT_STATE;
return SIGP_CC_STATUS_STORED; return SIGP_CC_STATUS_STORED;
...@@ -236,8 +233,7 @@ static int __sigp_sense_running(struct kvm_vcpu *vcpu, ...@@ -236,8 +233,7 @@ static int __sigp_sense_running(struct kvm_vcpu *vcpu,
return SIGP_CC_STATUS_STORED; return SIGP_CC_STATUS_STORED;
} }
if (atomic_read(&dst_vcpu->arch.sie_block->cpuflags) & if (kvm_s390_test_cpuflags(dst_vcpu, CPUSTAT_RUNNING)) {
CPUSTAT_RUNNING) {
/* running */ /* running */
rc = SIGP_CC_ORDER_CODE_ACCEPTED; rc = SIGP_CC_ORDER_CODE_ACCEPTED;
} else { } else {
......
...@@ -28,13 +28,23 @@ struct vsie_page { ...@@ -28,13 +28,23 @@ struct vsie_page {
* the same offset as that in struct sie_page! * the same offset as that in struct sie_page!
*/ */
struct mcck_volatile_info mcck_info; /* 0x0200 */ struct mcck_volatile_info mcck_info; /* 0x0200 */
/* the pinned originial scb */ /*
* The pinned original scb. Be aware that other VCPUs can modify
* it while we read from it. Values that are used for conditions or
* are reused conditionally, should be accessed via READ_ONCE.
*/
struct kvm_s390_sie_block *scb_o; /* 0x0218 */ struct kvm_s390_sie_block *scb_o; /* 0x0218 */
/* the shadow gmap in use by the vsie_page */ /* the shadow gmap in use by the vsie_page */
struct gmap *gmap; /* 0x0220 */ struct gmap *gmap; /* 0x0220 */
/* address of the last reported fault to guest2 */ /* address of the last reported fault to guest2 */
unsigned long fault_addr; /* 0x0228 */ unsigned long fault_addr; /* 0x0228 */
__u8 reserved[0x0700 - 0x0230]; /* 0x0230 */ /* calculated guest addresses of satellite control blocks */
gpa_t sca_gpa; /* 0x0230 */
gpa_t itdba_gpa; /* 0x0238 */
gpa_t gvrd_gpa; /* 0x0240 */
gpa_t riccbd_gpa; /* 0x0248 */
gpa_t sdnx_gpa; /* 0x0250 */
__u8 reserved[0x0700 - 0x0258]; /* 0x0258 */
struct kvm_s390_crypto_cb crycb; /* 0x0700 */ struct kvm_s390_crypto_cb crycb; /* 0x0700 */
__u8 fac[S390_ARCH_FAC_LIST_SIZE_BYTE]; /* 0x0800 */ __u8 fac[S390_ARCH_FAC_LIST_SIZE_BYTE]; /* 0x0800 */
}; };
...@@ -140,12 +150,13 @@ static int shadow_crycb(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) ...@@ -140,12 +150,13 @@ 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_s = &vsie_page->scb_s;
struct kvm_s390_sie_block *scb_o = vsie_page->scb_o; struct kvm_s390_sie_block *scb_o = vsie_page->scb_o;
u32 crycb_addr = scb_o->crycbd & 0x7ffffff8U; const uint32_t crycbd_o = READ_ONCE(scb_o->crycbd);
const u32 crycb_addr = crycbd_o & 0x7ffffff8U;
unsigned long *b1, *b2; unsigned long *b1, *b2;
u8 ecb3_flags; u8 ecb3_flags;
scb_s->crycbd = 0; scb_s->crycbd = 0;
if (!(scb_o->crycbd & vcpu->arch.sie_block->crycbd & CRYCB_FORMAT1)) if (!(crycbd_o & vcpu->arch.sie_block->crycbd & CRYCB_FORMAT1))
return 0; return 0;
/* format-1 is supported with message-security-assist extension 3 */ /* format-1 is supported with message-security-assist extension 3 */
if (!test_kvm_facility(vcpu->kvm, 76)) if (!test_kvm_facility(vcpu->kvm, 76))
...@@ -183,12 +194,15 @@ static void prepare_ibc(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) ...@@ -183,12 +194,15 @@ 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_s = &vsie_page->scb_s;
struct kvm_s390_sie_block *scb_o = vsie_page->scb_o; struct kvm_s390_sie_block *scb_o = vsie_page->scb_o;
/* READ_ONCE does not work on bitfields - use a temporary variable */
const uint32_t __new_ibc = scb_o->ibc;
const uint32_t new_ibc = READ_ONCE(__new_ibc) & 0x0fffU;
__u64 min_ibc = (sclp.ibc >> 16) & 0x0fffU; __u64 min_ibc = (sclp.ibc >> 16) & 0x0fffU;
scb_s->ibc = 0; scb_s->ibc = 0;
/* ibc installed in g2 and requested for g3 */ /* ibc installed in g2 and requested for g3 */
if (vcpu->kvm->arch.model.ibc && (scb_o->ibc & 0x0fffU)) { if (vcpu->kvm->arch.model.ibc && new_ibc) {
scb_s->ibc = scb_o->ibc & 0x0fffU; scb_s->ibc = new_ibc;
/* takte care of the minimum ibc level of the machine */ /* takte care of the minimum ibc level of the machine */
if (scb_s->ibc < min_ibc) if (scb_s->ibc < min_ibc)
scb_s->ibc = min_ibc; scb_s->ibc = min_ibc;
...@@ -253,6 +267,10 @@ static int shadow_scb(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) ...@@ -253,6 +267,10 @@ 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_o = vsie_page->scb_o;
struct kvm_s390_sie_block *scb_s = &vsie_page->scb_s; struct kvm_s390_sie_block *scb_s = &vsie_page->scb_s;
/* READ_ONCE does not work on bitfields - use a temporary variable */
const uint32_t __new_prefix = scb_o->prefix;
const uint32_t new_prefix = READ_ONCE(__new_prefix);
const bool wants_tx = READ_ONCE(scb_o->ecb) & ECB_TE;
bool had_tx = scb_s->ecb & ECB_TE; bool had_tx = scb_s->ecb & ECB_TE;
unsigned long new_mso = 0; unsigned long new_mso = 0;
int rc; int rc;
...@@ -299,14 +317,14 @@ static int shadow_scb(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) ...@@ -299,14 +317,14 @@ static int shadow_scb(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
scb_s->icpua = scb_o->icpua; scb_s->icpua = scb_o->icpua;
if (!(atomic_read(&scb_s->cpuflags) & CPUSTAT_SM)) if (!(atomic_read(&scb_s->cpuflags) & CPUSTAT_SM))
new_mso = scb_o->mso & 0xfffffffffff00000UL; new_mso = READ_ONCE(scb_o->mso) & 0xfffffffffff00000UL;
/* if the hva of the prefix changes, we have to remap the prefix */ /* 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) if (scb_s->mso != new_mso || scb_s->prefix != new_prefix)
prefix_unmapped(vsie_page); prefix_unmapped(vsie_page);
/* SIE will do mso/msl validity and exception checks for us */ /* SIE will do mso/msl validity and exception checks for us */
scb_s->msl = scb_o->msl & 0xfffffffffff00000UL; scb_s->msl = scb_o->msl & 0xfffffffffff00000UL;
scb_s->mso = new_mso; scb_s->mso = new_mso;
scb_s->prefix = scb_o->prefix; scb_s->prefix = new_prefix;
/* We have to definetly flush the tlb if this scb never ran */ /* We have to definetly flush the tlb if this scb never ran */
if (scb_s->ihcpu != 0xffffU) if (scb_s->ihcpu != 0xffffU)
...@@ -318,11 +336,11 @@ static int shadow_scb(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) ...@@ -318,11 +336,11 @@ static int shadow_scb(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
if (test_kvm_cpu_feat(vcpu->kvm, KVM_S390_VM_CPU_FEAT_ESOP)) if (test_kvm_cpu_feat(vcpu->kvm, KVM_S390_VM_CPU_FEAT_ESOP))
scb_s->ecb |= scb_o->ecb & ECB_HOSTPROTINT; scb_s->ecb |= scb_o->ecb & ECB_HOSTPROTINT;
/* transactional execution */ /* transactional execution */
if (test_kvm_facility(vcpu->kvm, 73)) { if (test_kvm_facility(vcpu->kvm, 73) && wants_tx) {
/* remap the prefix is tx is toggled on */ /* remap the prefix is tx is toggled on */
if ((scb_o->ecb & ECB_TE) && !had_tx) if (!had_tx)
prefix_unmapped(vsie_page); prefix_unmapped(vsie_page);
scb_s->ecb |= scb_o->ecb & ECB_TE; scb_s->ecb |= ECB_TE;
} }
/* SIMD */ /* SIMD */
if (test_kvm_facility(vcpu->kvm, 129)) { if (test_kvm_facility(vcpu->kvm, 129)) {
...@@ -463,46 +481,42 @@ static void unpin_guest_page(struct kvm *kvm, gpa_t gpa, hpa_t hpa) ...@@ -463,46 +481,42 @@ static void unpin_guest_page(struct kvm *kvm, gpa_t gpa, hpa_t hpa)
/* unpin all blocks previously pinned by pin_blocks(), marking them dirty */ /* unpin all blocks previously pinned by pin_blocks(), marking them dirty */
static void unpin_blocks(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) 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; struct kvm_s390_sie_block *scb_s = &vsie_page->scb_s;
hpa_t hpa; hpa_t hpa;
gpa_t gpa;
hpa = (u64) scb_s->scaoh << 32 | scb_s->scaol; hpa = (u64) scb_s->scaoh << 32 | scb_s->scaol;
if (hpa) { if (hpa) {
gpa = scb_o->scaol & ~0xfUL; unpin_guest_page(vcpu->kvm, vsie_page->sca_gpa, hpa);
if (test_kvm_cpu_feat(vcpu->kvm, KVM_S390_VM_CPU_FEAT_64BSCAO)) vsie_page->sca_gpa = 0;
gpa |= (u64) scb_o->scaoh << 32;
unpin_guest_page(vcpu->kvm, gpa, hpa);
scb_s->scaol = 0; scb_s->scaol = 0;
scb_s->scaoh = 0; scb_s->scaoh = 0;
} }
hpa = scb_s->itdba; hpa = scb_s->itdba;
if (hpa) { if (hpa) {
gpa = scb_o->itdba & ~0xffUL; unpin_guest_page(vcpu->kvm, vsie_page->itdba_gpa, hpa);
unpin_guest_page(vcpu->kvm, gpa, hpa); vsie_page->itdba_gpa = 0;
scb_s->itdba = 0; scb_s->itdba = 0;
} }
hpa = scb_s->gvrd; hpa = scb_s->gvrd;
if (hpa) { if (hpa) {
gpa = scb_o->gvrd & ~0x1ffUL; unpin_guest_page(vcpu->kvm, vsie_page->gvrd_gpa, hpa);
unpin_guest_page(vcpu->kvm, gpa, hpa); vsie_page->gvrd_gpa = 0;
scb_s->gvrd = 0; scb_s->gvrd = 0;
} }
hpa = scb_s->riccbd; hpa = scb_s->riccbd;
if (hpa) { if (hpa) {
gpa = scb_o->riccbd & ~0x3fUL; unpin_guest_page(vcpu->kvm, vsie_page->riccbd_gpa, hpa);
unpin_guest_page(vcpu->kvm, gpa, hpa); vsie_page->riccbd_gpa = 0;
scb_s->riccbd = 0; scb_s->riccbd = 0;
} }
hpa = scb_s->sdnxo; hpa = scb_s->sdnxo;
if (hpa) { if (hpa) {
gpa = scb_o->sdnxo; unpin_guest_page(vcpu->kvm, vsie_page->sdnx_gpa, hpa);
unpin_guest_page(vcpu->kvm, gpa, hpa); vsie_page->sdnx_gpa = 0;
scb_s->sdnxo = 0; scb_s->sdnxo = 0;
} }
} }
...@@ -529,9 +543,9 @@ static int pin_blocks(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) ...@@ -529,9 +543,9 @@ static int pin_blocks(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
gpa_t gpa; gpa_t gpa;
int rc = 0; int rc = 0;
gpa = scb_o->scaol & ~0xfUL; gpa = READ_ONCE(scb_o->scaol) & ~0xfUL;
if (test_kvm_cpu_feat(vcpu->kvm, KVM_S390_VM_CPU_FEAT_64BSCAO)) if (test_kvm_cpu_feat(vcpu->kvm, KVM_S390_VM_CPU_FEAT_64BSCAO))
gpa |= (u64) scb_o->scaoh << 32; gpa |= (u64) READ_ONCE(scb_o->scaoh) << 32;
if (gpa) { if (gpa) {
if (!(gpa & ~0x1fffUL)) if (!(gpa & ~0x1fffUL))
rc = set_validity_icpt(scb_s, 0x0038U); rc = set_validity_icpt(scb_s, 0x0038U);
...@@ -547,11 +561,12 @@ static int pin_blocks(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) ...@@ -547,11 +561,12 @@ static int pin_blocks(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
} }
if (rc) if (rc)
goto unpin; goto unpin;
vsie_page->sca_gpa = gpa;
scb_s->scaoh = (u32)((u64)hpa >> 32); scb_s->scaoh = (u32)((u64)hpa >> 32);
scb_s->scaol = (u32)(u64)hpa; scb_s->scaol = (u32)(u64)hpa;
} }
gpa = scb_o->itdba & ~0xffUL; gpa = READ_ONCE(scb_o->itdba) & ~0xffUL;
if (gpa && (scb_s->ecb & ECB_TE)) { if (gpa && (scb_s->ecb & ECB_TE)) {
if (!(gpa & ~0x1fffU)) { if (!(gpa & ~0x1fffU)) {
rc = set_validity_icpt(scb_s, 0x0080U); rc = set_validity_icpt(scb_s, 0x0080U);
...@@ -563,10 +578,11 @@ static int pin_blocks(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) ...@@ -563,10 +578,11 @@ static int pin_blocks(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
rc = set_validity_icpt(scb_s, 0x0080U); rc = set_validity_icpt(scb_s, 0x0080U);
goto unpin; goto unpin;
} }
vsie_page->itdba_gpa = gpa;
scb_s->itdba = hpa; scb_s->itdba = hpa;
} }
gpa = scb_o->gvrd & ~0x1ffUL; gpa = READ_ONCE(scb_o->gvrd) & ~0x1ffUL;
if (gpa && (scb_s->eca & ECA_VX) && !(scb_s->ecd & ECD_HOSTREGMGMT)) { if (gpa && (scb_s->eca & ECA_VX) && !(scb_s->ecd & ECD_HOSTREGMGMT)) {
if (!(gpa & ~0x1fffUL)) { if (!(gpa & ~0x1fffUL)) {
rc = set_validity_icpt(scb_s, 0x1310U); rc = set_validity_icpt(scb_s, 0x1310U);
...@@ -581,10 +597,11 @@ static int pin_blocks(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) ...@@ -581,10 +597,11 @@ static int pin_blocks(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
rc = set_validity_icpt(scb_s, 0x1310U); rc = set_validity_icpt(scb_s, 0x1310U);
goto unpin; goto unpin;
} }
vsie_page->gvrd_gpa = gpa;
scb_s->gvrd = hpa; scb_s->gvrd = hpa;
} }
gpa = scb_o->riccbd & ~0x3fUL; gpa = READ_ONCE(scb_o->riccbd) & ~0x3fUL;
if (gpa && (scb_s->ecb3 & ECB3_RI)) { if (gpa && (scb_s->ecb3 & ECB3_RI)) {
if (!(gpa & ~0x1fffUL)) { if (!(gpa & ~0x1fffUL)) {
rc = set_validity_icpt(scb_s, 0x0043U); rc = set_validity_icpt(scb_s, 0x0043U);
...@@ -597,13 +614,14 @@ static int pin_blocks(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) ...@@ -597,13 +614,14 @@ static int pin_blocks(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
goto unpin; goto unpin;
} }
/* Validity 0x0044 will be checked by SIE */ /* Validity 0x0044 will be checked by SIE */
vsie_page->riccbd_gpa = gpa;
scb_s->riccbd = hpa; scb_s->riccbd = hpa;
} }
if ((scb_s->ecb & ECB_GS) && !(scb_s->ecd & ECD_HOSTREGMGMT)) { if ((scb_s->ecb & ECB_GS) && !(scb_s->ecd & ECD_HOSTREGMGMT)) {
unsigned long sdnxc; unsigned long sdnxc;
gpa = scb_o->sdnxo & ~0xfUL; gpa = READ_ONCE(scb_o->sdnxo) & ~0xfUL;
sdnxc = scb_o->sdnxo & 0xfUL; sdnxc = READ_ONCE(scb_o->sdnxo) & 0xfUL;
if (!gpa || !(gpa & ~0x1fffUL)) { if (!gpa || !(gpa & ~0x1fffUL)) {
rc = set_validity_icpt(scb_s, 0x10b0U); rc = set_validity_icpt(scb_s, 0x10b0U);
goto unpin; goto unpin;
...@@ -624,6 +642,7 @@ static int pin_blocks(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) ...@@ -624,6 +642,7 @@ static int pin_blocks(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
rc = set_validity_icpt(scb_s, 0x10b0U); rc = set_validity_icpt(scb_s, 0x10b0U);
goto unpin; goto unpin;
} }
vsie_page->sdnx_gpa = gpa;
scb_s->sdnxo = hpa | sdnxc; scb_s->sdnxo = hpa | sdnxc;
} }
return 0; return 0;
...@@ -768,7 +787,7 @@ static void retry_vsie_icpt(struct vsie_page *vsie_page) ...@@ -768,7 +787,7 @@ static void retry_vsie_icpt(struct vsie_page *vsie_page)
static int handle_stfle(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) static int handle_stfle(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_s = &vsie_page->scb_s;
__u32 fac = vsie_page->scb_o->fac & 0x7ffffff8U; __u32 fac = READ_ONCE(vsie_page->scb_o->fac) & 0x7ffffff8U;
if (fac && test_kvm_facility(vcpu->kvm, 7)) { if (fac && test_kvm_facility(vcpu->kvm, 7)) {
retry_vsie_icpt(vsie_page); retry_vsie_icpt(vsie_page);
...@@ -894,7 +913,7 @@ static void register_shadow_scb(struct kvm_vcpu *vcpu, ...@@ -894,7 +913,7 @@ static void register_shadow_scb(struct kvm_vcpu *vcpu,
* External calls have to lead to a kick of the vcpu and * External calls have to lead to a kick of the vcpu and
* therefore the vsie -> Simulate Wait state. * therefore the vsie -> Simulate Wait state.
*/ */
atomic_or(CPUSTAT_WAIT, &vcpu->arch.sie_block->cpuflags); kvm_s390_set_cpuflags(vcpu, CPUSTAT_WAIT);
/* /*
* We have to adjust the g3 epoch by the g2 epoch. The epoch will * 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. * automatically be adjusted on tod clock changes via kvm_sync_clock.
...@@ -916,7 +935,7 @@ static void register_shadow_scb(struct kvm_vcpu *vcpu, ...@@ -916,7 +935,7 @@ static void register_shadow_scb(struct kvm_vcpu *vcpu,
*/ */
static void unregister_shadow_scb(struct kvm_vcpu *vcpu) static void unregister_shadow_scb(struct kvm_vcpu *vcpu)
{ {
atomic_andnot(CPUSTAT_WAIT, &vcpu->arch.sie_block->cpuflags); kvm_s390_clear_cpuflags(vcpu, CPUSTAT_WAIT);
WRITE_ONCE(vcpu->arch.vsie_block, NULL); WRITE_ONCE(vcpu->arch.vsie_block, NULL);
} }
......
...@@ -1021,18 +1021,17 @@ static inline void gmap_insert_rmap(struct gmap *sg, unsigned long vmaddr, ...@@ -1021,18 +1021,17 @@ static inline void gmap_insert_rmap(struct gmap *sg, unsigned long vmaddr,
} }
/** /**
* gmap_protect_rmap - modify access rights to memory and create an rmap * gmap_protect_rmap - restrict access rights to memory (RO) and create an rmap
* @sg: pointer to the shadow guest address space structure * @sg: pointer to the shadow guest address space structure
* @raddr: rmap address in the shadow gmap * @raddr: rmap address in the shadow gmap
* @paddr: address in the parent guest address space * @paddr: address in the parent guest address space
* @len: length of the memory area to protect * @len: length of the memory area to protect
* @prot: indicates access rights: none, read-only or read-write
* *
* Returns 0 if successfully protected and the rmap was created, -ENOMEM * Returns 0 if successfully protected and the rmap was created, -ENOMEM
* if out of memory and -EFAULT if paddr is invalid. * if out of memory and -EFAULT if paddr is invalid.
*/ */
static int gmap_protect_rmap(struct gmap *sg, unsigned long raddr, static int gmap_protect_rmap(struct gmap *sg, unsigned long raddr,
unsigned long paddr, unsigned long len, int prot) unsigned long paddr, unsigned long len)
{ {
struct gmap *parent; struct gmap *parent;
struct gmap_rmap *rmap; struct gmap_rmap *rmap;
...@@ -1060,7 +1059,7 @@ static int gmap_protect_rmap(struct gmap *sg, unsigned long raddr, ...@@ -1060,7 +1059,7 @@ static int gmap_protect_rmap(struct gmap *sg, unsigned long raddr,
ptep = gmap_pte_op_walk(parent, paddr, &ptl); ptep = gmap_pte_op_walk(parent, paddr, &ptl);
if (ptep) { if (ptep) {
spin_lock(&sg->guest_table_lock); spin_lock(&sg->guest_table_lock);
rc = ptep_force_prot(parent->mm, paddr, ptep, prot, rc = ptep_force_prot(parent->mm, paddr, ptep, PROT_READ,
PGSTE_VSIE_BIT); PGSTE_VSIE_BIT);
if (!rc) if (!rc)
gmap_insert_rmap(sg, vmaddr, rmap); gmap_insert_rmap(sg, vmaddr, rmap);
...@@ -1070,7 +1069,7 @@ static int gmap_protect_rmap(struct gmap *sg, unsigned long raddr, ...@@ -1070,7 +1069,7 @@ static int gmap_protect_rmap(struct gmap *sg, unsigned long raddr,
radix_tree_preload_end(); radix_tree_preload_end();
if (rc) { if (rc) {
kfree(rmap); kfree(rmap);
rc = gmap_pte_op_fixup(parent, paddr, vmaddr, prot); rc = gmap_pte_op_fixup(parent, paddr, vmaddr, PROT_READ);
if (rc) if (rc)
return rc; return rc;
continue; continue;
...@@ -1609,7 +1608,7 @@ int gmap_shadow_r2t(struct gmap *sg, unsigned long saddr, unsigned long r2t, ...@@ -1609,7 +1608,7 @@ int gmap_shadow_r2t(struct gmap *sg, unsigned long saddr, unsigned long r2t,
origin = r2t & _REGION_ENTRY_ORIGIN; origin = r2t & _REGION_ENTRY_ORIGIN;
offset = ((r2t & _REGION_ENTRY_OFFSET) >> 6) * PAGE_SIZE; offset = ((r2t & _REGION_ENTRY_OFFSET) >> 6) * PAGE_SIZE;
len = ((r2t & _REGION_ENTRY_LENGTH) + 1) * PAGE_SIZE - offset; len = ((r2t & _REGION_ENTRY_LENGTH) + 1) * PAGE_SIZE - offset;
rc = gmap_protect_rmap(sg, raddr, origin + offset, len, PROT_READ); rc = gmap_protect_rmap(sg, raddr, origin + offset, len);
spin_lock(&sg->guest_table_lock); spin_lock(&sg->guest_table_lock);
if (!rc) { if (!rc) {
table = gmap_table_walk(sg, saddr, 4); table = gmap_table_walk(sg, saddr, 4);
...@@ -1692,7 +1691,7 @@ int gmap_shadow_r3t(struct gmap *sg, unsigned long saddr, unsigned long r3t, ...@@ -1692,7 +1691,7 @@ int gmap_shadow_r3t(struct gmap *sg, unsigned long saddr, unsigned long r3t,
origin = r3t & _REGION_ENTRY_ORIGIN; origin = r3t & _REGION_ENTRY_ORIGIN;
offset = ((r3t & _REGION_ENTRY_OFFSET) >> 6) * PAGE_SIZE; offset = ((r3t & _REGION_ENTRY_OFFSET) >> 6) * PAGE_SIZE;
len = ((r3t & _REGION_ENTRY_LENGTH) + 1) * PAGE_SIZE - offset; len = ((r3t & _REGION_ENTRY_LENGTH) + 1) * PAGE_SIZE - offset;
rc = gmap_protect_rmap(sg, raddr, origin + offset, len, PROT_READ); rc = gmap_protect_rmap(sg, raddr, origin + offset, len);
spin_lock(&sg->guest_table_lock); spin_lock(&sg->guest_table_lock);
if (!rc) { if (!rc) {
table = gmap_table_walk(sg, saddr, 3); table = gmap_table_walk(sg, saddr, 3);
...@@ -1776,7 +1775,7 @@ int gmap_shadow_sgt(struct gmap *sg, unsigned long saddr, unsigned long sgt, ...@@ -1776,7 +1775,7 @@ int gmap_shadow_sgt(struct gmap *sg, unsigned long saddr, unsigned long sgt,
origin = sgt & _REGION_ENTRY_ORIGIN; origin = sgt & _REGION_ENTRY_ORIGIN;
offset = ((sgt & _REGION_ENTRY_OFFSET) >> 6) * PAGE_SIZE; offset = ((sgt & _REGION_ENTRY_OFFSET) >> 6) * PAGE_SIZE;
len = ((sgt & _REGION_ENTRY_LENGTH) + 1) * PAGE_SIZE - offset; len = ((sgt & _REGION_ENTRY_LENGTH) + 1) * PAGE_SIZE - offset;
rc = gmap_protect_rmap(sg, raddr, origin + offset, len, PROT_READ); rc = gmap_protect_rmap(sg, raddr, origin + offset, len);
spin_lock(&sg->guest_table_lock); spin_lock(&sg->guest_table_lock);
if (!rc) { if (!rc) {
table = gmap_table_walk(sg, saddr, 2); table = gmap_table_walk(sg, saddr, 2);
...@@ -1895,7 +1894,7 @@ int gmap_shadow_pgt(struct gmap *sg, unsigned long saddr, unsigned long pgt, ...@@ -1895,7 +1894,7 @@ int gmap_shadow_pgt(struct gmap *sg, unsigned long saddr, unsigned long pgt,
/* Make pgt read-only in parent gmap page table (not the pgste) */ /* Make pgt read-only in parent gmap page table (not the pgste) */
raddr = (saddr & _SEGMENT_MASK) | _SHADOW_RMAP_SEGMENT; raddr = (saddr & _SEGMENT_MASK) | _SHADOW_RMAP_SEGMENT;
origin = pgt & _SEGMENT_ENTRY_ORIGIN & PAGE_MASK; origin = pgt & _SEGMENT_ENTRY_ORIGIN & PAGE_MASK;
rc = gmap_protect_rmap(sg, raddr, origin, PAGE_SIZE, PROT_READ); rc = gmap_protect_rmap(sg, raddr, origin, PAGE_SIZE);
spin_lock(&sg->guest_table_lock); spin_lock(&sg->guest_table_lock);
if (!rc) { if (!rc) {
table = gmap_table_walk(sg, saddr, 1); table = gmap_table_walk(sg, saddr, 1);
...@@ -1998,7 +1997,7 @@ EXPORT_SYMBOL_GPL(gmap_shadow_page); ...@@ -1998,7 +1997,7 @@ EXPORT_SYMBOL_GPL(gmap_shadow_page);
* Called with sg->parent->shadow_lock. * Called with sg->parent->shadow_lock.
*/ */
static void gmap_shadow_notify(struct gmap *sg, unsigned long vmaddr, static void gmap_shadow_notify(struct gmap *sg, unsigned long vmaddr,
unsigned long gaddr, pte_t *pte) unsigned long gaddr)
{ {
struct gmap_rmap *rmap, *rnext, *head; struct gmap_rmap *rmap, *rnext, *head;
unsigned long start, end, bits, raddr; unsigned long start, end, bits, raddr;
...@@ -2083,7 +2082,7 @@ void ptep_notify(struct mm_struct *mm, unsigned long vmaddr, ...@@ -2083,7 +2082,7 @@ void ptep_notify(struct mm_struct *mm, unsigned long vmaddr,
spin_lock(&gmap->shadow_lock); spin_lock(&gmap->shadow_lock);
list_for_each_entry_safe(sg, next, list_for_each_entry_safe(sg, next,
&gmap->children, list) &gmap->children, list)
gmap_shadow_notify(sg, vmaddr, gaddr, pte); gmap_shadow_notify(sg, vmaddr, gaddr);
spin_unlock(&gmap->shadow_lock); spin_unlock(&gmap->shadow_lock);
} }
if (bits & PGSTE_IN_BIT) if (bits & PGSTE_IN_BIT)
......
...@@ -49,7 +49,7 @@ struct read_info_sccb { ...@@ -49,7 +49,7 @@ struct read_info_sccb {
u8 _pad_112[116 - 112]; /* 112-115 */ u8 _pad_112[116 - 112]; /* 112-115 */
u8 fac116; /* 116 */ u8 fac116; /* 116 */
u8 fac117; /* 117 */ u8 fac117; /* 117 */
u8 _pad_118; /* 118 */ u8 fac118; /* 118 */
u8 fac119; /* 119 */ u8 fac119; /* 119 */
u16 hcpua; /* 120-121 */ u16 hcpua; /* 120-121 */
u8 _pad_122[124 - 122]; /* 122-123 */ u8 _pad_122[124 - 122]; /* 122-123 */
...@@ -100,6 +100,7 @@ static void __init sclp_early_facilities_detect(struct read_info_sccb *sccb) ...@@ -100,6 +100,7 @@ static void __init sclp_early_facilities_detect(struct read_info_sccb *sccb)
sclp.has_esca = !!(sccb->fac116 & 0x08); sclp.has_esca = !!(sccb->fac116 & 0x08);
sclp.has_pfmfi = !!(sccb->fac117 & 0x40); sclp.has_pfmfi = !!(sccb->fac117 & 0x40);
sclp.has_ibs = !!(sccb->fac117 & 0x20); sclp.has_ibs = !!(sccb->fac117 & 0x20);
sclp.has_gisaf = !!(sccb->fac118 & 0x08);
sclp.has_hvs = !!(sccb->fac119 & 0x80); sclp.has_hvs = !!(sccb->fac119 & 0x80);
sclp.has_kss = !!(sccb->fac98 & 0x01); sclp.has_kss = !!(sccb->fac98 & 0x01);
if (sccb->fac85 & 0x02) if (sccb->fac85 & 0x02)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment