aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorQingFeng Hao <haoqf@linux.vnet.ibm.com>2017-09-29 06:41:50 -0400
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2017-10-09 05:15:33 -0400
commitb7c92f1a4e131e459bcf53a570e7265e5ce64455 (patch)
treedc227ee881d42de4577db06b2ed582058971fcc5
parent2bd6bf03f4c1c59381d62c61d03f6cc3fe71f66e (diff)
s390/sthyi: reorganize sthyi implementation
As we need to support sthyi instruction on LPAR too, move the common code to kernel part and kvm related code to intercept.c for better reuse. Signed-off-by: QingFeng Hao <haoqf@linux.vnet.ibm.com> Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
-rw-r--r--arch/s390/include/asm/sysinfo.h1
-rw-r--r--arch/s390/kernel/Makefile2
-rw-r--r--arch/s390/kernel/sthyi.c (renamed from arch/s390/kvm/sthyi.c)95
-rw-r--r--arch/s390/kvm/Makefile2
-rw-r--r--arch/s390/kvm/intercept.c66
-rw-r--r--arch/s390/kvm/kvm-s390.h5
6 files changed, 98 insertions, 73 deletions
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 {
198int register_service_level(struct service_level *); 198int register_service_level(struct service_level *);
199int unregister_service_level(struct service_level *); 199int unregister_service_level(struct service_level *);
200 200
201int sthyi_fill(void *dst, u64 *rc);
201#endif /* __ASM_S390_SYSINFO_H */ 202#endif /* __ASM_S390_SYSINFO_H */
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
55obj-y += processor.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o nmi.o 55obj-y += processor.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o nmi.o
56obj-y += debug.o irq.o ipl.o dis.o diag.o vdso.o als.o 56obj-y += debug.o irq.o ipl.o dis.o diag.o vdso.o als.o
57obj-y += sysinfo.o jump_label.o lgr.o os_info.o machine_kexec.o pgm_check.o 57obj-y += sysinfo.o jump_label.o lgr.o os_info.o machine_kexec.o pgm_check.o
58obj-y += runtime_instr.o cache.o fpu.o dumpstack.o guarded_storage.o 58obj-y += runtime_instr.o cache.o fpu.o dumpstack.o guarded_storage.o sthyi.o
59obj-y += entry.o reipl.o relocate_kernel.o kdebugfs.o 59obj-y += entry.o reipl.o relocate_kernel.o kdebugfs.o
60 60
61extra-y += head.o head64.o vmlinux.lds 61extra-y += head.o head64.o vmlinux.lds
diff --git a/arch/s390/kvm/sthyi.c b/arch/s390/kernel/sthyi.c
index 395926b8c1ed..3d51f86f9dec 100644
--- a/arch/s390/kvm/sthyi.c
+++ b/arch/s390/kernel/sthyi.c
@@ -8,22 +8,17 @@
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/ratelimit.h>
16 15
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"
25#include "gaccess.h"
26#include "trace.h"
27 22
28#define DED_WEIGHT 0xffff 23#define DED_WEIGHT 0xffff
29/* 24/*
@@ -382,88 +377,52 @@ out:
382 vfree(diag204_buf); 377 vfree(diag204_buf);
383} 378}
384 379
385static int sthyi(u64 vaddr) 380static int sthyi(u64 vaddr, u64 *rc)
386{ 381{
387 register u64 code asm("0") = 0; 382 register u64 code asm("0") = 0;
388 register u64 addr asm("2") = vaddr; 383 register u64 addr asm("2") = vaddr;
384 register u64 rcode asm("3");
389 int cc; 385 int cc;
390 386
391 asm volatile( 387 asm volatile(
392 ".insn rre,0xB2560000,%[code],%[addr]\n" 388 ".insn rre,0xB2560000,%[code],%[addr]\n"
393 "ipm %[cc]\n" 389 "ipm %[cc]\n"
394 "srl %[cc],28\n" 390 "srl %[cc],28\n"
395 : [cc] "=d" (cc) 391 : [cc] "=d" (cc), "=d" (rcode)
396 : [code] "d" (code), [addr] "a" (addr) 392 : [code] "d" (code), [addr] "a" (addr)
397 : "3", "memory", "cc"); 393 : "memory", "cc");
394 *rc = rcode;
398 return cc; 395 return cc;
399} 396}
400 397
401int handle_sthyi(struct kvm_vcpu *vcpu) 398/*
399 * sthyi_fill - Fill page with data returned by the STHYI instruction
400 *
401 * @dst: Pointer to zeroed page
402 * @rc: Pointer for storing the return code of the instruction
403 *
404 * Fills the destination with system information returned by the STHYI
405 * instruction. The data is generated by emulation or execution of STHYI,
406 * if available. The return value is the condition code that would be
407 * returned, the rc parameter is the return code which is passed in
408 * register R2 + 1.
409 */
410int sthyi_fill(void *dst, u64 *rc)
402{ 411{
403 int reg1, reg2, r = 0; 412 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
410 /*
411 * STHYI requires extensive locking in the higher hypervisors
412 * and is very computational/memory expensive. Therefore we
413 * ratelimit the executions per VM.
414 */
415 if (!__ratelimit(&vcpu->kvm->arch.sthyi_limit)) {
416 kvm_s390_retry_instr(vcpu);
417 return 0;
418 }
419
420 kvm_s390_get_regs_rre(vcpu, &reg1, &reg2);
421 code = vcpu->run->s.regs.gprs[reg1];
422 addr = vcpu->run->s.regs.gprs[reg2];
423
424 vcpu->stat.instruction_sthyi++;
425 VCPU_EVENT(vcpu, 3, "STHYI: fc: %llu addr: 0x%016llx", code, addr);
426 trace_kvm_s390_handle_sthyi(vcpu, code, addr);
427
428 if (reg1 == reg2 || reg1 & 1 || reg2 & 1)
429 return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
430
431 if (code & 0xffff) {
432 cc = 3;
433 goto out;
434 }
435
436 if (addr & ~PAGE_MASK)
437 return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
438
439 sctns = (void *)get_zeroed_page(GFP_KERNEL);
440 if (!sctns)
441 return -ENOMEM;
442 413
443 /* 414 /*
444 * If we are a guest, we don't want to emulate an emulated 415 * If the facility is on, we don't want to emulate the instruction.
445 * instruction. We ask the hypervisor to provide the data. 416 * We ask the hypervisor to provide the data.
446 */ 417 */
447 if (test_facility(74)) { 418 if (test_facility(74))
448 cc = sthyi((u64)sctns); 419 return sthyi((u64)dst, rc);
449 goto out;
450 }
451 420
452 fill_hdr(sctns); 421 fill_hdr(sctns);
453 fill_stsi(sctns); 422 fill_stsi(sctns);
454 fill_diag(sctns); 423 fill_diag(sctns);
455 424
456out: 425 *rc = 0;
457 if (!cc) { 426 return 0;
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;
469} 427}
428EXPORT_SYMBOL_GPL(sthyi_fill);
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
12ccflags-y := -Ivirt/kvm -Iarch/s390/kvm 12ccflags-y := -Ivirt/kvm -Iarch/s390/kvm
13 13
14kvm-objs := $(common-objs) kvm-s390.o intercept.o interrupt.o priv.o sigp.o 14kvm-objs := $(common-objs) kvm-s390.o intercept.o interrupt.o priv.o sigp.o
15kvm-objs += diag.o gaccess.o guestdbg.o sthyi.o vsie.o 15kvm-objs += diag.o gaccess.o guestdbg.o vsie.o
16 16
17obj-$(CONFIG_KVM) += kvm.o 17obj-$(CONFIG_KVM) += kvm.o
diff --git a/arch/s390/kvm/intercept.c b/arch/s390/kvm/intercept.c
index a4752bf6b526..46adda5e2b2c 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,71 @@ 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 */
369int 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 /*
379 * STHYI requires extensive locking in the higher hypervisors
380 * and is very computational/memory expensive. Therefore we
381 * ratelimit the executions per VM.
382 */
383 if (!__ratelimit(&vcpu->kvm->arch.sthyi_limit)) {
384 kvm_s390_retry_instr(vcpu);
385 return 0;
386 }
387
388 kvm_s390_get_regs_rre(vcpu, &reg1, &reg2);
389 code = vcpu->run->s.regs.gprs[reg1];
390 addr = vcpu->run->s.regs.gprs[reg2];
391
392 vcpu->stat.instruction_sthyi++;
393 VCPU_EVENT(vcpu, 3, "STHYI: fc: %llu addr: 0x%016llx", code, addr);
394 trace_kvm_s390_handle_sthyi(vcpu, code, addr);
395
396 if (reg1 == reg2 || reg1 & 1 || reg2 & 1)
397 return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
398
399 if (code & 0xffff) {
400 cc = 3;
401 rc = 4;
402 goto out;
403 }
404
405 if (addr & ~PAGE_MASK)
406 return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
407
408 sctns = (void *)get_zeroed_page(GFP_KERNEL);
409 if (!sctns)
410 return -ENOMEM;
411
412 cc = sthyi_fill(sctns, &rc);
413
414out:
415 if (!cc) {
416 r = write_guest(vcpu, addr, reg2, sctns, PAGE_SIZE);
417 if (r) {
418 free_page((unsigned long)sctns);
419 return kvm_s390_inject_prog_cond(vcpu, r);
420 }
421 }
422
423 free_page((unsigned long)sctns);
424 vcpu->run->s.regs.gprs[reg2 + 1] = rc;
425 kvm_s390_set_psw_cc(vcpu, cc);
426 return r;
427}
428
363static int handle_operexc(struct kvm_vcpu *vcpu) 429static int handle_operexc(struct kvm_vcpu *vcpu)
364{ 430{
365 psw_t oldpsw, newpsw; 431 psw_t oldpsw, newpsw;
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
245int handle_sthyi(struct kvm_vcpu *vcpu);
246
245/* implemented in priv.c */ 247/* implemented in priv.c */
246int is_valid_psw(psw_t *psw); 248int is_valid_psw(psw_t *psw);
247int kvm_s390_handle_aa(struct kvm_vcpu *vcpu); 249int kvm_s390_handle_aa(struct kvm_vcpu *vcpu);
@@ -268,9 +270,6 @@ void kvm_s390_vsie_destroy(struct kvm *kvm);
268int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu); 270int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu);
269int kvm_s390_handle_sigp_pei(struct kvm_vcpu *vcpu); 271int kvm_s390_handle_sigp_pei(struct kvm_vcpu *vcpu);
270 272
271/* implemented in sthyi.c */
272int handle_sthyi(struct kvm_vcpu *vcpu);
273
274/* implemented in kvm-s390.c */ 273/* implemented in kvm-s390.c */
275void kvm_s390_set_tod_clock_ext(struct kvm *kvm, 274void 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);