1
0
Fork 0

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
Paolo Bonzini 2014-12-03 15:20:11 +01:00
commit be06b6bece
9 changed files with 879 additions and 406 deletions

View File

@ -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 {

View File

@ -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)
{ {

View File

@ -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

View File

@ -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:

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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)