From: QingFeng Hao <haoqf@linux.vnet.ibm.com>
Subject: KVM: s390: Inject machine check into the nested guest
Patch-mainline: v4.13-rc1
Git-commit: d52cd2076eb2ace9fe95dbf795f6d93587453914
References: FATE#324256,LTC#160417,bsc#1066327
Summary: kvm: Robust Machine Check Handling
Description: A machine check is caused by a machine malfunction and not by data
or instructions. The machine check could happen on CPU, I/O,
storage etc.
There are several kinds of machine checks, e.g. System Damage(SD),
Instruction Processing Damage(IPD), Delayed Access Exception(DAE),
Channel Report Pending(CRW), External Damage(ED).
In general, they are of two types: exigent condition and
repressible condition. The 64 bits Machine-Check-Interruption
Code(MCIC) in lowcore is set to indicate the current machine
check's type with the validity bits when a machine check happens.
Meanwhile, the machine check handler set in lowcore is called to
handle it. Through the validity bits in MCIC, the program can
determine if the machine check could be recovered.
The present machine check handler can handle almost all of the
machine checks and validate the registers to recover the machine
by the validity bits in MCIC. It can also inject the CRW machine
check request from QEMU to the guest.
VS1522 improves it to inject most of the host supported machine
checks to the guest if they happen during the guest's running
and the necessary validity bits to recover are set. Exceptions are
the SD and Timer Facility Damage. The original handling is kept
and they will not be injected into the guest.
Additionally, this line item reinjects the DAE machine check
if it happens during the guest's running instead of damage host
because DAE could be caused by the program's using an improper
procedure to update the DAT tables.
The program will not inject the machine check for device hotplug
such as CRW into the guest. For machine checks happening during
the nested guest's(guest-3) running, guest-2 will reinject them
into guest-3.
Upstream-Description:
KVM: s390: Inject machine check into the nested guest
With vsie feature enabled, kvm can support nested guests (guest-3).
So inject machine check to the guest-2 if it happens when the nested
guest is running. And guest-2 will detect the machine check belongs
to guest-3 and reinject it into guest-3.
The host (guest-1) tries to inject the machine check to the picked
destination vcpu if it's a floating machine check.
Signed-off-by: QingFeng Hao <haoqf@linux.vnet.ibm.com>
Acked-by: Christian Borntraeger <borntraeger@de.ibm.com>
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
Signed-off-by: QingFeng Hao <haoqf@linux.vnet.ibm.com>
Acked-by: Hannes Reinecke <hare@suse.com>
---
arch/s390/kvm/vsie.c | 23 +++++++++++++++++++----
1 file changed, 19 insertions(+), 4 deletions(-)
--- a/arch/s390/kvm/vsie.c
+++ b/arch/s390/kvm/vsie.c
@@ -26,13 +26,18 @@
struct vsie_page {
struct kvm_s390_sie_block scb_s; /* 0x0000 */
+ /*
+ * the backup info for machine check. ensure it's at
+ * the same offset as that in struct sie_page!
+ */
+ struct mcck_volatile_info mcck_info; /* 0x0200 */
/* the pinned originial scb */
- struct kvm_s390_sie_block *scb_o; /* 0x0200 */
+ struct kvm_s390_sie_block *scb_o; /* 0x0218 */
/* the shadow gmap in use by the vsie_page */
- struct gmap *gmap; /* 0x0208 */
+ struct gmap *gmap; /* 0x0220 */
/* address of the last reported fault to guest2 */
- unsigned long fault_addr; /* 0x0210 */
- __u8 reserved[0x0700 - 0x0218]; /* 0x0218 */
+ unsigned long fault_addr; /* 0x0228 */
+ __u8 reserved[0x0700 - 0x0230]; /* 0x0230 */
struct kvm_s390_crypto_cb crycb; /* 0x0700 */
__u8 fac[S390_ARCH_FAC_LIST_SIZE_BYTE]; /* 0x0800 */
};
@@ -801,6 +806,8 @@
{
struct kvm_s390_sie_block *scb_s = &vsie_page->scb_s;
struct kvm_s390_sie_block *scb_o = vsie_page->scb_o;
+ struct mcck_volatile_info *mcck_info;
+ struct sie_page *sie_page;
int rc;
handle_last_fault(vcpu, vsie_page);
@@ -822,6 +829,14 @@
local_irq_enable();
vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu);
+ if (rc == -EINTR) {
+ VCPU_EVENT(vcpu, 3, "%s", "machine check");
+ sie_page = container_of(scb_s, struct sie_page, sie_block);
+ mcck_info = &sie_page->mcck_info;
+ kvm_s390_reinject_machine_check(vcpu, mcck_info);
+ return 0;
+ }
+
if (rc > 0)
rc = 0; /* we could still have an icpt */
else if (rc == -EFAULT)