aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Borntraeger <borntraeger@de.ibm.com>2013-06-12 07:54:53 -0400
committerPaolo Bonzini <pbonzini@redhat.com>2013-06-17 11:05:07 -0400
commit69d0d3a3160690cf64ea3bf484ca1f9d7a1bf798 (patch)
tree29a585340a1f98b379852ede5935df2d1dcb33c8
parentdb70ccdfb9953b984f5b95d98c50d8da335bab59 (diff)
KVM: s390: guest large pages
This patch enables kvm to give large pages to the guest. The heavy lifting is done by the hardware, the host only has to take care of the PFMF instruction, which is also part of EDAT-1. We also support the non-quiescing key setting facility if the host supports it, to behave similar to the interpretation of sske. Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com> Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
-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)