diff options
-rw-r--r-- | arch/s390/include/asm/kvm_host.h | 5 | ||||
-rw-r--r-- | arch/s390/kvm/kvm-s390.c | 7 | ||||
-rw-r--r-- | arch/s390/kvm/kvm-s390.h | 6 | ||||
-rw-r--r-- | arch/s390/kvm/priv.c | 86 |
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 | ||
89 | static 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 | |||
89 | static inline u64 kvm_s390_get_base_disp_rsy(struct kvm_vcpu *vcpu) | 95 | static 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 | |||
484 | static 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, ®1, ®2); | ||
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 | |||
471 | static const intercept_handler_t b9_handlers[256] = { | 552 | static 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 | ||
476 | int kvm_s390_handle_b9(struct kvm_vcpu *vcpu) | 558 | int kvm_s390_handle_b9(struct kvm_vcpu *vcpu) |