diff options
author | Christian Borntraeger <borntraeger@de.ibm.com> | 2017-10-09 06:06:24 -0400 |
---|---|---|
committer | Christian Borntraeger <borntraeger@de.ibm.com> | 2017-10-09 06:06:24 -0400 |
commit | 650da25099606db05e3546201410d92cf2e2545a (patch) | |
tree | d431083fe178687964c23eee52011b8a88636054 | |
parent | 2bd6bf03f4c1c59381d62c61d03f6cc3fe71f66e (diff) | |
parent | 3d8757b87d7fc15a87928bc970f060bc9c6dc618 (diff) |
Merge branch 'sthyi' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux into kvms390/next
get sthyi rework with the KVM changes
-rw-r--r-- | arch/s390/include/asm/kvm_host.h | 1 | ||||
-rw-r--r-- | arch/s390/include/asm/sysinfo.h | 1 | ||||
-rw-r--r-- | arch/s390/include/uapi/asm/sthyi.h | 6 | ||||
-rw-r--r-- | arch/s390/include/uapi/asm/unistd.h | 3 | ||||
-rw-r--r-- | arch/s390/kernel/Makefile | 2 | ||||
-rw-r--r-- | arch/s390/kernel/compat_wrapper.c | 1 | ||||
-rw-r--r-- | arch/s390/kernel/entry.h | 1 | ||||
-rw-r--r-- | arch/s390/kernel/sthyi.c (renamed from arch/s390/kvm/sthyi.c) | 172 | ||||
-rw-r--r-- | arch/s390/kernel/syscalls.S | 1 | ||||
-rw-r--r-- | arch/s390/kvm/Makefile | 2 | ||||
-rw-r--r-- | arch/s390/kvm/intercept.c | 56 | ||||
-rw-r--r-- | arch/s390/kvm/kvm-s390.c | 2 | ||||
-rw-r--r-- | arch/s390/kvm/kvm-s390.h | 5 |
13 files changed, 182 insertions, 71 deletions
diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h index 51375e766e90..fd006a272024 100644 --- a/arch/s390/include/asm/kvm_host.h +++ b/arch/s390/include/asm/kvm_host.h | |||
@@ -736,7 +736,6 @@ struct kvm_arch{ | |||
736 | wait_queue_head_t ipte_wq; | 736 | wait_queue_head_t ipte_wq; |
737 | int ipte_lock_count; | 737 | int ipte_lock_count; |
738 | struct mutex ipte_mutex; | 738 | struct mutex ipte_mutex; |
739 | struct ratelimit_state sthyi_limit; | ||
740 | spinlock_t start_stop_lock; | 739 | spinlock_t start_stop_lock; |
741 | struct sie_page2 *sie_page2; | 740 | struct sie_page2 *sie_page2; |
742 | struct kvm_s390_cpu_model model; | 741 | struct kvm_s390_cpu_model model; |
diff --git a/arch/s390/include/asm/sysinfo.h b/arch/s390/include/asm/sysinfo.h index 2b498e58b914..e4a28307bc5d 100644 --- a/arch/s390/include/asm/sysinfo.h +++ b/arch/s390/include/asm/sysinfo.h | |||
@@ -198,4 +198,5 @@ struct service_level { | |||
198 | int register_service_level(struct service_level *); | 198 | int register_service_level(struct service_level *); |
199 | int unregister_service_level(struct service_level *); | 199 | int unregister_service_level(struct service_level *); |
200 | 200 | ||
201 | int sthyi_fill(void *dst, u64 *rc); | ||
201 | #endif /* __ASM_S390_SYSINFO_H */ | 202 | #endif /* __ASM_S390_SYSINFO_H */ |
diff --git a/arch/s390/include/uapi/asm/sthyi.h b/arch/s390/include/uapi/asm/sthyi.h new file mode 100644 index 000000000000..ec113db4eb7e --- /dev/null +++ b/arch/s390/include/uapi/asm/sthyi.h | |||
@@ -0,0 +1,6 @@ | |||
1 | #ifndef _UAPI_ASM_STHYI_H | ||
2 | #define _UAPI_ASM_STHYI_H | ||
3 | |||
4 | #define STHYI_FC_CP_IFL_CAP 0 | ||
5 | |||
6 | #endif /* _UAPI_ASM_STHYI_H */ | ||
diff --git a/arch/s390/include/uapi/asm/unistd.h b/arch/s390/include/uapi/asm/unistd.h index ea42290e7d51..61c64f543769 100644 --- a/arch/s390/include/uapi/asm/unistd.h +++ b/arch/s390/include/uapi/asm/unistd.h | |||
@@ -315,7 +315,8 @@ | |||
315 | #define __NR_pwritev2 377 | 315 | #define __NR_pwritev2 377 |
316 | #define __NR_s390_guarded_storage 378 | 316 | #define __NR_s390_guarded_storage 378 |
317 | #define __NR_statx 379 | 317 | #define __NR_statx 379 |
318 | #define NR_syscalls 380 | 318 | #define __NR_s390_sthyi 380 |
319 | #define NR_syscalls 381 | ||
319 | 320 | ||
320 | /* | 321 | /* |
321 | * There are some system calls that are not present on 64 bit, some | 322 | * There are some system calls that are not present on 64 bit, some |
diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile index adb3fe2e3d42..1fefb7f9216f 100644 --- a/arch/s390/kernel/Makefile +++ b/arch/s390/kernel/Makefile | |||
@@ -55,7 +55,7 @@ obj-y := traps.o time.o process.o base.o early.o setup.o idle.o vtime.o | |||
55 | obj-y += processor.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o nmi.o | 55 | obj-y += processor.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o nmi.o |
56 | obj-y += debug.o irq.o ipl.o dis.o diag.o vdso.o als.o | 56 | obj-y += debug.o irq.o ipl.o dis.o diag.o vdso.o als.o |
57 | obj-y += sysinfo.o jump_label.o lgr.o os_info.o machine_kexec.o pgm_check.o | 57 | obj-y += sysinfo.o jump_label.o lgr.o os_info.o machine_kexec.o pgm_check.o |
58 | obj-y += runtime_instr.o cache.o fpu.o dumpstack.o guarded_storage.o | 58 | obj-y += runtime_instr.o cache.o fpu.o dumpstack.o guarded_storage.o sthyi.o |
59 | obj-y += entry.o reipl.o relocate_kernel.o kdebugfs.o | 59 | obj-y += entry.o reipl.o relocate_kernel.o kdebugfs.o |
60 | 60 | ||
61 | extra-y += head.o head64.o vmlinux.lds | 61 | extra-y += head.o head64.o vmlinux.lds |
diff --git a/arch/s390/kernel/compat_wrapper.c b/arch/s390/kernel/compat_wrapper.c index 986642a3543b..eb0b17ed95b6 100644 --- a/arch/s390/kernel/compat_wrapper.c +++ b/arch/s390/kernel/compat_wrapper.c | |||
@@ -180,3 +180,4 @@ COMPAT_SYSCALL_WRAP3(mlock2, unsigned long, start, size_t, len, int, flags); | |||
180 | COMPAT_SYSCALL_WRAP6(copy_file_range, int, fd_in, loff_t __user *, off_in, int, fd_out, loff_t __user *, off_out, size_t, len, unsigned int, flags); | 180 | COMPAT_SYSCALL_WRAP6(copy_file_range, int, fd_in, loff_t __user *, off_in, int, fd_out, loff_t __user *, off_out, size_t, len, unsigned int, flags); |
181 | COMPAT_SYSCALL_WRAP2(s390_guarded_storage, int, command, struct gs_cb *, gs_cb); | 181 | COMPAT_SYSCALL_WRAP2(s390_guarded_storage, int, command, struct gs_cb *, gs_cb); |
182 | COMPAT_SYSCALL_WRAP5(statx, int, dfd, const char __user *, path, unsigned, flags, unsigned, mask, struct statx __user *, buffer); | 182 | COMPAT_SYSCALL_WRAP5(statx, int, dfd, const char __user *, path, unsigned, flags, unsigned, mask, struct statx __user *, buffer); |
183 | COMPAT_SYSCALL_WRAP4(s390_sthyi, unsigned long, code, void __user *, info, u64 __user *, rc, unsigned long, flags); | ||
diff --git a/arch/s390/kernel/entry.h b/arch/s390/kernel/entry.h index dbf5f7e18246..bb5301eeb4f4 100644 --- a/arch/s390/kernel/entry.h +++ b/arch/s390/kernel/entry.h | |||
@@ -77,6 +77,7 @@ long sys_s390_runtime_instr(int command, int signum); | |||
77 | long sys_s390_guarded_storage(int command, struct gs_cb __user *); | 77 | long sys_s390_guarded_storage(int command, struct gs_cb __user *); |
78 | long sys_s390_pci_mmio_write(unsigned long, const void __user *, size_t); | 78 | long sys_s390_pci_mmio_write(unsigned long, const void __user *, size_t); |
79 | long sys_s390_pci_mmio_read(unsigned long, void __user *, size_t); | 79 | long sys_s390_pci_mmio_read(unsigned long, void __user *, size_t); |
80 | long sys_s390_sthyi(unsigned long function_code, void __user *buffer, u64 __user *return_code, unsigned long flags); | ||
80 | 81 | ||
81 | DECLARE_PER_CPU(u64, mt_cycles[8]); | 82 | DECLARE_PER_CPU(u64, mt_cycles[8]); |
82 | 83 | ||
diff --git a/arch/s390/kvm/sthyi.c b/arch/s390/kernel/sthyi.c index 395926b8c1ed..12981e197f01 100644 --- a/arch/s390/kvm/sthyi.c +++ b/arch/s390/kernel/sthyi.c | |||
@@ -8,22 +8,19 @@ | |||
8 | * Copyright IBM Corp. 2016 | 8 | * Copyright IBM Corp. 2016 |
9 | * Author(s): Janosch Frank <frankja@linux.vnet.ibm.com> | 9 | * Author(s): Janosch Frank <frankja@linux.vnet.ibm.com> |
10 | */ | 10 | */ |
11 | #include <linux/kvm_host.h> | ||
12 | #include <linux/errno.h> | 11 | #include <linux/errno.h> |
13 | #include <linux/pagemap.h> | 12 | #include <linux/pagemap.h> |
14 | #include <linux/vmalloc.h> | 13 | #include <linux/vmalloc.h> |
15 | #include <linux/ratelimit.h> | 14 | #include <linux/syscalls.h> |
16 | 15 | #include <linux/mutex.h> | |
17 | #include <asm/kvm_host.h> | ||
18 | #include <asm/asm-offsets.h> | 16 | #include <asm/asm-offsets.h> |
19 | #include <asm/sclp.h> | 17 | #include <asm/sclp.h> |
20 | #include <asm/diag.h> | 18 | #include <asm/diag.h> |
21 | #include <asm/sysinfo.h> | 19 | #include <asm/sysinfo.h> |
22 | #include <asm/ebcdic.h> | 20 | #include <asm/ebcdic.h> |
23 | 21 | #include <asm/facility.h> | |
24 | #include "kvm-s390.h" | 22 | #include <asm/sthyi.h> |
25 | #include "gaccess.h" | 23 | #include "entry.h" |
26 | #include "trace.h" | ||
27 | 24 | ||
28 | #define DED_WEIGHT 0xffff | 25 | #define DED_WEIGHT 0xffff |
29 | /* | 26 | /* |
@@ -144,6 +141,21 @@ struct lpar_cpu_inf { | |||
144 | struct cpu_inf ifl; | 141 | struct cpu_inf ifl; |
145 | }; | 142 | }; |
146 | 143 | ||
144 | /* | ||
145 | * STHYI requires extensive locking in the higher hypervisors | ||
146 | * and is very computational/memory expensive. Therefore we | ||
147 | * cache the retrieved data whose valid period is 1s. | ||
148 | */ | ||
149 | #define CACHE_VALID_JIFFIES HZ | ||
150 | |||
151 | struct sthyi_info { | ||
152 | void *info; | ||
153 | unsigned long end; | ||
154 | }; | ||
155 | |||
156 | static DEFINE_MUTEX(sthyi_mutex); | ||
157 | static struct sthyi_info sthyi_cache; | ||
158 | |||
147 | static inline u64 cpu_id(u8 ctidx, void *diag224_buf) | 159 | static inline u64 cpu_id(u8 ctidx, void *diag224_buf) |
148 | { | 160 | { |
149 | return *((u64 *)(diag224_buf + (ctidx + 1) * DIAG204_CPU_NAME_LEN)); | 161 | return *((u64 *)(diag224_buf + (ctidx + 1) * DIAG204_CPU_NAME_LEN)); |
@@ -382,88 +394,124 @@ out: | |||
382 | vfree(diag204_buf); | 394 | vfree(diag204_buf); |
383 | } | 395 | } |
384 | 396 | ||
385 | static int sthyi(u64 vaddr) | 397 | static int sthyi(u64 vaddr, u64 *rc) |
386 | { | 398 | { |
387 | register u64 code asm("0") = 0; | 399 | register u64 code asm("0") = 0; |
388 | register u64 addr asm("2") = vaddr; | 400 | register u64 addr asm("2") = vaddr; |
401 | register u64 rcode asm("3"); | ||
389 | int cc; | 402 | int cc; |
390 | 403 | ||
391 | asm volatile( | 404 | asm volatile( |
392 | ".insn rre,0xB2560000,%[code],%[addr]\n" | 405 | ".insn rre,0xB2560000,%[code],%[addr]\n" |
393 | "ipm %[cc]\n" | 406 | "ipm %[cc]\n" |
394 | "srl %[cc],28\n" | 407 | "srl %[cc],28\n" |
395 | : [cc] "=d" (cc) | 408 | : [cc] "=d" (cc), "=d" (rcode) |
396 | : [code] "d" (code), [addr] "a" (addr) | 409 | : [code] "d" (code), [addr] "a" (addr) |
397 | : "3", "memory", "cc"); | 410 | : "memory", "cc"); |
411 | *rc = rcode; | ||
398 | return cc; | 412 | return cc; |
399 | } | 413 | } |
400 | 414 | ||
401 | int handle_sthyi(struct kvm_vcpu *vcpu) | 415 | static int fill_dst(void *dst, u64 *rc) |
402 | { | 416 | { |
403 | int reg1, reg2, r = 0; | 417 | struct sthyi_sctns *sctns = (struct sthyi_sctns *)dst; |
404 | u64 code, addr, cc = 0; | ||
405 | struct sthyi_sctns *sctns = NULL; | ||
406 | |||
407 | if (!test_kvm_facility(vcpu->kvm, 74)) | ||
408 | return kvm_s390_inject_program_int(vcpu, PGM_OPERATION); | ||
409 | 418 | ||
410 | /* | 419 | /* |
411 | * STHYI requires extensive locking in the higher hypervisors | 420 | * If the facility is on, we don't want to emulate the instruction. |
412 | * and is very computational/memory expensive. Therefore we | 421 | * We ask the hypervisor to provide the data. |
413 | * ratelimit the executions per VM. | ||
414 | */ | 422 | */ |
415 | if (!__ratelimit(&vcpu->kvm->arch.sthyi_limit)) { | 423 | if (test_facility(74)) |
416 | kvm_s390_retry_instr(vcpu); | 424 | return sthyi((u64)dst, rc); |
425 | |||
426 | fill_hdr(sctns); | ||
427 | fill_stsi(sctns); | ||
428 | fill_diag(sctns); | ||
429 | *rc = 0; | ||
430 | return 0; | ||
431 | } | ||
432 | |||
433 | static int sthyi_init_cache(void) | ||
434 | { | ||
435 | if (sthyi_cache.info) | ||
417 | return 0; | 436 | return 0; |
418 | } | 437 | sthyi_cache.info = (void *)get_zeroed_page(GFP_KERNEL); |
438 | if (!sthyi_cache.info) | ||
439 | return -ENOMEM; | ||
440 | sthyi_cache.end = jiffies - 1; /* expired */ | ||
441 | return 0; | ||
442 | } | ||
419 | 443 | ||
420 | kvm_s390_get_regs_rre(vcpu, ®1, ®2); | 444 | static int sthyi_update_cache(u64 *rc) |
421 | code = vcpu->run->s.regs.gprs[reg1]; | 445 | { |
422 | addr = vcpu->run->s.regs.gprs[reg2]; | 446 | int r; |
423 | 447 | ||
424 | vcpu->stat.instruction_sthyi++; | 448 | memset(sthyi_cache.info, 0, PAGE_SIZE); |
425 | VCPU_EVENT(vcpu, 3, "STHYI: fc: %llu addr: 0x%016llx", code, addr); | 449 | r = fill_dst(sthyi_cache.info, rc); |
426 | trace_kvm_s390_handle_sthyi(vcpu, code, addr); | 450 | if (r) |
451 | return r; | ||
452 | sthyi_cache.end = jiffies + CACHE_VALID_JIFFIES; | ||
453 | return r; | ||
454 | } | ||
427 | 455 | ||
428 | if (reg1 == reg2 || reg1 & 1 || reg2 & 1) | 456 | /* |
429 | return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); | 457 | * sthyi_fill - Fill page with data returned by the STHYI instruction |
458 | * | ||
459 | * @dst: Pointer to zeroed page | ||
460 | * @rc: Pointer for storing the return code of the instruction | ||
461 | * | ||
462 | * Fills the destination with system information returned by the STHYI | ||
463 | * instruction. The data is generated by emulation or execution of STHYI, | ||
464 | * if available. The return value is the condition code that would be | ||
465 | * returned, the rc parameter is the return code which is passed in | ||
466 | * register R2 + 1. | ||
467 | */ | ||
468 | int sthyi_fill(void *dst, u64 *rc) | ||
469 | { | ||
470 | int r; | ||
430 | 471 | ||
431 | if (code & 0xffff) { | 472 | mutex_lock(&sthyi_mutex); |
432 | cc = 3; | 473 | r = sthyi_init_cache(); |
474 | if (r) | ||
433 | goto out; | 475 | goto out; |
434 | } | ||
435 | 476 | ||
436 | if (addr & ~PAGE_MASK) | 477 | if (time_is_before_jiffies(sthyi_cache.end)) { |
437 | return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); | 478 | /* cache expired */ |
479 | r = sthyi_update_cache(rc); | ||
480 | if (r) | ||
481 | goto out; | ||
482 | } | ||
483 | *rc = 0; | ||
484 | memcpy(dst, sthyi_cache.info, PAGE_SIZE); | ||
485 | out: | ||
486 | mutex_unlock(&sthyi_mutex); | ||
487 | return r; | ||
488 | } | ||
489 | EXPORT_SYMBOL_GPL(sthyi_fill); | ||
438 | 490 | ||
439 | sctns = (void *)get_zeroed_page(GFP_KERNEL); | 491 | SYSCALL_DEFINE4(s390_sthyi, unsigned long, function_code, void __user *, buffer, |
440 | if (!sctns) | 492 | u64 __user *, return_code, unsigned long, flags) |
493 | { | ||
494 | u64 sthyi_rc; | ||
495 | void *info; | ||
496 | int r; | ||
497 | |||
498 | if (flags) | ||
499 | return -EINVAL; | ||
500 | if (function_code != STHYI_FC_CP_IFL_CAP) | ||
501 | return -EOPNOTSUPP; | ||
502 | info = (void *)get_zeroed_page(GFP_KERNEL); | ||
503 | if (!info) | ||
441 | return -ENOMEM; | 504 | return -ENOMEM; |
442 | 505 | r = sthyi_fill(info, &sthyi_rc); | |
443 | /* | 506 | if (r < 0) |
444 | * If we are a guest, we don't want to emulate an emulated | 507 | goto out; |
445 | * instruction. We ask the hypervisor to provide the data. | 508 | if (return_code && put_user(sthyi_rc, return_code)) { |
446 | */ | 509 | r = -EFAULT; |
447 | if (test_facility(74)) { | ||
448 | cc = sthyi((u64)sctns); | ||
449 | goto out; | 510 | goto out; |
450 | } | 511 | } |
451 | 512 | if (copy_to_user(buffer, info, PAGE_SIZE)) | |
452 | fill_hdr(sctns); | 513 | r = -EFAULT; |
453 | fill_stsi(sctns); | ||
454 | fill_diag(sctns); | ||
455 | |||
456 | out: | 514 | out: |
457 | if (!cc) { | 515 | free_page((unsigned long)info); |
458 | r = write_guest(vcpu, addr, reg2, sctns, PAGE_SIZE); | ||
459 | if (r) { | ||
460 | free_page((unsigned long)sctns); | ||
461 | return kvm_s390_inject_prog_cond(vcpu, r); | ||
462 | } | ||
463 | } | ||
464 | |||
465 | free_page((unsigned long)sctns); | ||
466 | vcpu->run->s.regs.gprs[reg2 + 1] = cc ? 4 : 0; | ||
467 | kvm_s390_set_psw_cc(vcpu, cc); | ||
468 | return r; | 516 | return r; |
469 | } | 517 | } |
diff --git a/arch/s390/kernel/syscalls.S b/arch/s390/kernel/syscalls.S index 54fce7b065de..0fb407ebbf46 100644 --- a/arch/s390/kernel/syscalls.S +++ b/arch/s390/kernel/syscalls.S | |||
@@ -388,3 +388,4 @@ SYSCALL(sys_preadv2,compat_sys_preadv2) | |||
388 | SYSCALL(sys_pwritev2,compat_sys_pwritev2) | 388 | SYSCALL(sys_pwritev2,compat_sys_pwritev2) |
389 | SYSCALL(sys_s390_guarded_storage,compat_sys_s390_guarded_storage) /* 378 */ | 389 | SYSCALL(sys_s390_guarded_storage,compat_sys_s390_guarded_storage) /* 378 */ |
390 | SYSCALL(sys_statx,compat_sys_statx) | 390 | SYSCALL(sys_statx,compat_sys_statx) |
391 | SYSCALL(sys_s390_sthyi,compat_sys_s390_sthyi) | ||
diff --git a/arch/s390/kvm/Makefile b/arch/s390/kvm/Makefile index 09a9e6dfc09f..6048b1c6e580 100644 --- a/arch/s390/kvm/Makefile +++ b/arch/s390/kvm/Makefile | |||
@@ -12,6 +12,6 @@ common-objs = $(KVM)/kvm_main.o $(KVM)/eventfd.o $(KVM)/async_pf.o $(KVM)/irqch | |||
12 | ccflags-y := -Ivirt/kvm -Iarch/s390/kvm | 12 | ccflags-y := -Ivirt/kvm -Iarch/s390/kvm |
13 | 13 | ||
14 | kvm-objs := $(common-objs) kvm-s390.o intercept.o interrupt.o priv.o sigp.o | 14 | kvm-objs := $(common-objs) kvm-s390.o intercept.o interrupt.o priv.o sigp.o |
15 | kvm-objs += diag.o gaccess.o guestdbg.o sthyi.o vsie.o | 15 | kvm-objs += diag.o gaccess.o guestdbg.o vsie.o |
16 | 16 | ||
17 | obj-$(CONFIG_KVM) += kvm.o | 17 | obj-$(CONFIG_KVM) += kvm.o |
diff --git a/arch/s390/kvm/intercept.c b/arch/s390/kvm/intercept.c index a4752bf6b526..8fe034beb623 100644 --- a/arch/s390/kvm/intercept.c +++ b/arch/s390/kvm/intercept.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <asm/kvm_host.h> | 18 | #include <asm/kvm_host.h> |
19 | #include <asm/asm-offsets.h> | 19 | #include <asm/asm-offsets.h> |
20 | #include <asm/irq.h> | 20 | #include <asm/irq.h> |
21 | #include <asm/sysinfo.h> | ||
21 | 22 | ||
22 | #include "kvm-s390.h" | 23 | #include "kvm-s390.h" |
23 | #include "gaccess.h" | 24 | #include "gaccess.h" |
@@ -360,6 +361,61 @@ static int handle_partial_execution(struct kvm_vcpu *vcpu) | |||
360 | return -EOPNOTSUPP; | 361 | return -EOPNOTSUPP; |
361 | } | 362 | } |
362 | 363 | ||
364 | /* | ||
365 | * Handle the sthyi instruction that provides the guest with system | ||
366 | * information, like current CPU resources available at each level of | ||
367 | * the machine. | ||
368 | */ | ||
369 | int handle_sthyi(struct kvm_vcpu *vcpu) | ||
370 | { | ||
371 | int reg1, reg2, r = 0; | ||
372 | u64 code, addr, cc = 0, rc = 0; | ||
373 | struct sthyi_sctns *sctns = NULL; | ||
374 | |||
375 | if (!test_kvm_facility(vcpu->kvm, 74)) | ||
376 | return kvm_s390_inject_program_int(vcpu, PGM_OPERATION); | ||
377 | |||
378 | kvm_s390_get_regs_rre(vcpu, ®1, ®2); | ||
379 | code = vcpu->run->s.regs.gprs[reg1]; | ||
380 | addr = vcpu->run->s.regs.gprs[reg2]; | ||
381 | |||
382 | vcpu->stat.instruction_sthyi++; | ||
383 | VCPU_EVENT(vcpu, 3, "STHYI: fc: %llu addr: 0x%016llx", code, addr); | ||
384 | trace_kvm_s390_handle_sthyi(vcpu, code, addr); | ||
385 | |||
386 | if (reg1 == reg2 || reg1 & 1 || reg2 & 1) | ||
387 | return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); | ||
388 | |||
389 | if (code & 0xffff) { | ||
390 | cc = 3; | ||
391 | rc = 4; | ||
392 | goto out; | ||
393 | } | ||
394 | |||
395 | if (addr & ~PAGE_MASK) | ||
396 | return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); | ||
397 | |||
398 | sctns = (void *)get_zeroed_page(GFP_KERNEL); | ||
399 | if (!sctns) | ||
400 | return -ENOMEM; | ||
401 | |||
402 | cc = sthyi_fill(sctns, &rc); | ||
403 | |||
404 | out: | ||
405 | if (!cc) { | ||
406 | r = write_guest(vcpu, addr, reg2, sctns, PAGE_SIZE); | ||
407 | if (r) { | ||
408 | free_page((unsigned long)sctns); | ||
409 | return kvm_s390_inject_prog_cond(vcpu, r); | ||
410 | } | ||
411 | } | ||
412 | |||
413 | free_page((unsigned long)sctns); | ||
414 | vcpu->run->s.regs.gprs[reg2 + 1] = rc; | ||
415 | kvm_s390_set_psw_cc(vcpu, cc); | ||
416 | return r; | ||
417 | } | ||
418 | |||
363 | static int handle_operexc(struct kvm_vcpu *vcpu) | 419 | static int handle_operexc(struct kvm_vcpu *vcpu) |
364 | { | 420 | { |
365 | psw_t oldpsw, newpsw; | 421 | psw_t oldpsw, newpsw; |
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index 40d0a1a97889..de6a5b790da0 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c | |||
@@ -1884,8 +1884,6 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) | |||
1884 | 1884 | ||
1885 | rc = -ENOMEM; | 1885 | rc = -ENOMEM; |
1886 | 1886 | ||
1887 | ratelimit_state_init(&kvm->arch.sthyi_limit, 5 * HZ, 500); | ||
1888 | |||
1889 | kvm->arch.use_esca = 0; /* start with basic SCA */ | 1887 | kvm->arch.use_esca = 0; /* start with basic SCA */ |
1890 | if (!sclp.has_64bscao) | 1888 | if (!sclp.has_64bscao) |
1891 | alloc_flags |= GFP_DMA; | 1889 | alloc_flags |= GFP_DMA; |
diff --git a/arch/s390/kvm/kvm-s390.h b/arch/s390/kvm/kvm-s390.h index 9f8fdd7b2311..10d65dfbc306 100644 --- a/arch/s390/kvm/kvm-s390.h +++ b/arch/s390/kvm/kvm-s390.h | |||
@@ -242,6 +242,8 @@ static inline void kvm_s390_retry_instr(struct kvm_vcpu *vcpu) | |||
242 | kvm_s390_rewind_psw(vcpu, kvm_s390_get_ilen(vcpu)); | 242 | kvm_s390_rewind_psw(vcpu, kvm_s390_get_ilen(vcpu)); |
243 | } | 243 | } |
244 | 244 | ||
245 | int handle_sthyi(struct kvm_vcpu *vcpu); | ||
246 | |||
245 | /* implemented in priv.c */ | 247 | /* implemented in priv.c */ |
246 | int is_valid_psw(psw_t *psw); | 248 | int is_valid_psw(psw_t *psw); |
247 | int kvm_s390_handle_aa(struct kvm_vcpu *vcpu); | 249 | int kvm_s390_handle_aa(struct kvm_vcpu *vcpu); |
@@ -268,9 +270,6 @@ void kvm_s390_vsie_destroy(struct kvm *kvm); | |||
268 | int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu); | 270 | int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu); |
269 | int kvm_s390_handle_sigp_pei(struct kvm_vcpu *vcpu); | 271 | int kvm_s390_handle_sigp_pei(struct kvm_vcpu *vcpu); |
270 | 272 | ||
271 | /* implemented in sthyi.c */ | ||
272 | int handle_sthyi(struct kvm_vcpu *vcpu); | ||
273 | |||
274 | /* implemented in kvm-s390.c */ | 273 | /* implemented in kvm-s390.c */ |
275 | void kvm_s390_set_tod_clock_ext(struct kvm *kvm, | 274 | void kvm_s390_set_tod_clock_ext(struct kvm *kvm, |
276 | const struct kvm_s390_vm_tod_clock *gtod); | 275 | const struct kvm_s390_vm_tod_clock *gtod); |