aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
Diffstat (limited to 'arch')
-rw-r--r--arch/powerpc/include/asm/kvm_para.h114
-rw-r--r--arch/powerpc/include/asm/kvm_ppc.h1
-rw-r--r--arch/powerpc/kernel/Makefile2
-rw-r--r--arch/powerpc/kernel/kvm.c68
-rw-r--r--arch/powerpc/kvm/book3s.c9
-rw-r--r--arch/powerpc/kvm/booke.c10
-rw-r--r--arch/powerpc/kvm/powerpc.c32
7 files changed, 232 insertions, 4 deletions
diff --git a/arch/powerpc/include/asm/kvm_para.h b/arch/powerpc/include/asm/kvm_para.h
index e402999ba193..556fd59ee0f1 100644
--- a/arch/powerpc/include/asm/kvm_para.h
+++ b/arch/powerpc/include/asm/kvm_para.h
@@ -21,6 +21,7 @@
21#define __POWERPC_KVM_PARA_H__ 21#define __POWERPC_KVM_PARA_H__
22 22
23#include <linux/types.h> 23#include <linux/types.h>
24#include <linux/of.h>
24 25
25struct kvm_vcpu_arch_shared { 26struct kvm_vcpu_arch_shared {
26 __u64 sprg0; 27 __u64 sprg0;
@@ -34,16 +35,127 @@ struct kvm_vcpu_arch_shared {
34 __u32 dsisr; 35 __u32 dsisr;
35}; 36};
36 37
38#define KVM_SC_MAGIC_R0 0x4b564d21 /* "KVM!" */
39#define HC_VENDOR_KVM (42 << 16)
40#define HC_EV_SUCCESS 0
41#define HC_EV_UNIMPLEMENTED 12
42
37#ifdef __KERNEL__ 43#ifdef __KERNEL__
38 44
45#ifdef CONFIG_KVM_GUEST
46
47static inline int kvm_para_available(void)
48{
49 struct device_node *hyper_node;
50
51 hyper_node = of_find_node_by_path("/hypervisor");
52 if (!hyper_node)
53 return 0;
54
55 if (!of_device_is_compatible(hyper_node, "linux,kvm"))
56 return 0;
57
58 return 1;
59}
60
61extern unsigned long kvm_hypercall(unsigned long *in,
62 unsigned long *out,
63 unsigned long nr);
64
65#else
66
39static inline int kvm_para_available(void) 67static inline int kvm_para_available(void)
40{ 68{
41 return 0; 69 return 0;
42} 70}
43 71
72static unsigned long kvm_hypercall(unsigned long *in,
73 unsigned long *out,
74 unsigned long nr)
75{
76 return HC_EV_UNIMPLEMENTED;
77}
78
79#endif
80
81static inline long kvm_hypercall0_1(unsigned int nr, unsigned long *r2)
82{
83 unsigned long in[8];
84 unsigned long out[8];
85 unsigned long r;
86
87 r = kvm_hypercall(in, out, nr | HC_VENDOR_KVM);
88 *r2 = out[0];
89
90 return r;
91}
92
93static inline long kvm_hypercall0(unsigned int nr)
94{
95 unsigned long in[8];
96 unsigned long out[8];
97
98 return kvm_hypercall(in, out, nr | HC_VENDOR_KVM);
99}
100
101static inline long kvm_hypercall1(unsigned int nr, unsigned long p1)
102{
103 unsigned long in[8];
104 unsigned long out[8];
105
106 in[0] = p1;
107 return kvm_hypercall(in, out, nr | HC_VENDOR_KVM);
108}
109
110static inline long kvm_hypercall2(unsigned int nr, unsigned long p1,
111 unsigned long p2)
112{
113 unsigned long in[8];
114 unsigned long out[8];
115
116 in[0] = p1;
117 in[1] = p2;
118 return kvm_hypercall(in, out, nr | HC_VENDOR_KVM);
119}
120
121static inline long kvm_hypercall3(unsigned int nr, unsigned long p1,
122 unsigned long p2, unsigned long p3)
123{
124 unsigned long in[8];
125 unsigned long out[8];
126
127 in[0] = p1;
128 in[1] = p2;
129 in[2] = p3;
130 return kvm_hypercall(in, out, nr | HC_VENDOR_KVM);
131}
132
133static inline long kvm_hypercall4(unsigned int nr, unsigned long p1,
134 unsigned long p2, unsigned long p3,
135 unsigned long p4)
136{
137 unsigned long in[8];
138 unsigned long out[8];
139
140 in[0] = p1;
141 in[1] = p2;
142 in[2] = p3;
143 in[3] = p4;
144 return kvm_hypercall(in, out, nr | HC_VENDOR_KVM);
145}
146
147
44static inline unsigned int kvm_arch_para_features(void) 148static inline unsigned int kvm_arch_para_features(void)
45{ 149{
46 return 0; 150 unsigned long r;
151
152 if (!kvm_para_available())
153 return 0;
154
155 if(kvm_hypercall0_1(KVM_HC_FEATURES, &r))
156 return 0;
157
158 return r;
47} 159}
48 160
49#endif /* __KERNEL__ */ 161#endif /* __KERNEL__ */
diff --git a/arch/powerpc/include/asm/kvm_ppc.h b/arch/powerpc/include/asm/kvm_ppc.h
index 18d139ec2d22..ecb3bc74c344 100644
--- a/arch/powerpc/include/asm/kvm_ppc.h
+++ b/arch/powerpc/include/asm/kvm_ppc.h
@@ -107,6 +107,7 @@ extern int kvmppc_booke_init(void);
107extern void kvmppc_booke_exit(void); 107extern void kvmppc_booke_exit(void);
108 108
109extern void kvmppc_core_destroy_mmu(struct kvm_vcpu *vcpu); 109extern void kvmppc_core_destroy_mmu(struct kvm_vcpu *vcpu);
110extern int kvmppc_kvm_pv(struct kvm_vcpu *vcpu);
110 111
111/* 112/*
112 * Cuts out inst bits with ordering according to spec. 113 * Cuts out inst bits with ordering according to spec.
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile
index 1dda70129141..3a6955dc7191 100644
--- a/arch/powerpc/kernel/Makefile
+++ b/arch/powerpc/kernel/Makefile
@@ -127,6 +127,8 @@ ifneq ($(CONFIG_XMON)$(CONFIG_KEXEC),)
127obj-y += ppc_save_regs.o 127obj-y += ppc_save_regs.o
128endif 128endif
129 129
130obj-$(CONFIG_KVM_GUEST) += kvm.o
131
130# Disable GCOV in odd or sensitive code 132# Disable GCOV in odd or sensitive code
131GCOV_PROFILE_prom_init.o := n 133GCOV_PROFILE_prom_init.o := n
132GCOV_PROFILE_ftrace.o := n 134GCOV_PROFILE_ftrace.o := n
diff --git a/arch/powerpc/kernel/kvm.c b/arch/powerpc/kernel/kvm.c
new file mode 100644
index 000000000000..4f85505e4653
--- /dev/null
+++ b/arch/powerpc/kernel/kvm.c
@@ -0,0 +1,68 @@
1/*
2 * Copyright (C) 2010 SUSE Linux Products GmbH. All rights reserved.
3 *
4 * Authors:
5 * Alexander Graf <agraf@suse.de>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License, version 2, as
9 * published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 */
20
21#include <linux/kvm_host.h>
22#include <linux/init.h>
23#include <linux/kvm_para.h>
24#include <linux/slab.h>
25#include <linux/of.h>
26
27#include <asm/reg.h>
28#include <asm/kvm_ppc.h>
29#include <asm/sections.h>
30#include <asm/cacheflush.h>
31#include <asm/disassemble.h>
32
33unsigned long kvm_hypercall(unsigned long *in,
34 unsigned long *out,
35 unsigned long nr)
36{
37 unsigned long register r0 asm("r0");
38 unsigned long register r3 asm("r3") = in[0];
39 unsigned long register r4 asm("r4") = in[1];
40 unsigned long register r5 asm("r5") = in[2];
41 unsigned long register r6 asm("r6") = in[3];
42 unsigned long register r7 asm("r7") = in[4];
43 unsigned long register r8 asm("r8") = in[5];
44 unsigned long register r9 asm("r9") = in[6];
45 unsigned long register r10 asm("r10") = in[7];
46 unsigned long register r11 asm("r11") = nr;
47 unsigned long register r12 asm("r12");
48
49 asm volatile("bl kvm_hypercall_start"
50 : "=r"(r0), "=r"(r3), "=r"(r4), "=r"(r5), "=r"(r6),
51 "=r"(r7), "=r"(r8), "=r"(r9), "=r"(r10), "=r"(r11),
52 "=r"(r12)
53 : "r"(r3), "r"(r4), "r"(r5), "r"(r6), "r"(r7), "r"(r8),
54 "r"(r9), "r"(r10), "r"(r11)
55 : "memory", "cc", "xer", "ctr", "lr");
56
57 out[0] = r4;
58 out[1] = r5;
59 out[2] = r6;
60 out[3] = r7;
61 out[4] = r8;
62 out[5] = r9;
63 out[6] = r10;
64 out[7] = r11;
65
66 return r3;
67}
68EXPORT_SYMBOL_GPL(kvm_hypercall);
diff --git a/arch/powerpc/kvm/book3s.c b/arch/powerpc/kvm/book3s.c
index cfd7fe5c3a62..5cb5f0d9381f 100644
--- a/arch/powerpc/kvm/book3s.c
+++ b/arch/powerpc/kvm/book3s.c
@@ -947,10 +947,10 @@ program_interrupt:
947 break; 947 break;
948 } 948 }
949 case BOOK3S_INTERRUPT_SYSCALL: 949 case BOOK3S_INTERRUPT_SYSCALL:
950 // XXX make user settable
951 if (vcpu->arch.osi_enabled && 950 if (vcpu->arch.osi_enabled &&
952 (((u32)kvmppc_get_gpr(vcpu, 3)) == OSI_SC_MAGIC_R3) && 951 (((u32)kvmppc_get_gpr(vcpu, 3)) == OSI_SC_MAGIC_R3) &&
953 (((u32)kvmppc_get_gpr(vcpu, 4)) == OSI_SC_MAGIC_R4)) { 952 (((u32)kvmppc_get_gpr(vcpu, 4)) == OSI_SC_MAGIC_R4)) {
953 /* MOL hypercalls */
954 u64 *gprs = run->osi.gprs; 954 u64 *gprs = run->osi.gprs;
955 int i; 955 int i;
956 956
@@ -959,8 +959,13 @@ program_interrupt:
959 gprs[i] = kvmppc_get_gpr(vcpu, i); 959 gprs[i] = kvmppc_get_gpr(vcpu, i);
960 vcpu->arch.osi_needed = 1; 960 vcpu->arch.osi_needed = 1;
961 r = RESUME_HOST_NV; 961 r = RESUME_HOST_NV;
962 962 } else if (!(vcpu->arch.shared->msr & MSR_PR) &&
963 (((u32)kvmppc_get_gpr(vcpu, 0)) == KVM_SC_MAGIC_R0)) {
964 /* KVM PV hypercalls */
965 kvmppc_set_gpr(vcpu, 3, kvmppc_kvm_pv(vcpu));
966 r = RESUME_GUEST;
963 } else { 967 } else {
968 /* Guest syscalls */
964 vcpu->stat.syscall_exits++; 969 vcpu->stat.syscall_exits++;
965 kvmppc_book3s_queue_irqprio(vcpu, exit_nr); 970 kvmppc_book3s_queue_irqprio(vcpu, exit_nr);
966 r = RESUME_GUEST; 971 r = RESUME_GUEST;
diff --git a/arch/powerpc/kvm/booke.c b/arch/powerpc/kvm/booke.c
index b2c8c423c4d5..13e0747178e3 100644
--- a/arch/powerpc/kvm/booke.c
+++ b/arch/powerpc/kvm/booke.c
@@ -338,7 +338,15 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
338 break; 338 break;
339 339
340 case BOOKE_INTERRUPT_SYSCALL: 340 case BOOKE_INTERRUPT_SYSCALL:
341 kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_SYSCALL); 341 if (!(vcpu->arch.shared->msr & MSR_PR) &&
342 (((u32)kvmppc_get_gpr(vcpu, 0)) == KVM_SC_MAGIC_R0)) {
343 /* KVM PV hypercalls */
344 kvmppc_set_gpr(vcpu, 3, kvmppc_kvm_pv(vcpu));
345 r = RESUME_GUEST;
346 } else {
347 /* Guest syscalls */
348 kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_SYSCALL);
349 }
342 kvmppc_account_exit(vcpu, SYSCALL_EXITS); 350 kvmppc_account_exit(vcpu, SYSCALL_EXITS);
343 r = RESUME_GUEST; 351 r = RESUME_GUEST;
344 break; 352 break;
diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c
index 22f6fa2982f2..a4cf4b47e232 100644
--- a/arch/powerpc/kvm/powerpc.c
+++ b/arch/powerpc/kvm/powerpc.c
@@ -42,6 +42,38 @@ int kvm_arch_vcpu_runnable(struct kvm_vcpu *v)
42 !!(v->arch.pending_exceptions); 42 !!(v->arch.pending_exceptions);
43} 43}
44 44
45int kvmppc_kvm_pv(struct kvm_vcpu *vcpu)
46{
47 int nr = kvmppc_get_gpr(vcpu, 11);
48 int r;
49 unsigned long __maybe_unused param1 = kvmppc_get_gpr(vcpu, 3);
50 unsigned long __maybe_unused param2 = kvmppc_get_gpr(vcpu, 4);
51 unsigned long __maybe_unused param3 = kvmppc_get_gpr(vcpu, 5);
52 unsigned long __maybe_unused param4 = kvmppc_get_gpr(vcpu, 6);
53 unsigned long r2 = 0;
54
55 if (!(vcpu->arch.shared->msr & MSR_SF)) {
56 /* 32 bit mode */
57 param1 &= 0xffffffff;
58 param2 &= 0xffffffff;
59 param3 &= 0xffffffff;
60 param4 &= 0xffffffff;
61 }
62
63 switch (nr) {
64 case HC_VENDOR_KVM | KVM_HC_FEATURES:
65 r = HC_EV_SUCCESS;
66
67 /* Second return value is in r4 */
68 kvmppc_set_gpr(vcpu, 4, r2);
69 break;
70 default:
71 r = HC_EV_UNIMPLEMENTED;
72 break;
73 }
74
75 return r;
76}
45 77
46int kvmppc_emulate_mmio(struct kvm_run *run, struct kvm_vcpu *vcpu) 78int kvmppc_emulate_mmio(struct kvm_run *run, struct kvm_vcpu *vcpu)
47{ 79{