aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Borntraeger <borntraeger@de.ibm.com>2008-03-25 13:47:34 -0400
committerAvi Kivity <avi@qumranet.com>2008-04-27 05:00:46 -0400
commite28acfea5dd9dbc67c2594cbefc140129dbd0e3f (patch)
tree2f66c3afcf18fd938bae1460f1c5d35ccbf75550
parent5288fbf0ef041ba0e8b4dcb2df4536b5e3a48b32 (diff)
KVM: s390: intercepts for diagnose instructions
This patch introduces interpretation of some diagnose instruction intercepts. Diagnose is our classic architected way of doing a hypercall. This patch features the following diagnose codes: - vm storage size, that tells the guest about its memory layout - time slice end, which is used by the guest to indicate that it waits for a lock and thus cannot use up its time slice in a useful way - ipl functions, which a guest can use to reset and reboot itself In order to implement ipl functions, we also introduce an exit reason that causes userspace to perform various resets on the virtual machine. All resets are described in the principles of operation book, except KVM_S390_RESET_IPL which causes a reboot of the machine. Acked-by: Martin Schwidefsky <martin.schwidefsky@de.ibm.com> Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com> Signed-off-by: Carsten Otte <cotte@de.ibm.com> Signed-off-by: Avi Kivity <avi@qumranet.com>
-rw-r--r--arch/s390/kvm/Makefile2
-rw-r--r--arch/s390/kvm/diag.c67
-rw-r--r--arch/s390/kvm/intercept.c1
-rw-r--r--arch/s390/kvm/kvm-s390.c1
-rw-r--r--arch/s390/kvm/kvm-s390.h3
-rw-r--r--include/asm-s390/kvm_host.h5
-rw-r--r--include/linux/kvm.h8
7 files changed, 85 insertions, 2 deletions
diff --git a/arch/s390/kvm/Makefile b/arch/s390/kvm/Makefile
index f3bf11a88bc7..e5221ec0b8e3 100644
--- a/arch/s390/kvm/Makefile
+++ b/arch/s390/kvm/Makefile
@@ -10,5 +10,5 @@ common-objs = $(addprefix ../../../virt/kvm/, kvm_main.o)
10 10
11EXTRA_CFLAGS += -Ivirt/kvm -Iarch/s390/kvm 11EXTRA_CFLAGS += -Ivirt/kvm -Iarch/s390/kvm
12 12
13kvm-objs := $(common-objs) kvm-s390.o sie64a.o intercept.o interrupt.o priv.o sigp.o 13kvm-objs := $(common-objs) kvm-s390.o sie64a.o intercept.o interrupt.o priv.o sigp.o diag.o
14obj-$(CONFIG_KVM) += kvm.o 14obj-$(CONFIG_KVM) += kvm.o
diff --git a/arch/s390/kvm/diag.c b/arch/s390/kvm/diag.c
new file mode 100644
index 000000000000..f639a152869f
--- /dev/null
+++ b/arch/s390/kvm/diag.c
@@ -0,0 +1,67 @@
1/*
2 * diag.c - handling diagnose instructions
3 *
4 * Copyright IBM Corp. 2008
5 *
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)
8 * as published by the Free Software Foundation.
9 *
10 * Author(s): Carsten Otte <cotte@de.ibm.com>
11 * Christian Borntraeger <borntraeger@de.ibm.com>
12 */
13
14#include <linux/kvm.h>
15#include <linux/kvm_host.h>
16#include "kvm-s390.h"
17
18static int __diag_time_slice_end(struct kvm_vcpu *vcpu)
19{
20 VCPU_EVENT(vcpu, 5, "%s", "diag time slice end");
21 vcpu->stat.diagnose_44++;
22 vcpu_put(vcpu);
23 schedule();
24 vcpu_load(vcpu);
25 return 0;
26}
27
28static int __diag_ipl_functions(struct kvm_vcpu *vcpu)
29{
30 unsigned int reg = vcpu->arch.sie_block->ipa & 0xf;
31 unsigned long subcode = vcpu->arch.guest_gprs[reg] & 0xffff;
32
33 VCPU_EVENT(vcpu, 5, "diag ipl functions, subcode %lx", subcode);
34 switch (subcode) {
35 case 3:
36 vcpu->run->s390_reset_flags = KVM_S390_RESET_CLEAR;
37 break;
38 case 4:
39 vcpu->run->s390_reset_flags = 0;
40 break;
41 default:
42 return -ENOTSUPP;
43 }
44
45 atomic_clear_mask(CPUSTAT_RUNNING, &vcpu->arch.sie_block->cpuflags);
46 vcpu->run->s390_reset_flags |= KVM_S390_RESET_SUBSYSTEM;
47 vcpu->run->s390_reset_flags |= KVM_S390_RESET_IPL;
48 vcpu->run->s390_reset_flags |= KVM_S390_RESET_CPU_INIT;
49 vcpu->run->exit_reason = KVM_EXIT_S390_RESET;
50 VCPU_EVENT(vcpu, 3, "requesting userspace resets %lx",
51 vcpu->run->s390_reset_flags);
52 return -EREMOTE;
53}
54
55int kvm_s390_handle_diag(struct kvm_vcpu *vcpu)
56{
57 int code = (vcpu->arch.sie_block->ipb & 0xfff0000) >> 16;
58
59 switch (code) {
60 case 0x44:
61 return __diag_time_slice_end(vcpu);
62 case 0x308:
63 return __diag_ipl_functions(vcpu);
64 default:
65 return -ENOTSUPP;
66 }
67}
diff --git a/arch/s390/kvm/intercept.c b/arch/s390/kvm/intercept.c
index 9f0d8b239436..349581a26103 100644
--- a/arch/s390/kvm/intercept.c
+++ b/arch/s390/kvm/intercept.c
@@ -95,6 +95,7 @@ static int handle_lctl(struct kvm_vcpu *vcpu)
95} 95}
96 96
97static intercept_handler_t instruction_handlers[256] = { 97static intercept_handler_t instruction_handlers[256] = {
98 [0x83] = kvm_s390_handle_diag,
98 [0xae] = kvm_s390_handle_sigp, 99 [0xae] = kvm_s390_handle_sigp,
99 [0xb2] = kvm_s390_handle_priv, 100 [0xb2] = kvm_s390_handle_priv,
100 [0xb7] = handle_lctl, 101 [0xb7] = handle_lctl,
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index c632180739ee..d3b1de83678b 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -63,6 +63,7 @@ struct kvm_stats_debugfs_item debugfs_entries[] = {
63 { "instruction_sigp_set_arch", VCPU_STAT(instruction_sigp_arch) }, 63 { "instruction_sigp_set_arch", VCPU_STAT(instruction_sigp_arch) },
64 { "instruction_sigp_set_prefix", VCPU_STAT(instruction_sigp_prefix) }, 64 { "instruction_sigp_set_prefix", VCPU_STAT(instruction_sigp_prefix) },
65 { "instruction_sigp_restart", VCPU_STAT(instruction_sigp_restart) }, 65 { "instruction_sigp_restart", VCPU_STAT(instruction_sigp_restart) },
66 { "diagnose_44", VCPU_STAT(diagnose_44) },
66 { NULL } 67 { NULL }
67}; 68};
68 69
diff --git a/arch/s390/kvm/kvm-s390.h b/arch/s390/kvm/kvm-s390.h
index e6e5756a0e07..3893cf12eacf 100644
--- a/arch/s390/kvm/kvm-s390.h
+++ b/arch/s390/kvm/kvm-s390.h
@@ -58,4 +58,7 @@ int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu);
58/* implemented in kvm-s390.c */ 58/* implemented in kvm-s390.c */
59int __kvm_s390_vcpu_store_status(struct kvm_vcpu *vcpu, 59int __kvm_s390_vcpu_store_status(struct kvm_vcpu *vcpu,
60 unsigned long addr); 60 unsigned long addr);
61/* implemented in diag.c */
62int kvm_s390_handle_diag(struct kvm_vcpu *vcpu);
63
61#endif 64#endif
diff --git a/include/asm-s390/kvm_host.h b/include/asm-s390/kvm_host.h
index 1c829bdf5889..f8204a4f2e02 100644
--- a/include/asm-s390/kvm_host.h
+++ b/include/asm-s390/kvm_host.h
@@ -94,7 +94,9 @@ struct sie_block {
94 psw_t gpsw; /* 0x0090 */ 94 psw_t gpsw; /* 0x0090 */
95 __u64 gg14; /* 0x00a0 */ 95 __u64 gg14; /* 0x00a0 */
96 __u64 gg15; /* 0x00a8 */ 96 __u64 gg15; /* 0x00a8 */
97 __u8 reservedb0[80]; /* 0x00b0 */ 97 __u8 reservedb0[30]; /* 0x00b0 */
98 __u16 iprcc; /* 0x00ce */
99 __u8 reservedd0[48]; /* 0x00d0 */
98 __u64 gcr[16]; /* 0x0100 */ 100 __u64 gcr[16]; /* 0x0100 */
99 __u64 gbea; /* 0x0180 */ 101 __u64 gbea; /* 0x0180 */
100 __u8 reserved188[120]; /* 0x0188 */ 102 __u8 reserved188[120]; /* 0x0188 */
@@ -134,6 +136,7 @@ struct kvm_vcpu_stat {
134 u32 instruction_sigp_arch; 136 u32 instruction_sigp_arch;
135 u32 instruction_sigp_prefix; 137 u32 instruction_sigp_prefix;
136 u32 instruction_sigp_restart; 138 u32 instruction_sigp_restart;
139 u32 diagnose_44;
137}; 140};
138 141
139struct io_info { 142struct io_info {
diff --git a/include/linux/kvm.h b/include/linux/kvm.h
index 029f0284a2fd..f04bb426618f 100644
--- a/include/linux/kvm.h
+++ b/include/linux/kvm.h
@@ -75,6 +75,7 @@ struct kvm_irqchip {
75#define KVM_EXIT_SET_TPR 11 75#define KVM_EXIT_SET_TPR 11
76#define KVM_EXIT_TPR_ACCESS 12 76#define KVM_EXIT_TPR_ACCESS 12
77#define KVM_EXIT_S390_SIEIC 13 77#define KVM_EXIT_S390_SIEIC 13
78#define KVM_EXIT_S390_RESET 14
78 79
79/* for KVM_RUN, returned by mmap(vcpu_fd, offset=0) */ 80/* for KVM_RUN, returned by mmap(vcpu_fd, offset=0) */
80struct kvm_run { 81struct kvm_run {
@@ -147,6 +148,13 @@ struct kvm_run {
147 __u16 ipa; 148 __u16 ipa;
148 __u32 ipb; 149 __u32 ipb;
149 } s390_sieic; 150 } s390_sieic;
151 /* KVM_EXIT_S390_RESET */
152#define KVM_S390_RESET_POR 1
153#define KVM_S390_RESET_CLEAR 2
154#define KVM_S390_RESET_SUBSYSTEM 4
155#define KVM_S390_RESET_CPU_INIT 8
156#define KVM_S390_RESET_IPL 16
157 __u64 s390_reset_flags;
150 /* Fix the size of the union. */ 158 /* Fix the size of the union. */
151 char padding[256]; 159 char padding[256];
152 }; 160 };