summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorQingFeng Hao <haoqf@linux.vnet.ibm.com>2017-06-07 05:41:19 -0400
committerChristian Borntraeger <borntraeger@de.ibm.com>2017-06-27 10:05:38 -0400
commitda72ca4d4090a8ab0e6b0a23682ef42d39d7ae00 (patch)
tree6ebff6f83cbc639d76554660494d42f83c60c08e
parentc929500d7a5aaea4f2eeba10816bc5341c66ae57 (diff)
KVM: s390: Backup the guest's machine check info
When a machine check happens in the guest, related mcck info (mcic, external damage code, ...) is stored in the vcpu's lowcore on the host. Then the machine check handler's low-level part is executed, followed by the high-level part. If the high-level part's execution is interrupted by a new machine check happening on the same vcpu on the host, the mcck info in the lowcore is overwritten with the new machine check's data. If the high-level part's execution is scheduled to a different cpu, the mcck info in the lowcore is uncertain. Therefore, for both cases, the further reinjection to the guest will use the wrong data. Let's backup the mcck info in the lowcore to the sie page for further reinjection, so that the right data will be used. Add new member into struct sie_page to store related machine check's info of mcic, failing storage address and external damage code. 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>
-rw-r--r--arch/s390/include/asm/kvm_host.h17
-rw-r--r--arch/s390/kernel/nmi.c34
-rw-r--r--arch/s390/kvm/kvm-s390.c1
3 files changed, 51 insertions, 1 deletions
diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h
index 426614a882a9..c6e1d5fa1ad1 100644
--- a/arch/s390/include/asm/kvm_host.h
+++ b/arch/s390/include/asm/kvm_host.h
@@ -107,6 +107,20 @@ struct esca_block {
107 struct esca_entry cpu[KVM_S390_ESCA_CPU_SLOTS]; 107 struct esca_entry cpu[KVM_S390_ESCA_CPU_SLOTS];
108} __packed; 108} __packed;
109 109
110/*
111 * This struct is used to store some machine check info from lowcore
112 * for machine checks that happen while the guest is running.
113 * This info in host's lowcore might be overwritten by a second machine
114 * check from host when host is in the machine check's high-level handling.
115 * The size is 24 bytes.
116 */
117struct mcck_volatile_info {
118 __u64 mcic;
119 __u64 failing_storage_address;
120 __u32 ext_damage_code;
121 __u32 reserved;
122};
123
110#define CPUSTAT_STOPPED 0x80000000 124#define CPUSTAT_STOPPED 0x80000000
111#define CPUSTAT_WAIT 0x10000000 125#define CPUSTAT_WAIT 0x10000000
112#define CPUSTAT_ECALL_PEND 0x08000000 126#define CPUSTAT_ECALL_PEND 0x08000000
@@ -264,7 +278,8 @@ struct kvm_s390_itdb {
264 278
265struct sie_page { 279struct sie_page {
266 struct kvm_s390_sie_block sie_block; 280 struct kvm_s390_sie_block sie_block;
267 __u8 reserved200[1024]; /* 0x0200 */ 281 struct mcck_volatile_info mcck_info; /* 0x0200 */
282 __u8 reserved218[1000]; /* 0x0218 */
268 struct kvm_s390_itdb itdb; /* 0x0600 */ 283 struct kvm_s390_itdb itdb; /* 0x0600 */
269 __u8 reserved700[2304]; /* 0x0700 */ 284 __u8 reserved700[2304]; /* 0x0700 */
270} __packed; 285} __packed;
diff --git a/arch/s390/kernel/nmi.c b/arch/s390/kernel/nmi.c
index 958cc3352faa..31d03a84126c 100644
--- a/arch/s390/kernel/nmi.c
+++ b/arch/s390/kernel/nmi.c
@@ -26,6 +26,7 @@
26#include <asm/switch_to.h> 26#include <asm/switch_to.h>
27#include <asm/ctl_reg.h> 27#include <asm/ctl_reg.h>
28#include <asm/asm-offsets.h> 28#include <asm/asm-offsets.h>
29#include <linux/kvm_host.h>
29 30
30struct mcck_struct { 31struct mcck_struct {
31 unsigned int kill_task : 1; 32 unsigned int kill_task : 1;
@@ -275,6 +276,31 @@ static int notrace s390_validate_registers(union mci mci, int umode)
275 return kill_task; 276 return kill_task;
276} 277}
277 278
279/*
280 * Backup the guest's machine check info to its description block
281 */
282static void notrace s390_backup_mcck_info(struct pt_regs *regs)
283{
284 struct mcck_volatile_info *mcck_backup;
285 struct sie_page *sie_page;
286
287 /* r14 contains the sie block, which was set in sie64a */
288 struct kvm_s390_sie_block *sie_block =
289 (struct kvm_s390_sie_block *) regs->gprs[14];
290
291 if (sie_block == NULL)
292 /* Something's seriously wrong, stop system. */
293 s390_handle_damage();
294
295 sie_page = container_of(sie_block, struct sie_page, sie_block);
296 mcck_backup = &sie_page->mcck_info;
297 mcck_backup->mcic = S390_lowcore.mcck_interruption_code &
298 ~(MCCK_CODE_CP | MCCK_CODE_EXT_DAMAGE);
299 mcck_backup->ext_damage_code = S390_lowcore.external_damage_code;
300 mcck_backup->failing_storage_address
301 = S390_lowcore.failing_storage_address;
302}
303
278#define MAX_IPD_COUNT 29 304#define MAX_IPD_COUNT 29
279#define MAX_IPD_TIME (5 * 60 * USEC_PER_SEC) /* 5 minutes */ 305#define MAX_IPD_TIME (5 * 60 * USEC_PER_SEC) /* 5 minutes */
280 306
@@ -355,6 +381,14 @@ void notrace s390_do_machine_check(struct pt_regs *regs)
355 mcck->mcck_code = mci.val; 381 mcck->mcck_code = mci.val;
356 set_cpu_flag(CIF_MCCK_PENDING); 382 set_cpu_flag(CIF_MCCK_PENDING);
357 } 383 }
384
385 /*
386 * Backup the machine check's info if it happens when the guest
387 * is running.
388 */
389 if (test_cpu_flag(CIF_MCCK_GUEST))
390 s390_backup_mcck_info(regs);
391
358 if (mci.cd) { 392 if (mci.cd) {
359 /* Timing facility damage */ 393 /* Timing facility damage */
360 s390_handle_damage(); 394 s390_handle_damage();
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index 689ac48361c6..0457e03199c5 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -2069,6 +2069,7 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm,
2069 if (!vcpu) 2069 if (!vcpu)
2070 goto out; 2070 goto out;
2071 2071
2072 BUILD_BUG_ON(sizeof(struct sie_page) != 4096);
2072 sie_page = (struct sie_page *) get_zeroed_page(GFP_KERNEL); 2073 sie_page = (struct sie_page *) get_zeroed_page(GFP_KERNEL);
2073 if (!sie_page) 2074 if (!sie_page)
2074 goto out_free_cpu; 2075 goto out_free_cpu;