mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2025-01-19 12:16:38 +07:00
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.
This commit is contained in:
commit
be06b6bece
@ -123,7 +123,7 @@ struct kvm_s390_sie_block {
|
||||
#define ICPT_PARTEXEC 0x38
|
||||
#define ICPT_IOINST 0x40
|
||||
__u8 icptcode; /* 0x0050 */
|
||||
__u8 reserved51; /* 0x0051 */
|
||||
__u8 icptstatus; /* 0x0051 */
|
||||
__u16 ihcpu; /* 0x0052 */
|
||||
__u8 reserved54[2]; /* 0x0054 */
|
||||
__u16 ipa; /* 0x0056 */
|
||||
@ -295,6 +295,79 @@ struct kvm_vcpu_stat {
|
||||
#define PGM_PER 0x80
|
||||
#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 list_head list;
|
||||
u64 type;
|
||||
@ -313,14 +386,25 @@ struct kvm_s390_interrupt_info {
|
||||
#define ACTION_STORE_ON_STOP (1<<0)
|
||||
#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 {
|
||||
spinlock_t lock;
|
||||
struct list_head list;
|
||||
atomic_t active;
|
||||
struct kvm_s390_float_interrupt *float_int;
|
||||
wait_queue_head_t *wq;
|
||||
atomic_t *cpuflags;
|
||||
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 {
|
||||
|
@ -26,6 +26,7 @@ void page_table_reset_pgste(struct mm_struct *, unsigned long, unsigned long,
|
||||
bool init_skey);
|
||||
int set_guest_storage_key(struct mm_struct *mm, unsigned long addr,
|
||||
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)
|
||||
{
|
||||
|
@ -38,6 +38,19 @@ static const intercept_handler_t instruction_handlers[256] = {
|
||||
[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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
u16 eic = vcpu->arch.sie_block->eic;
|
||||
struct kvm_s390_interrupt irq;
|
||||
struct kvm_s390_irq irq;
|
||||
psw_t newpsw;
|
||||
int rc;
|
||||
|
||||
@ -269,7 +282,7 @@ static int handle_external_interrupt(struct kvm_vcpu *vcpu)
|
||||
if (kvm_s390_si_ext_call_pending(vcpu))
|
||||
return 0;
|
||||
irq.type = KVM_S390_INT_EXTERNAL_CALL;
|
||||
irq.parm = vcpu->arch.sie_block->extcpuaddr;
|
||||
irq.u.extcall.code = vcpu->arch.sie_block->extcpuaddr;
|
||||
break;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
@ -288,7 +301,6 @@ static int handle_external_interrupt(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;
|
||||
int reg1, reg2, rc;
|
||||
|
||||
@ -310,7 +322,7 @@ static int handle_mvpg_pei(struct kvm_vcpu *vcpu)
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
psw->addr = __rewind_psw(*psw, 4);
|
||||
kvm_s390_rewind_psw(vcpu, 4);
|
||||
|
||||
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);
|
||||
INIT_LIST_HEAD(&vcpu->arch.local_int.list);
|
||||
vcpu->arch.local_int.float_int = &kvm->arch.float_int;
|
||||
vcpu->arch.local_int.wq = &vcpu->wq;
|
||||
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)
|
||||
{
|
||||
struct kvm_s390_interrupt inti;
|
||||
inti.parm64 = token;
|
||||
struct kvm_s390_irq irq;
|
||||
|
||||
if (start_token) {
|
||||
inti.type = KVM_S390_INT_PFAULT_INIT;
|
||||
WARN_ON_ONCE(kvm_s390_inject_vcpu(vcpu, &inti));
|
||||
irq.u.ext.ext_params2 = token;
|
||||
irq.type = KVM_S390_INT_PFAULT_INIT;
|
||||
WARN_ON_ONCE(kvm_s390_inject_vcpu(vcpu, &irq));
|
||||
} else {
|
||||
inti.type = KVM_S390_INT_PFAULT_DONE;
|
||||
inti.parm64 = token;
|
||||
WARN_ON_ONCE(kvm_s390_inject_vm(vcpu->kvm, &inti));
|
||||
}
|
||||
}
|
||||
@ -1622,11 +1623,14 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
|
||||
switch (ioctl) {
|
||||
case KVM_S390_INTERRUPT: {
|
||||
struct kvm_s390_interrupt s390int;
|
||||
struct kvm_s390_irq s390irq;
|
||||
|
||||
r = -EFAULT;
|
||||
if (copy_from_user(&s390int, argp, sizeof(s390int)))
|
||||
break;
|
||||
r = kvm_s390_inject_vcpu(vcpu, &s390int);
|
||||
if (s390int_to_s390irq(&s390int, &s390irq))
|
||||
return -EINVAL;
|
||||
r = kvm_s390_inject_vcpu(vcpu, &s390irq);
|
||||
break;
|
||||
}
|
||||
case KVM_S390_STORE_STATUS:
|
||||
|
@ -24,8 +24,6 @@ typedef int (*intercept_handler_t)(struct kvm_vcpu *vcpu);
|
||||
/* declare vfacilities extern */
|
||||
extern unsigned long *vfacilities;
|
||||
|
||||
int kvm_handle_sie_intercept(struct kvm_vcpu *vcpu);
|
||||
|
||||
/* Transactional Memory Execution related macros */
|
||||
#define IS_TE_ENABLED(vcpu) ((vcpu->arch.sie_block->ecb & 0x10))
|
||||
#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,
|
||||
struct kvm_s390_interrupt *s390int);
|
||||
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);
|
||||
struct kvm_s390_interrupt_info *kvm_s390_get_io_int(struct kvm *kvm,
|
||||
u64 cr6, u64 schid);
|
||||
@ -152,6 +150,10 @@ void kvm_s390_reinject_io_int(struct kvm *kvm,
|
||||
struct kvm_s390_interrupt_info *inti);
|
||||
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 */
|
||||
int is_valid_psw(psw_t *psw);
|
||||
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);
|
||||
}
|
||||
|
||||
int s390int_to_s390irq(struct kvm_s390_interrupt *s390int,
|
||||
struct kvm_s390_irq *s390irq);
|
||||
|
||||
/* implemented in interrupt.c */
|
||||
int kvm_cpu_has_interrupt(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)
|
||||
return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
|
||||
|
||||
vcpu->arch.sie_block->gpsw.addr =
|
||||
__rewind_psw(vcpu->arch.sie_block->gpsw, 4);
|
||||
kvm_s390_rewind_psw(vcpu, 4);
|
||||
VCPU_EVENT(vcpu, 4, "%s", "retrying storage key operation");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int handle_ipte_interlock(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
psw_t *psw = &vcpu->arch.sie_block->gpsw;
|
||||
|
||||
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);
|
||||
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");
|
||||
return 0;
|
||||
}
|
||||
@ -646,10 +643,7 @@ static int handle_pfmf(struct kvm_vcpu *vcpu)
|
||||
return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
|
||||
|
||||
start = vcpu->run->s.regs.gprs[reg2] & PAGE_MASK;
|
||||
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);
|
||||
}
|
||||
start = kvm_s390_logical_to_effective(vcpu, start);
|
||||
|
||||
switch (vcpu->run->s.regs.gprs[reg1] & PFMF_FSC) {
|
||||
case 0x00000000:
|
||||
@ -665,6 +659,12 @@ static int handle_pfmf(struct kvm_vcpu *vcpu)
|
||||
default:
|
||||
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) {
|
||||
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);
|
||||
|
||||
/* Rewind PSW to repeat the ESSA instruction */
|
||||
vcpu->arch.sie_block->gpsw.addr =
|
||||
__rewind_psw(vcpu->arch.sie_block->gpsw, 4);
|
||||
kvm_s390_rewind_psw(vcpu, 4);
|
||||
vcpu->arch.sie_block->cbrlo &= PAGE_MASK; /* reset nceo */
|
||||
cbrlo = phys_to_virt(vcpu->arch.sie_block->cbrlo);
|
||||
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,
|
||||
struct kvm_vcpu *dst_vcpu)
|
||||
{
|
||||
struct kvm_s390_interrupt s390int = {
|
||||
struct kvm_s390_irq irq = {
|
||||
.type = KVM_S390_INT_EMERGENCY,
|
||||
.parm = vcpu->vcpu_id,
|
||||
.u.emerg.code = vcpu->vcpu_id,
|
||||
};
|
||||
int rc = 0;
|
||||
|
||||
rc = kvm_s390_inject_vcpu(dst_vcpu, &s390int);
|
||||
rc = kvm_s390_inject_vcpu(dst_vcpu, &irq);
|
||||
if (!rc)
|
||||
VCPU_EVENT(vcpu, 4, "sent sigp emerg to cpu %x",
|
||||
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,
|
||||
struct kvm_vcpu *dst_vcpu)
|
||||
{
|
||||
struct kvm_s390_interrupt s390int = {
|
||||
struct kvm_s390_irq irq = {
|
||||
.type = KVM_S390_INT_EXTERNAL_CALL,
|
||||
.parm = vcpu->vcpu_id,
|
||||
.u.extcall.code = vcpu->vcpu_id,
|
||||
};
|
||||
int rc;
|
||||
|
||||
rc = kvm_s390_inject_vcpu(dst_vcpu, &s390int);
|
||||
rc = kvm_s390_inject_vcpu(dst_vcpu, &irq);
|
||||
if (!rc)
|
||||
VCPU_EVENT(vcpu, 4, "sent sigp ext call to cpu %x",
|
||||
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)
|
||||
{
|
||||
struct kvm_s390_local_interrupt *li = &dst_vcpu->arch.local_int;
|
||||
struct kvm_s390_interrupt_info *inti;
|
||||
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);
|
||||
if (li->action_bits & ACTION_STOP_ON_STOP) {
|
||||
/* another SIGP STOP is pending */
|
||||
kfree(inti);
|
||||
rc = SIGP_CC_BUSY;
|
||||
goto out;
|
||||
}
|
||||
if ((atomic_read(li->cpuflags) & CPUSTAT_STOPPED)) {
|
||||
kfree(inti);
|
||||
if ((action & ACTION_STORE_ON_STOP) != 0)
|
||||
rc = -ESHUTDOWN;
|
||||
goto out;
|
||||
}
|
||||
list_add_tail(&inti->list, &li->list);
|
||||
atomic_set(&li->active, 1);
|
||||
set_bit(IRQ_PEND_SIGP_STOP, &li->pending_irqs);
|
||||
li->action_bits |= action;
|
||||
atomic_set_mask(CPUSTAT_STOP_INT, li->cpuflags);
|
||||
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)
|
||||
{
|
||||
struct kvm_s390_local_interrupt *li;
|
||||
struct kvm_s390_interrupt_info *inti;
|
||||
int rc;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
inti = kzalloc(sizeof(*inti), GFP_KERNEL);
|
||||
if (!inti)
|
||||
return SIGP_CC_BUSY;
|
||||
|
||||
spin_lock(&li->lock);
|
||||
/* cpu must be in stopped state */
|
||||
if (!(atomic_read(li->cpuflags) & CPUSTAT_STOPPED)) {
|
||||
*reg &= 0xffffffff00000000UL;
|
||||
*reg |= SIGP_STATUS_INCORRECT_STATE;
|
||||
rc = SIGP_CC_STATUS_STORED;
|
||||
kfree(inti);
|
||||
goto out_li;
|
||||
}
|
||||
|
||||
inti->type = KVM_S390_SIGP_SET_PREFIX;
|
||||
inti->prefix.address = address;
|
||||
|
||||
list_add_tail(&inti->list, &li->list);
|
||||
atomic_set(&li->active, 1);
|
||||
li->irq.prefix.address = address;
|
||||
set_bit(IRQ_PEND_SET_PREFIX, &li->pending_irqs);
|
||||
kvm_s390_vcpu_wakeup(dst_vcpu);
|
||||
rc = SIGP_CC_ORDER_CODE_ACCEPTED;
|
||||
|
||||
|
@ -980,6 +980,45 @@ int set_guest_storage_key(struct mm_struct *mm, unsigned long addr,
|
||||
}
|
||||
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 */
|
||||
|
||||
static inline int page_table_with_pgste(struct page *page)
|
||||
|
Loading…
Reference in New Issue
Block a user