diff options
Diffstat (limited to 'arch/s390')
-rw-r--r-- | arch/s390/include/asm/kvm.h | 5 | ||||
-rw-r--r-- | arch/s390/include/asm/kvm_host.h | 1 | ||||
-rw-r--r-- | arch/s390/include/asm/kvm_para.h | 5 | ||||
-rw-r--r-- | arch/s390/include/asm/sclp.h | 1 | ||||
-rw-r--r-- | arch/s390/kvm/diag.c | 29 | ||||
-rw-r--r-- | arch/s390/kvm/intercept.c | 1 | ||||
-rw-r--r-- | arch/s390/kvm/kvm-s390.c | 87 | ||||
-rw-r--r-- | arch/s390/kvm/kvm-s390.h | 1 | ||||
-rw-r--r-- | arch/s390/kvm/priv.c | 31 |
9 files changed, 158 insertions, 3 deletions
diff --git a/arch/s390/include/asm/kvm.h b/arch/s390/include/asm/kvm.h index 96076676e224..bdcbe0f8dd7b 100644 --- a/arch/s390/include/asm/kvm.h +++ b/arch/s390/include/asm/kvm.h | |||
@@ -52,4 +52,9 @@ struct kvm_sync_regs { | |||
52 | __u32 acrs[16]; /* access registers */ | 52 | __u32 acrs[16]; /* access registers */ |
53 | __u64 crs[16]; /* control registers */ | 53 | __u64 crs[16]; /* control registers */ |
54 | }; | 54 | }; |
55 | |||
56 | #define KVM_REG_S390_TODPR (KVM_REG_S390 | KVM_REG_SIZE_U32 | 0x1) | ||
57 | #define KVM_REG_S390_EPOCHDIFF (KVM_REG_S390 | KVM_REG_SIZE_U64 | 0x2) | ||
58 | #define KVM_REG_S390_CPU_TIMER (KVM_REG_S390 | KVM_REG_SIZE_U64 | 0x3) | ||
59 | #define KVM_REG_S390_CLOCK_COMP (KVM_REG_S390 | KVM_REG_SIZE_U64 | 0x4) | ||
55 | #endif | 60 | #endif |
diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h index 7343872890a2..dd17537b9a9d 100644 --- a/arch/s390/include/asm/kvm_host.h +++ b/arch/s390/include/asm/kvm_host.h | |||
@@ -148,6 +148,7 @@ struct kvm_vcpu_stat { | |||
148 | u32 instruction_sigp_restart; | 148 | u32 instruction_sigp_restart; |
149 | u32 diagnose_10; | 149 | u32 diagnose_10; |
150 | u32 diagnose_44; | 150 | u32 diagnose_44; |
151 | u32 diagnose_9c; | ||
151 | }; | 152 | }; |
152 | 153 | ||
153 | struct kvm_s390_io_info { | 154 | struct kvm_s390_io_info { |
diff --git a/arch/s390/include/asm/kvm_para.h b/arch/s390/include/asm/kvm_para.h index 6964db226f83..a98832961035 100644 --- a/arch/s390/include/asm/kvm_para.h +++ b/arch/s390/include/asm/kvm_para.h | |||
@@ -149,6 +149,11 @@ static inline unsigned int kvm_arch_para_features(void) | |||
149 | return 0; | 149 | return 0; |
150 | } | 150 | } |
151 | 151 | ||
152 | static inline bool kvm_check_and_clear_guest_paused(void) | ||
153 | { | ||
154 | return false; | ||
155 | } | ||
156 | |||
152 | #endif | 157 | #endif |
153 | 158 | ||
154 | #endif /* __S390_KVM_PARA_H */ | 159 | #endif /* __S390_KVM_PARA_H */ |
diff --git a/arch/s390/include/asm/sclp.h b/arch/s390/include/asm/sclp.h index fed7bee650a0..bf238c55740b 100644 --- a/arch/s390/include/asm/sclp.h +++ b/arch/s390/include/asm/sclp.h | |||
@@ -48,6 +48,7 @@ int sclp_cpu_deconfigure(u8 cpu); | |||
48 | void sclp_facilities_detect(void); | 48 | void sclp_facilities_detect(void); |
49 | unsigned long long sclp_get_rnmax(void); | 49 | unsigned long long sclp_get_rnmax(void); |
50 | unsigned long long sclp_get_rzm(void); | 50 | unsigned long long sclp_get_rzm(void); |
51 | u8 sclp_get_fac85(void); | ||
51 | int sclp_sdias_blk_count(void); | 52 | int sclp_sdias_blk_count(void); |
52 | int sclp_sdias_copy(void *dest, int blk_num, int nr_blks); | 53 | int sclp_sdias_copy(void *dest, int blk_num, int nr_blks); |
53 | int sclp_chp_configure(struct chp_id chpid); | 54 | int sclp_chp_configure(struct chp_id chpid); |
diff --git a/arch/s390/kvm/diag.c b/arch/s390/kvm/diag.c index a353f0ea45c2..b23d9ac77dfc 100644 --- a/arch/s390/kvm/diag.c +++ b/arch/s390/kvm/diag.c | |||
@@ -47,9 +47,30 @@ static int __diag_time_slice_end(struct kvm_vcpu *vcpu) | |||
47 | { | 47 | { |
48 | VCPU_EVENT(vcpu, 5, "%s", "diag time slice end"); | 48 | VCPU_EVENT(vcpu, 5, "%s", "diag time slice end"); |
49 | vcpu->stat.diagnose_44++; | 49 | vcpu->stat.diagnose_44++; |
50 | vcpu_put(vcpu); | 50 | kvm_vcpu_on_spin(vcpu); |
51 | yield(); | 51 | return 0; |
52 | vcpu_load(vcpu); | 52 | } |
53 | |||
54 | static int __diag_time_slice_end_directed(struct kvm_vcpu *vcpu) | ||
55 | { | ||
56 | struct kvm *kvm = vcpu->kvm; | ||
57 | struct kvm_vcpu *tcpu; | ||
58 | int tid; | ||
59 | int i; | ||
60 | |||
61 | tid = vcpu->run->s.regs.gprs[(vcpu->arch.sie_block->ipa & 0xf0) >> 4]; | ||
62 | vcpu->stat.diagnose_9c++; | ||
63 | VCPU_EVENT(vcpu, 5, "diag time slice end directed to %d", tid); | ||
64 | |||
65 | if (tid == vcpu->vcpu_id) | ||
66 | return 0; | ||
67 | |||
68 | kvm_for_each_vcpu(i, tcpu, kvm) | ||
69 | if (tcpu->vcpu_id == tid) { | ||
70 | kvm_vcpu_yield_to(tcpu); | ||
71 | break; | ||
72 | } | ||
73 | |||
53 | return 0; | 74 | return 0; |
54 | } | 75 | } |
55 | 76 | ||
@@ -89,6 +110,8 @@ int kvm_s390_handle_diag(struct kvm_vcpu *vcpu) | |||
89 | return diag_release_pages(vcpu); | 110 | return diag_release_pages(vcpu); |
90 | case 0x44: | 111 | case 0x44: |
91 | return __diag_time_slice_end(vcpu); | 112 | return __diag_time_slice_end(vcpu); |
113 | case 0x9c: | ||
114 | return __diag_time_slice_end_directed(vcpu); | ||
92 | case 0x308: | 115 | case 0x308: |
93 | return __diag_ipl_functions(vcpu); | 116 | return __diag_ipl_functions(vcpu); |
94 | default: | 117 | default: |
diff --git a/arch/s390/kvm/intercept.c b/arch/s390/kvm/intercept.c index 361456577c6f..979cbe55bf5e 100644 --- a/arch/s390/kvm/intercept.c +++ b/arch/s390/kvm/intercept.c | |||
@@ -101,6 +101,7 @@ static int handle_lctl(struct kvm_vcpu *vcpu) | |||
101 | } | 101 | } |
102 | 102 | ||
103 | static intercept_handler_t instruction_handlers[256] = { | 103 | static intercept_handler_t instruction_handlers[256] = { |
104 | [0x01] = kvm_s390_handle_01, | ||
104 | [0x83] = kvm_s390_handle_diag, | 105 | [0x83] = kvm_s390_handle_diag, |
105 | [0xae] = kvm_s390_handle_sigp, | 106 | [0xae] = kvm_s390_handle_sigp, |
106 | [0xb2] = kvm_s390_handle_b2, | 107 | [0xb2] = kvm_s390_handle_b2, |
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index 217ce44395a4..664766d0c83c 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <asm/pgtable.h> | 28 | #include <asm/pgtable.h> |
29 | #include <asm/nmi.h> | 29 | #include <asm/nmi.h> |
30 | #include <asm/switch_to.h> | 30 | #include <asm/switch_to.h> |
31 | #include <asm/sclp.h> | ||
31 | #include "kvm-s390.h" | 32 | #include "kvm-s390.h" |
32 | #include "gaccess.h" | 33 | #include "gaccess.h" |
33 | 34 | ||
@@ -74,6 +75,7 @@ struct kvm_stats_debugfs_item debugfs_entries[] = { | |||
74 | { "instruction_sigp_restart", VCPU_STAT(instruction_sigp_restart) }, | 75 | { "instruction_sigp_restart", VCPU_STAT(instruction_sigp_restart) }, |
75 | { "diagnose_10", VCPU_STAT(diagnose_10) }, | 76 | { "diagnose_10", VCPU_STAT(diagnose_10) }, |
76 | { "diagnose_44", VCPU_STAT(diagnose_44) }, | 77 | { "diagnose_44", VCPU_STAT(diagnose_44) }, |
78 | { "diagnose_9c", VCPU_STAT(diagnose_9c) }, | ||
77 | { NULL } | 79 | { NULL } |
78 | }; | 80 | }; |
79 | 81 | ||
@@ -133,8 +135,16 @@ int kvm_dev_ioctl_check_extension(long ext) | |||
133 | case KVM_CAP_S390_UCONTROL: | 135 | case KVM_CAP_S390_UCONTROL: |
134 | #endif | 136 | #endif |
135 | case KVM_CAP_SYNC_REGS: | 137 | case KVM_CAP_SYNC_REGS: |
138 | case KVM_CAP_ONE_REG: | ||
136 | r = 1; | 139 | r = 1; |
137 | break; | 140 | break; |
141 | case KVM_CAP_NR_VCPUS: | ||
142 | case KVM_CAP_MAX_VCPUS: | ||
143 | r = KVM_MAX_VCPUS; | ||
144 | break; | ||
145 | case KVM_CAP_S390_COW: | ||
146 | r = sclp_get_fac85() & 0x2; | ||
147 | break; | ||
138 | default: | 148 | default: |
139 | r = 0; | 149 | r = 0; |
140 | } | 150 | } |
@@ -423,6 +433,71 @@ int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu) | |||
423 | return 0; | 433 | return 0; |
424 | } | 434 | } |
425 | 435 | ||
436 | int kvm_arch_vcpu_should_kick(struct kvm_vcpu *vcpu) | ||
437 | { | ||
438 | /* kvm common code refers to this, but never calls it */ | ||
439 | BUG(); | ||
440 | return 0; | ||
441 | } | ||
442 | |||
443 | static int kvm_arch_vcpu_ioctl_get_one_reg(struct kvm_vcpu *vcpu, | ||
444 | struct kvm_one_reg *reg) | ||
445 | { | ||
446 | int r = -EINVAL; | ||
447 | |||
448 | switch (reg->id) { | ||
449 | case KVM_REG_S390_TODPR: | ||
450 | r = put_user(vcpu->arch.sie_block->todpr, | ||
451 | (u32 __user *)reg->addr); | ||
452 | break; | ||
453 | case KVM_REG_S390_EPOCHDIFF: | ||
454 | r = put_user(vcpu->arch.sie_block->epoch, | ||
455 | (u64 __user *)reg->addr); | ||
456 | break; | ||
457 | case KVM_REG_S390_CPU_TIMER: | ||
458 | r = put_user(vcpu->arch.sie_block->cputm, | ||
459 | (u64 __user *)reg->addr); | ||
460 | break; | ||
461 | case KVM_REG_S390_CLOCK_COMP: | ||
462 | r = put_user(vcpu->arch.sie_block->ckc, | ||
463 | (u64 __user *)reg->addr); | ||
464 | break; | ||
465 | default: | ||
466 | break; | ||
467 | } | ||
468 | |||
469 | return r; | ||
470 | } | ||
471 | |||
472 | static int kvm_arch_vcpu_ioctl_set_one_reg(struct kvm_vcpu *vcpu, | ||
473 | struct kvm_one_reg *reg) | ||
474 | { | ||
475 | int r = -EINVAL; | ||
476 | |||
477 | switch (reg->id) { | ||
478 | case KVM_REG_S390_TODPR: | ||
479 | r = get_user(vcpu->arch.sie_block->todpr, | ||
480 | (u32 __user *)reg->addr); | ||
481 | break; | ||
482 | case KVM_REG_S390_EPOCHDIFF: | ||
483 | r = get_user(vcpu->arch.sie_block->epoch, | ||
484 | (u64 __user *)reg->addr); | ||
485 | break; | ||
486 | case KVM_REG_S390_CPU_TIMER: | ||
487 | r = get_user(vcpu->arch.sie_block->cputm, | ||
488 | (u64 __user *)reg->addr); | ||
489 | break; | ||
490 | case KVM_REG_S390_CLOCK_COMP: | ||
491 | r = get_user(vcpu->arch.sie_block->ckc, | ||
492 | (u64 __user *)reg->addr); | ||
493 | break; | ||
494 | default: | ||
495 | break; | ||
496 | } | ||
497 | |||
498 | return r; | ||
499 | } | ||
500 | |||
426 | static int kvm_arch_vcpu_ioctl_initial_reset(struct kvm_vcpu *vcpu) | 501 | static int kvm_arch_vcpu_ioctl_initial_reset(struct kvm_vcpu *vcpu) |
427 | { | 502 | { |
428 | kvm_s390_vcpu_initial_reset(vcpu); | 503 | kvm_s390_vcpu_initial_reset(vcpu); |
@@ -753,6 +828,18 @@ long kvm_arch_vcpu_ioctl(struct file *filp, | |||
753 | case KVM_S390_INITIAL_RESET: | 828 | case KVM_S390_INITIAL_RESET: |
754 | r = kvm_arch_vcpu_ioctl_initial_reset(vcpu); | 829 | r = kvm_arch_vcpu_ioctl_initial_reset(vcpu); |
755 | break; | 830 | break; |
831 | case KVM_SET_ONE_REG: | ||
832 | case KVM_GET_ONE_REG: { | ||
833 | struct kvm_one_reg reg; | ||
834 | r = -EFAULT; | ||
835 | if (copy_from_user(®, argp, sizeof(reg))) | ||
836 | break; | ||
837 | if (ioctl == KVM_SET_ONE_REG) | ||
838 | r = kvm_arch_vcpu_ioctl_set_one_reg(vcpu, ®); | ||
839 | else | ||
840 | r = kvm_arch_vcpu_ioctl_get_one_reg(vcpu, ®); | ||
841 | break; | ||
842 | } | ||
756 | #ifdef CONFIG_KVM_S390_UCONTROL | 843 | #ifdef CONFIG_KVM_S390_UCONTROL |
757 | case KVM_S390_UCAS_MAP: { | 844 | case KVM_S390_UCAS_MAP: { |
758 | struct kvm_s390_ucas_mapping ucasmap; | 845 | struct kvm_s390_ucas_mapping ucasmap; |
diff --git a/arch/s390/kvm/kvm-s390.h b/arch/s390/kvm/kvm-s390.h index ff28f9d1c9eb..2294377975e8 100644 --- a/arch/s390/kvm/kvm-s390.h +++ b/arch/s390/kvm/kvm-s390.h | |||
@@ -79,6 +79,7 @@ int kvm_s390_inject_sigp_stop(struct kvm_vcpu *vcpu, int action); | |||
79 | /* implemented in priv.c */ | 79 | /* implemented in priv.c */ |
80 | int kvm_s390_handle_b2(struct kvm_vcpu *vcpu); | 80 | int kvm_s390_handle_b2(struct kvm_vcpu *vcpu); |
81 | int kvm_s390_handle_e5(struct kvm_vcpu *vcpu); | 81 | int kvm_s390_handle_e5(struct kvm_vcpu *vcpu); |
82 | int kvm_s390_handle_01(struct kvm_vcpu *vcpu); | ||
82 | 83 | ||
83 | /* implemented in sigp.c */ | 84 | /* implemented in sigp.c */ |
84 | int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu); | 85 | int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu); |
diff --git a/arch/s390/kvm/priv.c b/arch/s390/kvm/priv.c index e5a45dbd26ac..68a6b2ed16bf 100644 --- a/arch/s390/kvm/priv.c +++ b/arch/s390/kvm/priv.c | |||
@@ -380,3 +380,34 @@ int kvm_s390_handle_e5(struct kvm_vcpu *vcpu) | |||
380 | return -EOPNOTSUPP; | 380 | return -EOPNOTSUPP; |
381 | } | 381 | } |
382 | 382 | ||
383 | static int handle_sckpf(struct kvm_vcpu *vcpu) | ||
384 | { | ||
385 | u32 value; | ||
386 | |||
387 | if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) | ||
388 | return kvm_s390_inject_program_int(vcpu, | ||
389 | PGM_PRIVILEGED_OPERATION); | ||
390 | |||
391 | if (vcpu->run->s.regs.gprs[0] & 0x00000000ffff0000) | ||
392 | return kvm_s390_inject_program_int(vcpu, | ||
393 | PGM_SPECIFICATION); | ||
394 | |||
395 | value = vcpu->run->s.regs.gprs[0] & 0x000000000000ffff; | ||
396 | vcpu->arch.sie_block->todpr = value; | ||
397 | |||
398 | return 0; | ||
399 | } | ||
400 | |||
401 | static intercept_handler_t x01_handlers[256] = { | ||
402 | [0x07] = handle_sckpf, | ||
403 | }; | ||
404 | |||
405 | int kvm_s390_handle_01(struct kvm_vcpu *vcpu) | ||
406 | { | ||
407 | intercept_handler_t handler; | ||
408 | |||
409 | handler = x01_handlers[vcpu->arch.sie_block->ipa & 0x00ff]; | ||
410 | if (handler) | ||
411 | return handler(vcpu); | ||
412 | return -EOPNOTSUPP; | ||
413 | } | ||