aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/s390/include/asm/kvm_host.h5
-rw-r--r--arch/s390/kvm/kvm-s390.c7
-rw-r--r--arch/s390/kvm/kvm-s390.h6
-rw-r--r--arch/s390/kvm/priv.c86
4 files changed, 99 insertions, 5 deletions
diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h
index 9a809f935580..43207dd45fab 100644
--- a/arch/s390/include/asm/kvm_host.h
+++ b/arch/s390/include/asm/kvm_host.h
@@ -62,6 +62,7 @@ struct sca_block {
62#define CPUSTAT_MCDS 0x00000100 62#define CPUSTAT_MCDS 0x00000100
63#define CPUSTAT_SM 0x00000080 63#define CPUSTAT_SM 0x00000080
64#define CPUSTAT_G 0x00000008 64#define CPUSTAT_G 0x00000008
65#define CPUSTAT_GED 0x00000004
65#define CPUSTAT_J 0x00000002 66#define CPUSTAT_J 0x00000002
66#define CPUSTAT_P 0x00000001 67#define CPUSTAT_P 0x00000001
67 68
@@ -96,7 +97,8 @@ struct kvm_s390_sie_block {
96 __u32 scaoh; /* 0x005c */ 97 __u32 scaoh; /* 0x005c */
97 __u8 reserved60; /* 0x0060 */ 98 __u8 reserved60; /* 0x0060 */
98 __u8 ecb; /* 0x0061 */ 99 __u8 ecb; /* 0x0061 */
99 __u8 reserved62[2]; /* 0x0062 */ 100 __u8 ecb2; /* 0x0062 */
101 __u8 reserved63[1]; /* 0x0063 */
100 __u32 scaol; /* 0x0064 */ 102 __u32 scaol; /* 0x0064 */
101 __u8 reserved68[4]; /* 0x0068 */ 103 __u8 reserved68[4]; /* 0x0068 */
102 __u32 todpr; /* 0x006c */ 104 __u32 todpr; /* 0x006c */
@@ -136,6 +138,7 @@ struct kvm_vcpu_stat {
136 u32 deliver_program_int; 138 u32 deliver_program_int;
137 u32 deliver_io_int; 139 u32 deliver_io_int;
138 u32 exit_wait_state; 140 u32 exit_wait_state;
141 u32 instruction_pfmf;
139 u32 instruction_stidp; 142 u32 instruction_stidp;
140 u32 instruction_spx; 143 u32 instruction_spx;
141 u32 instruction_stpx; 144 u32 instruction_stpx;
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index 3b597e590a75..426e259b6a69 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -59,6 +59,7 @@ struct kvm_stats_debugfs_item debugfs_entries[] = {
59 { "deliver_restart_signal", VCPU_STAT(deliver_restart_signal) }, 59 { "deliver_restart_signal", VCPU_STAT(deliver_restart_signal) },
60 { "deliver_program_interruption", VCPU_STAT(deliver_program_int) }, 60 { "deliver_program_interruption", VCPU_STAT(deliver_program_int) },
61 { "exit_wait_state", VCPU_STAT(exit_wait_state) }, 61 { "exit_wait_state", VCPU_STAT(exit_wait_state) },
62 { "instruction_pfmf", VCPU_STAT(instruction_pfmf) },
62 { "instruction_stidp", VCPU_STAT(instruction_stidp) }, 63 { "instruction_stidp", VCPU_STAT(instruction_stidp) },
63 { "instruction_spx", VCPU_STAT(instruction_spx) }, 64 { "instruction_spx", VCPU_STAT(instruction_spx) },
64 { "instruction_stpx", VCPU_STAT(instruction_stpx) }, 65 { "instruction_stpx", VCPU_STAT(instruction_stpx) },
@@ -381,8 +382,10 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
381{ 382{
382 atomic_set(&vcpu->arch.sie_block->cpuflags, CPUSTAT_ZARCH | 383 atomic_set(&vcpu->arch.sie_block->cpuflags, CPUSTAT_ZARCH |
383 CPUSTAT_SM | 384 CPUSTAT_SM |
384 CPUSTAT_STOPPED); 385 CPUSTAT_STOPPED |
386 CPUSTAT_GED);
385 vcpu->arch.sie_block->ecb = 6; 387 vcpu->arch.sie_block->ecb = 6;
388 vcpu->arch.sie_block->ecb2 = 8;
386 vcpu->arch.sie_block->eca = 0xC1002001U; 389 vcpu->arch.sie_block->eca = 0xC1002001U;
387 vcpu->arch.sie_block->fac = (int) (long) facilities; 390 vcpu->arch.sie_block->fac = (int) (long) facilities;
388 hrtimer_init(&vcpu->arch.ckc_timer, CLOCK_REALTIME, HRTIMER_MODE_ABS); 391 hrtimer_init(&vcpu->arch.ckc_timer, CLOCK_REALTIME, HRTIMER_MODE_ABS);
@@ -1125,7 +1128,7 @@ static int __init kvm_s390_init(void)
1125 return -ENOMEM; 1128 return -ENOMEM;
1126 } 1129 }
1127 memcpy(facilities, S390_lowcore.stfle_fac_list, 16); 1130 memcpy(facilities, S390_lowcore.stfle_fac_list, 16);
1128 facilities[0] &= 0xff00fff3f47c0000ULL; 1131 facilities[0] &= 0xff82fff3f47c0000ULL;
1129 facilities[1] &= 0x001c000000000000ULL; 1132 facilities[1] &= 0x001c000000000000ULL;
1130 return 0; 1133 return 0;
1131} 1134}
diff --git a/arch/s390/kvm/kvm-s390.h b/arch/s390/kvm/kvm-s390.h
index 269b523d0f6e..15795b8f8ff5 100644
--- a/arch/s390/kvm/kvm-s390.h
+++ b/arch/s390/kvm/kvm-s390.h
@@ -86,6 +86,12 @@ static inline void kvm_s390_get_base_disp_sse(struct kvm_vcpu *vcpu,
86 *address2 = (base2 ? vcpu->run->s.regs.gprs[base2] : 0) + disp2; 86 *address2 = (base2 ? vcpu->run->s.regs.gprs[base2] : 0) + disp2;
87} 87}
88 88
89static inline void kvm_s390_get_regs_rre(struct kvm_vcpu *vcpu, int *r1, int *r2)
90{
91 *r1 = (vcpu->arch.sie_block->ipb & 0x00f00000) >> 20;
92 *r2 = (vcpu->arch.sie_block->ipb & 0x000f0000) >> 16;
93}
94
89static inline u64 kvm_s390_get_base_disp_rsy(struct kvm_vcpu *vcpu) 95static inline u64 kvm_s390_get_base_disp_rsy(struct kvm_vcpu *vcpu)
90{ 96{
91 u32 base2 = vcpu->arch.sie_block->ipb >> 28; 97 u32 base2 = vcpu->arch.sie_block->ipb >> 28;
diff --git a/arch/s390/kvm/priv.c b/arch/s390/kvm/priv.c
index ecc58a694df7..bda9c9b494f0 100644
--- a/arch/s390/kvm/priv.c
+++ b/arch/s390/kvm/priv.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * handling privileged instructions 2 * handling privileged instructions
3 * 3 *
4 * Copyright IBM Corp. 2008 4 * Copyright IBM Corp. 2008, 2013
5 * 5 *
6 * This program is free software; you can redistribute it and/or modify 6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License (version 2 only) 7 * it under the terms of the GNU General Public License (version 2 only)
@@ -20,6 +20,9 @@
20#include <asm/debug.h> 20#include <asm/debug.h>
21#include <asm/ebcdic.h> 21#include <asm/ebcdic.h>
22#include <asm/sysinfo.h> 22#include <asm/sysinfo.h>
23#include <asm/pgtable.h>
24#include <asm/pgalloc.h>
25#include <asm/io.h>
23#include <asm/ptrace.h> 26#include <asm/ptrace.h>
24#include <asm/compat.h> 27#include <asm/compat.h>
25#include "gaccess.h" 28#include "gaccess.h"
@@ -212,7 +215,7 @@ static int handle_stfl(struct kvm_vcpu *vcpu)
212 215
213 vcpu->stat.instruction_stfl++; 216 vcpu->stat.instruction_stfl++;
214 /* only pass the facility bits, which we can handle */ 217 /* only pass the facility bits, which we can handle */
215 facility_list = S390_lowcore.stfl_fac_list & 0xff00fff3; 218 facility_list = S390_lowcore.stfl_fac_list & 0xff82fff3;
216 219
217 rc = copy_to_guest(vcpu, offsetof(struct _lowcore, stfl_fac_list), 220 rc = copy_to_guest(vcpu, offsetof(struct _lowcore, stfl_fac_list),
218 &facility_list, sizeof(facility_list)); 221 &facility_list, sizeof(facility_list));
@@ -468,9 +471,88 @@ static int handle_epsw(struct kvm_vcpu *vcpu)
468 return 0; 471 return 0;
469} 472}
470 473
474#define PFMF_RESERVED 0xfffc0101UL
475#define PFMF_SK 0x00020000UL
476#define PFMF_CF 0x00010000UL
477#define PFMF_UI 0x00008000UL
478#define PFMF_FSC 0x00007000UL
479#define PFMF_NQ 0x00000800UL
480#define PFMF_MR 0x00000400UL
481#define PFMF_MC 0x00000200UL
482#define PFMF_KEY 0x000000feUL
483
484static int handle_pfmf(struct kvm_vcpu *vcpu)
485{
486 int reg1, reg2;
487 unsigned long start, end;
488
489 vcpu->stat.instruction_pfmf++;
490
491 kvm_s390_get_regs_rre(vcpu, &reg1, &reg2);
492
493 if (!MACHINE_HAS_PFMF)
494 return kvm_s390_inject_program_int(vcpu, PGM_OPERATION);
495
496 if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
497 return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OPERATION);
498
499 if (vcpu->run->s.regs.gprs[reg1] & PFMF_RESERVED)
500 return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
501
502 /* Only provide non-quiescing support if the host supports it */
503 if (vcpu->run->s.regs.gprs[reg1] & PFMF_NQ &&
504 S390_lowcore.stfl_fac_list & 0x00020000)
505 return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
506
507 /* No support for conditional-SSKE */
508 if (vcpu->run->s.regs.gprs[reg1] & (PFMF_MR | PFMF_MC))
509 return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
510
511 start = vcpu->run->s.regs.gprs[reg2] & PAGE_MASK;
512 switch (vcpu->run->s.regs.gprs[reg1] & PFMF_FSC) {
513 case 0x00000000:
514 end = (start + (1UL << 12)) & ~((1UL << 12) - 1);
515 break;
516 case 0x00001000:
517 end = (start + (1UL << 20)) & ~((1UL << 20) - 1);
518 break;
519 /* We dont support EDAT2
520 case 0x00002000:
521 end = (start + (1UL << 31)) & ~((1UL << 31) - 1);
522 break;*/
523 default:
524 return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
525 }
526 while (start < end) {
527 unsigned long useraddr;
528
529 useraddr = gmap_translate(start, vcpu->arch.gmap);
530 if (IS_ERR((void *)useraddr))
531 return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
532
533 if (vcpu->run->s.regs.gprs[reg1] & PFMF_CF) {
534 if (clear_user((void __user *)useraddr, PAGE_SIZE))
535 return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
536 }
537
538 if (vcpu->run->s.regs.gprs[reg1] & PFMF_SK) {
539 if (set_guest_storage_key(current->mm, useraddr,
540 vcpu->run->s.regs.gprs[reg1] & PFMF_KEY,
541 vcpu->run->s.regs.gprs[reg1] & PFMF_NQ))
542 return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
543 }
544
545 start += PAGE_SIZE;
546 }
547 if (vcpu->run->s.regs.gprs[reg1] & PFMF_FSC)
548 vcpu->run->s.regs.gprs[reg2] = end;
549 return 0;
550}
551
471static const intercept_handler_t b9_handlers[256] = { 552static const intercept_handler_t b9_handlers[256] = {
472 [0x8d] = handle_epsw, 553 [0x8d] = handle_epsw,
473 [0x9c] = handle_io_inst, 554 [0x9c] = handle_io_inst,
555 [0xaf] = handle_pfmf,
474}; 556};
475 557
476int kvm_s390_handle_b9(struct kvm_vcpu *vcpu) 558int kvm_s390_handle_b9(struct kvm_vcpu *vcpu)