KVM: s390: Several fixes,cleanups and reworks
Here is a bunch of fixes that deal mostly with architectural compliance: - interrupt priorities - interrupt handling - intruction exit handling We also provide a helper function for getting the guest visible storage key. -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.14 (GNU/Linux) iQIcBAABAgAGBQJUeHKOAAoJEBF7vIC1phx8fS8P/2i1zXvsB+Mp9FafU6FO3Ci6 yM/ZBLFEsX2jmU0TGR2szZCP4xuHqomJm441+2CX9bXzjf8vnA2hGiDYX0bnBraK 1/klx6Li1fQxsiSHXIgBXr0wh5ftNUdFVZiJoifY9dEdrhVI+YEiptIl7lADCFXi SdGtjEAzrVEe8H0g6OuBXeEfPzHvxAzNJ31yHuiCKl7vbFVnXNVPeZhq3dJZwmWC iIdlSqGIjbcHNMLXvrScLDAScBe6WruBLhPSy5aTIA2eBU6f4qkOedSFABJkIAq+ V6v5pXWbrVBIqfLXE7Vp7jxhP7+viBGzu/gPkfT8HV1pQZDa94WojF8hGU0DLGLd vgZuFDV8cMOZMUS/onXOwnIXN5VPvP8V2v3y8gTiap3MykRiyTGEzq2auU9p0K5n /8W6Cn1P/WBS8MOFYg726DGmMAWkzpEVz9rxpCLaTpzz7QVyLuSLq/n3SXyQNQIl zhox/KzwUQD0t1062USoK3w4suYNvnX0BuFOwxXvS7f4bsb+6V/t0GyIBnVAL/OF DZzJSIyzP/Ur/9krxJQxML3kEELU1CjwSLOrzDUnZA3ytaKvsLrHkTb9nK6fREDK 14AGRnp94B3EMPR6T+7T6gvwK2Y/QIo8Y/EFAa2BwXY4Q/BQPSVU3x3RK6L9+7jY VaG9sgn4OC2ZPzxjqMTc =MQUy -----END PGP SIGNATURE----- Merge tag 'kvm-s390-next-20141128' of git://git.kernel.org/pub/scm/linux/kernel/git/kvms390/linux into HEAD KVM: s390: Several fixes,cleanups and reworks Here is a bunch of fixes that deal mostly with architectural compliance: - interrupt priorities - interrupt handling - intruction exit handling We also provide a helper function for getting the guest visible storage key.hifive-unleashed-5.1
commit
be06b6bece
|
@ -123,7 +123,7 @@ struct kvm_s390_sie_block {
|
||||||
#define ICPT_PARTEXEC 0x38
|
#define ICPT_PARTEXEC 0x38
|
||||||
#define ICPT_IOINST 0x40
|
#define ICPT_IOINST 0x40
|
||||||
__u8 icptcode; /* 0x0050 */
|
__u8 icptcode; /* 0x0050 */
|
||||||
__u8 reserved51; /* 0x0051 */
|
__u8 icptstatus; /* 0x0051 */
|
||||||
__u16 ihcpu; /* 0x0052 */
|
__u16 ihcpu; /* 0x0052 */
|
||||||
__u8 reserved54[2]; /* 0x0054 */
|
__u8 reserved54[2]; /* 0x0054 */
|
||||||
__u16 ipa; /* 0x0056 */
|
__u16 ipa; /* 0x0056 */
|
||||||
|
@ -295,6 +295,79 @@ 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 */
|
||||||
|
enum irq_types {
|
||||||
|
IRQ_PEND_MCHK_EX = 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_SET_PREFIX,
|
||||||
|
IRQ_PEND_COUNT
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Repressible (non-floating) machine check interrupts
|
||||||
|
* subclass bits in MCIC
|
||||||
|
*/
|
||||||
|
#define MCHK_EXTD_BIT 58
|
||||||
|
#define MCHK_DEGR_BIT 56
|
||||||
|
#define MCHK_WARN_BIT 55
|
||||||
|
#define MCHK_REP_MASK ((1UL << MCHK_DEGR_BIT) | \
|
||||||
|
(1UL << MCHK_EXTD_BIT) | \
|
||||||
|
(1UL << MCHK_WARN_BIT))
|
||||||
|
|
||||||
|
/* Exigent machine check interrupts subclass bits in MCIC */
|
||||||
|
#define MCHK_SD_BIT 63
|
||||||
|
#define MCHK_PD_BIT 62
|
||||||
|
#define MCHK_EX_MASK ((1UL << MCHK_SD_BIT) | (1UL << MCHK_PD_BIT))
|
||||||
|
|
||||||
|
#define IRQ_PEND_EXT_MASK ((1UL << IRQ_PEND_EXT_IRQ_KEY) | \
|
||||||
|
(1UL << IRQ_PEND_EXT_CLOCK_COMP) | \
|
||||||
|
(1UL << IRQ_PEND_EXT_CPU_TIMER) | \
|
||||||
|
(1UL << IRQ_PEND_EXT_MALFUNC) | \
|
||||||
|
(1UL << IRQ_PEND_EXT_EMERGENCY) | \
|
||||||
|
(1UL << IRQ_PEND_EXT_EXTERNAL) | \
|
||||||
|
(1UL << IRQ_PEND_EXT_TIMING) | \
|
||||||
|
(1UL << IRQ_PEND_EXT_HOST) | \
|
||||||
|
(1UL << IRQ_PEND_EXT_SERVICE) | \
|
||||||
|
(1UL << IRQ_PEND_VIRTIO) | \
|
||||||
|
(1UL << IRQ_PEND_PFAULT_INIT) | \
|
||||||
|
(1UL << IRQ_PEND_PFAULT_DONE))
|
||||||
|
|
||||||
|
#define IRQ_PEND_IO_MASK ((1UL << IRQ_PEND_IO_ISC_0) | \
|
||||||
|
(1UL << IRQ_PEND_IO_ISC_1) | \
|
||||||
|
(1UL << IRQ_PEND_IO_ISC_2) | \
|
||||||
|
(1UL << IRQ_PEND_IO_ISC_3) | \
|
||||||
|
(1UL << IRQ_PEND_IO_ISC_4) | \
|
||||||
|
(1UL << IRQ_PEND_IO_ISC_5) | \
|
||||||
|
(1UL << IRQ_PEND_IO_ISC_6) | \
|
||||||
|
(1UL << IRQ_PEND_IO_ISC_7))
|
||||||
|
|
||||||
|
#define IRQ_PEND_MCHK_MASK ((1UL << IRQ_PEND_MCHK_REP) | \
|
||||||
|
(1UL << IRQ_PEND_MCHK_EX))
|
||||||
|
|
||||||
struct kvm_s390_interrupt_info {
|
struct kvm_s390_interrupt_info {
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
u64 type;
|
u64 type;
|
||||||
|
@ -313,14 +386,25 @@ struct kvm_s390_interrupt_info {
|
||||||
#define ACTION_STORE_ON_STOP (1<<0)
|
#define ACTION_STORE_ON_STOP (1<<0)
|
||||||
#define ACTION_STOP_ON_STOP (1<<1)
|
#define ACTION_STOP_ON_STOP (1<<1)
|
||||||
|
|
||||||
|
struct kvm_s390_irq_payload {
|
||||||
|
struct kvm_s390_io_info io;
|
||||||
|
struct kvm_s390_ext_info ext;
|
||||||
|
struct kvm_s390_pgm_info pgm;
|
||||||
|
struct kvm_s390_emerg_info emerg;
|
||||||
|
struct kvm_s390_extcall_info extcall;
|
||||||
|
struct kvm_s390_prefix_info prefix;
|
||||||
|
struct kvm_s390_mchk_info mchk;
|
||||||
|
};
|
||||||
|
|
||||||
struct kvm_s390_local_interrupt {
|
struct kvm_s390_local_interrupt {
|
||||||
spinlock_t lock;
|
spinlock_t lock;
|
||||||
struct list_head list;
|
|
||||||
atomic_t active;
|
|
||||||
struct kvm_s390_float_interrupt *float_int;
|
struct kvm_s390_float_interrupt *float_int;
|
||||||
wait_queue_head_t *wq;
|
wait_queue_head_t *wq;
|
||||||
atomic_t *cpuflags;
|
atomic_t *cpuflags;
|
||||||
unsigned int action_bits;
|
unsigned int action_bits;
|
||||||
|
DECLARE_BITMAP(sigp_emerg_pending, KVM_MAX_VCPUS);
|
||||||
|
struct kvm_s390_irq_payload irq;
|
||||||
|
unsigned long pending_irqs;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct kvm_s390_float_interrupt {
|
struct kvm_s390_float_interrupt {
|
||||||
|
|
|
@ -26,6 +26,7 @@ void page_table_reset_pgste(struct mm_struct *, unsigned long, unsigned long,
|
||||||
bool init_skey);
|
bool init_skey);
|
||||||
int set_guest_storage_key(struct mm_struct *mm, unsigned long addr,
|
int set_guest_storage_key(struct mm_struct *mm, unsigned long addr,
|
||||||
unsigned long key, bool nq);
|
unsigned long key, bool nq);
|
||||||
|
unsigned long get_guest_storage_key(struct mm_struct *mm, unsigned long addr);
|
||||||
|
|
||||||
static inline void clear_table(unsigned long *s, unsigned long val, size_t n)
|
static inline void clear_table(unsigned long *s, unsigned long val, size_t n)
|
||||||
{
|
{
|
||||||
|
|
|
@ -38,6 +38,19 @@ static const intercept_handler_t instruction_handlers[256] = {
|
||||||
[0xeb] = kvm_s390_handle_eb,
|
[0xeb] = kvm_s390_handle_eb,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void kvm_s390_rewind_psw(struct kvm_vcpu *vcpu, int ilc)
|
||||||
|
{
|
||||||
|
struct kvm_s390_sie_block *sie_block = vcpu->arch.sie_block;
|
||||||
|
|
||||||
|
/* Use the length of the EXECUTE instruction if necessary */
|
||||||
|
if (sie_block->icptstatus & 1) {
|
||||||
|
ilc = (sie_block->icptstatus >> 4) & 0x6;
|
||||||
|
if (!ilc)
|
||||||
|
ilc = 4;
|
||||||
|
}
|
||||||
|
sie_block->gpsw.addr = __rewind_psw(sie_block->gpsw, ilc);
|
||||||
|
}
|
||||||
|
|
||||||
static int handle_noop(struct kvm_vcpu *vcpu)
|
static int handle_noop(struct kvm_vcpu *vcpu)
|
||||||
{
|
{
|
||||||
switch (vcpu->arch.sie_block->icptcode) {
|
switch (vcpu->arch.sie_block->icptcode) {
|
||||||
|
@ -244,7 +257,7 @@ static int handle_instruction_and_prog(struct kvm_vcpu *vcpu)
|
||||||
static int handle_external_interrupt(struct kvm_vcpu *vcpu)
|
static int handle_external_interrupt(struct kvm_vcpu *vcpu)
|
||||||
{
|
{
|
||||||
u16 eic = vcpu->arch.sie_block->eic;
|
u16 eic = vcpu->arch.sie_block->eic;
|
||||||
struct kvm_s390_interrupt irq;
|
struct kvm_s390_irq irq;
|
||||||
psw_t newpsw;
|
psw_t newpsw;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
|
@ -269,7 +282,7 @@ static int handle_external_interrupt(struct kvm_vcpu *vcpu)
|
||||||
if (kvm_s390_si_ext_call_pending(vcpu))
|
if (kvm_s390_si_ext_call_pending(vcpu))
|
||||||
return 0;
|
return 0;
|
||||||
irq.type = KVM_S390_INT_EXTERNAL_CALL;
|
irq.type = KVM_S390_INT_EXTERNAL_CALL;
|
||||||
irq.parm = vcpu->arch.sie_block->extcpuaddr;
|
irq.u.extcall.code = vcpu->arch.sie_block->extcpuaddr;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
|
@ -288,7 +301,6 @@ static int handle_external_interrupt(struct kvm_vcpu *vcpu)
|
||||||
*/
|
*/
|
||||||
static int handle_mvpg_pei(struct kvm_vcpu *vcpu)
|
static int handle_mvpg_pei(struct kvm_vcpu *vcpu)
|
||||||
{
|
{
|
||||||
psw_t *psw = &vcpu->arch.sie_block->gpsw;
|
|
||||||
unsigned long srcaddr, dstaddr;
|
unsigned long srcaddr, dstaddr;
|
||||||
int reg1, reg2, rc;
|
int reg1, reg2, rc;
|
||||||
|
|
||||||
|
@ -310,7 +322,7 @@ static int handle_mvpg_pei(struct kvm_vcpu *vcpu)
|
||||||
if (rc != 0)
|
if (rc != 0)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
psw->addr = __rewind_psw(*psw, 4);
|
kvm_s390_rewind_psw(vcpu, 4);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -719,7 +719,6 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm,
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_lock_init(&vcpu->arch.local_int.lock);
|
spin_lock_init(&vcpu->arch.local_int.lock);
|
||||||
INIT_LIST_HEAD(&vcpu->arch.local_int.list);
|
|
||||||
vcpu->arch.local_int.float_int = &kvm->arch.float_int;
|
vcpu->arch.local_int.float_int = &kvm->arch.float_int;
|
||||||
vcpu->arch.local_int.wq = &vcpu->wq;
|
vcpu->arch.local_int.wq = &vcpu->wq;
|
||||||
vcpu->arch.local_int.cpuflags = &vcpu->arch.sie_block->cpuflags;
|
vcpu->arch.local_int.cpuflags = &vcpu->arch.sie_block->cpuflags;
|
||||||
|
@ -1122,13 +1121,15 @@ static void __kvm_inject_pfault_token(struct kvm_vcpu *vcpu, bool start_token,
|
||||||
unsigned long token)
|
unsigned long token)
|
||||||
{
|
{
|
||||||
struct kvm_s390_interrupt inti;
|
struct kvm_s390_interrupt inti;
|
||||||
inti.parm64 = token;
|
struct kvm_s390_irq irq;
|
||||||
|
|
||||||
if (start_token) {
|
if (start_token) {
|
||||||
inti.type = KVM_S390_INT_PFAULT_INIT;
|
irq.u.ext.ext_params2 = token;
|
||||||
WARN_ON_ONCE(kvm_s390_inject_vcpu(vcpu, &inti));
|
irq.type = KVM_S390_INT_PFAULT_INIT;
|
||||||
|
WARN_ON_ONCE(kvm_s390_inject_vcpu(vcpu, &irq));
|
||||||
} else {
|
} else {
|
||||||
inti.type = KVM_S390_INT_PFAULT_DONE;
|
inti.type = KVM_S390_INT_PFAULT_DONE;
|
||||||
|
inti.parm64 = token;
|
||||||
WARN_ON_ONCE(kvm_s390_inject_vm(vcpu->kvm, &inti));
|
WARN_ON_ONCE(kvm_s390_inject_vm(vcpu->kvm, &inti));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1622,11 +1623,14 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
|
||||||
switch (ioctl) {
|
switch (ioctl) {
|
||||||
case KVM_S390_INTERRUPT: {
|
case KVM_S390_INTERRUPT: {
|
||||||
struct kvm_s390_interrupt s390int;
|
struct kvm_s390_interrupt s390int;
|
||||||
|
struct kvm_s390_irq s390irq;
|
||||||
|
|
||||||
r = -EFAULT;
|
r = -EFAULT;
|
||||||
if (copy_from_user(&s390int, argp, sizeof(s390int)))
|
if (copy_from_user(&s390int, argp, sizeof(s390int)))
|
||||||
break;
|
break;
|
||||||
r = kvm_s390_inject_vcpu(vcpu, &s390int);
|
if (s390int_to_s390irq(&s390int, &s390irq))
|
||||||
|
return -EINVAL;
|
||||||
|
r = kvm_s390_inject_vcpu(vcpu, &s390irq);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case KVM_S390_STORE_STATUS:
|
case KVM_S390_STORE_STATUS:
|
||||||
|
|
|
@ -24,8 +24,6 @@ typedef int (*intercept_handler_t)(struct kvm_vcpu *vcpu);
|
||||||
/* declare vfacilities extern */
|
/* declare vfacilities extern */
|
||||||
extern unsigned long *vfacilities;
|
extern unsigned long *vfacilities;
|
||||||
|
|
||||||
int kvm_handle_sie_intercept(struct kvm_vcpu *vcpu);
|
|
||||||
|
|
||||||
/* Transactional Memory Execution related macros */
|
/* Transactional Memory Execution related macros */
|
||||||
#define IS_TE_ENABLED(vcpu) ((vcpu->arch.sie_block->ecb & 0x10))
|
#define IS_TE_ENABLED(vcpu) ((vcpu->arch.sie_block->ecb & 0x10))
|
||||||
#define TDB_FORMAT1 1
|
#define TDB_FORMAT1 1
|
||||||
|
@ -144,7 +142,7 @@ void kvm_s390_clear_float_irqs(struct kvm *kvm);
|
||||||
int __must_check kvm_s390_inject_vm(struct kvm *kvm,
|
int __must_check kvm_s390_inject_vm(struct kvm *kvm,
|
||||||
struct kvm_s390_interrupt *s390int);
|
struct kvm_s390_interrupt *s390int);
|
||||||
int __must_check kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu,
|
int __must_check kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu,
|
||||||
struct kvm_s390_interrupt *s390int);
|
struct kvm_s390_irq *irq);
|
||||||
int __must_check kvm_s390_inject_program_int(struct kvm_vcpu *vcpu, u16 code);
|
int __must_check kvm_s390_inject_program_int(struct kvm_vcpu *vcpu, u16 code);
|
||||||
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 cr6, u64 schid);
|
u64 cr6, u64 schid);
|
||||||
|
@ -152,6 +150,10 @@ void kvm_s390_reinject_io_int(struct kvm *kvm,
|
||||||
struct kvm_s390_interrupt_info *inti);
|
struct kvm_s390_interrupt_info *inti);
|
||||||
int kvm_s390_mask_adapter(struct kvm *kvm, unsigned int id, bool masked);
|
int kvm_s390_mask_adapter(struct kvm *kvm, unsigned int id, bool masked);
|
||||||
|
|
||||||
|
/* implemented in intercept.c */
|
||||||
|
void kvm_s390_rewind_psw(struct kvm_vcpu *vcpu, int ilc);
|
||||||
|
int kvm_handle_sie_intercept(struct kvm_vcpu *vcpu);
|
||||||
|
|
||||||
/* implemented in priv.c */
|
/* implemented in priv.c */
|
||||||
int is_valid_psw(psw_t *psw);
|
int is_valid_psw(psw_t *psw);
|
||||||
int kvm_s390_handle_b2(struct kvm_vcpu *vcpu);
|
int kvm_s390_handle_b2(struct kvm_vcpu *vcpu);
|
||||||
|
@ -222,6 +224,9 @@ static inline int kvm_s390_inject_prog_cond(struct kvm_vcpu *vcpu, int rc)
|
||||||
return kvm_s390_inject_prog_irq(vcpu, &vcpu->arch.pgm);
|
return kvm_s390_inject_prog_irq(vcpu, &vcpu->arch.pgm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int s390int_to_s390irq(struct kvm_s390_interrupt *s390int,
|
||||||
|
struct kvm_s390_irq *s390irq);
|
||||||
|
|
||||||
/* implemented in interrupt.c */
|
/* implemented in interrupt.c */
|
||||||
int kvm_cpu_has_interrupt(struct kvm_vcpu *vcpu);
|
int kvm_cpu_has_interrupt(struct kvm_vcpu *vcpu);
|
||||||
int psw_extint_disabled(struct kvm_vcpu *vcpu);
|
int psw_extint_disabled(struct kvm_vcpu *vcpu);
|
||||||
|
|
|
@ -176,21 +176,18 @@ static int handle_skey(struct kvm_vcpu *vcpu)
|
||||||
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);
|
||||||
|
|
||||||
vcpu->arch.sie_block->gpsw.addr =
|
kvm_s390_rewind_psw(vcpu, 4);
|
||||||
__rewind_psw(vcpu->arch.sie_block->gpsw, 4);
|
|
||||||
VCPU_EVENT(vcpu, 4, "%s", "retrying storage key operation");
|
VCPU_EVENT(vcpu, 4, "%s", "retrying storage key operation");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int handle_ipte_interlock(struct kvm_vcpu *vcpu)
|
static int handle_ipte_interlock(struct kvm_vcpu *vcpu)
|
||||||
{
|
{
|
||||||
psw_t *psw = &vcpu->arch.sie_block->gpsw;
|
|
||||||
|
|
||||||
vcpu->stat.instruction_ipte_interlock++;
|
vcpu->stat.instruction_ipte_interlock++;
|
||||||
if (psw_bits(*psw).p)
|
if (psw_bits(vcpu->arch.sie_block->gpsw).p)
|
||||||
return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
|
return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
|
||||||
wait_event(vcpu->kvm->arch.ipte_wq, !ipte_lock_held(vcpu));
|
wait_event(vcpu->kvm->arch.ipte_wq, !ipte_lock_held(vcpu));
|
||||||
psw->addr = __rewind_psw(*psw, 4);
|
kvm_s390_rewind_psw(vcpu, 4);
|
||||||
VCPU_EVENT(vcpu, 4, "%s", "retrying ipte interlock operation");
|
VCPU_EVENT(vcpu, 4, "%s", "retrying ipte interlock operation");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -646,10 +643,7 @@ static int handle_pfmf(struct kvm_vcpu *vcpu)
|
||||||
return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
|
return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
|
||||||
|
|
||||||
start = vcpu->run->s.regs.gprs[reg2] & PAGE_MASK;
|
start = vcpu->run->s.regs.gprs[reg2] & PAGE_MASK;
|
||||||
if (vcpu->run->s.regs.gprs[reg1] & PFMF_CF) {
|
start = kvm_s390_logical_to_effective(vcpu, start);
|
||||||
if (kvm_s390_check_low_addr_protection(vcpu, start))
|
|
||||||
return kvm_s390_inject_prog_irq(vcpu, &vcpu->arch.pgm);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (vcpu->run->s.regs.gprs[reg1] & PFMF_FSC) {
|
switch (vcpu->run->s.regs.gprs[reg1] & PFMF_FSC) {
|
||||||
case 0x00000000:
|
case 0x00000000:
|
||||||
|
@ -665,6 +659,12 @@ static int handle_pfmf(struct kvm_vcpu *vcpu)
|
||||||
default:
|
default:
|
||||||
return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
|
return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (vcpu->run->s.regs.gprs[reg1] & PFMF_CF) {
|
||||||
|
if (kvm_s390_check_low_addr_protection(vcpu, start))
|
||||||
|
return kvm_s390_inject_prog_irq(vcpu, &vcpu->arch.pgm);
|
||||||
|
}
|
||||||
|
|
||||||
while (start < end) {
|
while (start < end) {
|
||||||
unsigned long useraddr, abs_addr;
|
unsigned long useraddr, abs_addr;
|
||||||
|
|
||||||
|
@ -718,8 +718,7 @@ static int handle_essa(struct kvm_vcpu *vcpu)
|
||||||
return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
|
return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
|
||||||
|
|
||||||
/* Rewind PSW to repeat the ESSA instruction */
|
/* Rewind PSW to repeat the ESSA instruction */
|
||||||
vcpu->arch.sie_block->gpsw.addr =
|
kvm_s390_rewind_psw(vcpu, 4);
|
||||||
__rewind_psw(vcpu->arch.sie_block->gpsw, 4);
|
|
||||||
vcpu->arch.sie_block->cbrlo &= PAGE_MASK; /* reset nceo */
|
vcpu->arch.sie_block->cbrlo &= PAGE_MASK; /* reset nceo */
|
||||||
cbrlo = phys_to_virt(vcpu->arch.sie_block->cbrlo);
|
cbrlo = phys_to_virt(vcpu->arch.sie_block->cbrlo);
|
||||||
down_read(&gmap->mm->mmap_sem);
|
down_read(&gmap->mm->mmap_sem);
|
||||||
|
|
|
@ -49,13 +49,13 @@ static int __sigp_sense(struct kvm_vcpu *vcpu, struct kvm_vcpu *dst_vcpu,
|
||||||
static int __inject_sigp_emergency(struct kvm_vcpu *vcpu,
|
static int __inject_sigp_emergency(struct kvm_vcpu *vcpu,
|
||||||
struct kvm_vcpu *dst_vcpu)
|
struct kvm_vcpu *dst_vcpu)
|
||||||
{
|
{
|
||||||
struct kvm_s390_interrupt s390int = {
|
struct kvm_s390_irq irq = {
|
||||||
.type = KVM_S390_INT_EMERGENCY,
|
.type = KVM_S390_INT_EMERGENCY,
|
||||||
.parm = vcpu->vcpu_id,
|
.u.emerg.code = vcpu->vcpu_id,
|
||||||
};
|
};
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
||||||
rc = kvm_s390_inject_vcpu(dst_vcpu, &s390int);
|
rc = kvm_s390_inject_vcpu(dst_vcpu, &irq);
|
||||||
if (!rc)
|
if (!rc)
|
||||||
VCPU_EVENT(vcpu, 4, "sent sigp emerg to cpu %x",
|
VCPU_EVENT(vcpu, 4, "sent sigp emerg to cpu %x",
|
||||||
dst_vcpu->vcpu_id);
|
dst_vcpu->vcpu_id);
|
||||||
|
@ -98,13 +98,13 @@ static int __sigp_conditional_emergency(struct kvm_vcpu *vcpu,
|
||||||
static int __sigp_external_call(struct kvm_vcpu *vcpu,
|
static int __sigp_external_call(struct kvm_vcpu *vcpu,
|
||||||
struct kvm_vcpu *dst_vcpu)
|
struct kvm_vcpu *dst_vcpu)
|
||||||
{
|
{
|
||||||
struct kvm_s390_interrupt s390int = {
|
struct kvm_s390_irq irq = {
|
||||||
.type = KVM_S390_INT_EXTERNAL_CALL,
|
.type = KVM_S390_INT_EXTERNAL_CALL,
|
||||||
.parm = vcpu->vcpu_id,
|
.u.extcall.code = vcpu->vcpu_id,
|
||||||
};
|
};
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
rc = kvm_s390_inject_vcpu(dst_vcpu, &s390int);
|
rc = kvm_s390_inject_vcpu(dst_vcpu, &irq);
|
||||||
if (!rc)
|
if (!rc)
|
||||||
VCPU_EVENT(vcpu, 4, "sent sigp ext call to cpu %x",
|
VCPU_EVENT(vcpu, 4, "sent sigp ext call to cpu %x",
|
||||||
dst_vcpu->vcpu_id);
|
dst_vcpu->vcpu_id);
|
||||||
|
@ -115,29 +115,20 @@ static int __sigp_external_call(struct kvm_vcpu *vcpu,
|
||||||
static int __inject_sigp_stop(struct kvm_vcpu *dst_vcpu, int action)
|
static int __inject_sigp_stop(struct kvm_vcpu *dst_vcpu, int action)
|
||||||
{
|
{
|
||||||
struct kvm_s390_local_interrupt *li = &dst_vcpu->arch.local_int;
|
struct kvm_s390_local_interrupt *li = &dst_vcpu->arch.local_int;
|
||||||
struct kvm_s390_interrupt_info *inti;
|
|
||||||
int rc = SIGP_CC_ORDER_CODE_ACCEPTED;
|
int rc = SIGP_CC_ORDER_CODE_ACCEPTED;
|
||||||
|
|
||||||
inti = kzalloc(sizeof(*inti), GFP_ATOMIC);
|
|
||||||
if (!inti)
|
|
||||||
return -ENOMEM;
|
|
||||||
inti->type = KVM_S390_SIGP_STOP;
|
|
||||||
|
|
||||||
spin_lock(&li->lock);
|
spin_lock(&li->lock);
|
||||||
if (li->action_bits & ACTION_STOP_ON_STOP) {
|
if (li->action_bits & ACTION_STOP_ON_STOP) {
|
||||||
/* another SIGP STOP is pending */
|
/* another SIGP STOP is pending */
|
||||||
kfree(inti);
|
|
||||||
rc = SIGP_CC_BUSY;
|
rc = SIGP_CC_BUSY;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
if ((atomic_read(li->cpuflags) & CPUSTAT_STOPPED)) {
|
if ((atomic_read(li->cpuflags) & CPUSTAT_STOPPED)) {
|
||||||
kfree(inti);
|
|
||||||
if ((action & ACTION_STORE_ON_STOP) != 0)
|
if ((action & ACTION_STORE_ON_STOP) != 0)
|
||||||
rc = -ESHUTDOWN;
|
rc = -ESHUTDOWN;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
list_add_tail(&inti->list, &li->list);
|
set_bit(IRQ_PEND_SIGP_STOP, &li->pending_irqs);
|
||||||
atomic_set(&li->active, 1);
|
|
||||||
li->action_bits |= action;
|
li->action_bits |= action;
|
||||||
atomic_set_mask(CPUSTAT_STOP_INT, li->cpuflags);
|
atomic_set_mask(CPUSTAT_STOP_INT, li->cpuflags);
|
||||||
kvm_s390_vcpu_wakeup(dst_vcpu);
|
kvm_s390_vcpu_wakeup(dst_vcpu);
|
||||||
|
@ -207,7 +198,6 @@ static int __sigp_set_prefix(struct kvm_vcpu *vcpu, struct kvm_vcpu *dst_vcpu,
|
||||||
u32 address, u64 *reg)
|
u32 address, u64 *reg)
|
||||||
{
|
{
|
||||||
struct kvm_s390_local_interrupt *li;
|
struct kvm_s390_local_interrupt *li;
|
||||||
struct kvm_s390_interrupt_info *inti;
|
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
li = &dst_vcpu->arch.local_int;
|
li = &dst_vcpu->arch.local_int;
|
||||||
|
@ -224,25 +214,17 @@ static int __sigp_set_prefix(struct kvm_vcpu *vcpu, struct kvm_vcpu *dst_vcpu,
|
||||||
return SIGP_CC_STATUS_STORED;
|
return SIGP_CC_STATUS_STORED;
|
||||||
}
|
}
|
||||||
|
|
||||||
inti = kzalloc(sizeof(*inti), GFP_KERNEL);
|
|
||||||
if (!inti)
|
|
||||||
return SIGP_CC_BUSY;
|
|
||||||
|
|
||||||
spin_lock(&li->lock);
|
spin_lock(&li->lock);
|
||||||
/* cpu must be in stopped state */
|
/* cpu must be in stopped state */
|
||||||
if (!(atomic_read(li->cpuflags) & CPUSTAT_STOPPED)) {
|
if (!(atomic_read(li->cpuflags) & CPUSTAT_STOPPED)) {
|
||||||
*reg &= 0xffffffff00000000UL;
|
*reg &= 0xffffffff00000000UL;
|
||||||
*reg |= SIGP_STATUS_INCORRECT_STATE;
|
*reg |= SIGP_STATUS_INCORRECT_STATE;
|
||||||
rc = SIGP_CC_STATUS_STORED;
|
rc = SIGP_CC_STATUS_STORED;
|
||||||
kfree(inti);
|
|
||||||
goto out_li;
|
goto out_li;
|
||||||
}
|
}
|
||||||
|
|
||||||
inti->type = KVM_S390_SIGP_SET_PREFIX;
|
li->irq.prefix.address = address;
|
||||||
inti->prefix.address = address;
|
set_bit(IRQ_PEND_SET_PREFIX, &li->pending_irqs);
|
||||||
|
|
||||||
list_add_tail(&inti->list, &li->list);
|
|
||||||
atomic_set(&li->active, 1);
|
|
||||||
kvm_s390_vcpu_wakeup(dst_vcpu);
|
kvm_s390_vcpu_wakeup(dst_vcpu);
|
||||||
rc = SIGP_CC_ORDER_CODE_ACCEPTED;
|
rc = SIGP_CC_ORDER_CODE_ACCEPTED;
|
||||||
|
|
||||||
|
|
|
@ -980,6 +980,45 @@ retry:
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(set_guest_storage_key);
|
EXPORT_SYMBOL(set_guest_storage_key);
|
||||||
|
|
||||||
|
unsigned long get_guest_storage_key(struct mm_struct *mm, unsigned long addr)
|
||||||
|
{
|
||||||
|
spinlock_t *ptl;
|
||||||
|
pgste_t pgste;
|
||||||
|
pte_t *ptep;
|
||||||
|
uint64_t physaddr;
|
||||||
|
unsigned long key = 0;
|
||||||
|
|
||||||
|
down_read(&mm->mmap_sem);
|
||||||
|
ptep = get_locked_pte(mm, addr, &ptl);
|
||||||
|
if (unlikely(!ptep)) {
|
||||||
|
up_read(&mm->mmap_sem);
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
|
pgste = pgste_get_lock(ptep);
|
||||||
|
|
||||||
|
if (pte_val(*ptep) & _PAGE_INVALID) {
|
||||||
|
key |= (pgste_val(pgste) & PGSTE_ACC_BITS) >> 56;
|
||||||
|
key |= (pgste_val(pgste) & PGSTE_FP_BIT) >> 56;
|
||||||
|
key |= (pgste_val(pgste) & PGSTE_GR_BIT) >> 48;
|
||||||
|
key |= (pgste_val(pgste) & PGSTE_GC_BIT) >> 48;
|
||||||
|
} else {
|
||||||
|
physaddr = pte_val(*ptep) & PAGE_MASK;
|
||||||
|
key = page_get_storage_key(physaddr);
|
||||||
|
|
||||||
|
/* Reflect guest's logical view, not physical */
|
||||||
|
if (pgste_val(pgste) & PGSTE_GR_BIT)
|
||||||
|
key |= _PAGE_REFERENCED;
|
||||||
|
if (pgste_val(pgste) & PGSTE_GC_BIT)
|
||||||
|
key |= _PAGE_CHANGED;
|
||||||
|
}
|
||||||
|
|
||||||
|
pgste_set_unlock(ptep, pgste);
|
||||||
|
pte_unmap_unlock(ptep, ptl);
|
||||||
|
up_read(&mm->mmap_sem);
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(get_guest_storage_key);
|
||||||
|
|
||||||
#else /* CONFIG_PGSTE */
|
#else /* CONFIG_PGSTE */
|
||||||
|
|
||||||
static inline int page_table_with_pgste(struct page *page)
|
static inline int page_table_with_pgste(struct page *page)
|
||||||
|
|
Loading…
Reference in New Issue