2017-11-24 14:00:33 +00:00
|
|
|
// SPDX-License-Identifier: GPL-2.0
|
2008-03-25 17:47:23 +00:00
|
|
|
/*
|
2012-07-20 09:15:04 +00:00
|
|
|
* in-kernel handling for sie intercepts
|
2008-03-25 17:47:23 +00:00
|
|
|
*
|
2019-04-01 08:54:09 +00:00
|
|
|
* Copyright IBM Corp. 2008, 2020
|
2008-03-25 17:47:23 +00:00
|
|
|
*
|
|
|
|
* Author(s): Carsten Otte <cotte@de.ibm.com>
|
|
|
|
* Christian Borntraeger <borntraeger@de.ibm.com>
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <linux/kvm_host.h>
|
|
|
|
#include <linux/errno.h>
|
|
|
|
#include <linux/pagemap.h>
|
|
|
|
|
2014-03-13 18:29:09 +00:00
|
|
|
#include <asm/asm-offsets.h>
|
2014-01-15 15:46:07 +00:00
|
|
|
#include <asm/irq.h>
|
2017-09-29 10:41:50 +00:00
|
|
|
#include <asm/sysinfo.h>
|
2020-01-31 20:00:39 +00:00
|
|
|
#include <asm/uv.h>
|
2008-03-25 17:47:23 +00:00
|
|
|
|
|
|
|
#include "kvm-s390.h"
|
KVM: s390: interrupt subsystem, cpu timer, waitpsw
This patch contains the s390 interrupt subsystem (similar to in kernel apic)
including timer interrupts (similar to in-kernel-pit) and enabled wait
(similar to in kernel hlt).
In order to achieve that, this patch also introduces intercept handling
for instruction intercepts, and it implements load control instructions.
This patch introduces an ioctl KVM_S390_INTERRUPT which is valid for both
the vm file descriptors and the vcpu file descriptors. In case this ioctl is
issued against a vm file descriptor, the interrupt is considered floating.
Floating interrupts may be delivered to any virtual cpu in the configuration.
The following interrupts are supported:
SIGP STOP - interprocessor signal that stops a remote cpu
SIGP SET PREFIX - interprocessor signal that sets the prefix register of a
(stopped) remote cpu
INT EMERGENCY - interprocessor interrupt, usually used to signal need_reshed
and for smp_call_function() in the guest.
PROGRAM INT - exception during program execution such as page fault, illegal
instruction and friends
RESTART - interprocessor signal that starts a stopped cpu
INT VIRTIO - floating interrupt for virtio signalisation
INT SERVICE - floating interrupt for signalisations from the system
service processor
struct kvm_s390_interrupt, which is submitted as ioctl parameter when injecting
an interrupt, also carrys parameter data for interrupts along with the interrupt
type. Interrupts on s390 usually have a state that represents the current
operation, or identifies which device has caused the interruption on s390.
kvm_s390_handle_wait() does handle waitpsw in two flavors: in case of a
disabled wait (that is, disabled for interrupts), we exit to userspace. In case
of an enabled wait we set up a timer that equals the cpu clock comparator value
and sleep on a wait queue.
[christian: change virtio interrupt to 0x2603]
Acked-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: Carsten Otte <cotte@de.ibm.com>
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
Signed-off-by: Avi Kivity <avi@qumranet.com>
2008-03-25 17:47:26 +00:00
|
|
|
#include "gaccess.h"
|
2012-07-23 15:20:29 +00:00
|
|
|
#include "trace.h"
|
2012-07-23 15:20:30 +00:00
|
|
|
#include "trace-s390.h"
|
KVM: s390: interrupt subsystem, cpu timer, waitpsw
This patch contains the s390 interrupt subsystem (similar to in kernel apic)
including timer interrupts (similar to in-kernel-pit) and enabled wait
(similar to in kernel hlt).
In order to achieve that, this patch also introduces intercept handling
for instruction intercepts, and it implements load control instructions.
This patch introduces an ioctl KVM_S390_INTERRUPT which is valid for both
the vm file descriptors and the vcpu file descriptors. In case this ioctl is
issued against a vm file descriptor, the interrupt is considered floating.
Floating interrupts may be delivered to any virtual cpu in the configuration.
The following interrupts are supported:
SIGP STOP - interprocessor signal that stops a remote cpu
SIGP SET PREFIX - interprocessor signal that sets the prefix register of a
(stopped) remote cpu
INT EMERGENCY - interprocessor interrupt, usually used to signal need_reshed
and for smp_call_function() in the guest.
PROGRAM INT - exception during program execution such as page fault, illegal
instruction and friends
RESTART - interprocessor signal that starts a stopped cpu
INT VIRTIO - floating interrupt for virtio signalisation
INT SERVICE - floating interrupt for signalisations from the system
service processor
struct kvm_s390_interrupt, which is submitted as ioctl parameter when injecting
an interrupt, also carrys parameter data for interrupts along with the interrupt
type. Interrupts on s390 usually have a state that represents the current
operation, or identifies which device has caused the interruption on s390.
kvm_s390_handle_wait() does handle waitpsw in two flavors: in case of a
disabled wait (that is, disabled for interrupts), we exit to userspace. In case
of an enabled wait we set up a timer that equals the cpu clock comparator value
and sleep on a wait queue.
[christian: change virtio interrupt to 0x2603]
Acked-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: Carsten Otte <cotte@de.ibm.com>
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
Signed-off-by: Avi Kivity <avi@qumranet.com>
2008-03-25 17:47:26 +00:00
|
|
|
|
2015-11-04 12:47:58 +00:00
|
|
|
u8 kvm_s390_get_ilen(struct kvm_vcpu *vcpu)
|
2014-11-12 16:13:29 +00:00
|
|
|
{
|
|
|
|
struct kvm_s390_sie_block *sie_block = vcpu->arch.sie_block;
|
2015-11-04 12:47:58 +00:00
|
|
|
u8 ilen = 0;
|
2014-11-12 16:13:29 +00:00
|
|
|
|
2015-11-04 12:47:58 +00:00
|
|
|
switch (vcpu->arch.sie_block->icptcode) {
|
|
|
|
case ICPT_INST:
|
|
|
|
case ICPT_INSTPROGI:
|
|
|
|
case ICPT_OPEREXC:
|
|
|
|
case ICPT_PARTEXEC:
|
|
|
|
case ICPT_IOINST:
|
|
|
|
/* instruction only stored for these icptcodes */
|
|
|
|
ilen = insn_length(vcpu->arch.sie_block->ipa >> 8);
|
|
|
|
/* Use the length of the EXECUTE instruction if necessary */
|
|
|
|
if (sie_block->icptstatus & 1) {
|
|
|
|
ilen = (sie_block->icptstatus >> 4) & 0x6;
|
|
|
|
if (!ilen)
|
|
|
|
ilen = 4;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case ICPT_PROGI:
|
|
|
|
/* bit 1+2 of pgmilc are the ilc, so we directly get ilen */
|
|
|
|
ilen = vcpu->arch.sie_block->pgmilc & 0x6;
|
|
|
|
break;
|
2014-11-12 16:13:29 +00:00
|
|
|
}
|
2015-11-04 12:47:58 +00:00
|
|
|
return ilen;
|
2014-11-12 16:13:29 +00:00
|
|
|
}
|
|
|
|
|
2008-03-25 17:47:23 +00:00
|
|
|
static int handle_stop(struct kvm_vcpu *vcpu)
|
|
|
|
{
|
2014-10-15 14:48:53 +00:00
|
|
|
struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
|
2009-05-20 13:34:55 +00:00
|
|
|
int rc = 0;
|
2014-10-15 14:48:53 +00:00
|
|
|
uint8_t flags, stop_pending;
|
2008-03-25 17:47:31 +00:00
|
|
|
|
2008-03-25 17:47:23 +00:00
|
|
|
vcpu->stat.exit_stop_request++;
|
2012-07-23 15:20:30 +00:00
|
|
|
|
2014-08-05 15:40:47 +00:00
|
|
|
/* delay the stop if any non-stop irq is pending */
|
|
|
|
if (kvm_s390_vcpu_has_irq(vcpu, 1))
|
|
|
|
return 0;
|
|
|
|
|
2014-10-15 14:48:53 +00:00
|
|
|
/* avoid races with the injection/SIGP STOP code */
|
|
|
|
spin_lock(&li->lock);
|
|
|
|
flags = li->irq.stop.flags;
|
|
|
|
stop_pending = kvm_s390_is_stop_irq_pending(vcpu);
|
|
|
|
spin_unlock(&li->lock);
|
2014-04-14 10:40:03 +00:00
|
|
|
|
2014-10-15 14:48:53 +00:00
|
|
|
trace_kvm_s390_stop_request(stop_pending, flags);
|
|
|
|
if (!stop_pending)
|
2014-04-14 10:40:03 +00:00
|
|
|
return 0;
|
2009-05-20 13:34:55 +00:00
|
|
|
|
2014-10-15 14:48:53 +00:00
|
|
|
if (flags & KVM_S390_STOP_FLAG_STORE_STATUS) {
|
2012-02-06 09:59:03 +00:00
|
|
|
rc = kvm_s390_vcpu_store_status(vcpu,
|
|
|
|
KVM_S390_STORE_STATUS_NOADDR);
|
2014-04-14 10:40:03 +00:00
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2019-05-15 11:24:30 +00:00
|
|
|
/*
|
|
|
|
* no need to check the return value of vcpu_stop as it can only have
|
|
|
|
* an error for protvirt, but protvirt means user cpu state
|
|
|
|
*/
|
2014-04-10 15:35:00 +00:00
|
|
|
if (!kvm_s390_user_cpu_state_ctrl(vcpu->kvm))
|
|
|
|
kvm_s390_vcpu_stop(vcpu);
|
2014-04-14 10:40:03 +00:00
|
|
|
return -EOPNOTSUPP;
|
2008-03-25 17:47:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int handle_validity(struct kvm_vcpu *vcpu)
|
|
|
|
{
|
|
|
|
int viwhy = vcpu->arch.sie_block->ipb >> 16;
|
2009-05-12 15:21:52 +00:00
|
|
|
|
2008-03-25 17:47:23 +00:00
|
|
|
vcpu->stat.exit_validity++;
|
2012-07-23 15:20:29 +00:00
|
|
|
trace_kvm_s390_intercept_validity(vcpu, viwhy);
|
2016-09-28 14:18:47 +00:00
|
|
|
KVM_EVENT(3, "validity intercept 0x%x for pid %u (kvm 0x%pK)", viwhy,
|
|
|
|
current->pid, vcpu->kvm);
|
|
|
|
|
|
|
|
/* do not warn on invalid runtime instrumentation mode */
|
|
|
|
WARN_ONCE(viwhy != 0x44, "kvm: unhandled validity intercept 0x%x\n",
|
|
|
|
viwhy);
|
|
|
|
return -EINVAL;
|
2008-03-25 17:47:23 +00:00
|
|
|
}
|
|
|
|
|
KVM: s390: interrupt subsystem, cpu timer, waitpsw
This patch contains the s390 interrupt subsystem (similar to in kernel apic)
including timer interrupts (similar to in-kernel-pit) and enabled wait
(similar to in kernel hlt).
In order to achieve that, this patch also introduces intercept handling
for instruction intercepts, and it implements load control instructions.
This patch introduces an ioctl KVM_S390_INTERRUPT which is valid for both
the vm file descriptors and the vcpu file descriptors. In case this ioctl is
issued against a vm file descriptor, the interrupt is considered floating.
Floating interrupts may be delivered to any virtual cpu in the configuration.
The following interrupts are supported:
SIGP STOP - interprocessor signal that stops a remote cpu
SIGP SET PREFIX - interprocessor signal that sets the prefix register of a
(stopped) remote cpu
INT EMERGENCY - interprocessor interrupt, usually used to signal need_reshed
and for smp_call_function() in the guest.
PROGRAM INT - exception during program execution such as page fault, illegal
instruction and friends
RESTART - interprocessor signal that starts a stopped cpu
INT VIRTIO - floating interrupt for virtio signalisation
INT SERVICE - floating interrupt for signalisations from the system
service processor
struct kvm_s390_interrupt, which is submitted as ioctl parameter when injecting
an interrupt, also carrys parameter data for interrupts along with the interrupt
type. Interrupts on s390 usually have a state that represents the current
operation, or identifies which device has caused the interruption on s390.
kvm_s390_handle_wait() does handle waitpsw in two flavors: in case of a
disabled wait (that is, disabled for interrupts), we exit to userspace. In case
of an enabled wait we set up a timer that equals the cpu clock comparator value
and sleep on a wait queue.
[christian: change virtio interrupt to 0x2603]
Acked-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: Carsten Otte <cotte@de.ibm.com>
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
Signed-off-by: Avi Kivity <avi@qumranet.com>
2008-03-25 17:47:26 +00:00
|
|
|
static int handle_instruction(struct kvm_vcpu *vcpu)
|
|
|
|
{
|
|
|
|
vcpu->stat.exit_instruction++;
|
2012-07-23 15:20:29 +00:00
|
|
|
trace_kvm_s390_intercept_instruction(vcpu,
|
|
|
|
vcpu->arch.sie_block->ipa,
|
|
|
|
vcpu->arch.sie_block->ipb);
|
2018-02-06 10:19:28 +00:00
|
|
|
|
|
|
|
switch (vcpu->arch.sie_block->ipa >> 8) {
|
|
|
|
case 0x01:
|
|
|
|
return kvm_s390_handle_01(vcpu);
|
|
|
|
case 0x82:
|
|
|
|
return kvm_s390_handle_lpsw(vcpu);
|
|
|
|
case 0x83:
|
|
|
|
return kvm_s390_handle_diag(vcpu);
|
|
|
|
case 0xaa:
|
|
|
|
return kvm_s390_handle_aa(vcpu);
|
|
|
|
case 0xae:
|
|
|
|
return kvm_s390_handle_sigp(vcpu);
|
|
|
|
case 0xb2:
|
|
|
|
return kvm_s390_handle_b2(vcpu);
|
|
|
|
case 0xb6:
|
|
|
|
return kvm_s390_handle_stctl(vcpu);
|
|
|
|
case 0xb7:
|
|
|
|
return kvm_s390_handle_lctl(vcpu);
|
|
|
|
case 0xb9:
|
|
|
|
return kvm_s390_handle_b9(vcpu);
|
|
|
|
case 0xe3:
|
|
|
|
return kvm_s390_handle_e3(vcpu);
|
|
|
|
case 0xe5:
|
|
|
|
return kvm_s390_handle_e5(vcpu);
|
|
|
|
case 0xeb:
|
|
|
|
return kvm_s390_handle_eb(vcpu);
|
|
|
|
default:
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
}
|
KVM: s390: interrupt subsystem, cpu timer, waitpsw
This patch contains the s390 interrupt subsystem (similar to in kernel apic)
including timer interrupts (similar to in-kernel-pit) and enabled wait
(similar to in kernel hlt).
In order to achieve that, this patch also introduces intercept handling
for instruction intercepts, and it implements load control instructions.
This patch introduces an ioctl KVM_S390_INTERRUPT which is valid for both
the vm file descriptors and the vcpu file descriptors. In case this ioctl is
issued against a vm file descriptor, the interrupt is considered floating.
Floating interrupts may be delivered to any virtual cpu in the configuration.
The following interrupts are supported:
SIGP STOP - interprocessor signal that stops a remote cpu
SIGP SET PREFIX - interprocessor signal that sets the prefix register of a
(stopped) remote cpu
INT EMERGENCY - interprocessor interrupt, usually used to signal need_reshed
and for smp_call_function() in the guest.
PROGRAM INT - exception during program execution such as page fault, illegal
instruction and friends
RESTART - interprocessor signal that starts a stopped cpu
INT VIRTIO - floating interrupt for virtio signalisation
INT SERVICE - floating interrupt for signalisations from the system
service processor
struct kvm_s390_interrupt, which is submitted as ioctl parameter when injecting
an interrupt, also carrys parameter data for interrupts along with the interrupt
type. Interrupts on s390 usually have a state that represents the current
operation, or identifies which device has caused the interruption on s390.
kvm_s390_handle_wait() does handle waitpsw in two flavors: in case of a
disabled wait (that is, disabled for interrupts), we exit to userspace. In case
of an enabled wait we set up a timer that equals the cpu clock comparator value
and sleep on a wait queue.
[christian: change virtio interrupt to 0x2603]
Acked-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: Carsten Otte <cotte@de.ibm.com>
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
Signed-off-by: Avi Kivity <avi@qumranet.com>
2008-03-25 17:47:26 +00:00
|
|
|
}
|
|
|
|
|
2015-11-04 15:22:19 +00:00
|
|
|
static int inject_prog_on_prog_intercept(struct kvm_vcpu *vcpu)
|
2014-03-03 09:54:33 +00:00
|
|
|
{
|
2015-11-04 15:22:19 +00:00
|
|
|
struct kvm_s390_pgm_info pgm_info = {
|
|
|
|
.code = vcpu->arch.sie_block->iprcc,
|
2015-11-04 15:46:55 +00:00
|
|
|
/* the PSW has already been rewound */
|
|
|
|
.flags = KVM_S390_PGM_FLAGS_NO_REWIND,
|
2015-11-04 15:22:19 +00:00
|
|
|
};
|
2014-03-03 09:54:33 +00:00
|
|
|
|
|
|
|
switch (vcpu->arch.sie_block->iprcc & ~PGM_PER) {
|
|
|
|
case PGM_AFX_TRANSLATION:
|
|
|
|
case PGM_ASX_TRANSLATION:
|
|
|
|
case PGM_EX_TRANSLATION:
|
|
|
|
case PGM_LFX_TRANSLATION:
|
|
|
|
case PGM_LSTE_SEQUENCE:
|
|
|
|
case PGM_LSX_TRANSLATION:
|
|
|
|
case PGM_LX_TRANSLATION:
|
|
|
|
case PGM_PRIMARY_AUTHORITY:
|
|
|
|
case PGM_SECONDARY_AUTHORITY:
|
|
|
|
case PGM_SPACE_SWITCH:
|
2015-11-04 15:22:19 +00:00
|
|
|
pgm_info.trans_exc_code = vcpu->arch.sie_block->tecmc;
|
2014-03-03 09:54:33 +00:00
|
|
|
break;
|
|
|
|
case PGM_ALEN_TRANSLATION:
|
|
|
|
case PGM_ALE_SEQUENCE:
|
|
|
|
case PGM_ASTE_INSTANCE:
|
|
|
|
case PGM_ASTE_SEQUENCE:
|
|
|
|
case PGM_ASTE_VALIDITY:
|
|
|
|
case PGM_EXTENDED_AUTHORITY:
|
2015-11-04 15:22:19 +00:00
|
|
|
pgm_info.exc_access_id = vcpu->arch.sie_block->eai;
|
2014-03-03 09:54:33 +00:00
|
|
|
break;
|
|
|
|
case PGM_ASCE_TYPE:
|
|
|
|
case PGM_PAGE_TRANSLATION:
|
|
|
|
case PGM_REGION_FIRST_TRANS:
|
|
|
|
case PGM_REGION_SECOND_TRANS:
|
|
|
|
case PGM_REGION_THIRD_TRANS:
|
|
|
|
case PGM_SEGMENT_TRANSLATION:
|
2015-11-04 15:22:19 +00:00
|
|
|
pgm_info.trans_exc_code = vcpu->arch.sie_block->tecmc;
|
|
|
|
pgm_info.exc_access_id = vcpu->arch.sie_block->eai;
|
|
|
|
pgm_info.op_access_id = vcpu->arch.sie_block->oai;
|
2014-03-03 09:54:33 +00:00
|
|
|
break;
|
|
|
|
case PGM_MONITOR:
|
2015-11-04 15:22:19 +00:00
|
|
|
pgm_info.mon_class_nr = vcpu->arch.sie_block->mcn;
|
|
|
|
pgm_info.mon_code = vcpu->arch.sie_block->tecmc;
|
2014-03-03 09:54:33 +00:00
|
|
|
break;
|
2015-02-02 20:01:06 +00:00
|
|
|
case PGM_VECTOR_PROCESSING:
|
2014-03-03 09:54:33 +00:00
|
|
|
case PGM_DATA:
|
2015-11-04 15:22:19 +00:00
|
|
|
pgm_info.data_exc_code = vcpu->arch.sie_block->dxc;
|
2014-03-03 09:54:33 +00:00
|
|
|
break;
|
|
|
|
case PGM_PROTECTION:
|
2015-11-04 15:22:19 +00:00
|
|
|
pgm_info.trans_exc_code = vcpu->arch.sie_block->tecmc;
|
|
|
|
pgm_info.exc_access_id = vcpu->arch.sie_block->eai;
|
2014-03-03 09:54:33 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (vcpu->arch.sie_block->iprcc & PGM_PER) {
|
2015-11-04 15:22:19 +00:00
|
|
|
pgm_info.per_code = vcpu->arch.sie_block->perc;
|
|
|
|
pgm_info.per_atmid = vcpu->arch.sie_block->peratmid;
|
|
|
|
pgm_info.per_address = vcpu->arch.sie_block->peraddr;
|
|
|
|
pgm_info.per_access_id = vcpu->arch.sie_block->peraid;
|
2014-03-03 09:54:33 +00:00
|
|
|
}
|
2015-11-04 15:22:19 +00:00
|
|
|
return kvm_s390_inject_prog_irq(vcpu, &pgm_info);
|
2014-03-03 09:54:33 +00:00
|
|
|
}
|
|
|
|
|
2014-03-13 11:16:45 +00:00
|
|
|
/*
|
|
|
|
* restore ITDB to program-interruption TDB in guest lowcore
|
|
|
|
* and set TX abort indication if required
|
|
|
|
*/
|
|
|
|
static int handle_itdb(struct kvm_vcpu *vcpu)
|
|
|
|
{
|
|
|
|
struct kvm_s390_itdb *itdb;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
if (!IS_TE_ENABLED(vcpu) || !IS_ITDB_VALID(vcpu))
|
|
|
|
return 0;
|
|
|
|
if (current->thread.per_flags & PER_FLAG_NO_TE)
|
|
|
|
return 0;
|
2022-10-20 14:31:57 +00:00
|
|
|
itdb = phys_to_virt(vcpu->arch.sie_block->itdba);
|
2014-03-13 11:16:45 +00:00
|
|
|
rc = write_guest_lc(vcpu, __LC_PGM_TDB, itdb, sizeof(*itdb));
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
memset(itdb, 0, sizeof(*itdb));
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-01-23 11:26:52 +00:00
|
|
|
#define per_event(vcpu) (vcpu->arch.sie_block->iprcc & PGM_PER)
|
|
|
|
|
2023-07-25 14:37:17 +00:00
|
|
|
static bool should_handle_per_event(const struct kvm_vcpu *vcpu)
|
|
|
|
{
|
|
|
|
if (!guestdbg_enabled(vcpu) || !per_event(vcpu))
|
|
|
|
return false;
|
|
|
|
if (guestdbg_sstep_enabled(vcpu) &&
|
|
|
|
vcpu->arch.sie_block->iprcc != PGM_PER) {
|
|
|
|
/*
|
|
|
|
* __vcpu_run() will exit after delivering the concurrently
|
|
|
|
* indicated condition.
|
|
|
|
*/
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
KVM: s390: interrupt subsystem, cpu timer, waitpsw
This patch contains the s390 interrupt subsystem (similar to in kernel apic)
including timer interrupts (similar to in-kernel-pit) and enabled wait
(similar to in kernel hlt).
In order to achieve that, this patch also introduces intercept handling
for instruction intercepts, and it implements load control instructions.
This patch introduces an ioctl KVM_S390_INTERRUPT which is valid for both
the vm file descriptors and the vcpu file descriptors. In case this ioctl is
issued against a vm file descriptor, the interrupt is considered floating.
Floating interrupts may be delivered to any virtual cpu in the configuration.
The following interrupts are supported:
SIGP STOP - interprocessor signal that stops a remote cpu
SIGP SET PREFIX - interprocessor signal that sets the prefix register of a
(stopped) remote cpu
INT EMERGENCY - interprocessor interrupt, usually used to signal need_reshed
and for smp_call_function() in the guest.
PROGRAM INT - exception during program execution such as page fault, illegal
instruction and friends
RESTART - interprocessor signal that starts a stopped cpu
INT VIRTIO - floating interrupt for virtio signalisation
INT SERVICE - floating interrupt for signalisations from the system
service processor
struct kvm_s390_interrupt, which is submitted as ioctl parameter when injecting
an interrupt, also carrys parameter data for interrupts along with the interrupt
type. Interrupts on s390 usually have a state that represents the current
operation, or identifies which device has caused the interruption on s390.
kvm_s390_handle_wait() does handle waitpsw in two flavors: in case of a
disabled wait (that is, disabled for interrupts), we exit to userspace. In case
of an enabled wait we set up a timer that equals the cpu clock comparator value
and sleep on a wait queue.
[christian: change virtio interrupt to 0x2603]
Acked-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: Carsten Otte <cotte@de.ibm.com>
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
Signed-off-by: Avi Kivity <avi@qumranet.com>
2008-03-25 17:47:26 +00:00
|
|
|
static int handle_prog(struct kvm_vcpu *vcpu)
|
|
|
|
{
|
2014-04-17 07:57:10 +00:00
|
|
|
psw_t psw;
|
2014-01-01 15:37:47 +00:00
|
|
|
int rc;
|
|
|
|
|
KVM: s390: interrupt subsystem, cpu timer, waitpsw
This patch contains the s390 interrupt subsystem (similar to in kernel apic)
including timer interrupts (similar to in-kernel-pit) and enabled wait
(similar to in kernel hlt).
In order to achieve that, this patch also introduces intercept handling
for instruction intercepts, and it implements load control instructions.
This patch introduces an ioctl KVM_S390_INTERRUPT which is valid for both
the vm file descriptors and the vcpu file descriptors. In case this ioctl is
issued against a vm file descriptor, the interrupt is considered floating.
Floating interrupts may be delivered to any virtual cpu in the configuration.
The following interrupts are supported:
SIGP STOP - interprocessor signal that stops a remote cpu
SIGP SET PREFIX - interprocessor signal that sets the prefix register of a
(stopped) remote cpu
INT EMERGENCY - interprocessor interrupt, usually used to signal need_reshed
and for smp_call_function() in the guest.
PROGRAM INT - exception during program execution such as page fault, illegal
instruction and friends
RESTART - interprocessor signal that starts a stopped cpu
INT VIRTIO - floating interrupt for virtio signalisation
INT SERVICE - floating interrupt for signalisations from the system
service processor
struct kvm_s390_interrupt, which is submitted as ioctl parameter when injecting
an interrupt, also carrys parameter data for interrupts along with the interrupt
type. Interrupts on s390 usually have a state that represents the current
operation, or identifies which device has caused the interruption on s390.
kvm_s390_handle_wait() does handle waitpsw in two flavors: in case of a
disabled wait (that is, disabled for interrupts), we exit to userspace. In case
of an enabled wait we set up a timer that equals the cpu clock comparator value
and sleep on a wait queue.
[christian: change virtio interrupt to 0x2603]
Acked-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: Carsten Otte <cotte@de.ibm.com>
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
Signed-off-by: Avi Kivity <avi@qumranet.com>
2008-03-25 17:47:26 +00:00
|
|
|
vcpu->stat.exit_program_interruption++;
|
2013-06-28 11:30:24 +00:00
|
|
|
|
2019-06-06 08:09:15 +00:00
|
|
|
/*
|
|
|
|
* Intercept 8 indicates a loop of specification exceptions
|
|
|
|
* for protected guests.
|
|
|
|
*/
|
|
|
|
if (kvm_s390_pv_cpu_is_protected(vcpu))
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
2023-07-25 14:37:17 +00:00
|
|
|
if (should_handle_per_event(vcpu)) {
|
2016-05-24 10:40:11 +00:00
|
|
|
rc = kvm_s390_handle_per_event(vcpu);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
2014-01-23 11:26:52 +00:00
|
|
|
/* the interrupt might have been filtered out completely */
|
|
|
|
if (vcpu->arch.sie_block->iprcc == 0)
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-03-13 11:16:45 +00:00
|
|
|
trace_kvm_s390_intercept_prog(vcpu, vcpu->arch.sie_block->iprcc);
|
2014-04-17 07:57:10 +00:00
|
|
|
if (vcpu->arch.sie_block->iprcc == PGM_SPECIFICATION) {
|
|
|
|
rc = read_guest_lc(vcpu, __LC_PGM_NEW_PSW, &psw, sizeof(psw_t));
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
/* Avoid endless loops of specification exceptions */
|
|
|
|
if (!is_valid_psw(&psw))
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
}
|
2014-03-13 11:16:45 +00:00
|
|
|
rc = handle_itdb(vcpu);
|
2014-01-01 15:37:47 +00:00
|
|
|
if (rc)
|
|
|
|
return rc;
|
2014-03-03 09:54:33 +00:00
|
|
|
|
2015-11-04 15:22:19 +00:00
|
|
|
return inject_prog_on_prog_intercept(vcpu);
|
KVM: s390: interrupt subsystem, cpu timer, waitpsw
This patch contains the s390 interrupt subsystem (similar to in kernel apic)
including timer interrupts (similar to in-kernel-pit) and enabled wait
(similar to in kernel hlt).
In order to achieve that, this patch also introduces intercept handling
for instruction intercepts, and it implements load control instructions.
This patch introduces an ioctl KVM_S390_INTERRUPT which is valid for both
the vm file descriptors and the vcpu file descriptors. In case this ioctl is
issued against a vm file descriptor, the interrupt is considered floating.
Floating interrupts may be delivered to any virtual cpu in the configuration.
The following interrupts are supported:
SIGP STOP - interprocessor signal that stops a remote cpu
SIGP SET PREFIX - interprocessor signal that sets the prefix register of a
(stopped) remote cpu
INT EMERGENCY - interprocessor interrupt, usually used to signal need_reshed
and for smp_call_function() in the guest.
PROGRAM INT - exception during program execution such as page fault, illegal
instruction and friends
RESTART - interprocessor signal that starts a stopped cpu
INT VIRTIO - floating interrupt for virtio signalisation
INT SERVICE - floating interrupt for signalisations from the system
service processor
struct kvm_s390_interrupt, which is submitted as ioctl parameter when injecting
an interrupt, also carrys parameter data for interrupts along with the interrupt
type. Interrupts on s390 usually have a state that represents the current
operation, or identifies which device has caused the interruption on s390.
kvm_s390_handle_wait() does handle waitpsw in two flavors: in case of a
disabled wait (that is, disabled for interrupts), we exit to userspace. In case
of an enabled wait we set up a timer that equals the cpu clock comparator value
and sleep on a wait queue.
[christian: change virtio interrupt to 0x2603]
Acked-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: Carsten Otte <cotte@de.ibm.com>
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
Signed-off-by: Avi Kivity <avi@qumranet.com>
2008-03-25 17:47:26 +00:00
|
|
|
}
|
|
|
|
|
2014-01-15 15:46:07 +00:00
|
|
|
/**
|
|
|
|
* handle_external_interrupt - used for external interruption interceptions
|
2021-09-10 08:04:20 +00:00
|
|
|
* @vcpu: virtual cpu
|
2014-01-15 15:46:07 +00:00
|
|
|
*
|
2023-02-13 08:55:20 +00:00
|
|
|
* This interception occurs if:
|
|
|
|
* - the CPUSTAT_EXT_INT bit was already set when the external interrupt
|
|
|
|
* occurred. In this case, the interrupt needs to be injected manually to
|
|
|
|
* preserve interrupt priority.
|
|
|
|
* - the external new PSW has external interrupts enabled, which will cause an
|
|
|
|
* interruption loop. We drop to userspace in this case.
|
|
|
|
*
|
|
|
|
* The latter case can be detected by inspecting the external mask bit in the
|
|
|
|
* external new psw.
|
|
|
|
*
|
|
|
|
* Under PV, only the latter case can occur, since interrupt priorities are
|
|
|
|
* handled in the ultravisor.
|
2014-01-15 15:46:07 +00:00
|
|
|
*/
|
|
|
|
static int handle_external_interrupt(struct kvm_vcpu *vcpu)
|
|
|
|
{
|
|
|
|
u16 eic = vcpu->arch.sie_block->eic;
|
2014-07-29 13:11:49 +00:00
|
|
|
struct kvm_s390_irq irq;
|
2014-01-15 15:46:07 +00:00
|
|
|
psw_t newpsw;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
vcpu->stat.exit_external_interrupt++;
|
|
|
|
|
2023-02-13 08:55:20 +00:00
|
|
|
if (kvm_s390_pv_cpu_is_protected(vcpu)) {
|
|
|
|
newpsw = vcpu->arch.sie_block->gpsw;
|
|
|
|
} else {
|
|
|
|
rc = read_guest_lc(vcpu, __LC_EXT_NEW_PSW, &newpsw, sizeof(psw_t));
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Clock comparator or timer interrupt with external interrupt enabled
|
|
|
|
* will cause interrupt loop. Drop to userspace.
|
|
|
|
*/
|
2014-01-15 15:46:07 +00:00
|
|
|
if ((eic == EXT_IRQ_CLK_COMP || eic == EXT_IRQ_CPU_TIMER) &&
|
|
|
|
(newpsw.mask & PSW_MASK_EXT))
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
switch (eic) {
|
|
|
|
case EXT_IRQ_CLK_COMP:
|
|
|
|
irq.type = KVM_S390_INT_CLOCK_COMP;
|
|
|
|
break;
|
|
|
|
case EXT_IRQ_CPU_TIMER:
|
|
|
|
irq.type = KVM_S390_INT_CPU_TIMER;
|
|
|
|
break;
|
|
|
|
case EXT_IRQ_EXTERNAL_CALL:
|
|
|
|
irq.type = KVM_S390_INT_EXTERNAL_CALL;
|
2014-07-29 13:11:49 +00:00
|
|
|
irq.u.extcall.code = vcpu->arch.sie_block->extcpuaddr;
|
2014-10-14 13:29:30 +00:00
|
|
|
rc = kvm_s390_inject_vcpu(vcpu, &irq);
|
|
|
|
/* ignore if another external call is already pending */
|
|
|
|
if (rc == -EBUSY)
|
|
|
|
return 0;
|
|
|
|
return rc;
|
2014-01-15 15:46:07 +00:00
|
|
|
default:
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
}
|
|
|
|
|
|
|
|
return kvm_s390_inject_vcpu(vcpu, &irq);
|
|
|
|
}
|
|
|
|
|
2014-02-03 09:42:30 +00:00
|
|
|
/**
|
2021-09-10 08:04:20 +00:00
|
|
|
* handle_mvpg_pei - Handle MOVE PAGE partial execution interception.
|
|
|
|
* @vcpu: virtual cpu
|
2014-02-03 09:42:30 +00:00
|
|
|
*
|
|
|
|
* This interception can only happen for guests with DAT disabled and
|
|
|
|
* addresses that are currently not mapped in the host. Thus we try to
|
|
|
|
* set up the mappings for the corresponding user pages here (or throw
|
|
|
|
* addressing exceptions in case of illegal guest addresses).
|
|
|
|
*/
|
|
|
|
static int handle_mvpg_pei(struct kvm_vcpu *vcpu)
|
|
|
|
{
|
2014-05-07 09:44:17 +00:00
|
|
|
unsigned long srcaddr, dstaddr;
|
2014-02-03 09:42:30 +00:00
|
|
|
int reg1, reg2, rc;
|
|
|
|
|
|
|
|
kvm_s390_get_regs_rre(vcpu, ®1, ®2);
|
|
|
|
|
2022-02-11 18:22:07 +00:00
|
|
|
/* Ensure that the source is paged-in, no actual access -> no key checking */
|
|
|
|
rc = guest_translate_address_with_key(vcpu, vcpu->run->s.regs.gprs[reg2],
|
|
|
|
reg2, &srcaddr, GACC_FETCH, 0);
|
2015-01-07 15:27:02 +00:00
|
|
|
if (rc)
|
|
|
|
return kvm_s390_inject_prog_cond(vcpu, rc);
|
2014-05-07 09:44:17 +00:00
|
|
|
rc = kvm_arch_fault_in_page(vcpu, srcaddr, 0);
|
|
|
|
if (rc != 0)
|
2014-02-03 09:42:30 +00:00
|
|
|
return rc;
|
|
|
|
|
2022-02-11 18:22:07 +00:00
|
|
|
/* Ensure that the source is paged-in, no actual access -> no key checking */
|
|
|
|
rc = guest_translate_address_with_key(vcpu, vcpu->run->s.regs.gprs[reg1],
|
|
|
|
reg1, &dstaddr, GACC_STORE, 0);
|
2015-01-07 15:27:02 +00:00
|
|
|
if (rc)
|
|
|
|
return kvm_s390_inject_prog_cond(vcpu, rc);
|
2014-05-07 09:44:17 +00:00
|
|
|
rc = kvm_arch_fault_in_page(vcpu, dstaddr, 1);
|
|
|
|
if (rc != 0)
|
2014-02-03 09:42:30 +00:00
|
|
|
return rc;
|
|
|
|
|
2015-11-04 12:47:58 +00:00
|
|
|
kvm_s390_retry_instr(vcpu);
|
2014-02-03 09:42:30 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int handle_partial_execution(struct kvm_vcpu *vcpu)
|
|
|
|
{
|
2016-05-06 13:33:06 +00:00
|
|
|
vcpu->stat.exit_pei++;
|
|
|
|
|
2014-02-03 09:42:30 +00:00
|
|
|
if (vcpu->arch.sie_block->ipa == 0xb254) /* MVPG */
|
|
|
|
return handle_mvpg_pei(vcpu);
|
2014-02-21 07:59:59 +00:00
|
|
|
if (vcpu->arch.sie_block->ipa >> 8 == 0xae) /* SIGP */
|
|
|
|
return kvm_s390_handle_sigp_pei(vcpu);
|
2014-02-03 09:42:30 +00:00
|
|
|
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
}
|
|
|
|
|
2017-09-29 10:41:50 +00:00
|
|
|
/*
|
|
|
|
* Handle the sthyi instruction that provides the guest with system
|
|
|
|
* information, like current CPU resources available at each level of
|
|
|
|
* the machine.
|
|
|
|
*/
|
|
|
|
int handle_sthyi(struct kvm_vcpu *vcpu)
|
|
|
|
{
|
2023-07-27 18:29:39 +00:00
|
|
|
int reg1, reg2, cc = 0, r = 0;
|
|
|
|
u64 code, addr, rc = 0;
|
2017-09-29 10:41:50 +00:00
|
|
|
struct sthyi_sctns *sctns = NULL;
|
|
|
|
|
|
|
|
if (!test_kvm_facility(vcpu->kvm, 74))
|
|
|
|
return kvm_s390_inject_program_int(vcpu, PGM_OPERATION);
|
|
|
|
|
|
|
|
kvm_s390_get_regs_rre(vcpu, ®1, ®2);
|
|
|
|
code = vcpu->run->s.regs.gprs[reg1];
|
|
|
|
addr = vcpu->run->s.regs.gprs[reg2];
|
|
|
|
|
|
|
|
vcpu->stat.instruction_sthyi++;
|
|
|
|
VCPU_EVENT(vcpu, 3, "STHYI: fc: %llu addr: 0x%016llx", code, addr);
|
|
|
|
trace_kvm_s390_handle_sthyi(vcpu, code, addr);
|
|
|
|
|
|
|
|
if (reg1 == reg2 || reg1 & 1 || reg2 & 1)
|
|
|
|
return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
|
|
|
|
|
|
|
|
if (code & 0xffff) {
|
|
|
|
cc = 3;
|
|
|
|
rc = 4;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2019-05-09 08:23:16 +00:00
|
|
|
if (!kvm_s390_pv_cpu_is_protected(vcpu) && (addr & ~PAGE_MASK))
|
2017-09-29 10:41:50 +00:00
|
|
|
return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
|
|
|
|
|
2020-11-06 07:34:23 +00:00
|
|
|
sctns = (void *)get_zeroed_page(GFP_KERNEL_ACCOUNT);
|
2017-09-29 10:41:50 +00:00
|
|
|
if (!sctns)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
cc = sthyi_fill(sctns, &rc);
|
2023-07-27 18:29:39 +00:00
|
|
|
if (cc < 0) {
|
|
|
|
free_page((unsigned long)sctns);
|
|
|
|
return cc;
|
|
|
|
}
|
2017-09-29 10:41:50 +00:00
|
|
|
out:
|
|
|
|
if (!cc) {
|
2019-05-09 08:23:16 +00:00
|
|
|
if (kvm_s390_pv_cpu_is_protected(vcpu)) {
|
2022-10-20 14:31:58 +00:00
|
|
|
memcpy(sida_addr(vcpu->arch.sie_block), sctns, PAGE_SIZE);
|
2019-05-09 08:23:16 +00:00
|
|
|
} else {
|
|
|
|
r = write_guest(vcpu, addr, reg2, sctns, PAGE_SIZE);
|
|
|
|
if (r) {
|
|
|
|
free_page((unsigned long)sctns);
|
|
|
|
return kvm_s390_inject_prog_cond(vcpu, r);
|
|
|
|
}
|
2017-09-29 10:41:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
free_page((unsigned long)sctns);
|
|
|
|
vcpu->run->s.regs.gprs[reg2 + 1] = rc;
|
|
|
|
kvm_s390_set_psw_cc(vcpu, cc);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2016-05-09 12:14:01 +00:00
|
|
|
static int handle_operexc(struct kvm_vcpu *vcpu)
|
|
|
|
{
|
2017-01-26 19:45:33 +00:00
|
|
|
psw_t oldpsw, newpsw;
|
|
|
|
int rc;
|
|
|
|
|
2016-05-09 12:14:01 +00:00
|
|
|
vcpu->stat.exit_operation_exception++;
|
|
|
|
trace_kvm_s390_handle_operexc(vcpu, vcpu->arch.sie_block->ipa,
|
|
|
|
vcpu->arch.sie_block->ipb);
|
|
|
|
|
2017-02-27 20:14:47 +00:00
|
|
|
if (vcpu->arch.sie_block->ipa == 0xb256)
|
2016-05-23 13:11:58 +00:00
|
|
|
return handle_sthyi(vcpu);
|
|
|
|
|
2016-06-21 12:19:51 +00:00
|
|
|
if (vcpu->arch.sie_block->ipa == 0 && vcpu->kvm->arch.user_instr0)
|
|
|
|
return -EOPNOTSUPP;
|
2017-01-26 19:45:33 +00:00
|
|
|
rc = read_guest_lc(vcpu, __LC_PGM_NEW_PSW, &newpsw, sizeof(psw_t));
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
/*
|
|
|
|
* Avoid endless loops of operation exceptions, if the pgm new
|
|
|
|
* PSW will cause a new operation exception.
|
|
|
|
* The heuristic checks if the pgm new psw is within 6 bytes before
|
|
|
|
* the faulting psw address (with same DAT, AS settings) and the
|
|
|
|
* new psw is not a wait psw and the fault was not triggered by
|
|
|
|
* problem state.
|
|
|
|
*/
|
|
|
|
oldpsw = vcpu->arch.sie_block->gpsw;
|
|
|
|
if (oldpsw.addr - newpsw.addr <= 6 &&
|
|
|
|
!(newpsw.mask & PSW_MASK_WAIT) &&
|
|
|
|
!(oldpsw.mask & PSW_MASK_PSTATE) &&
|
|
|
|
(newpsw.mask & PSW_MASK_ASC) == (oldpsw.mask & PSW_MASK_ASC) &&
|
|
|
|
(newpsw.mask & PSW_MASK_DAT) == (oldpsw.mask & PSW_MASK_DAT))
|
|
|
|
return -EOPNOTSUPP;
|
2016-06-21 12:19:51 +00:00
|
|
|
|
2016-05-09 12:14:01 +00:00
|
|
|
return kvm_s390_inject_program_int(vcpu, PGM_OPERATION);
|
|
|
|
}
|
|
|
|
|
2019-09-17 12:53:53 +00:00
|
|
|
static int handle_pv_spx(struct kvm_vcpu *vcpu)
|
|
|
|
{
|
2022-10-20 14:31:58 +00:00
|
|
|
u32 pref = *(u32 *)sida_addr(vcpu->arch.sie_block);
|
2019-09-17 12:53:53 +00:00
|
|
|
|
|
|
|
kvm_s390_set_prefix(vcpu, pref);
|
|
|
|
trace_kvm_s390_handle_prefix(vcpu, 1, pref);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-02-03 08:13:37 +00:00
|
|
|
static int handle_pv_sclp(struct kvm_vcpu *vcpu)
|
|
|
|
{
|
|
|
|
struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int;
|
|
|
|
|
|
|
|
spin_lock(&fi->lock);
|
|
|
|
/*
|
|
|
|
* 2 cases:
|
|
|
|
* a: an sccb answering interrupt was already pending or in flight.
|
|
|
|
* As the sccb value is not known we can simply set some value to
|
|
|
|
* trigger delivery of a saved SCCB. UV will then use its saved
|
|
|
|
* copy of the SCCB value.
|
|
|
|
* b: an error SCCB interrupt needs to be injected so we also inject
|
|
|
|
* a fake SCCB address. Firmware will use the proper one.
|
|
|
|
* This makes sure, that both errors and real sccb returns will only
|
|
|
|
* be delivered after a notification intercept (instruction has
|
|
|
|
* finished) but not after others.
|
|
|
|
*/
|
|
|
|
fi->srv_signal.ext_params |= 0x43000;
|
|
|
|
set_bit(IRQ_PEND_EXT_SERVICE, &fi->pending_irqs);
|
|
|
|
clear_bit(IRQ_PEND_EXT_SERVICE, &fi->masked_irqs);
|
|
|
|
spin_unlock(&fi->lock);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-01-31 20:00:39 +00:00
|
|
|
static int handle_pv_uvc(struct kvm_vcpu *vcpu)
|
|
|
|
{
|
2022-10-20 14:31:58 +00:00
|
|
|
struct uv_cb_share *guest_uvcb = sida_addr(vcpu->arch.sie_block);
|
2020-01-31 20:00:39 +00:00
|
|
|
struct uv_cb_cts uvcb = {
|
|
|
|
.header.cmd = UVC_CMD_UNPIN_PAGE_SHARED,
|
|
|
|
.header.len = sizeof(uvcb),
|
|
|
|
.guest_handle = kvm_s390_pv_get_handle(vcpu->kvm),
|
|
|
|
.gaddr = guest_uvcb->paddr,
|
|
|
|
};
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
if (guest_uvcb->header.cmd != UVC_CMD_REMOVE_SHARED_ACCESS) {
|
|
|
|
WARN_ONCE(1, "Unexpected notification intercept for UVC 0x%x\n",
|
|
|
|
guest_uvcb->header.cmd);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
rc = gmap_make_secure(vcpu->arch.gmap, uvcb.gaddr, &uvcb);
|
|
|
|
/*
|
|
|
|
* If the unpin did not succeed, the guest will exit again for the UVC
|
|
|
|
* and we will retry the unpin.
|
|
|
|
*/
|
|
|
|
if (rc == -EINVAL)
|
|
|
|
return 0;
|
2021-09-20 13:24:52 +00:00
|
|
|
/*
|
|
|
|
* If we got -EAGAIN here, we simply return it. It will eventually
|
|
|
|
* get propagated all the way to userspace, which should then try
|
|
|
|
* again.
|
|
|
|
*/
|
2020-01-31 20:00:39 +00:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2019-10-22 08:42:52 +00:00
|
|
|
static int handle_pv_notification(struct kvm_vcpu *vcpu)
|
|
|
|
{
|
KVM: s390: pv: don't present the ecall interrupt twice
When the SIGP interpretation facility is present and a VCPU sends an
ecall to another VCPU in enabled wait, the sending VCPU receives a 56
intercept (partial execution), so KVM can wake up the receiving CPU.
Note that the SIGP interpretation facility will take care of the
interrupt delivery and KVM's only job is to wake the receiving VCPU.
For PV, the sending VCPU will receive a 108 intercept (pv notify) and
should continue like in the non-PV case, i.e. wake the receiving VCPU.
For PV and non-PV guests the interrupt delivery will occur through the
SIGP interpretation facility on SIE entry when SIE finds the X bit in
the status field set.
However, in handle_pv_notification(), there was no special handling for
SIGP, which leads to interrupt injection being requested by KVM for the
next SIE entry. This results in the interrupt being delivered twice:
once by the SIGP interpretation facility and once by KVM through the
IICTL.
Add the necessary special handling in handle_pv_notification(), similar
to handle_partial_execution(), which simply wakes the receiving VCPU and
leave interrupt delivery to the SIGP interpretation facility.
In contrast to external calls, emergency calls are not interpreted but
also cause a 108 intercept, which is why we still need to call
handle_instruction() for SIGP orders other than ecall.
Since kvm_s390_handle_sigp_pei() is now called for all SIGP orders which
cause a 108 intercept - even if they are actually handled by
handle_instruction() - move the tracepoint in kvm_s390_handle_sigp_pei()
to avoid possibly confusing trace messages.
Signed-off-by: Nico Boehr <nrb@linux.ibm.com>
Cc: <stable@vger.kernel.org> # 5.7
Fixes: da24a0cc58ed ("KVM: s390: protvirt: Instruction emulation")
Reviewed-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
Reviewed-by: Janosch Frank <frankja@linux.ibm.com>
Reviewed-by: Christian Borntraeger <borntraeger@linux.ibm.com>
Link: https://lore.kernel.org/r/20220718130434.73302-1-nrb@linux.ibm.com
Message-Id: <20220718130434.73302-1-nrb@linux.ibm.com>
Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
2022-07-18 13:04:34 +00:00
|
|
|
int ret;
|
|
|
|
|
2019-09-17 12:53:53 +00:00
|
|
|
if (vcpu->arch.sie_block->ipa == 0xb210)
|
|
|
|
return handle_pv_spx(vcpu);
|
2020-02-03 08:13:37 +00:00
|
|
|
if (vcpu->arch.sie_block->ipa == 0xb220)
|
|
|
|
return handle_pv_sclp(vcpu);
|
2020-01-31 20:00:39 +00:00
|
|
|
if (vcpu->arch.sie_block->ipa == 0xb9a4)
|
|
|
|
return handle_pv_uvc(vcpu);
|
KVM: s390: pv: don't present the ecall interrupt twice
When the SIGP interpretation facility is present and a VCPU sends an
ecall to another VCPU in enabled wait, the sending VCPU receives a 56
intercept (partial execution), so KVM can wake up the receiving CPU.
Note that the SIGP interpretation facility will take care of the
interrupt delivery and KVM's only job is to wake the receiving VCPU.
For PV, the sending VCPU will receive a 108 intercept (pv notify) and
should continue like in the non-PV case, i.e. wake the receiving VCPU.
For PV and non-PV guests the interrupt delivery will occur through the
SIGP interpretation facility on SIE entry when SIE finds the X bit in
the status field set.
However, in handle_pv_notification(), there was no special handling for
SIGP, which leads to interrupt injection being requested by KVM for the
next SIE entry. This results in the interrupt being delivered twice:
once by the SIGP interpretation facility and once by KVM through the
IICTL.
Add the necessary special handling in handle_pv_notification(), similar
to handle_partial_execution(), which simply wakes the receiving VCPU and
leave interrupt delivery to the SIGP interpretation facility.
In contrast to external calls, emergency calls are not interpreted but
also cause a 108 intercept, which is why we still need to call
handle_instruction() for SIGP orders other than ecall.
Since kvm_s390_handle_sigp_pei() is now called for all SIGP orders which
cause a 108 intercept - even if they are actually handled by
handle_instruction() - move the tracepoint in kvm_s390_handle_sigp_pei()
to avoid possibly confusing trace messages.
Signed-off-by: Nico Boehr <nrb@linux.ibm.com>
Cc: <stable@vger.kernel.org> # 5.7
Fixes: da24a0cc58ed ("KVM: s390: protvirt: Instruction emulation")
Reviewed-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
Reviewed-by: Janosch Frank <frankja@linux.ibm.com>
Reviewed-by: Christian Borntraeger <borntraeger@linux.ibm.com>
Link: https://lore.kernel.org/r/20220718130434.73302-1-nrb@linux.ibm.com
Message-Id: <20220718130434.73302-1-nrb@linux.ibm.com>
Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
2022-07-18 13:04:34 +00:00
|
|
|
if (vcpu->arch.sie_block->ipa >> 8 == 0xae) {
|
|
|
|
/*
|
|
|
|
* Besides external call, other SIGP orders also cause a
|
|
|
|
* 108 (pv notify) intercept. In contrast to external call,
|
|
|
|
* these orders need to be emulated and hence the appropriate
|
|
|
|
* place to handle them is in handle_instruction().
|
|
|
|
* So first try kvm_s390_handle_sigp_pei() and if that isn't
|
|
|
|
* successful, go on with handle_instruction().
|
|
|
|
*/
|
|
|
|
ret = kvm_s390_handle_sigp_pei(vcpu);
|
|
|
|
if (!ret)
|
|
|
|
return ret;
|
|
|
|
}
|
2020-02-03 08:13:37 +00:00
|
|
|
|
2019-10-22 08:42:52 +00:00
|
|
|
return handle_instruction(vcpu);
|
|
|
|
}
|
|
|
|
|
2023-07-25 14:37:18 +00:00
|
|
|
static bool should_handle_per_ifetch(const struct kvm_vcpu *vcpu, int rc)
|
|
|
|
{
|
|
|
|
/* Process PER, also if the instruction is processed in user space. */
|
|
|
|
if (!(vcpu->arch.sie_block->icptstatus & 0x02))
|
|
|
|
return false;
|
|
|
|
if (rc != 0 && rc != -EOPNOTSUPP)
|
|
|
|
return false;
|
|
|
|
if (guestdbg_sstep_enabled(vcpu) && vcpu->arch.local_int.pending_irqs)
|
|
|
|
/* __vcpu_run() will exit after delivering the interrupt. */
|
|
|
|
return false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2008-03-25 17:47:23 +00:00
|
|
|
int kvm_handle_sie_intercept(struct kvm_vcpu *vcpu)
|
|
|
|
{
|
2016-05-24 10:10:27 +00:00
|
|
|
int rc, per_rc = 0;
|
|
|
|
|
2015-10-19 14:24:28 +00:00
|
|
|
if (kvm_is_ucontrol(vcpu->kvm))
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
2015-07-23 13:24:03 +00:00
|
|
|
switch (vcpu->arch.sie_block->icptcode) {
|
2017-03-17 13:59:32 +00:00
|
|
|
case ICPT_EXTREQ:
|
2018-02-23 07:57:33 +00:00
|
|
|
vcpu->stat.exit_external_request++;
|
|
|
|
return 0;
|
2017-03-17 13:59:32 +00:00
|
|
|
case ICPT_IOREQ:
|
2018-02-23 07:57:33 +00:00
|
|
|
vcpu->stat.exit_io_request++;
|
|
|
|
return 0;
|
2017-03-17 13:59:32 +00:00
|
|
|
case ICPT_INST:
|
2016-05-24 10:10:27 +00:00
|
|
|
rc = handle_instruction(vcpu);
|
|
|
|
break;
|
2017-03-17 13:59:32 +00:00
|
|
|
case ICPT_PROGI:
|
2015-07-23 13:24:03 +00:00
|
|
|
return handle_prog(vcpu);
|
2017-03-17 13:59:32 +00:00
|
|
|
case ICPT_EXTINT:
|
2015-07-23 13:24:03 +00:00
|
|
|
return handle_external_interrupt(vcpu);
|
2017-03-17 13:59:32 +00:00
|
|
|
case ICPT_WAIT:
|
2015-07-23 13:24:03 +00:00
|
|
|
return kvm_s390_handle_wait(vcpu);
|
2017-03-17 13:59:32 +00:00
|
|
|
case ICPT_VALIDITY:
|
2015-07-23 13:24:03 +00:00
|
|
|
return handle_validity(vcpu);
|
2017-03-17 13:59:32 +00:00
|
|
|
case ICPT_STOP:
|
2015-07-23 13:24:03 +00:00
|
|
|
return handle_stop(vcpu);
|
2017-03-17 13:59:32 +00:00
|
|
|
case ICPT_OPEREXC:
|
2016-05-24 10:10:27 +00:00
|
|
|
rc = handle_operexc(vcpu);
|
|
|
|
break;
|
2017-03-17 13:59:32 +00:00
|
|
|
case ICPT_PARTEXEC:
|
2016-05-24 10:10:27 +00:00
|
|
|
rc = handle_partial_execution(vcpu);
|
|
|
|
break;
|
2017-02-24 21:12:56 +00:00
|
|
|
case ICPT_KSS:
|
2023-07-25 14:37:20 +00:00
|
|
|
/* Instruction will be redriven, skip the PER check. */
|
|
|
|
return kvm_s390_skey_check_enable(vcpu);
|
2019-04-01 08:54:09 +00:00
|
|
|
case ICPT_MCHKREQ:
|
|
|
|
case ICPT_INT_ENABLE:
|
|
|
|
/*
|
|
|
|
* PSW bit 13 or a CR (0, 6, 14) changed and we might
|
|
|
|
* now be able to deliver interrupts. The pre-run code
|
|
|
|
* will take care of this.
|
|
|
|
*/
|
|
|
|
rc = 0;
|
|
|
|
break;
|
2019-10-22 08:42:52 +00:00
|
|
|
case ICPT_PV_INSTR:
|
|
|
|
rc = handle_instruction(vcpu);
|
|
|
|
break;
|
|
|
|
case ICPT_PV_NOTIFY:
|
|
|
|
rc = handle_pv_notification(vcpu);
|
|
|
|
break;
|
2019-09-17 12:53:53 +00:00
|
|
|
case ICPT_PV_PREF:
|
|
|
|
rc = 0;
|
|
|
|
gmap_convert_to_secure(vcpu->arch.gmap,
|
|
|
|
kvm_s390_get_prefix(vcpu));
|
|
|
|
gmap_convert_to_secure(vcpu->arch.gmap,
|
|
|
|
kvm_s390_get_prefix(vcpu) + PAGE_SIZE);
|
|
|
|
break;
|
2015-07-23 13:24:03 +00:00
|
|
|
default:
|
2010-02-26 21:37:41 +00:00
|
|
|
return -EOPNOTSUPP;
|
2015-07-23 13:24:03 +00:00
|
|
|
}
|
2016-05-24 10:10:27 +00:00
|
|
|
|
2023-07-25 14:37:18 +00:00
|
|
|
if (should_handle_per_ifetch(vcpu, rc))
|
2016-05-24 10:10:27 +00:00
|
|
|
per_rc = kvm_s390_handle_per_ifetch_icpt(vcpu);
|
|
|
|
return per_rc ? per_rc : rc;
|
2008-03-25 17:47:23 +00:00
|
|
|
}
|