aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/kvm/priv.c
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 /arch/s390/kvm/priv.c
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>
Diffstat (limited to 'arch/s390/kvm/priv.c')
-rw-r--r--arch/s390/kvm/priv.c86
1 files changed, 84 insertions, 2 deletions
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)