summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Schwidefsky <schwidefsky@de.ibm.com>2017-06-28 06:57:47 -0400
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2017-06-28 06:57:47 -0400
commit9e293b5a7062981016ace93160c56a980fcb73b8 (patch)
tree69f557de9c1a1c2deaa28bdc42f8228a33247116
parent795c9a5106119f45d2501c4fb01051178904753f (diff)
parentda72ca4d4090a8ab0e6b0a23682ef42d39d7ae00 (diff)
Merge tag 'nmiforkvm' of git://git.kernel.org/pub/scm/linux/kernel/git/kvms390/linux into features
Pull kvm patches from Christian Borntraeger: "s390,kvm: provide plumbing for machines checks when running guests" This provides the basic plumbing for handling machine checks when running guests
-rw-r--r--arch/s390/include/asm/kvm_host.h17
-rw-r--r--arch/s390/include/asm/nmi.h7
-rw-r--r--arch/s390/include/asm/processor.h2
-rw-r--r--arch/s390/kernel/asm-offsets.c3
-rw-r--r--arch/s390/kernel/entry.S13
-rw-r--r--arch/s390/kernel/nmi.c84
-rw-r--r--arch/s390/kvm/kvm-s390.c1
7 files changed, 115 insertions, 12 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/include/asm/nmi.h b/arch/s390/include/asm/nmi.h
index e3e8895f5d3e..13623b9991d4 100644
--- a/arch/s390/include/asm/nmi.h
+++ b/arch/s390/include/asm/nmi.h
@@ -14,7 +14,14 @@
14#include <linux/const.h> 14#include <linux/const.h>
15#include <linux/types.h> 15#include <linux/types.h>
16 16
17#define MCIC_SUBCLASS_MASK (1ULL<<63 | 1ULL<<62 | 1ULL<<61 | \
18 1ULL<<59 | 1ULL<<58 | 1ULL<<56 | \
19 1ULL<<55 | 1ULL<<54 | 1ULL<<53 | \
20 1ULL<<52 | 1ULL<<47 | 1ULL<<46 | \
21 1ULL<<45 | 1ULL<<44)
17#define MCCK_CODE_SYSTEM_DAMAGE _BITUL(63) 22#define MCCK_CODE_SYSTEM_DAMAGE _BITUL(63)
23#define MCCK_CODE_EXT_DAMAGE _BITUL(63 - 5)
24#define MCCK_CODE_CP _BITUL(63 - 9)
18#define MCCK_CODE_CPU_TIMER_VALID _BITUL(63 - 46) 25#define MCCK_CODE_CPU_TIMER_VALID _BITUL(63 - 46)
19#define MCCK_CODE_PSW_MWP_VALID _BITUL(63 - 20) 26#define MCCK_CODE_PSW_MWP_VALID _BITUL(63 - 20)
20#define MCCK_CODE_PSW_IA_VALID _BITUL(63 - 23) 27#define MCCK_CODE_PSW_IA_VALID _BITUL(63 - 23)
diff --git a/arch/s390/include/asm/processor.h b/arch/s390/include/asm/processor.h
index f57c017a5c03..72c7b88f8d2c 100644
--- a/arch/s390/include/asm/processor.h
+++ b/arch/s390/include/asm/processor.h
@@ -20,6 +20,7 @@
20#define CIF_FPU 4 /* restore FPU registers */ 20#define CIF_FPU 4 /* restore FPU registers */
21#define CIF_IGNORE_IRQ 5 /* ignore interrupt (for udelay) */ 21#define CIF_IGNORE_IRQ 5 /* ignore interrupt (for udelay) */
22#define CIF_ENABLED_WAIT 6 /* in enabled wait state */ 22#define CIF_ENABLED_WAIT 6 /* in enabled wait state */
23#define CIF_MCCK_GUEST 7 /* machine check happening in guest */
23 24
24#define _CIF_MCCK_PENDING _BITUL(CIF_MCCK_PENDING) 25#define _CIF_MCCK_PENDING _BITUL(CIF_MCCK_PENDING)
25#define _CIF_ASCE_PRIMARY _BITUL(CIF_ASCE_PRIMARY) 26#define _CIF_ASCE_PRIMARY _BITUL(CIF_ASCE_PRIMARY)
@@ -28,6 +29,7 @@
28#define _CIF_FPU _BITUL(CIF_FPU) 29#define _CIF_FPU _BITUL(CIF_FPU)
29#define _CIF_IGNORE_IRQ _BITUL(CIF_IGNORE_IRQ) 30#define _CIF_IGNORE_IRQ _BITUL(CIF_IGNORE_IRQ)
30#define _CIF_ENABLED_WAIT _BITUL(CIF_ENABLED_WAIT) 31#define _CIF_ENABLED_WAIT _BITUL(CIF_ENABLED_WAIT)
32#define _CIF_MCCK_GUEST _BITUL(CIF_MCCK_GUEST)
31 33
32#ifndef __ASSEMBLY__ 34#ifndef __ASSEMBLY__
33 35
diff --git a/arch/s390/kernel/asm-offsets.c b/arch/s390/kernel/asm-offsets.c
index 6bb29633e1f1..b65c414b6c0e 100644
--- a/arch/s390/kernel/asm-offsets.c
+++ b/arch/s390/kernel/asm-offsets.c
@@ -58,6 +58,9 @@ int main(void)
58 OFFSET(__SF_BACKCHAIN, stack_frame, back_chain); 58 OFFSET(__SF_BACKCHAIN, stack_frame, back_chain);
59 OFFSET(__SF_GPRS, stack_frame, gprs); 59 OFFSET(__SF_GPRS, stack_frame, gprs);
60 OFFSET(__SF_EMPTY, stack_frame, empty1); 60 OFFSET(__SF_EMPTY, stack_frame, empty1);
61 OFFSET(__SF_SIE_CONTROL, stack_frame, empty1[0]);
62 OFFSET(__SF_SIE_SAVEAREA, stack_frame, empty1[1]);
63 OFFSET(__SF_SIE_REASON, stack_frame, empty1[2]);
61 BLANK(); 64 BLANK();
62 /* timeval/timezone offsets for use by vdso */ 65 /* timeval/timezone offsets for use by vdso */
63 OFFSET(__VDSO_UPD_COUNT, vdso_data, tb_update_count); 66 OFFSET(__VDSO_UPD_COUNT, vdso_data, tb_update_count);
diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S
index e83aff630bcf..21900e1cee9c 100644
--- a/arch/s390/kernel/entry.S
+++ b/arch/s390/kernel/entry.S
@@ -225,6 +225,7 @@ ENTRY(sie64a)
225 jnz .Lsie_skip 225 jnz .Lsie_skip
226 TSTMSK __LC_CPU_FLAGS,_CIF_FPU 226 TSTMSK __LC_CPU_FLAGS,_CIF_FPU
227 jo .Lsie_skip # exit if fp/vx regs changed 227 jo .Lsie_skip # exit if fp/vx regs changed
228.Lsie_entry:
228 sie 0(%r14) 229 sie 0(%r14)
229.Lsie_skip: 230.Lsie_skip:
230 ni __SIE_PROG0C+3(%r14),0xfe # no longer in SIE 231 ni __SIE_PROG0C+3(%r14),0xfe # no longer in SIE
@@ -1122,7 +1123,13 @@ cleanup_critical:
1122 .quad .Lsie_done 1123 .quad .Lsie_done
1123 1124
1124.Lcleanup_sie: 1125.Lcleanup_sie:
1125 lg %r9,__SF_EMPTY(%r15) # get control block pointer 1126 cghi %r11,__LC_SAVE_AREA_ASYNC #Is this in normal interrupt?
1127 je 1f
1128 slg %r9,BASED(.Lsie_crit_mcck_start)
1129 clg %r9,BASED(.Lsie_crit_mcck_length)
1130 jh 1f
1131 oi __LC_CPU_FLAGS+7, _CIF_MCCK_GUEST
11321: lg %r9,__SF_EMPTY(%r15) # get control block pointer
1126 ni __SIE_PROG0C+3(%r9),0xfe # no longer in SIE 1133 ni __SIE_PROG0C+3(%r9),0xfe # no longer in SIE
1127 lctlg %c1,%c1,__LC_USER_ASCE # load primary asce 1134 lctlg %c1,%c1,__LC_USER_ASCE # load primary asce
1128 larl %r9,sie_exit # skip forward to sie_exit 1135 larl %r9,sie_exit # skip forward to sie_exit
@@ -1307,6 +1314,10 @@ cleanup_critical:
1307 .quad .Lsie_gmap 1314 .quad .Lsie_gmap
1308.Lsie_critical_length: 1315.Lsie_critical_length:
1309 .quad .Lsie_done - .Lsie_gmap 1316 .quad .Lsie_done - .Lsie_gmap
1317.Lsie_crit_mcck_start:
1318 .quad .Lsie_entry
1319.Lsie_crit_mcck_length:
1320 .quad .Lsie_skip - .Lsie_entry
1310#endif 1321#endif
1311 1322
1312 .section .rodata, "a" 1323 .section .rodata, "a"
diff --git a/arch/s390/kernel/nmi.c b/arch/s390/kernel/nmi.c
index 985589523970..31d03a84126c 100644
--- a/arch/s390/kernel/nmi.c
+++ b/arch/s390/kernel/nmi.c
@@ -25,6 +25,8 @@
25#include <asm/crw.h> 25#include <asm/crw.h>
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>
29#include <linux/kvm_host.h>
28 30
29struct mcck_struct { 31struct mcck_struct {
30 unsigned int kill_task : 1; 32 unsigned int kill_task : 1;
@@ -274,12 +276,39 @@ static int notrace s390_validate_registers(union mci mci, int umode)
274 return kill_task; 276 return kill_task;
275} 277}
276 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
277#define MAX_IPD_COUNT 29 304#define MAX_IPD_COUNT 29
278#define MAX_IPD_TIME (5 * 60 * USEC_PER_SEC) /* 5 minutes */ 305#define MAX_IPD_TIME (5 * 60 * USEC_PER_SEC) /* 5 minutes */
279 306
280#define ED_STP_ISLAND 6 /* External damage STP island check */ 307#define ED_STP_ISLAND 6 /* External damage STP island check */
281#define ED_STP_SYNC 7 /* External damage STP sync check */ 308#define ED_STP_SYNC 7 /* External damage STP sync check */
282 309
310#define MCCK_CODE_NO_GUEST (MCCK_CODE_CP | MCCK_CODE_EXT_DAMAGE)
311
283/* 312/*
284 * machine check handler. 313 * machine check handler.
285 */ 314 */
@@ -291,6 +320,7 @@ void notrace s390_do_machine_check(struct pt_regs *regs)
291 struct mcck_struct *mcck; 320 struct mcck_struct *mcck;
292 unsigned long long tmp; 321 unsigned long long tmp;
293 union mci mci; 322 union mci mci;
323 unsigned long mcck_dam_code;
294 324
295 nmi_enter(); 325 nmi_enter();
296 inc_irq_stat(NMI_NMI); 326 inc_irq_stat(NMI_NMI);
@@ -301,7 +331,13 @@ void notrace s390_do_machine_check(struct pt_regs *regs)
301 /* System damage -> stopping machine */ 331 /* System damage -> stopping machine */
302 s390_handle_damage(); 332 s390_handle_damage();
303 } 333 }
304 if (mci.pd) { 334
335 /*
336 * Reinject the instruction processing damages' machine checks
337 * including Delayed Access Exception into the guest
338 * instead of damaging the host if they happen in the guest.
339 */
340 if (mci.pd && !test_cpu_flag(CIF_MCCK_GUEST)) {
305 if (mci.b) { 341 if (mci.b) {
306 /* Processing backup -> verify if we can survive this */ 342 /* Processing backup -> verify if we can survive this */
307 u64 z_mcic, o_mcic, t_mcic; 343 u64 z_mcic, o_mcic, t_mcic;
@@ -345,6 +381,14 @@ void notrace s390_do_machine_check(struct pt_regs *regs)
345 mcck->mcck_code = mci.val; 381 mcck->mcck_code = mci.val;
346 set_cpu_flag(CIF_MCCK_PENDING); 382 set_cpu_flag(CIF_MCCK_PENDING);
347 } 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
348 if (mci.cd) { 392 if (mci.cd) {
349 /* Timing facility damage */ 393 /* Timing facility damage */
350 s390_handle_damage(); 394 s390_handle_damage();
@@ -358,15 +402,22 @@ void notrace s390_do_machine_check(struct pt_regs *regs)
358 if (mcck->stp_queue) 402 if (mcck->stp_queue)
359 set_cpu_flag(CIF_MCCK_PENDING); 403 set_cpu_flag(CIF_MCCK_PENDING);
360 } 404 }
361 if (mci.se) 405
362 /* Storage error uncorrected */ 406 /*
363 s390_handle_damage(); 407 * Reinject storage related machine checks into the guest if they
364 if (mci.ke) 408 * happen when the guest is running.
365 /* Storage key-error uncorrected */ 409 */
366 s390_handle_damage(); 410 if (!test_cpu_flag(CIF_MCCK_GUEST)) {
367 if (mci.ds && mci.fa) 411 if (mci.se)
368 /* Storage degradation */ 412 /* Storage error uncorrected */
369 s390_handle_damage(); 413 s390_handle_damage();
414 if (mci.ke)
415 /* Storage key-error uncorrected */
416 s390_handle_damage();
417 if (mci.ds && mci.fa)
418 /* Storage degradation */
419 s390_handle_damage();
420 }
370 if (mci.cp) { 421 if (mci.cp) {
371 /* Channel report word pending */ 422 /* Channel report word pending */
372 mcck->channel_report = 1; 423 mcck->channel_report = 1;
@@ -377,6 +428,19 @@ void notrace s390_do_machine_check(struct pt_regs *regs)
377 mcck->warning = 1; 428 mcck->warning = 1;
378 set_cpu_flag(CIF_MCCK_PENDING); 429 set_cpu_flag(CIF_MCCK_PENDING);
379 } 430 }
431
432 /*
433 * If there are only Channel Report Pending and External Damage
434 * machine checks, they will not be reinjected into the guest
435 * because they refer to host conditions only.
436 */
437 mcck_dam_code = (mci.val & MCIC_SUBCLASS_MASK);
438 if (test_cpu_flag(CIF_MCCK_GUEST) &&
439 (mcck_dam_code & MCCK_CODE_NO_GUEST) != mcck_dam_code) {
440 /* Set exit reason code for host's later handling */
441 *((long *)(regs->gprs[15] + __SF_SIE_REASON)) = -EINTR;
442 }
443 clear_cpu_flag(CIF_MCCK_GUEST);
380 nmi_exit(); 444 nmi_exit();
381} 445}
382 446
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;