Commit be06b6be authored by Paolo Bonzini's avatar Paolo Bonzini

Merge tag 'kvm-s390-next-20141128' of...

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.
parents 2b4a273b fc2020cf
...@@ -123,7 +123,7 @@ struct kvm_s390_sie_block { ...@@ -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 { ...@@ -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 { ...@@ -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, ...@@ -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] = { ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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;
} }
......
This diff is collapsed.
...@@ -719,7 +719,6 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, ...@@ -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, ...@@ -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, ...@@ -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); ...@@ -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); ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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 @@ int set_guest_storage_key(struct mm_struct *mm, unsigned long addr, ...@@ -980,6 +980,45 @@ int set_guest_storage_key(struct mm_struct *mm, unsigned long addr,
} }
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)
......
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