diff options
author | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2009-11-05 01:16:13 -0500 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2009-11-05 01:16:13 -0500 |
commit | d4e09f8432a428d6a46ca4f3c2b28d0385f5b93d (patch) | |
tree | c5d7ef8e5a9e69e011e6361f076b43d3e3767575 /arch/powerpc | |
parent | 41c8c46bfe52488779e227b77222402579573ccf (diff) | |
parent | 544c6761bb05a1dd19a39cb9bed096273f9bdb36 (diff) |
Merge branch 'kvm' into next
Diffstat (limited to 'arch/powerpc')
30 files changed, 3830 insertions, 31 deletions
diff --git a/arch/powerpc/include/asm/exception-64s.h b/arch/powerpc/include/asm/exception-64s.h index a98653b26231..57c400071995 100644 --- a/arch/powerpc/include/asm/exception-64s.h +++ b/arch/powerpc/include/asm/exception-64s.h | |||
@@ -147,6 +147,7 @@ | |||
147 | .globl label##_pSeries; \ | 147 | .globl label##_pSeries; \ |
148 | label##_pSeries: \ | 148 | label##_pSeries: \ |
149 | HMT_MEDIUM; \ | 149 | HMT_MEDIUM; \ |
150 | DO_KVM n; \ | ||
150 | mtspr SPRN_SPRG_SCRATCH0,r13; /* save r13 */ \ | 151 | mtspr SPRN_SPRG_SCRATCH0,r13; /* save r13 */ \ |
151 | EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common) | 152 | EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common) |
152 | 153 | ||
@@ -170,6 +171,7 @@ label##_pSeries: \ | |||
170 | .globl label##_pSeries; \ | 171 | .globl label##_pSeries; \ |
171 | label##_pSeries: \ | 172 | label##_pSeries: \ |
172 | HMT_MEDIUM; \ | 173 | HMT_MEDIUM; \ |
174 | DO_KVM n; \ | ||
173 | mtspr SPRN_SPRG_SCRATCH0,r13; /* save r13 */ \ | 175 | mtspr SPRN_SPRG_SCRATCH0,r13; /* save r13 */ \ |
174 | mfspr r13,SPRN_SPRG_PACA; /* get paca address into r13 */ \ | 176 | mfspr r13,SPRN_SPRG_PACA; /* get paca address into r13 */ \ |
175 | std r9,PACA_EXGEN+EX_R9(r13); /* save r9, r10 */ \ | 177 | std r9,PACA_EXGEN+EX_R9(r13); /* save r9, r10 */ \ |
diff --git a/arch/powerpc/include/asm/kvm.h b/arch/powerpc/include/asm/kvm.h index bb2de6aa5ce0..c9ca97f43bc1 100644 --- a/arch/powerpc/include/asm/kvm.h +++ b/arch/powerpc/include/asm/kvm.h | |||
@@ -46,6 +46,8 @@ struct kvm_regs { | |||
46 | }; | 46 | }; |
47 | 47 | ||
48 | struct kvm_sregs { | 48 | struct kvm_sregs { |
49 | __u32 pvr; | ||
50 | char pad[1020]; | ||
49 | }; | 51 | }; |
50 | 52 | ||
51 | struct kvm_fpu { | 53 | struct kvm_fpu { |
diff --git a/arch/powerpc/include/asm/kvm_asm.h b/arch/powerpc/include/asm/kvm_asm.h index 56bfae59837f..19ddb352fd0f 100644 --- a/arch/powerpc/include/asm/kvm_asm.h +++ b/arch/powerpc/include/asm/kvm_asm.h | |||
@@ -49,6 +49,45 @@ | |||
49 | #define BOOKE_INTERRUPT_SPE_FP_ROUND 34 | 49 | #define BOOKE_INTERRUPT_SPE_FP_ROUND 34 |
50 | #define BOOKE_INTERRUPT_PERFORMANCE_MONITOR 35 | 50 | #define BOOKE_INTERRUPT_PERFORMANCE_MONITOR 35 |
51 | 51 | ||
52 | /* book3s */ | ||
53 | |||
54 | #define BOOK3S_INTERRUPT_SYSTEM_RESET 0x100 | ||
55 | #define BOOK3S_INTERRUPT_MACHINE_CHECK 0x200 | ||
56 | #define BOOK3S_INTERRUPT_DATA_STORAGE 0x300 | ||
57 | #define BOOK3S_INTERRUPT_DATA_SEGMENT 0x380 | ||
58 | #define BOOK3S_INTERRUPT_INST_STORAGE 0x400 | ||
59 | #define BOOK3S_INTERRUPT_INST_SEGMENT 0x480 | ||
60 | #define BOOK3S_INTERRUPT_EXTERNAL 0x500 | ||
61 | #define BOOK3S_INTERRUPT_ALIGNMENT 0x600 | ||
62 | #define BOOK3S_INTERRUPT_PROGRAM 0x700 | ||
63 | #define BOOK3S_INTERRUPT_FP_UNAVAIL 0x800 | ||
64 | #define BOOK3S_INTERRUPT_DECREMENTER 0x900 | ||
65 | #define BOOK3S_INTERRUPT_SYSCALL 0xc00 | ||
66 | #define BOOK3S_INTERRUPT_TRACE 0xd00 | ||
67 | #define BOOK3S_INTERRUPT_PERFMON 0xf00 | ||
68 | #define BOOK3S_INTERRUPT_ALTIVEC 0xf20 | ||
69 | #define BOOK3S_INTERRUPT_VSX 0xf40 | ||
70 | |||
71 | #define BOOK3S_IRQPRIO_SYSTEM_RESET 0 | ||
72 | #define BOOK3S_IRQPRIO_DATA_SEGMENT 1 | ||
73 | #define BOOK3S_IRQPRIO_INST_SEGMENT 2 | ||
74 | #define BOOK3S_IRQPRIO_DATA_STORAGE 3 | ||
75 | #define BOOK3S_IRQPRIO_INST_STORAGE 4 | ||
76 | #define BOOK3S_IRQPRIO_ALIGNMENT 5 | ||
77 | #define BOOK3S_IRQPRIO_PROGRAM 6 | ||
78 | #define BOOK3S_IRQPRIO_FP_UNAVAIL 7 | ||
79 | #define BOOK3S_IRQPRIO_ALTIVEC 8 | ||
80 | #define BOOK3S_IRQPRIO_VSX 9 | ||
81 | #define BOOK3S_IRQPRIO_SYSCALL 10 | ||
82 | #define BOOK3S_IRQPRIO_MACHINE_CHECK 11 | ||
83 | #define BOOK3S_IRQPRIO_DEBUG 12 | ||
84 | #define BOOK3S_IRQPRIO_EXTERNAL 13 | ||
85 | #define BOOK3S_IRQPRIO_DECREMENTER 14 | ||
86 | #define BOOK3S_IRQPRIO_PERFORMANCE_MONITOR 15 | ||
87 | #define BOOK3S_IRQPRIO_MAX 16 | ||
88 | |||
89 | #define BOOK3S_HFLAG_DCBZ32 0x1 | ||
90 | |||
52 | #define RESUME_FLAG_NV (1<<0) /* Reload guest nonvolatile state? */ | 91 | #define RESUME_FLAG_NV (1<<0) /* Reload guest nonvolatile state? */ |
53 | #define RESUME_FLAG_HOST (1<<1) /* Resume host? */ | 92 | #define RESUME_FLAG_HOST (1<<1) /* Resume host? */ |
54 | 93 | ||
diff --git a/arch/powerpc/include/asm/kvm_book3s.h b/arch/powerpc/include/asm/kvm_book3s.h new file mode 100644 index 000000000000..c6011336371e --- /dev/null +++ b/arch/powerpc/include/asm/kvm_book3s.h | |||
@@ -0,0 +1,136 @@ | |||
1 | /* | ||
2 | * This program is free software; you can redistribute it and/or modify | ||
3 | * it under the terms of the GNU General Public License, version 2, as | ||
4 | * published by the Free Software Foundation. | ||
5 | * | ||
6 | * This program is distributed in the hope that it will be useful, | ||
7 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
8 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
9 | * GNU General Public License for more details. | ||
10 | * | ||
11 | * You should have received a copy of the GNU General Public License | ||
12 | * along with this program; if not, write to the Free Software | ||
13 | * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
14 | * | ||
15 | * Copyright SUSE Linux Products GmbH 2009 | ||
16 | * | ||
17 | * Authors: Alexander Graf <agraf@suse.de> | ||
18 | */ | ||
19 | |||
20 | #ifndef __ASM_KVM_BOOK3S_H__ | ||
21 | #define __ASM_KVM_BOOK3S_H__ | ||
22 | |||
23 | #include <linux/types.h> | ||
24 | #include <linux/kvm_host.h> | ||
25 | #include <asm/kvm_ppc.h> | ||
26 | |||
27 | struct kvmppc_slb { | ||
28 | u64 esid; | ||
29 | u64 vsid; | ||
30 | u64 orige; | ||
31 | u64 origv; | ||
32 | bool valid; | ||
33 | bool Ks; | ||
34 | bool Kp; | ||
35 | bool nx; | ||
36 | bool large; | ||
37 | bool class; | ||
38 | }; | ||
39 | |||
40 | struct kvmppc_sr { | ||
41 | u32 raw; | ||
42 | u32 vsid; | ||
43 | bool Ks; | ||
44 | bool Kp; | ||
45 | bool nx; | ||
46 | }; | ||
47 | |||
48 | struct kvmppc_bat { | ||
49 | u32 bepi; | ||
50 | u32 bepi_mask; | ||
51 | bool vs; | ||
52 | bool vp; | ||
53 | u32 brpn; | ||
54 | u8 wimg; | ||
55 | u8 pp; | ||
56 | }; | ||
57 | |||
58 | struct kvmppc_sid_map { | ||
59 | u64 guest_vsid; | ||
60 | u64 guest_esid; | ||
61 | u64 host_vsid; | ||
62 | bool valid; | ||
63 | }; | ||
64 | |||
65 | #define SID_MAP_BITS 9 | ||
66 | #define SID_MAP_NUM (1 << SID_MAP_BITS) | ||
67 | #define SID_MAP_MASK (SID_MAP_NUM - 1) | ||
68 | |||
69 | struct kvmppc_vcpu_book3s { | ||
70 | struct kvm_vcpu vcpu; | ||
71 | struct kvmppc_sid_map sid_map[SID_MAP_NUM]; | ||
72 | struct kvmppc_slb slb[64]; | ||
73 | struct { | ||
74 | u64 esid; | ||
75 | u64 vsid; | ||
76 | } slb_shadow[64]; | ||
77 | u8 slb_shadow_max; | ||
78 | struct kvmppc_sr sr[16]; | ||
79 | struct kvmppc_bat ibat[8]; | ||
80 | struct kvmppc_bat dbat[8]; | ||
81 | u64 hid[6]; | ||
82 | int slb_nr; | ||
83 | u64 sdr1; | ||
84 | u64 dsisr; | ||
85 | u64 hior; | ||
86 | u64 msr_mask; | ||
87 | u64 vsid_first; | ||
88 | u64 vsid_next; | ||
89 | u64 vsid_max; | ||
90 | int context_id; | ||
91 | }; | ||
92 | |||
93 | #define CONTEXT_HOST 0 | ||
94 | #define CONTEXT_GUEST 1 | ||
95 | #define CONTEXT_GUEST_END 2 | ||
96 | |||
97 | #define VSID_REAL 0xfffffffffff00000 | ||
98 | #define VSID_REAL_DR 0xffffffffffe00000 | ||
99 | #define VSID_REAL_IR 0xffffffffffd00000 | ||
100 | #define VSID_BAT 0xffffffffffc00000 | ||
101 | #define VSID_PR 0x8000000000000000 | ||
102 | |||
103 | extern void kvmppc_mmu_pte_flush(struct kvm_vcpu *vcpu, u64 ea, u64 ea_mask); | ||
104 | extern void kvmppc_mmu_pte_vflush(struct kvm_vcpu *vcpu, u64 vp, u64 vp_mask); | ||
105 | extern void kvmppc_mmu_pte_pflush(struct kvm_vcpu *vcpu, u64 pa_start, u64 pa_end); | ||
106 | extern void kvmppc_set_msr(struct kvm_vcpu *vcpu, u64 new_msr); | ||
107 | extern void kvmppc_mmu_book3s_64_init(struct kvm_vcpu *vcpu); | ||
108 | extern void kvmppc_mmu_book3s_32_init(struct kvm_vcpu *vcpu); | ||
109 | extern int kvmppc_mmu_map_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *pte); | ||
110 | extern int kvmppc_mmu_map_segment(struct kvm_vcpu *vcpu, ulong eaddr); | ||
111 | extern void kvmppc_mmu_flush_segments(struct kvm_vcpu *vcpu); | ||
112 | extern struct kvmppc_pte *kvmppc_mmu_find_pte(struct kvm_vcpu *vcpu, u64 ea, bool data); | ||
113 | extern int kvmppc_ld(struct kvm_vcpu *vcpu, ulong eaddr, int size, void *ptr, bool data); | ||
114 | extern int kvmppc_st(struct kvm_vcpu *vcpu, ulong eaddr, int size, void *ptr); | ||
115 | extern void kvmppc_book3s_queue_irqprio(struct kvm_vcpu *vcpu, unsigned int vec); | ||
116 | |||
117 | extern u32 kvmppc_trampoline_lowmem; | ||
118 | extern u32 kvmppc_trampoline_enter; | ||
119 | |||
120 | static inline struct kvmppc_vcpu_book3s *to_book3s(struct kvm_vcpu *vcpu) | ||
121 | { | ||
122 | return container_of(vcpu, struct kvmppc_vcpu_book3s, vcpu); | ||
123 | } | ||
124 | |||
125 | static inline ulong dsisr(void) | ||
126 | { | ||
127 | ulong r; | ||
128 | asm ( "mfdsisr %0 " : "=r" (r) ); | ||
129 | return r; | ||
130 | } | ||
131 | |||
132 | extern void kvm_return_point(void); | ||
133 | |||
134 | #define INS_DCBZ 0x7c0007ec | ||
135 | |||
136 | #endif /* __ASM_KVM_BOOK3S_H__ */ | ||
diff --git a/arch/powerpc/include/asm/kvm_book3s_64_asm.h b/arch/powerpc/include/asm/kvm_book3s_64_asm.h new file mode 100644 index 000000000000..2e06ee8184ef --- /dev/null +++ b/arch/powerpc/include/asm/kvm_book3s_64_asm.h | |||
@@ -0,0 +1,58 @@ | |||
1 | /* | ||
2 | * This program is free software; you can redistribute it and/or modify | ||
3 | * it under the terms of the GNU General Public License, version 2, as | ||
4 | * published by the Free Software Foundation. | ||
5 | * | ||
6 | * This program is distributed in the hope that it will be useful, | ||
7 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
8 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
9 | * GNU General Public License for more details. | ||
10 | * | ||
11 | * You should have received a copy of the GNU General Public License | ||
12 | * along with this program; if not, write to the Free Software | ||
13 | * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
14 | * | ||
15 | * Copyright SUSE Linux Products GmbH 2009 | ||
16 | * | ||
17 | * Authors: Alexander Graf <agraf@suse.de> | ||
18 | */ | ||
19 | |||
20 | #ifndef __ASM_KVM_BOOK3S_ASM_H__ | ||
21 | #define __ASM_KVM_BOOK3S_ASM_H__ | ||
22 | |||
23 | #ifdef CONFIG_KVM_BOOK3S_64_HANDLER | ||
24 | |||
25 | #include <asm/kvm_asm.h> | ||
26 | |||
27 | .macro DO_KVM intno | ||
28 | .if (\intno == BOOK3S_INTERRUPT_SYSTEM_RESET) || \ | ||
29 | (\intno == BOOK3S_INTERRUPT_MACHINE_CHECK) || \ | ||
30 | (\intno == BOOK3S_INTERRUPT_DATA_STORAGE) || \ | ||
31 | (\intno == BOOK3S_INTERRUPT_INST_STORAGE) || \ | ||
32 | (\intno == BOOK3S_INTERRUPT_DATA_SEGMENT) || \ | ||
33 | (\intno == BOOK3S_INTERRUPT_INST_SEGMENT) || \ | ||
34 | (\intno == BOOK3S_INTERRUPT_EXTERNAL) || \ | ||
35 | (\intno == BOOK3S_INTERRUPT_ALIGNMENT) || \ | ||
36 | (\intno == BOOK3S_INTERRUPT_PROGRAM) || \ | ||
37 | (\intno == BOOK3S_INTERRUPT_FP_UNAVAIL) || \ | ||
38 | (\intno == BOOK3S_INTERRUPT_DECREMENTER) || \ | ||
39 | (\intno == BOOK3S_INTERRUPT_SYSCALL) || \ | ||
40 | (\intno == BOOK3S_INTERRUPT_TRACE) || \ | ||
41 | (\intno == BOOK3S_INTERRUPT_PERFMON) || \ | ||
42 | (\intno == BOOK3S_INTERRUPT_ALTIVEC) || \ | ||
43 | (\intno == BOOK3S_INTERRUPT_VSX) | ||
44 | |||
45 | b kvmppc_trampoline_\intno | ||
46 | kvmppc_resume_\intno: | ||
47 | |||
48 | .endif | ||
49 | .endm | ||
50 | |||
51 | #else | ||
52 | |||
53 | .macro DO_KVM intno | ||
54 | .endm | ||
55 | |||
56 | #endif /* CONFIG_KVM_BOOK3S_64_HANDLER */ | ||
57 | |||
58 | #endif /* __ASM_KVM_BOOK3S_ASM_H__ */ | ||
diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h index c9c930ed11d7..1201f62d0d73 100644 --- a/arch/powerpc/include/asm/kvm_host.h +++ b/arch/powerpc/include/asm/kvm_host.h | |||
@@ -21,7 +21,8 @@ | |||
21 | #define __POWERPC_KVM_HOST_H__ | 21 | #define __POWERPC_KVM_HOST_H__ |
22 | 22 | ||
23 | #include <linux/mutex.h> | 23 | #include <linux/mutex.h> |
24 | #include <linux/timer.h> | 24 | #include <linux/hrtimer.h> |
25 | #include <linux/interrupt.h> | ||
25 | #include <linux/types.h> | 26 | #include <linux/types.h> |
26 | #include <linux/kvm_types.h> | 27 | #include <linux/kvm_types.h> |
27 | #include <asm/kvm_asm.h> | 28 | #include <asm/kvm_asm.h> |
@@ -37,6 +38,8 @@ | |||
37 | #define KVM_NR_PAGE_SIZES 1 | 38 | #define KVM_NR_PAGE_SIZES 1 |
38 | #define KVM_PAGES_PER_HPAGE(x) (1UL<<31) | 39 | #define KVM_PAGES_PER_HPAGE(x) (1UL<<31) |
39 | 40 | ||
41 | #define HPTEG_CACHE_NUM 1024 | ||
42 | |||
40 | struct kvm; | 43 | struct kvm; |
41 | struct kvm_run; | 44 | struct kvm_run; |
42 | struct kvm_vcpu; | 45 | struct kvm_vcpu; |
@@ -63,6 +66,17 @@ struct kvm_vcpu_stat { | |||
63 | u32 dec_exits; | 66 | u32 dec_exits; |
64 | u32 ext_intr_exits; | 67 | u32 ext_intr_exits; |
65 | u32 halt_wakeup; | 68 | u32 halt_wakeup; |
69 | #ifdef CONFIG_PPC64 | ||
70 | u32 pf_storage; | ||
71 | u32 pf_instruc; | ||
72 | u32 sp_storage; | ||
73 | u32 sp_instruc; | ||
74 | u32 queue_intr; | ||
75 | u32 ld; | ||
76 | u32 ld_slow; | ||
77 | u32 st; | ||
78 | u32 st_slow; | ||
79 | #endif | ||
66 | }; | 80 | }; |
67 | 81 | ||
68 | enum kvm_exit_types { | 82 | enum kvm_exit_types { |
@@ -109,9 +123,53 @@ struct kvmppc_exit_timing { | |||
109 | struct kvm_arch { | 123 | struct kvm_arch { |
110 | }; | 124 | }; |
111 | 125 | ||
126 | struct kvmppc_pte { | ||
127 | u64 eaddr; | ||
128 | u64 vpage; | ||
129 | u64 raddr; | ||
130 | bool may_read; | ||
131 | bool may_write; | ||
132 | bool may_execute; | ||
133 | }; | ||
134 | |||
135 | struct kvmppc_mmu { | ||
136 | /* book3s_64 only */ | ||
137 | void (*slbmte)(struct kvm_vcpu *vcpu, u64 rb, u64 rs); | ||
138 | u64 (*slbmfee)(struct kvm_vcpu *vcpu, u64 slb_nr); | ||
139 | u64 (*slbmfev)(struct kvm_vcpu *vcpu, u64 slb_nr); | ||
140 | void (*slbie)(struct kvm_vcpu *vcpu, u64 slb_nr); | ||
141 | void (*slbia)(struct kvm_vcpu *vcpu); | ||
142 | /* book3s */ | ||
143 | void (*mtsrin)(struct kvm_vcpu *vcpu, u32 srnum, ulong value); | ||
144 | u32 (*mfsrin)(struct kvm_vcpu *vcpu, u32 srnum); | ||
145 | int (*xlate)(struct kvm_vcpu *vcpu, gva_t eaddr, struct kvmppc_pte *pte, bool data); | ||
146 | void (*reset_msr)(struct kvm_vcpu *vcpu); | ||
147 | void (*tlbie)(struct kvm_vcpu *vcpu, ulong addr, bool large); | ||
148 | int (*esid_to_vsid)(struct kvm_vcpu *vcpu, u64 esid, u64 *vsid); | ||
149 | u64 (*ea_to_vp)(struct kvm_vcpu *vcpu, gva_t eaddr, bool data); | ||
150 | bool (*is_dcbz32)(struct kvm_vcpu *vcpu); | ||
151 | }; | ||
152 | |||
153 | struct hpte_cache { | ||
154 | u64 host_va; | ||
155 | u64 pfn; | ||
156 | ulong slot; | ||
157 | struct kvmppc_pte pte; | ||
158 | }; | ||
159 | |||
112 | struct kvm_vcpu_arch { | 160 | struct kvm_vcpu_arch { |
113 | u32 host_stack; | 161 | ulong host_stack; |
114 | u32 host_pid; | 162 | u32 host_pid; |
163 | #ifdef CONFIG_PPC64 | ||
164 | ulong host_msr; | ||
165 | ulong host_r2; | ||
166 | void *host_retip; | ||
167 | ulong trampoline_lowmem; | ||
168 | ulong trampoline_enter; | ||
169 | ulong highmem_handler; | ||
170 | ulong host_paca_phys; | ||
171 | struct kvmppc_mmu mmu; | ||
172 | #endif | ||
115 | 173 | ||
116 | u64 fpr[32]; | 174 | u64 fpr[32]; |
117 | ulong gpr[32]; | 175 | ulong gpr[32]; |
@@ -123,6 +181,10 @@ struct kvm_vcpu_arch { | |||
123 | ulong xer; | 181 | ulong xer; |
124 | 182 | ||
125 | ulong msr; | 183 | ulong msr; |
184 | #ifdef CONFIG_PPC64 | ||
185 | ulong shadow_msr; | ||
186 | ulong hflags; | ||
187 | #endif | ||
126 | u32 mmucr; | 188 | u32 mmucr; |
127 | ulong sprg0; | 189 | ulong sprg0; |
128 | ulong sprg1; | 190 | ulong sprg1; |
@@ -149,6 +211,7 @@ struct kvm_vcpu_arch { | |||
149 | u32 ivor[64]; | 211 | u32 ivor[64]; |
150 | ulong ivpr; | 212 | ulong ivpr; |
151 | u32 pir; | 213 | u32 pir; |
214 | u32 pvr; | ||
152 | 215 | ||
153 | u32 shadow_pid; | 216 | u32 shadow_pid; |
154 | u32 pid; | 217 | u32 pid; |
@@ -174,6 +237,9 @@ struct kvm_vcpu_arch { | |||
174 | #endif | 237 | #endif |
175 | 238 | ||
176 | u32 last_inst; | 239 | u32 last_inst; |
240 | #ifdef CONFIG_PPC64 | ||
241 | ulong fault_dsisr; | ||
242 | #endif | ||
177 | ulong fault_dear; | 243 | ulong fault_dear; |
178 | ulong fault_esr; | 244 | ulong fault_esr; |
179 | gpa_t paddr_accessed; | 245 | gpa_t paddr_accessed; |
@@ -185,8 +251,15 @@ struct kvm_vcpu_arch { | |||
185 | 251 | ||
186 | u32 cpr0_cfgaddr; /* holds the last set cpr0_cfgaddr */ | 252 | u32 cpr0_cfgaddr; /* holds the last set cpr0_cfgaddr */ |
187 | 253 | ||
188 | struct timer_list dec_timer; | 254 | struct hrtimer dec_timer; |
255 | struct tasklet_struct tasklet; | ||
256 | u64 dec_jiffies; | ||
189 | unsigned long pending_exceptions; | 257 | unsigned long pending_exceptions; |
258 | |||
259 | #ifdef CONFIG_PPC64 | ||
260 | struct hpte_cache hpte_cache[HPTEG_CACHE_NUM]; | ||
261 | int hpte_cache_offset; | ||
262 | #endif | ||
190 | }; | 263 | }; |
191 | 264 | ||
192 | #endif /* __POWERPC_KVM_HOST_H__ */ | 265 | #endif /* __POWERPC_KVM_HOST_H__ */ |
diff --git a/arch/powerpc/include/asm/kvm_ppc.h b/arch/powerpc/include/asm/kvm_ppc.h index 2c6ee349df5e..269ee46ab028 100644 --- a/arch/powerpc/include/asm/kvm_ppc.h +++ b/arch/powerpc/include/asm/kvm_ppc.h | |||
@@ -39,6 +39,7 @@ enum emulation_result { | |||
39 | extern int __kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu); | 39 | extern int __kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu); |
40 | extern char kvmppc_handlers_start[]; | 40 | extern char kvmppc_handlers_start[]; |
41 | extern unsigned long kvmppc_handler_len; | 41 | extern unsigned long kvmppc_handler_len; |
42 | extern void kvmppc_handler_highmem(void); | ||
42 | 43 | ||
43 | extern void kvmppc_dump_vcpu(struct kvm_vcpu *vcpu); | 44 | extern void kvmppc_dump_vcpu(struct kvm_vcpu *vcpu); |
44 | extern int kvmppc_handle_load(struct kvm_run *run, struct kvm_vcpu *vcpu, | 45 | extern int kvmppc_handle_load(struct kvm_run *run, struct kvm_vcpu *vcpu, |
diff --git a/arch/powerpc/include/asm/mmu_context.h b/arch/powerpc/include/asm/mmu_context.h index b34e94d94435..26383e0778aa 100644 --- a/arch/powerpc/include/asm/mmu_context.h +++ b/arch/powerpc/include/asm/mmu_context.h | |||
@@ -23,6 +23,8 @@ extern void switch_slb(struct task_struct *tsk, struct mm_struct *mm); | |||
23 | extern void set_context(unsigned long id, pgd_t *pgd); | 23 | extern void set_context(unsigned long id, pgd_t *pgd); |
24 | 24 | ||
25 | #ifdef CONFIG_PPC_BOOK3S_64 | 25 | #ifdef CONFIG_PPC_BOOK3S_64 |
26 | extern int __init_new_context(void); | ||
27 | extern void __destroy_context(int context_id); | ||
26 | static inline void mmu_context_init(void) { } | 28 | static inline void mmu_context_init(void) { } |
27 | #else | 29 | #else |
28 | extern void mmu_context_init(void); | 30 | extern void mmu_context_init(void); |
diff --git a/arch/powerpc/include/asm/paca.h b/arch/powerpc/include/asm/paca.h index 7d8514ceceae..5e9b4ef71415 100644 --- a/arch/powerpc/include/asm/paca.h +++ b/arch/powerpc/include/asm/paca.h | |||
@@ -129,6 +129,15 @@ struct paca_struct { | |||
129 | u64 system_time; /* accumulated system TB ticks */ | 129 | u64 system_time; /* accumulated system TB ticks */ |
130 | u64 startpurr; /* PURR/TB value snapshot */ | 130 | u64 startpurr; /* PURR/TB value snapshot */ |
131 | u64 startspurr; /* SPURR value snapshot */ | 131 | u64 startspurr; /* SPURR value snapshot */ |
132 | |||
133 | #ifdef CONFIG_KVM_BOOK3S_64_HANDLER | ||
134 | struct { | ||
135 | u64 esid; | ||
136 | u64 vsid; | ||
137 | } kvm_slb[64]; /* guest SLB */ | ||
138 | u8 kvm_slb_max; /* highest used guest slb entry */ | ||
139 | u8 kvm_in_guest; /* are we inside the guest? */ | ||
140 | #endif | ||
132 | }; | 141 | }; |
133 | 142 | ||
134 | extern struct paca_struct paca[]; | 143 | extern struct paca_struct paca[]; |
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index 0812b0f414bb..e2e2082acf29 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c | |||
@@ -190,6 +190,11 @@ int main(void) | |||
190 | DEFINE(PACA_SYSTEM_TIME, offsetof(struct paca_struct, system_time)); | 190 | DEFINE(PACA_SYSTEM_TIME, offsetof(struct paca_struct, system_time)); |
191 | DEFINE(PACA_DATA_OFFSET, offsetof(struct paca_struct, data_offset)); | 191 | DEFINE(PACA_DATA_OFFSET, offsetof(struct paca_struct, data_offset)); |
192 | DEFINE(PACA_TRAP_SAVE, offsetof(struct paca_struct, trap_save)); | 192 | DEFINE(PACA_TRAP_SAVE, offsetof(struct paca_struct, trap_save)); |
193 | #ifdef CONFIG_KVM_BOOK3S_64_HANDLER | ||
194 | DEFINE(PACA_KVM_IN_GUEST, offsetof(struct paca_struct, kvm_in_guest)); | ||
195 | DEFINE(PACA_KVM_SLB, offsetof(struct paca_struct, kvm_slb)); | ||
196 | DEFINE(PACA_KVM_SLB_MAX, offsetof(struct paca_struct, kvm_slb_max)); | ||
197 | #endif | ||
193 | #endif /* CONFIG_PPC64 */ | 198 | #endif /* CONFIG_PPC64 */ |
194 | 199 | ||
195 | /* RTAS */ | 200 | /* RTAS */ |
@@ -398,6 +403,19 @@ int main(void) | |||
398 | DEFINE(VCPU_LAST_INST, offsetof(struct kvm_vcpu, arch.last_inst)); | 403 | DEFINE(VCPU_LAST_INST, offsetof(struct kvm_vcpu, arch.last_inst)); |
399 | DEFINE(VCPU_FAULT_DEAR, offsetof(struct kvm_vcpu, arch.fault_dear)); | 404 | DEFINE(VCPU_FAULT_DEAR, offsetof(struct kvm_vcpu, arch.fault_dear)); |
400 | DEFINE(VCPU_FAULT_ESR, offsetof(struct kvm_vcpu, arch.fault_esr)); | 405 | DEFINE(VCPU_FAULT_ESR, offsetof(struct kvm_vcpu, arch.fault_esr)); |
406 | |||
407 | /* book3s_64 */ | ||
408 | #ifdef CONFIG_PPC64 | ||
409 | DEFINE(VCPU_FAULT_DSISR, offsetof(struct kvm_vcpu, arch.fault_dsisr)); | ||
410 | DEFINE(VCPU_HOST_RETIP, offsetof(struct kvm_vcpu, arch.host_retip)); | ||
411 | DEFINE(VCPU_HOST_R2, offsetof(struct kvm_vcpu, arch.host_r2)); | ||
412 | DEFINE(VCPU_HOST_MSR, offsetof(struct kvm_vcpu, arch.host_msr)); | ||
413 | DEFINE(VCPU_SHADOW_MSR, offsetof(struct kvm_vcpu, arch.shadow_msr)); | ||
414 | DEFINE(VCPU_TRAMPOLINE_LOWMEM, offsetof(struct kvm_vcpu, arch.trampoline_lowmem)); | ||
415 | DEFINE(VCPU_TRAMPOLINE_ENTER, offsetof(struct kvm_vcpu, arch.trampoline_enter)); | ||
416 | DEFINE(VCPU_HIGHMEM_HANDLER, offsetof(struct kvm_vcpu, arch.highmem_handler)); | ||
417 | DEFINE(VCPU_HFLAGS, offsetof(struct kvm_vcpu, arch.hflags)); | ||
418 | #endif | ||
401 | #endif | 419 | #endif |
402 | #ifdef CONFIG_44x | 420 | #ifdef CONFIG_44x |
403 | DEFINE(PGD_T_LOG2, PGD_T_LOG2); | 421 | DEFINE(PGD_T_LOG2, PGD_T_LOG2); |
diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S index 1808876edcc9..fc3ead066cec 100644 --- a/arch/powerpc/kernel/exceptions-64s.S +++ b/arch/powerpc/kernel/exceptions-64s.S | |||
@@ -41,6 +41,7 @@ __start_interrupts: | |||
41 | . = 0x200 | 41 | . = 0x200 |
42 | _machine_check_pSeries: | 42 | _machine_check_pSeries: |
43 | HMT_MEDIUM | 43 | HMT_MEDIUM |
44 | DO_KVM 0x200 | ||
44 | mtspr SPRN_SPRG_SCRATCH0,r13 /* save r13 */ | 45 | mtspr SPRN_SPRG_SCRATCH0,r13 /* save r13 */ |
45 | EXCEPTION_PROLOG_PSERIES(PACA_EXMC, machine_check_common) | 46 | EXCEPTION_PROLOG_PSERIES(PACA_EXMC, machine_check_common) |
46 | 47 | ||
@@ -48,6 +49,7 @@ _machine_check_pSeries: | |||
48 | .globl data_access_pSeries | 49 | .globl data_access_pSeries |
49 | data_access_pSeries: | 50 | data_access_pSeries: |
50 | HMT_MEDIUM | 51 | HMT_MEDIUM |
52 | DO_KVM 0x300 | ||
51 | mtspr SPRN_SPRG_SCRATCH0,r13 | 53 | mtspr SPRN_SPRG_SCRATCH0,r13 |
52 | BEGIN_FTR_SECTION | 54 | BEGIN_FTR_SECTION |
53 | mfspr r13,SPRN_SPRG_PACA | 55 | mfspr r13,SPRN_SPRG_PACA |
@@ -77,6 +79,7 @@ ALT_FTR_SECTION_END_IFCLR(CPU_FTR_SLB) | |||
77 | .globl data_access_slb_pSeries | 79 | .globl data_access_slb_pSeries |
78 | data_access_slb_pSeries: | 80 | data_access_slb_pSeries: |
79 | HMT_MEDIUM | 81 | HMT_MEDIUM |
82 | DO_KVM 0x380 | ||
80 | mtspr SPRN_SPRG_SCRATCH0,r13 | 83 | mtspr SPRN_SPRG_SCRATCH0,r13 |
81 | mfspr r13,SPRN_SPRG_PACA /* get paca address into r13 */ | 84 | mfspr r13,SPRN_SPRG_PACA /* get paca address into r13 */ |
82 | std r3,PACA_EXSLB+EX_R3(r13) | 85 | std r3,PACA_EXSLB+EX_R3(r13) |
@@ -115,6 +118,7 @@ data_access_slb_pSeries: | |||
115 | .globl instruction_access_slb_pSeries | 118 | .globl instruction_access_slb_pSeries |
116 | instruction_access_slb_pSeries: | 119 | instruction_access_slb_pSeries: |
117 | HMT_MEDIUM | 120 | HMT_MEDIUM |
121 | DO_KVM 0x480 | ||
118 | mtspr SPRN_SPRG_SCRATCH0,r13 | 122 | mtspr SPRN_SPRG_SCRATCH0,r13 |
119 | mfspr r13,SPRN_SPRG_PACA /* get paca address into r13 */ | 123 | mfspr r13,SPRN_SPRG_PACA /* get paca address into r13 */ |
120 | std r3,PACA_EXSLB+EX_R3(r13) | 124 | std r3,PACA_EXSLB+EX_R3(r13) |
@@ -154,6 +158,7 @@ instruction_access_slb_pSeries: | |||
154 | .globl system_call_pSeries | 158 | .globl system_call_pSeries |
155 | system_call_pSeries: | 159 | system_call_pSeries: |
156 | HMT_MEDIUM | 160 | HMT_MEDIUM |
161 | DO_KVM 0xc00 | ||
157 | BEGIN_FTR_SECTION | 162 | BEGIN_FTR_SECTION |
158 | cmpdi r0,0x1ebe | 163 | cmpdi r0,0x1ebe |
159 | beq- 1f | 164 | beq- 1f |
@@ -186,12 +191,15 @@ END_FTR_SECTION_IFSET(CPU_FTR_REAL_LE) | |||
186 | * trickery is thus necessary | 191 | * trickery is thus necessary |
187 | */ | 192 | */ |
188 | . = 0xf00 | 193 | . = 0xf00 |
194 | DO_KVM 0xf00 | ||
189 | b performance_monitor_pSeries | 195 | b performance_monitor_pSeries |
190 | 196 | ||
191 | . = 0xf20 | 197 | . = 0xf20 |
198 | DO_KVM 0xf20 | ||
192 | b altivec_unavailable_pSeries | 199 | b altivec_unavailable_pSeries |
193 | 200 | ||
194 | . = 0xf40 | 201 | . = 0xf40 |
202 | DO_KVM 0xf40 | ||
195 | b vsx_unavailable_pSeries | 203 | b vsx_unavailable_pSeries |
196 | 204 | ||
197 | #ifdef CONFIG_CBE_RAS | 205 | #ifdef CONFIG_CBE_RAS |
diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S index c38afdb45d7b..925807488022 100644 --- a/arch/powerpc/kernel/head_64.S +++ b/arch/powerpc/kernel/head_64.S | |||
@@ -37,6 +37,7 @@ | |||
37 | #include <asm/firmware.h> | 37 | #include <asm/firmware.h> |
38 | #include <asm/page_64.h> | 38 | #include <asm/page_64.h> |
39 | #include <asm/irqflags.h> | 39 | #include <asm/irqflags.h> |
40 | #include <asm/kvm_book3s_64_asm.h> | ||
40 | 41 | ||
41 | /* The physical memory is layed out such that the secondary processor | 42 | /* The physical memory is layed out such that the secondary processor |
42 | * spin code sits at 0x0000...0x00ff. On server, the vectors follow | 43 | * spin code sits at 0x0000...0x00ff. On server, the vectors follow |
@@ -165,6 +166,12 @@ exception_marker: | |||
165 | #include "exceptions-64s.S" | 166 | #include "exceptions-64s.S" |
166 | #endif | 167 | #endif |
167 | 168 | ||
169 | /* KVM trampoline code needs to be close to the interrupt handlers */ | ||
170 | |||
171 | #ifdef CONFIG_KVM_BOOK3S_64_HANDLER | ||
172 | #include "../kvm/book3s_64_rmhandlers.S" | ||
173 | #endif | ||
174 | |||
168 | _GLOBAL(generic_secondary_thread_init) | 175 | _GLOBAL(generic_secondary_thread_init) |
169 | mr r24,r3 | 176 | mr r24,r3 |
170 | 177 | ||
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index 92dc844299b6..e05f6af64353 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c | |||
@@ -268,6 +268,7 @@ void account_system_vtime(struct task_struct *tsk) | |||
268 | per_cpu(cputime_scaled_last_delta, smp_processor_id()) = deltascaled; | 268 | per_cpu(cputime_scaled_last_delta, smp_processor_id()) = deltascaled; |
269 | local_irq_restore(flags); | 269 | local_irq_restore(flags); |
270 | } | 270 | } |
271 | EXPORT_SYMBOL_GPL(account_system_vtime); | ||
271 | 272 | ||
272 | /* | 273 | /* |
273 | * Transfer the user and system times accumulated in the paca | 274 | * Transfer the user and system times accumulated in the paca |
diff --git a/arch/powerpc/kvm/Kconfig b/arch/powerpc/kvm/Kconfig index c29926846613..07703f72330e 100644 --- a/arch/powerpc/kvm/Kconfig +++ b/arch/powerpc/kvm/Kconfig | |||
@@ -21,6 +21,23 @@ config KVM | |||
21 | select PREEMPT_NOTIFIERS | 21 | select PREEMPT_NOTIFIERS |
22 | select ANON_INODES | 22 | select ANON_INODES |
23 | 23 | ||
24 | config KVM_BOOK3S_64_HANDLER | ||
25 | bool | ||
26 | |||
27 | config KVM_BOOK3S_64 | ||
28 | tristate "KVM support for PowerPC book3s_64 processors" | ||
29 | depends on EXPERIMENTAL && PPC64 | ||
30 | select KVM | ||
31 | select KVM_BOOK3S_64_HANDLER | ||
32 | ---help--- | ||
33 | Support running unmodified book3s_64 and book3s_32 guest kernels | ||
34 | in virtual machines on book3s_64 host processors. | ||
35 | |||
36 | This module provides access to the hardware capabilities through | ||
37 | a character device node named /dev/kvm. | ||
38 | |||
39 | If unsure, say N. | ||
40 | |||
24 | config KVM_440 | 41 | config KVM_440 |
25 | bool "KVM support for PowerPC 440 processors" | 42 | bool "KVM support for PowerPC 440 processors" |
26 | depends on EXPERIMENTAL && 44x | 43 | depends on EXPERIMENTAL && 44x |
diff --git a/arch/powerpc/kvm/Makefile b/arch/powerpc/kvm/Makefile index 37655fe19f2f..56484d652377 100644 --- a/arch/powerpc/kvm/Makefile +++ b/arch/powerpc/kvm/Makefile | |||
@@ -12,26 +12,45 @@ CFLAGS_44x_tlb.o := -I. | |||
12 | CFLAGS_e500_tlb.o := -I. | 12 | CFLAGS_e500_tlb.o := -I. |
13 | CFLAGS_emulate.o := -I. | 13 | CFLAGS_emulate.o := -I. |
14 | 14 | ||
15 | kvm-objs := $(common-objs-y) powerpc.o emulate.o | 15 | common-objs-y += powerpc.o emulate.o |
16 | obj-$(CONFIG_KVM_EXIT_TIMING) += timing.o | 16 | obj-$(CONFIG_KVM_EXIT_TIMING) += timing.o |
17 | obj-$(CONFIG_KVM) += kvm.o | 17 | obj-$(CONFIG_KVM_BOOK3S_64_HANDLER) += book3s_64_exports.o |
18 | 18 | ||
19 | AFLAGS_booke_interrupts.o := -I$(obj) | 19 | AFLAGS_booke_interrupts.o := -I$(obj) |
20 | 20 | ||
21 | kvm-440-objs := \ | 21 | kvm-440-objs := \ |
22 | $(common-objs-y) \ | ||
22 | booke.o \ | 23 | booke.o \ |
23 | booke_emulate.o \ | 24 | booke_emulate.o \ |
24 | booke_interrupts.o \ | 25 | booke_interrupts.o \ |
25 | 44x.o \ | 26 | 44x.o \ |
26 | 44x_tlb.o \ | 27 | 44x_tlb.o \ |
27 | 44x_emulate.o | 28 | 44x_emulate.o |
28 | obj-$(CONFIG_KVM_440) += kvm-440.o | 29 | kvm-objs-$(CONFIG_KVM_440) := $(kvm-440-objs) |
29 | 30 | ||
30 | kvm-e500-objs := \ | 31 | kvm-e500-objs := \ |
32 | $(common-objs-y) \ | ||
31 | booke.o \ | 33 | booke.o \ |
32 | booke_emulate.o \ | 34 | booke_emulate.o \ |
33 | booke_interrupts.o \ | 35 | booke_interrupts.o \ |
34 | e500.o \ | 36 | e500.o \ |
35 | e500_tlb.o \ | 37 | e500_tlb.o \ |
36 | e500_emulate.o | 38 | e500_emulate.o |
37 | obj-$(CONFIG_KVM_E500) += kvm-e500.o | 39 | kvm-objs-$(CONFIG_KVM_E500) := $(kvm-e500-objs) |
40 | |||
41 | kvm-book3s_64-objs := \ | ||
42 | $(common-objs-y) \ | ||
43 | book3s.o \ | ||
44 | book3s_64_emulate.o \ | ||
45 | book3s_64_interrupts.o \ | ||
46 | book3s_64_mmu_host.o \ | ||
47 | book3s_64_mmu.o \ | ||
48 | book3s_32_mmu.o | ||
49 | kvm-objs-$(CONFIG_KVM_BOOK3S_64) := $(kvm-book3s_64-objs) | ||
50 | |||
51 | kvm-objs := $(kvm-objs-m) $(kvm-objs-y) | ||
52 | |||
53 | obj-$(CONFIG_KVM_440) += kvm.o | ||
54 | obj-$(CONFIG_KVM_E500) += kvm.o | ||
55 | obj-$(CONFIG_KVM_BOOK3S_64) += kvm.o | ||
56 | |||
diff --git a/arch/powerpc/kvm/book3s.c b/arch/powerpc/kvm/book3s.c new file mode 100644 index 000000000000..42037d46a416 --- /dev/null +++ b/arch/powerpc/kvm/book3s.c | |||
@@ -0,0 +1,925 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2009. SUSE Linux Products GmbH. All rights reserved. | ||
3 | * | ||
4 | * Authors: | ||
5 | * Alexander Graf <agraf@suse.de> | ||
6 | * Kevin Wolf <mail@kevin-wolf.de> | ||
7 | * | ||
8 | * Description: | ||
9 | * This file is derived from arch/powerpc/kvm/44x.c, | ||
10 | * by Hollis Blanchard <hollisb@us.ibm.com>. | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License, version 2, as | ||
14 | * published by the Free Software Foundation. | ||
15 | */ | ||
16 | |||
17 | #include <linux/kvm_host.h> | ||
18 | #include <linux/err.h> | ||
19 | |||
20 | #include <asm/reg.h> | ||
21 | #include <asm/cputable.h> | ||
22 | #include <asm/cacheflush.h> | ||
23 | #include <asm/tlbflush.h> | ||
24 | #include <asm/uaccess.h> | ||
25 | #include <asm/io.h> | ||
26 | #include <asm/kvm_ppc.h> | ||
27 | #include <asm/kvm_book3s.h> | ||
28 | #include <asm/mmu_context.h> | ||
29 | #include <linux/sched.h> | ||
30 | #include <linux/vmalloc.h> | ||
31 | |||
32 | #define VCPU_STAT(x) offsetof(struct kvm_vcpu, stat.x), KVM_STAT_VCPU | ||
33 | |||
34 | /* #define EXIT_DEBUG */ | ||
35 | /* #define EXIT_DEBUG_SIMPLE */ | ||
36 | |||
37 | /* Without AGGRESSIVE_DEC we only fire off a DEC interrupt when DEC turns 0. | ||
38 | * When set, we retrigger a DEC interrupt after that if DEC <= 0. | ||
39 | * PPC32 Linux runs faster without AGGRESSIVE_DEC, PPC64 Linux requires it. */ | ||
40 | |||
41 | /* #define AGGRESSIVE_DEC */ | ||
42 | |||
43 | struct kvm_stats_debugfs_item debugfs_entries[] = { | ||
44 | { "exits", VCPU_STAT(sum_exits) }, | ||
45 | { "mmio", VCPU_STAT(mmio_exits) }, | ||
46 | { "sig", VCPU_STAT(signal_exits) }, | ||
47 | { "sysc", VCPU_STAT(syscall_exits) }, | ||
48 | { "inst_emu", VCPU_STAT(emulated_inst_exits) }, | ||
49 | { "dec", VCPU_STAT(dec_exits) }, | ||
50 | { "ext_intr", VCPU_STAT(ext_intr_exits) }, | ||
51 | { "queue_intr", VCPU_STAT(queue_intr) }, | ||
52 | { "halt_wakeup", VCPU_STAT(halt_wakeup) }, | ||
53 | { "pf_storage", VCPU_STAT(pf_storage) }, | ||
54 | { "sp_storage", VCPU_STAT(sp_storage) }, | ||
55 | { "pf_instruc", VCPU_STAT(pf_instruc) }, | ||
56 | { "sp_instruc", VCPU_STAT(sp_instruc) }, | ||
57 | { "ld", VCPU_STAT(ld) }, | ||
58 | { "ld_slow", VCPU_STAT(ld_slow) }, | ||
59 | { "st", VCPU_STAT(st) }, | ||
60 | { "st_slow", VCPU_STAT(st_slow) }, | ||
61 | { NULL } | ||
62 | }; | ||
63 | |||
64 | void kvmppc_core_load_host_debugstate(struct kvm_vcpu *vcpu) | ||
65 | { | ||
66 | } | ||
67 | |||
68 | void kvmppc_core_load_guest_debugstate(struct kvm_vcpu *vcpu) | ||
69 | { | ||
70 | } | ||
71 | |||
72 | void kvmppc_core_vcpu_load(struct kvm_vcpu *vcpu, int cpu) | ||
73 | { | ||
74 | memcpy(get_paca()->kvm_slb, to_book3s(vcpu)->slb_shadow, sizeof(get_paca()->kvm_slb)); | ||
75 | get_paca()->kvm_slb_max = to_book3s(vcpu)->slb_shadow_max; | ||
76 | } | ||
77 | |||
78 | void kvmppc_core_vcpu_put(struct kvm_vcpu *vcpu) | ||
79 | { | ||
80 | memcpy(to_book3s(vcpu)->slb_shadow, get_paca()->kvm_slb, sizeof(get_paca()->kvm_slb)); | ||
81 | to_book3s(vcpu)->slb_shadow_max = get_paca()->kvm_slb_max; | ||
82 | } | ||
83 | |||
84 | #if defined(AGGRESSIVE_DEC) || defined(EXIT_DEBUG) | ||
85 | static u32 kvmppc_get_dec(struct kvm_vcpu *vcpu) | ||
86 | { | ||
87 | u64 jd = mftb() - vcpu->arch.dec_jiffies; | ||
88 | return vcpu->arch.dec - jd; | ||
89 | } | ||
90 | #endif | ||
91 | |||
92 | void kvmppc_set_msr(struct kvm_vcpu *vcpu, u64 msr) | ||
93 | { | ||
94 | ulong old_msr = vcpu->arch.msr; | ||
95 | |||
96 | #ifdef EXIT_DEBUG | ||
97 | printk(KERN_INFO "KVM: Set MSR to 0x%llx\n", msr); | ||
98 | #endif | ||
99 | msr &= to_book3s(vcpu)->msr_mask; | ||
100 | vcpu->arch.msr = msr; | ||
101 | vcpu->arch.shadow_msr = msr | MSR_USER32; | ||
102 | vcpu->arch.shadow_msr &= ( MSR_VEC | MSR_VSX | MSR_FP | MSR_FE0 | | ||
103 | MSR_USER64 | MSR_SE | MSR_BE | MSR_DE | | ||
104 | MSR_FE1); | ||
105 | |||
106 | if (msr & (MSR_WE|MSR_POW)) { | ||
107 | if (!vcpu->arch.pending_exceptions) { | ||
108 | kvm_vcpu_block(vcpu); | ||
109 | vcpu->stat.halt_wakeup++; | ||
110 | } | ||
111 | } | ||
112 | |||
113 | if (((vcpu->arch.msr & (MSR_IR|MSR_DR)) != (old_msr & (MSR_IR|MSR_DR))) || | ||
114 | (vcpu->arch.msr & MSR_PR) != (old_msr & MSR_PR)) { | ||
115 | kvmppc_mmu_flush_segments(vcpu); | ||
116 | kvmppc_mmu_map_segment(vcpu, vcpu->arch.pc); | ||
117 | } | ||
118 | } | ||
119 | |||
120 | void kvmppc_inject_interrupt(struct kvm_vcpu *vcpu, int vec, u64 flags) | ||
121 | { | ||
122 | vcpu->arch.srr0 = vcpu->arch.pc; | ||
123 | vcpu->arch.srr1 = vcpu->arch.msr | flags; | ||
124 | vcpu->arch.pc = to_book3s(vcpu)->hior + vec; | ||
125 | vcpu->arch.mmu.reset_msr(vcpu); | ||
126 | } | ||
127 | |||
128 | void kvmppc_book3s_queue_irqprio(struct kvm_vcpu *vcpu, unsigned int vec) | ||
129 | { | ||
130 | unsigned int prio; | ||
131 | |||
132 | vcpu->stat.queue_intr++; | ||
133 | switch (vec) { | ||
134 | case 0x100: prio = BOOK3S_IRQPRIO_SYSTEM_RESET; break; | ||
135 | case 0x200: prio = BOOK3S_IRQPRIO_MACHINE_CHECK; break; | ||
136 | case 0x300: prio = BOOK3S_IRQPRIO_DATA_STORAGE; break; | ||
137 | case 0x380: prio = BOOK3S_IRQPRIO_DATA_SEGMENT; break; | ||
138 | case 0x400: prio = BOOK3S_IRQPRIO_INST_STORAGE; break; | ||
139 | case 0x480: prio = BOOK3S_IRQPRIO_INST_SEGMENT; break; | ||
140 | case 0x500: prio = BOOK3S_IRQPRIO_EXTERNAL; break; | ||
141 | case 0x600: prio = BOOK3S_IRQPRIO_ALIGNMENT; break; | ||
142 | case 0x700: prio = BOOK3S_IRQPRIO_PROGRAM; break; | ||
143 | case 0x800: prio = BOOK3S_IRQPRIO_FP_UNAVAIL; break; | ||
144 | case 0x900: prio = BOOK3S_IRQPRIO_DECREMENTER; break; | ||
145 | case 0xc00: prio = BOOK3S_IRQPRIO_SYSCALL; break; | ||
146 | case 0xd00: prio = BOOK3S_IRQPRIO_DEBUG; break; | ||
147 | case 0xf20: prio = BOOK3S_IRQPRIO_ALTIVEC; break; | ||
148 | case 0xf40: prio = BOOK3S_IRQPRIO_VSX; break; | ||
149 | default: prio = BOOK3S_IRQPRIO_MAX; break; | ||
150 | } | ||
151 | |||
152 | set_bit(prio, &vcpu->arch.pending_exceptions); | ||
153 | #ifdef EXIT_DEBUG | ||
154 | printk(KERN_INFO "Queueing interrupt %x\n", vec); | ||
155 | #endif | ||
156 | } | ||
157 | |||
158 | |||
159 | void kvmppc_core_queue_program(struct kvm_vcpu *vcpu) | ||
160 | { | ||
161 | kvmppc_book3s_queue_irqprio(vcpu, BOOK3S_INTERRUPT_PROGRAM); | ||
162 | } | ||
163 | |||
164 | void kvmppc_core_queue_dec(struct kvm_vcpu *vcpu) | ||
165 | { | ||
166 | kvmppc_book3s_queue_irqprio(vcpu, BOOK3S_INTERRUPT_DECREMENTER); | ||
167 | } | ||
168 | |||
169 | int kvmppc_core_pending_dec(struct kvm_vcpu *vcpu) | ||
170 | { | ||
171 | return test_bit(BOOK3S_INTERRUPT_DECREMENTER >> 7, &vcpu->arch.pending_exceptions); | ||
172 | } | ||
173 | |||
174 | void kvmppc_core_queue_external(struct kvm_vcpu *vcpu, | ||
175 | struct kvm_interrupt *irq) | ||
176 | { | ||
177 | kvmppc_book3s_queue_irqprio(vcpu, BOOK3S_INTERRUPT_EXTERNAL); | ||
178 | } | ||
179 | |||
180 | int kvmppc_book3s_irqprio_deliver(struct kvm_vcpu *vcpu, unsigned int priority) | ||
181 | { | ||
182 | int deliver = 1; | ||
183 | int vec = 0; | ||
184 | |||
185 | switch (priority) { | ||
186 | case BOOK3S_IRQPRIO_DECREMENTER: | ||
187 | deliver = vcpu->arch.msr & MSR_EE; | ||
188 | vec = BOOK3S_INTERRUPT_DECREMENTER; | ||
189 | break; | ||
190 | case BOOK3S_IRQPRIO_EXTERNAL: | ||
191 | deliver = vcpu->arch.msr & MSR_EE; | ||
192 | vec = BOOK3S_INTERRUPT_EXTERNAL; | ||
193 | break; | ||
194 | case BOOK3S_IRQPRIO_SYSTEM_RESET: | ||
195 | vec = BOOK3S_INTERRUPT_SYSTEM_RESET; | ||
196 | break; | ||
197 | case BOOK3S_IRQPRIO_MACHINE_CHECK: | ||
198 | vec = BOOK3S_INTERRUPT_MACHINE_CHECK; | ||
199 | break; | ||
200 | case BOOK3S_IRQPRIO_DATA_STORAGE: | ||
201 | vec = BOOK3S_INTERRUPT_DATA_STORAGE; | ||
202 | break; | ||
203 | case BOOK3S_IRQPRIO_INST_STORAGE: | ||
204 | vec = BOOK3S_INTERRUPT_INST_STORAGE; | ||
205 | break; | ||
206 | case BOOK3S_IRQPRIO_DATA_SEGMENT: | ||
207 | vec = BOOK3S_INTERRUPT_DATA_SEGMENT; | ||
208 | break; | ||
209 | case BOOK3S_IRQPRIO_INST_SEGMENT: | ||
210 | vec = BOOK3S_INTERRUPT_INST_SEGMENT; | ||
211 | break; | ||
212 | case BOOK3S_IRQPRIO_ALIGNMENT: | ||
213 | vec = BOOK3S_INTERRUPT_ALIGNMENT; | ||
214 | break; | ||
215 | case BOOK3S_IRQPRIO_PROGRAM: | ||
216 | vec = BOOK3S_INTERRUPT_PROGRAM; | ||
217 | break; | ||
218 | case BOOK3S_IRQPRIO_VSX: | ||
219 | vec = BOOK3S_INTERRUPT_VSX; | ||
220 | break; | ||
221 | case BOOK3S_IRQPRIO_ALTIVEC: | ||
222 | vec = BOOK3S_INTERRUPT_ALTIVEC; | ||
223 | break; | ||
224 | case BOOK3S_IRQPRIO_FP_UNAVAIL: | ||
225 | vec = BOOK3S_INTERRUPT_FP_UNAVAIL; | ||
226 | break; | ||
227 | case BOOK3S_IRQPRIO_SYSCALL: | ||
228 | vec = BOOK3S_INTERRUPT_SYSCALL; | ||
229 | break; | ||
230 | case BOOK3S_IRQPRIO_DEBUG: | ||
231 | vec = BOOK3S_INTERRUPT_TRACE; | ||
232 | break; | ||
233 | case BOOK3S_IRQPRIO_PERFORMANCE_MONITOR: | ||
234 | vec = BOOK3S_INTERRUPT_PERFMON; | ||
235 | break; | ||
236 | default: | ||
237 | deliver = 0; | ||
238 | printk(KERN_ERR "KVM: Unknown interrupt: 0x%x\n", priority); | ||
239 | break; | ||
240 | } | ||
241 | |||
242 | #if 0 | ||
243 | printk(KERN_INFO "Deliver interrupt 0x%x? %x\n", vec, deliver); | ||
244 | #endif | ||
245 | |||
246 | if (deliver) | ||
247 | kvmppc_inject_interrupt(vcpu, vec, 0ULL); | ||
248 | |||
249 | return deliver; | ||
250 | } | ||
251 | |||
252 | void kvmppc_core_deliver_interrupts(struct kvm_vcpu *vcpu) | ||
253 | { | ||
254 | unsigned long *pending = &vcpu->arch.pending_exceptions; | ||
255 | unsigned int priority; | ||
256 | |||
257 | /* XXX be more clever here - no need to mftb() on every entry */ | ||
258 | /* Issue DEC again if it's still active */ | ||
259 | #ifdef AGGRESSIVE_DEC | ||
260 | if (vcpu->arch.msr & MSR_EE) | ||
261 | if (kvmppc_get_dec(vcpu) & 0x80000000) | ||
262 | kvmppc_core_queue_dec(vcpu); | ||
263 | #endif | ||
264 | |||
265 | #ifdef EXIT_DEBUG | ||
266 | if (vcpu->arch.pending_exceptions) | ||
267 | printk(KERN_EMERG "KVM: Check pending: %lx\n", vcpu->arch.pending_exceptions); | ||
268 | #endif | ||
269 | priority = __ffs(*pending); | ||
270 | while (priority <= (sizeof(unsigned int) * 8)) { | ||
271 | if (kvmppc_book3s_irqprio_deliver(vcpu, priority)) { | ||
272 | clear_bit(priority, &vcpu->arch.pending_exceptions); | ||
273 | break; | ||
274 | } | ||
275 | |||
276 | priority = find_next_bit(pending, | ||
277 | BITS_PER_BYTE * sizeof(*pending), | ||
278 | priority + 1); | ||
279 | } | ||
280 | } | ||
281 | |||
282 | void kvmppc_set_pvr(struct kvm_vcpu *vcpu, u32 pvr) | ||
283 | { | ||
284 | vcpu->arch.pvr = pvr; | ||
285 | if ((pvr >= 0x330000) && (pvr < 0x70330000)) { | ||
286 | kvmppc_mmu_book3s_64_init(vcpu); | ||
287 | to_book3s(vcpu)->hior = 0xfff00000; | ||
288 | to_book3s(vcpu)->msr_mask = 0xffffffffffffffffULL; | ||
289 | } else { | ||
290 | kvmppc_mmu_book3s_32_init(vcpu); | ||
291 | to_book3s(vcpu)->hior = 0; | ||
292 | to_book3s(vcpu)->msr_mask = 0xffffffffULL; | ||
293 | } | ||
294 | |||
295 | /* If we are in hypervisor level on 970, we can tell the CPU to | ||
296 | * treat DCBZ as 32 bytes store */ | ||
297 | vcpu->arch.hflags &= ~BOOK3S_HFLAG_DCBZ32; | ||
298 | if (vcpu->arch.mmu.is_dcbz32(vcpu) && (mfmsr() & MSR_HV) && | ||
299 | !strcmp(cur_cpu_spec->platform, "ppc970")) | ||
300 | vcpu->arch.hflags |= BOOK3S_HFLAG_DCBZ32; | ||
301 | |||
302 | } | ||
303 | |||
304 | /* Book3s_32 CPUs always have 32 bytes cache line size, which Linux assumes. To | ||
305 | * make Book3s_32 Linux work on Book3s_64, we have to make sure we trap dcbz to | ||
306 | * emulate 32 bytes dcbz length. | ||
307 | * | ||
308 | * The Book3s_64 inventors also realized this case and implemented a special bit | ||
309 | * in the HID5 register, which is a hypervisor ressource. Thus we can't use it. | ||
310 | * | ||
311 | * My approach here is to patch the dcbz instruction on executing pages. | ||
312 | */ | ||
313 | static void kvmppc_patch_dcbz(struct kvm_vcpu *vcpu, struct kvmppc_pte *pte) | ||
314 | { | ||
315 | bool touched = false; | ||
316 | hva_t hpage; | ||
317 | u32 *page; | ||
318 | int i; | ||
319 | |||
320 | hpage = gfn_to_hva(vcpu->kvm, pte->raddr >> PAGE_SHIFT); | ||
321 | if (kvm_is_error_hva(hpage)) | ||
322 | return; | ||
323 | |||
324 | hpage |= pte->raddr & ~PAGE_MASK; | ||
325 | hpage &= ~0xFFFULL; | ||
326 | |||
327 | page = vmalloc(HW_PAGE_SIZE); | ||
328 | |||
329 | if (copy_from_user(page, (void __user *)hpage, HW_PAGE_SIZE)) | ||
330 | goto out; | ||
331 | |||
332 | for (i=0; i < HW_PAGE_SIZE / 4; i++) | ||
333 | if ((page[i] & 0xff0007ff) == INS_DCBZ) { | ||
334 | page[i] &= 0xfffffff7; // reserved instruction, so we trap | ||
335 | touched = true; | ||
336 | } | ||
337 | |||
338 | if (touched) | ||
339 | copy_to_user((void __user *)hpage, page, HW_PAGE_SIZE); | ||
340 | |||
341 | out: | ||
342 | vfree(page); | ||
343 | } | ||
344 | |||
345 | static int kvmppc_xlate(struct kvm_vcpu *vcpu, ulong eaddr, bool data, | ||
346 | struct kvmppc_pte *pte) | ||
347 | { | ||
348 | int relocated = (vcpu->arch.msr & (data ? MSR_DR : MSR_IR)); | ||
349 | int r; | ||
350 | |||
351 | if (relocated) { | ||
352 | r = vcpu->arch.mmu.xlate(vcpu, eaddr, pte, data); | ||
353 | } else { | ||
354 | pte->eaddr = eaddr; | ||
355 | pte->raddr = eaddr & 0xffffffff; | ||
356 | pte->vpage = eaddr >> 12; | ||
357 | switch (vcpu->arch.msr & (MSR_DR|MSR_IR)) { | ||
358 | case 0: | ||
359 | pte->vpage |= VSID_REAL; | ||
360 | case MSR_DR: | ||
361 | pte->vpage |= VSID_REAL_DR; | ||
362 | case MSR_IR: | ||
363 | pte->vpage |= VSID_REAL_IR; | ||
364 | } | ||
365 | pte->may_read = true; | ||
366 | pte->may_write = true; | ||
367 | pte->may_execute = true; | ||
368 | r = 0; | ||
369 | } | ||
370 | |||
371 | return r; | ||
372 | } | ||
373 | |||
374 | static hva_t kvmppc_bad_hva(void) | ||
375 | { | ||
376 | return PAGE_OFFSET; | ||
377 | } | ||
378 | |||
379 | static hva_t kvmppc_pte_to_hva(struct kvm_vcpu *vcpu, struct kvmppc_pte *pte, | ||
380 | bool read) | ||
381 | { | ||
382 | hva_t hpage; | ||
383 | |||
384 | if (read && !pte->may_read) | ||
385 | goto err; | ||
386 | |||
387 | if (!read && !pte->may_write) | ||
388 | goto err; | ||
389 | |||
390 | hpage = gfn_to_hva(vcpu->kvm, pte->raddr >> PAGE_SHIFT); | ||
391 | if (kvm_is_error_hva(hpage)) | ||
392 | goto err; | ||
393 | |||
394 | return hpage | (pte->raddr & ~PAGE_MASK); | ||
395 | err: | ||
396 | return kvmppc_bad_hva(); | ||
397 | } | ||
398 | |||
399 | int kvmppc_st(struct kvm_vcpu *vcpu, ulong eaddr, int size, void *ptr) | ||
400 | { | ||
401 | struct kvmppc_pte pte; | ||
402 | hva_t hva = eaddr; | ||
403 | |||
404 | vcpu->stat.st++; | ||
405 | |||
406 | if (kvmppc_xlate(vcpu, eaddr, false, &pte)) | ||
407 | goto err; | ||
408 | |||
409 | hva = kvmppc_pte_to_hva(vcpu, &pte, false); | ||
410 | if (kvm_is_error_hva(hva)) | ||
411 | goto err; | ||
412 | |||
413 | if (copy_to_user((void __user *)hva, ptr, size)) { | ||
414 | printk(KERN_INFO "kvmppc_st at 0x%lx failed\n", hva); | ||
415 | goto err; | ||
416 | } | ||
417 | |||
418 | return 0; | ||
419 | |||
420 | err: | ||
421 | return -ENOENT; | ||
422 | } | ||
423 | |||
424 | int kvmppc_ld(struct kvm_vcpu *vcpu, ulong eaddr, int size, void *ptr, | ||
425 | bool data) | ||
426 | { | ||
427 | struct kvmppc_pte pte; | ||
428 | hva_t hva = eaddr; | ||
429 | |||
430 | vcpu->stat.ld++; | ||
431 | |||
432 | if (kvmppc_xlate(vcpu, eaddr, data, &pte)) | ||
433 | goto err; | ||
434 | |||
435 | hva = kvmppc_pte_to_hva(vcpu, &pte, true); | ||
436 | if (kvm_is_error_hva(hva)) | ||
437 | goto err; | ||
438 | |||
439 | if (copy_from_user(ptr, (void __user *)hva, size)) { | ||
440 | printk(KERN_INFO "kvmppc_ld at 0x%lx failed\n", hva); | ||
441 | goto err; | ||
442 | } | ||
443 | |||
444 | return 0; | ||
445 | |||
446 | err: | ||
447 | return -ENOENT; | ||
448 | } | ||
449 | |||
450 | static int kvmppc_visible_gfn(struct kvm_vcpu *vcpu, gfn_t gfn) | ||
451 | { | ||
452 | return kvm_is_visible_gfn(vcpu->kvm, gfn); | ||
453 | } | ||
454 | |||
455 | int kvmppc_handle_pagefault(struct kvm_run *run, struct kvm_vcpu *vcpu, | ||
456 | ulong eaddr, int vec) | ||
457 | { | ||
458 | bool data = (vec == BOOK3S_INTERRUPT_DATA_STORAGE); | ||
459 | int r = RESUME_GUEST; | ||
460 | int relocated; | ||
461 | int page_found = 0; | ||
462 | struct kvmppc_pte pte; | ||
463 | bool is_mmio = false; | ||
464 | |||
465 | if ( vec == BOOK3S_INTERRUPT_DATA_STORAGE ) { | ||
466 | relocated = (vcpu->arch.msr & MSR_DR); | ||
467 | } else { | ||
468 | relocated = (vcpu->arch.msr & MSR_IR); | ||
469 | } | ||
470 | |||
471 | /* Resolve real address if translation turned on */ | ||
472 | if (relocated) { | ||
473 | page_found = vcpu->arch.mmu.xlate(vcpu, eaddr, &pte, data); | ||
474 | } else { | ||
475 | pte.may_execute = true; | ||
476 | pte.may_read = true; | ||
477 | pte.may_write = true; | ||
478 | pte.raddr = eaddr & 0xffffffff; | ||
479 | pte.eaddr = eaddr; | ||
480 | pte.vpage = eaddr >> 12; | ||
481 | switch (vcpu->arch.msr & (MSR_DR|MSR_IR)) { | ||
482 | case 0: | ||
483 | pte.vpage |= VSID_REAL; | ||
484 | case MSR_DR: | ||
485 | pte.vpage |= VSID_REAL_DR; | ||
486 | case MSR_IR: | ||
487 | pte.vpage |= VSID_REAL_IR; | ||
488 | } | ||
489 | } | ||
490 | |||
491 | if (vcpu->arch.mmu.is_dcbz32(vcpu) && | ||
492 | (!(vcpu->arch.hflags & BOOK3S_HFLAG_DCBZ32))) { | ||
493 | /* | ||
494 | * If we do the dcbz hack, we have to NX on every execution, | ||
495 | * so we can patch the executing code. This renders our guest | ||
496 | * NX-less. | ||
497 | */ | ||
498 | pte.may_execute = !data; | ||
499 | } | ||
500 | |||
501 | if (page_found == -ENOENT) { | ||
502 | /* Page not found in guest PTE entries */ | ||
503 | vcpu->arch.dear = vcpu->arch.fault_dear; | ||
504 | to_book3s(vcpu)->dsisr = vcpu->arch.fault_dsisr; | ||
505 | vcpu->arch.msr |= (vcpu->arch.shadow_msr & 0x00000000f8000000ULL); | ||
506 | kvmppc_book3s_queue_irqprio(vcpu, vec); | ||
507 | } else if (page_found == -EPERM) { | ||
508 | /* Storage protection */ | ||
509 | vcpu->arch.dear = vcpu->arch.fault_dear; | ||
510 | to_book3s(vcpu)->dsisr = vcpu->arch.fault_dsisr & ~DSISR_NOHPTE; | ||
511 | to_book3s(vcpu)->dsisr |= DSISR_PROTFAULT; | ||
512 | vcpu->arch.msr |= (vcpu->arch.shadow_msr & 0x00000000f8000000ULL); | ||
513 | kvmppc_book3s_queue_irqprio(vcpu, vec); | ||
514 | } else if (page_found == -EINVAL) { | ||
515 | /* Page not found in guest SLB */ | ||
516 | vcpu->arch.dear = vcpu->arch.fault_dear; | ||
517 | kvmppc_book3s_queue_irqprio(vcpu, vec + 0x80); | ||
518 | } else if (!is_mmio && | ||
519 | kvmppc_visible_gfn(vcpu, pte.raddr >> PAGE_SHIFT)) { | ||
520 | /* The guest's PTE is not mapped yet. Map on the host */ | ||
521 | kvmppc_mmu_map_page(vcpu, &pte); | ||
522 | if (data) | ||
523 | vcpu->stat.sp_storage++; | ||
524 | else if (vcpu->arch.mmu.is_dcbz32(vcpu) && | ||
525 | (!(vcpu->arch.hflags & BOOK3S_HFLAG_DCBZ32))) | ||
526 | kvmppc_patch_dcbz(vcpu, &pte); | ||
527 | } else { | ||
528 | /* MMIO */ | ||
529 | vcpu->stat.mmio_exits++; | ||
530 | vcpu->arch.paddr_accessed = pte.raddr; | ||
531 | r = kvmppc_emulate_mmio(run, vcpu); | ||
532 | if ( r == RESUME_HOST_NV ) | ||
533 | r = RESUME_HOST; | ||
534 | if ( r == RESUME_GUEST_NV ) | ||
535 | r = RESUME_GUEST; | ||
536 | } | ||
537 | |||
538 | return r; | ||
539 | } | ||
540 | |||
541 | int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu, | ||
542 | unsigned int exit_nr) | ||
543 | { | ||
544 | int r = RESUME_HOST; | ||
545 | |||
546 | vcpu->stat.sum_exits++; | ||
547 | |||
548 | run->exit_reason = KVM_EXIT_UNKNOWN; | ||
549 | run->ready_for_interrupt_injection = 1; | ||
550 | #ifdef EXIT_DEBUG | ||
551 | printk(KERN_EMERG "exit_nr=0x%x | pc=0x%lx | dar=0x%lx | dec=0x%x | msr=0x%lx\n", | ||
552 | exit_nr, vcpu->arch.pc, vcpu->arch.fault_dear, | ||
553 | kvmppc_get_dec(vcpu), vcpu->arch.msr); | ||
554 | #elif defined (EXIT_DEBUG_SIMPLE) | ||
555 | if ((exit_nr != 0x900) && (exit_nr != 0x500)) | ||
556 | printk(KERN_EMERG "exit_nr=0x%x | pc=0x%lx | dar=0x%lx | msr=0x%lx\n", | ||
557 | exit_nr, vcpu->arch.pc, vcpu->arch.fault_dear, | ||
558 | vcpu->arch.msr); | ||
559 | #endif | ||
560 | kvm_resched(vcpu); | ||
561 | switch (exit_nr) { | ||
562 | case BOOK3S_INTERRUPT_INST_STORAGE: | ||
563 | vcpu->stat.pf_instruc++; | ||
564 | /* only care about PTEG not found errors, but leave NX alone */ | ||
565 | if (vcpu->arch.shadow_msr & 0x40000000) { | ||
566 | r = kvmppc_handle_pagefault(run, vcpu, vcpu->arch.pc, exit_nr); | ||
567 | vcpu->stat.sp_instruc++; | ||
568 | } else if (vcpu->arch.mmu.is_dcbz32(vcpu) && | ||
569 | (!(vcpu->arch.hflags & BOOK3S_HFLAG_DCBZ32))) { | ||
570 | /* | ||
571 | * XXX If we do the dcbz hack we use the NX bit to flush&patch the page, | ||
572 | * so we can't use the NX bit inside the guest. Let's cross our fingers, | ||
573 | * that no guest that needs the dcbz hack does NX. | ||
574 | */ | ||
575 | kvmppc_mmu_pte_flush(vcpu, vcpu->arch.pc, ~0xFFFULL); | ||
576 | } else { | ||
577 | vcpu->arch.msr |= (vcpu->arch.shadow_msr & 0x58000000); | ||
578 | kvmppc_book3s_queue_irqprio(vcpu, exit_nr); | ||
579 | kvmppc_mmu_pte_flush(vcpu, vcpu->arch.pc, ~0xFFFULL); | ||
580 | r = RESUME_GUEST; | ||
581 | } | ||
582 | break; | ||
583 | case BOOK3S_INTERRUPT_DATA_STORAGE: | ||
584 | vcpu->stat.pf_storage++; | ||
585 | /* The only case we need to handle is missing shadow PTEs */ | ||
586 | if (vcpu->arch.fault_dsisr & DSISR_NOHPTE) { | ||
587 | r = kvmppc_handle_pagefault(run, vcpu, vcpu->arch.fault_dear, exit_nr); | ||
588 | } else { | ||
589 | vcpu->arch.dear = vcpu->arch.fault_dear; | ||
590 | to_book3s(vcpu)->dsisr = vcpu->arch.fault_dsisr; | ||
591 | kvmppc_book3s_queue_irqprio(vcpu, exit_nr); | ||
592 | kvmppc_mmu_pte_flush(vcpu, vcpu->arch.dear, ~0xFFFULL); | ||
593 | r = RESUME_GUEST; | ||
594 | } | ||
595 | break; | ||
596 | case BOOK3S_INTERRUPT_DATA_SEGMENT: | ||
597 | if (kvmppc_mmu_map_segment(vcpu, vcpu->arch.fault_dear) < 0) { | ||
598 | vcpu->arch.dear = vcpu->arch.fault_dear; | ||
599 | kvmppc_book3s_queue_irqprio(vcpu, | ||
600 | BOOK3S_INTERRUPT_DATA_SEGMENT); | ||
601 | } | ||
602 | r = RESUME_GUEST; | ||
603 | break; | ||
604 | case BOOK3S_INTERRUPT_INST_SEGMENT: | ||
605 | if (kvmppc_mmu_map_segment(vcpu, vcpu->arch.pc) < 0) { | ||
606 | kvmppc_book3s_queue_irqprio(vcpu, | ||
607 | BOOK3S_INTERRUPT_INST_SEGMENT); | ||
608 | } | ||
609 | r = RESUME_GUEST; | ||
610 | break; | ||
611 | /* We're good on these - the host merely wanted to get our attention */ | ||
612 | case BOOK3S_INTERRUPT_DECREMENTER: | ||
613 | vcpu->stat.dec_exits++; | ||
614 | r = RESUME_GUEST; | ||
615 | break; | ||
616 | case BOOK3S_INTERRUPT_EXTERNAL: | ||
617 | vcpu->stat.ext_intr_exits++; | ||
618 | r = RESUME_GUEST; | ||
619 | break; | ||
620 | case BOOK3S_INTERRUPT_PROGRAM: | ||
621 | { | ||
622 | enum emulation_result er; | ||
623 | |||
624 | if (vcpu->arch.msr & MSR_PR) { | ||
625 | #ifdef EXIT_DEBUG | ||
626 | printk(KERN_INFO "Userspace triggered 0x700 exception at 0x%lx (0x%x)\n", vcpu->arch.pc, vcpu->arch.last_inst); | ||
627 | #endif | ||
628 | if ((vcpu->arch.last_inst & 0xff0007ff) != | ||
629 | (INS_DCBZ & 0xfffffff7)) { | ||
630 | kvmppc_book3s_queue_irqprio(vcpu, exit_nr); | ||
631 | r = RESUME_GUEST; | ||
632 | break; | ||
633 | } | ||
634 | } | ||
635 | |||
636 | vcpu->stat.emulated_inst_exits++; | ||
637 | er = kvmppc_emulate_instruction(run, vcpu); | ||
638 | switch (er) { | ||
639 | case EMULATE_DONE: | ||
640 | r = RESUME_GUEST; | ||
641 | break; | ||
642 | case EMULATE_FAIL: | ||
643 | printk(KERN_CRIT "%s: emulation at %lx failed (%08x)\n", | ||
644 | __func__, vcpu->arch.pc, vcpu->arch.last_inst); | ||
645 | kvmppc_book3s_queue_irqprio(vcpu, exit_nr); | ||
646 | r = RESUME_GUEST; | ||
647 | break; | ||
648 | default: | ||
649 | BUG(); | ||
650 | } | ||
651 | break; | ||
652 | } | ||
653 | case BOOK3S_INTERRUPT_SYSCALL: | ||
654 | #ifdef EXIT_DEBUG | ||
655 | printk(KERN_INFO "Syscall Nr %d\n", (int)vcpu->arch.gpr[0]); | ||
656 | #endif | ||
657 | vcpu->stat.syscall_exits++; | ||
658 | kvmppc_book3s_queue_irqprio(vcpu, exit_nr); | ||
659 | r = RESUME_GUEST; | ||
660 | break; | ||
661 | case BOOK3S_INTERRUPT_MACHINE_CHECK: | ||
662 | case BOOK3S_INTERRUPT_FP_UNAVAIL: | ||
663 | case BOOK3S_INTERRUPT_TRACE: | ||
664 | case BOOK3S_INTERRUPT_ALTIVEC: | ||
665 | case BOOK3S_INTERRUPT_VSX: | ||
666 | kvmppc_book3s_queue_irqprio(vcpu, exit_nr); | ||
667 | r = RESUME_GUEST; | ||
668 | break; | ||
669 | default: | ||
670 | /* Ugh - bork here! What did we get? */ | ||
671 | printk(KERN_EMERG "exit_nr=0x%x | pc=0x%lx | msr=0x%lx\n", exit_nr, vcpu->arch.pc, vcpu->arch.shadow_msr); | ||
672 | r = RESUME_HOST; | ||
673 | BUG(); | ||
674 | break; | ||
675 | } | ||
676 | |||
677 | |||
678 | if (!(r & RESUME_HOST)) { | ||
679 | /* To avoid clobbering exit_reason, only check for signals if | ||
680 | * we aren't already exiting to userspace for some other | ||
681 | * reason. */ | ||
682 | if (signal_pending(current)) { | ||
683 | #ifdef EXIT_DEBUG | ||
684 | printk(KERN_EMERG "KVM: Going back to host\n"); | ||
685 | #endif | ||
686 | vcpu->stat.signal_exits++; | ||
687 | run->exit_reason = KVM_EXIT_INTR; | ||
688 | r = -EINTR; | ||
689 | } else { | ||
690 | /* In case an interrupt came in that was triggered | ||
691 | * from userspace (like DEC), we need to check what | ||
692 | * to inject now! */ | ||
693 | kvmppc_core_deliver_interrupts(vcpu); | ||
694 | } | ||
695 | } | ||
696 | |||
697 | #ifdef EXIT_DEBUG | ||
698 | printk(KERN_EMERG "KVM exit: vcpu=0x%p pc=0x%lx r=0x%x\n", vcpu, vcpu->arch.pc, r); | ||
699 | #endif | ||
700 | |||
701 | return r; | ||
702 | } | ||
703 | |||
704 | int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu) | ||
705 | { | ||
706 | return 0; | ||
707 | } | ||
708 | |||
709 | int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs) | ||
710 | { | ||
711 | int i; | ||
712 | |||
713 | regs->pc = vcpu->arch.pc; | ||
714 | regs->cr = vcpu->arch.cr; | ||
715 | regs->ctr = vcpu->arch.ctr; | ||
716 | regs->lr = vcpu->arch.lr; | ||
717 | regs->xer = vcpu->arch.xer; | ||
718 | regs->msr = vcpu->arch.msr; | ||
719 | regs->srr0 = vcpu->arch.srr0; | ||
720 | regs->srr1 = vcpu->arch.srr1; | ||
721 | regs->pid = vcpu->arch.pid; | ||
722 | regs->sprg0 = vcpu->arch.sprg0; | ||
723 | regs->sprg1 = vcpu->arch.sprg1; | ||
724 | regs->sprg2 = vcpu->arch.sprg2; | ||
725 | regs->sprg3 = vcpu->arch.sprg3; | ||
726 | regs->sprg5 = vcpu->arch.sprg4; | ||
727 | regs->sprg6 = vcpu->arch.sprg5; | ||
728 | regs->sprg7 = vcpu->arch.sprg6; | ||
729 | |||
730 | for (i = 0; i < ARRAY_SIZE(regs->gpr); i++) | ||
731 | regs->gpr[i] = vcpu->arch.gpr[i]; | ||
732 | |||
733 | return 0; | ||
734 | } | ||
735 | |||
736 | int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs) | ||
737 | { | ||
738 | int i; | ||
739 | |||
740 | vcpu->arch.pc = regs->pc; | ||
741 | vcpu->arch.cr = regs->cr; | ||
742 | vcpu->arch.ctr = regs->ctr; | ||
743 | vcpu->arch.lr = regs->lr; | ||
744 | vcpu->arch.xer = regs->xer; | ||
745 | kvmppc_set_msr(vcpu, regs->msr); | ||
746 | vcpu->arch.srr0 = regs->srr0; | ||
747 | vcpu->arch.srr1 = regs->srr1; | ||
748 | vcpu->arch.sprg0 = regs->sprg0; | ||
749 | vcpu->arch.sprg1 = regs->sprg1; | ||
750 | vcpu->arch.sprg2 = regs->sprg2; | ||
751 | vcpu->arch.sprg3 = regs->sprg3; | ||
752 | vcpu->arch.sprg5 = regs->sprg4; | ||
753 | vcpu->arch.sprg6 = regs->sprg5; | ||
754 | vcpu->arch.sprg7 = regs->sprg6; | ||
755 | |||
756 | for (i = 0; i < ARRAY_SIZE(vcpu->arch.gpr); i++) | ||
757 | vcpu->arch.gpr[i] = regs->gpr[i]; | ||
758 | |||
759 | return 0; | ||
760 | } | ||
761 | |||
762 | int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu, | ||
763 | struct kvm_sregs *sregs) | ||
764 | { | ||
765 | sregs->pvr = vcpu->arch.pvr; | ||
766 | return 0; | ||
767 | } | ||
768 | |||
769 | int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu, | ||
770 | struct kvm_sregs *sregs) | ||
771 | { | ||
772 | kvmppc_set_pvr(vcpu, sregs->pvr); | ||
773 | return 0; | ||
774 | } | ||
775 | |||
776 | int kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu) | ||
777 | { | ||
778 | return -ENOTSUPP; | ||
779 | } | ||
780 | |||
781 | int kvm_arch_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu) | ||
782 | { | ||
783 | return -ENOTSUPP; | ||
784 | } | ||
785 | |||
786 | int kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu, | ||
787 | struct kvm_translation *tr) | ||
788 | { | ||
789 | return 0; | ||
790 | } | ||
791 | |||
792 | /* | ||
793 | * Get (and clear) the dirty memory log for a memory slot. | ||
794 | */ | ||
795 | int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm, | ||
796 | struct kvm_dirty_log *log) | ||
797 | { | ||
798 | struct kvm_memory_slot *memslot; | ||
799 | struct kvm_vcpu *vcpu; | ||
800 | ulong ga, ga_end; | ||
801 | int is_dirty = 0; | ||
802 | int r, n; | ||
803 | |||
804 | down_write(&kvm->slots_lock); | ||
805 | |||
806 | r = kvm_get_dirty_log(kvm, log, &is_dirty); | ||
807 | if (r) | ||
808 | goto out; | ||
809 | |||
810 | /* If nothing is dirty, don't bother messing with page tables. */ | ||
811 | if (is_dirty) { | ||
812 | memslot = &kvm->memslots[log->slot]; | ||
813 | |||
814 | ga = memslot->base_gfn << PAGE_SHIFT; | ||
815 | ga_end = ga + (memslot->npages << PAGE_SHIFT); | ||
816 | |||
817 | kvm_for_each_vcpu(n, vcpu, kvm) | ||
818 | kvmppc_mmu_pte_pflush(vcpu, ga, ga_end); | ||
819 | |||
820 | n = ALIGN(memslot->npages, BITS_PER_LONG) / 8; | ||
821 | memset(memslot->dirty_bitmap, 0, n); | ||
822 | } | ||
823 | |||
824 | r = 0; | ||
825 | out: | ||
826 | up_write(&kvm->slots_lock); | ||
827 | return r; | ||
828 | } | ||
829 | |||
830 | int kvmppc_core_check_processor_compat(void) | ||
831 | { | ||
832 | return 0; | ||
833 | } | ||
834 | |||
835 | struct kvm_vcpu *kvmppc_core_vcpu_create(struct kvm *kvm, unsigned int id) | ||
836 | { | ||
837 | struct kvmppc_vcpu_book3s *vcpu_book3s; | ||
838 | struct kvm_vcpu *vcpu; | ||
839 | int err; | ||
840 | |||
841 | vcpu_book3s = (struct kvmppc_vcpu_book3s *)__get_free_pages( GFP_KERNEL | __GFP_ZERO, | ||
842 | get_order(sizeof(struct kvmppc_vcpu_book3s))); | ||
843 | if (!vcpu_book3s) { | ||
844 | err = -ENOMEM; | ||
845 | goto out; | ||
846 | } | ||
847 | |||
848 | vcpu = &vcpu_book3s->vcpu; | ||
849 | err = kvm_vcpu_init(vcpu, kvm, id); | ||
850 | if (err) | ||
851 | goto free_vcpu; | ||
852 | |||
853 | vcpu->arch.host_retip = kvm_return_point; | ||
854 | vcpu->arch.host_msr = mfmsr(); | ||
855 | /* default to book3s_64 (970fx) */ | ||
856 | vcpu->arch.pvr = 0x3C0301; | ||
857 | kvmppc_set_pvr(vcpu, vcpu->arch.pvr); | ||
858 | vcpu_book3s->slb_nr = 64; | ||
859 | |||
860 | /* remember where some real-mode handlers are */ | ||
861 | vcpu->arch.trampoline_lowmem = kvmppc_trampoline_lowmem; | ||
862 | vcpu->arch.trampoline_enter = kvmppc_trampoline_enter; | ||
863 | vcpu->arch.highmem_handler = (ulong)kvmppc_handler_highmem; | ||
864 | |||
865 | vcpu->arch.shadow_msr = MSR_USER64; | ||
866 | |||
867 | err = __init_new_context(); | ||
868 | if (err < 0) | ||
869 | goto free_vcpu; | ||
870 | vcpu_book3s->context_id = err; | ||
871 | |||
872 | vcpu_book3s->vsid_max = ((vcpu_book3s->context_id + 1) << USER_ESID_BITS) - 1; | ||
873 | vcpu_book3s->vsid_first = vcpu_book3s->context_id << USER_ESID_BITS; | ||
874 | vcpu_book3s->vsid_next = vcpu_book3s->vsid_first; | ||
875 | |||
876 | return vcpu; | ||
877 | |||
878 | free_vcpu: | ||
879 | free_pages((long)vcpu_book3s, get_order(sizeof(struct kvmppc_vcpu_book3s))); | ||
880 | out: | ||
881 | return ERR_PTR(err); | ||
882 | } | ||
883 | |||
884 | void kvmppc_core_vcpu_free(struct kvm_vcpu *vcpu) | ||
885 | { | ||
886 | struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu); | ||
887 | |||
888 | __destroy_context(vcpu_book3s->context_id); | ||
889 | kvm_vcpu_uninit(vcpu); | ||
890 | free_pages((long)vcpu_book3s, get_order(sizeof(struct kvmppc_vcpu_book3s))); | ||
891 | } | ||
892 | |||
893 | extern int __kvmppc_vcpu_entry(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu); | ||
894 | int __kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu) | ||
895 | { | ||
896 | int ret; | ||
897 | |||
898 | /* No need to go into the guest when all we do is going out */ | ||
899 | if (signal_pending(current)) { | ||
900 | kvm_run->exit_reason = KVM_EXIT_INTR; | ||
901 | return -EINTR; | ||
902 | } | ||
903 | |||
904 | /* XXX we get called with irq disabled - change that! */ | ||
905 | local_irq_enable(); | ||
906 | |||
907 | ret = __kvmppc_vcpu_entry(kvm_run, vcpu); | ||
908 | |||
909 | local_irq_disable(); | ||
910 | |||
911 | return ret; | ||
912 | } | ||
913 | |||
914 | static int kvmppc_book3s_init(void) | ||
915 | { | ||
916 | return kvm_init(NULL, sizeof(struct kvmppc_vcpu_book3s), THIS_MODULE); | ||
917 | } | ||
918 | |||
919 | static void kvmppc_book3s_exit(void) | ||
920 | { | ||
921 | kvm_exit(); | ||
922 | } | ||
923 | |||
924 | module_init(kvmppc_book3s_init); | ||
925 | module_exit(kvmppc_book3s_exit); | ||
diff --git a/arch/powerpc/kvm/book3s_32_mmu.c b/arch/powerpc/kvm/book3s_32_mmu.c new file mode 100644 index 000000000000..faf99f20d993 --- /dev/null +++ b/arch/powerpc/kvm/book3s_32_mmu.c | |||
@@ -0,0 +1,372 @@ | |||
1 | /* | ||
2 | * This program is free software; you can redistribute it and/or modify | ||
3 | * it under the terms of the GNU General Public License, version 2, as | ||
4 | * published by the Free Software Foundation. | ||
5 | * | ||
6 | * This program is distributed in the hope that it will be useful, | ||
7 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
8 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
9 | * GNU General Public License for more details. | ||
10 | * | ||
11 | * You should have received a copy of the GNU General Public License | ||
12 | * along with this program; if not, write to the Free Software | ||
13 | * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
14 | * | ||
15 | * Copyright SUSE Linux Products GmbH 2009 | ||
16 | * | ||
17 | * Authors: Alexander Graf <agraf@suse.de> | ||
18 | */ | ||
19 | |||
20 | #include <linux/types.h> | ||
21 | #include <linux/string.h> | ||
22 | #include <linux/kvm.h> | ||
23 | #include <linux/kvm_host.h> | ||
24 | #include <linux/highmem.h> | ||
25 | |||
26 | #include <asm/tlbflush.h> | ||
27 | #include <asm/kvm_ppc.h> | ||
28 | #include <asm/kvm_book3s.h> | ||
29 | |||
30 | /* #define DEBUG_MMU */ | ||
31 | /* #define DEBUG_MMU_PTE */ | ||
32 | /* #define DEBUG_MMU_PTE_IP 0xfff14c40 */ | ||
33 | |||
34 | #ifdef DEBUG_MMU | ||
35 | #define dprintk(X...) printk(KERN_INFO X) | ||
36 | #else | ||
37 | #define dprintk(X...) do { } while(0) | ||
38 | #endif | ||
39 | |||
40 | #ifdef DEBUG_PTE | ||
41 | #define dprintk_pte(X...) printk(KERN_INFO X) | ||
42 | #else | ||
43 | #define dprintk_pte(X...) do { } while(0) | ||
44 | #endif | ||
45 | |||
46 | #define PTEG_FLAG_ACCESSED 0x00000100 | ||
47 | #define PTEG_FLAG_DIRTY 0x00000080 | ||
48 | |||
49 | static inline bool check_debug_ip(struct kvm_vcpu *vcpu) | ||
50 | { | ||
51 | #ifdef DEBUG_MMU_PTE_IP | ||
52 | return vcpu->arch.pc == DEBUG_MMU_PTE_IP; | ||
53 | #else | ||
54 | return true; | ||
55 | #endif | ||
56 | } | ||
57 | |||
58 | static int kvmppc_mmu_book3s_32_xlate_bat(struct kvm_vcpu *vcpu, gva_t eaddr, | ||
59 | struct kvmppc_pte *pte, bool data); | ||
60 | |||
61 | static struct kvmppc_sr *find_sr(struct kvmppc_vcpu_book3s *vcpu_book3s, gva_t eaddr) | ||
62 | { | ||
63 | return &vcpu_book3s->sr[(eaddr >> 28) & 0xf]; | ||
64 | } | ||
65 | |||
66 | static u64 kvmppc_mmu_book3s_32_ea_to_vp(struct kvm_vcpu *vcpu, gva_t eaddr, | ||
67 | bool data) | ||
68 | { | ||
69 | struct kvmppc_sr *sre = find_sr(to_book3s(vcpu), eaddr); | ||
70 | struct kvmppc_pte pte; | ||
71 | |||
72 | if (!kvmppc_mmu_book3s_32_xlate_bat(vcpu, eaddr, &pte, data)) | ||
73 | return pte.vpage; | ||
74 | |||
75 | return (((u64)eaddr >> 12) & 0xffff) | (((u64)sre->vsid) << 16); | ||
76 | } | ||
77 | |||
78 | static void kvmppc_mmu_book3s_32_reset_msr(struct kvm_vcpu *vcpu) | ||
79 | { | ||
80 | kvmppc_set_msr(vcpu, 0); | ||
81 | } | ||
82 | |||
83 | static hva_t kvmppc_mmu_book3s_32_get_pteg(struct kvmppc_vcpu_book3s *vcpu_book3s, | ||
84 | struct kvmppc_sr *sre, gva_t eaddr, | ||
85 | bool primary) | ||
86 | { | ||
87 | u32 page, hash, pteg, htabmask; | ||
88 | hva_t r; | ||
89 | |||
90 | page = (eaddr & 0x0FFFFFFF) >> 12; | ||
91 | htabmask = ((vcpu_book3s->sdr1 & 0x1FF) << 16) | 0xFFC0; | ||
92 | |||
93 | hash = ((sre->vsid ^ page) << 6); | ||
94 | if (!primary) | ||
95 | hash = ~hash; | ||
96 | hash &= htabmask; | ||
97 | |||
98 | pteg = (vcpu_book3s->sdr1 & 0xffff0000) | hash; | ||
99 | |||
100 | dprintk("MMU: pc=0x%lx eaddr=0x%lx sdr1=0x%llx pteg=0x%x vsid=0x%x\n", | ||
101 | vcpu_book3s->vcpu.arch.pc, eaddr, vcpu_book3s->sdr1, pteg, | ||
102 | sre->vsid); | ||
103 | |||
104 | r = gfn_to_hva(vcpu_book3s->vcpu.kvm, pteg >> PAGE_SHIFT); | ||
105 | if (kvm_is_error_hva(r)) | ||
106 | return r; | ||
107 | return r | (pteg & ~PAGE_MASK); | ||
108 | } | ||
109 | |||
110 | static u32 kvmppc_mmu_book3s_32_get_ptem(struct kvmppc_sr *sre, gva_t eaddr, | ||
111 | bool primary) | ||
112 | { | ||
113 | return ((eaddr & 0x0fffffff) >> 22) | (sre->vsid << 7) | | ||
114 | (primary ? 0 : 0x40) | 0x80000000; | ||
115 | } | ||
116 | |||
117 | static int kvmppc_mmu_book3s_32_xlate_bat(struct kvm_vcpu *vcpu, gva_t eaddr, | ||
118 | struct kvmppc_pte *pte, bool data) | ||
119 | { | ||
120 | struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu); | ||
121 | struct kvmppc_bat *bat; | ||
122 | int i; | ||
123 | |||
124 | for (i = 0; i < 8; i++) { | ||
125 | if (data) | ||
126 | bat = &vcpu_book3s->dbat[i]; | ||
127 | else | ||
128 | bat = &vcpu_book3s->ibat[i]; | ||
129 | |||
130 | if (vcpu->arch.msr & MSR_PR) { | ||
131 | if (!bat->vp) | ||
132 | continue; | ||
133 | } else { | ||
134 | if (!bat->vs) | ||
135 | continue; | ||
136 | } | ||
137 | |||
138 | if (check_debug_ip(vcpu)) | ||
139 | { | ||
140 | dprintk_pte("%cBAT %02d: 0x%lx - 0x%x (0x%x)\n", | ||
141 | data ? 'd' : 'i', i, eaddr, bat->bepi, | ||
142 | bat->bepi_mask); | ||
143 | } | ||
144 | if ((eaddr & bat->bepi_mask) == bat->bepi) { | ||
145 | pte->raddr = bat->brpn | (eaddr & ~bat->bepi_mask); | ||
146 | pte->vpage = (eaddr >> 12) | VSID_BAT; | ||
147 | pte->may_read = bat->pp; | ||
148 | pte->may_write = bat->pp > 1; | ||
149 | pte->may_execute = true; | ||
150 | if (!pte->may_read) { | ||
151 | printk(KERN_INFO "BAT is not readable!\n"); | ||
152 | continue; | ||
153 | } | ||
154 | if (!pte->may_write) { | ||
155 | /* let's treat r/o BATs as not-readable for now */ | ||
156 | dprintk_pte("BAT is read-only!\n"); | ||
157 | continue; | ||
158 | } | ||
159 | |||
160 | return 0; | ||
161 | } | ||
162 | } | ||
163 | |||
164 | return -ENOENT; | ||
165 | } | ||
166 | |||
167 | static int kvmppc_mmu_book3s_32_xlate_pte(struct kvm_vcpu *vcpu, gva_t eaddr, | ||
168 | struct kvmppc_pte *pte, bool data, | ||
169 | bool primary) | ||
170 | { | ||
171 | struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu); | ||
172 | struct kvmppc_sr *sre; | ||
173 | hva_t ptegp; | ||
174 | u32 pteg[16]; | ||
175 | u64 ptem = 0; | ||
176 | int i; | ||
177 | int found = 0; | ||
178 | |||
179 | sre = find_sr(vcpu_book3s, eaddr); | ||
180 | |||
181 | dprintk_pte("SR 0x%lx: vsid=0x%x, raw=0x%x\n", eaddr >> 28, | ||
182 | sre->vsid, sre->raw); | ||
183 | |||
184 | pte->vpage = kvmppc_mmu_book3s_32_ea_to_vp(vcpu, eaddr, data); | ||
185 | |||
186 | ptegp = kvmppc_mmu_book3s_32_get_pteg(vcpu_book3s, sre, eaddr, primary); | ||
187 | if (kvm_is_error_hva(ptegp)) { | ||
188 | printk(KERN_INFO "KVM: Invalid PTEG!\n"); | ||
189 | goto no_page_found; | ||
190 | } | ||
191 | |||
192 | ptem = kvmppc_mmu_book3s_32_get_ptem(sre, eaddr, primary); | ||
193 | |||
194 | if(copy_from_user(pteg, (void __user *)ptegp, sizeof(pteg))) { | ||
195 | printk(KERN_ERR "KVM: Can't copy data from 0x%lx!\n", ptegp); | ||
196 | goto no_page_found; | ||
197 | } | ||
198 | |||
199 | for (i=0; i<16; i+=2) { | ||
200 | if (ptem == pteg[i]) { | ||
201 | u8 pp; | ||
202 | |||
203 | pte->raddr = (pteg[i+1] & ~(0xFFFULL)) | (eaddr & 0xFFF); | ||
204 | pp = pteg[i+1] & 3; | ||
205 | |||
206 | if ((sre->Kp && (vcpu->arch.msr & MSR_PR)) || | ||
207 | (sre->Ks && !(vcpu->arch.msr & MSR_PR))) | ||
208 | pp |= 4; | ||
209 | |||
210 | pte->may_write = false; | ||
211 | pte->may_read = false; | ||
212 | pte->may_execute = true; | ||
213 | switch (pp) { | ||
214 | case 0: | ||
215 | case 1: | ||
216 | case 2: | ||
217 | case 6: | ||
218 | pte->may_write = true; | ||
219 | case 3: | ||
220 | case 5: | ||
221 | case 7: | ||
222 | pte->may_read = true; | ||
223 | break; | ||
224 | } | ||
225 | |||
226 | if ( !pte->may_read ) | ||
227 | continue; | ||
228 | |||
229 | dprintk_pte("MMU: Found PTE -> %x %x - %x\n", | ||
230 | pteg[i], pteg[i+1], pp); | ||
231 | found = 1; | ||
232 | break; | ||
233 | } | ||
234 | } | ||
235 | |||
236 | /* Update PTE C and A bits, so the guest's swapper knows we used the | ||
237 | page */ | ||
238 | if (found) { | ||
239 | u32 oldpte = pteg[i+1]; | ||
240 | |||
241 | if (pte->may_read) | ||
242 | pteg[i+1] |= PTEG_FLAG_ACCESSED; | ||
243 | if (pte->may_write) | ||
244 | pteg[i+1] |= PTEG_FLAG_DIRTY; | ||
245 | else | ||
246 | dprintk_pte("KVM: Mapping read-only page!\n"); | ||
247 | |||
248 | /* Write back into the PTEG */ | ||
249 | if (pteg[i+1] != oldpte) | ||
250 | copy_to_user((void __user *)ptegp, pteg, sizeof(pteg)); | ||
251 | |||
252 | return 0; | ||
253 | } | ||
254 | |||
255 | no_page_found: | ||
256 | |||
257 | if (check_debug_ip(vcpu)) { | ||
258 | dprintk_pte("KVM MMU: No PTE found (sdr1=0x%llx ptegp=0x%lx)\n", | ||
259 | to_book3s(vcpu)->sdr1, ptegp); | ||
260 | for (i=0; i<16; i+=2) { | ||
261 | dprintk_pte(" %02d: 0x%x - 0x%x (0x%llx)\n", | ||
262 | i, pteg[i], pteg[i+1], ptem); | ||
263 | } | ||
264 | } | ||
265 | |||
266 | return -ENOENT; | ||
267 | } | ||
268 | |||
269 | static int kvmppc_mmu_book3s_32_xlate(struct kvm_vcpu *vcpu, gva_t eaddr, | ||
270 | struct kvmppc_pte *pte, bool data) | ||
271 | { | ||
272 | int r; | ||
273 | |||
274 | pte->eaddr = eaddr; | ||
275 | r = kvmppc_mmu_book3s_32_xlate_bat(vcpu, eaddr, pte, data); | ||
276 | if (r < 0) | ||
277 | r = kvmppc_mmu_book3s_32_xlate_pte(vcpu, eaddr, pte, data, true); | ||
278 | if (r < 0) | ||
279 | r = kvmppc_mmu_book3s_32_xlate_pte(vcpu, eaddr, pte, data, false); | ||
280 | |||
281 | return r; | ||
282 | } | ||
283 | |||
284 | |||
285 | static u32 kvmppc_mmu_book3s_32_mfsrin(struct kvm_vcpu *vcpu, u32 srnum) | ||
286 | { | ||
287 | return to_book3s(vcpu)->sr[srnum].raw; | ||
288 | } | ||
289 | |||
290 | static void kvmppc_mmu_book3s_32_mtsrin(struct kvm_vcpu *vcpu, u32 srnum, | ||
291 | ulong value) | ||
292 | { | ||
293 | struct kvmppc_sr *sre; | ||
294 | |||
295 | sre = &to_book3s(vcpu)->sr[srnum]; | ||
296 | |||
297 | /* Flush any left-over shadows from the previous SR */ | ||
298 | |||
299 | /* XXX Not necessary? */ | ||
300 | /* kvmppc_mmu_pte_flush(vcpu, ((u64)sre->vsid) << 28, 0xf0000000ULL); */ | ||
301 | |||
302 | /* And then put in the new SR */ | ||
303 | sre->raw = value; | ||
304 | sre->vsid = (value & 0x0fffffff); | ||
305 | sre->Ks = (value & 0x40000000) ? true : false; | ||
306 | sre->Kp = (value & 0x20000000) ? true : false; | ||
307 | sre->nx = (value & 0x10000000) ? true : false; | ||
308 | |||
309 | /* Map the new segment */ | ||
310 | kvmppc_mmu_map_segment(vcpu, srnum << SID_SHIFT); | ||
311 | } | ||
312 | |||
313 | static void kvmppc_mmu_book3s_32_tlbie(struct kvm_vcpu *vcpu, ulong ea, bool large) | ||
314 | { | ||
315 | kvmppc_mmu_pte_flush(vcpu, ea, ~0xFFFULL); | ||
316 | } | ||
317 | |||
318 | static int kvmppc_mmu_book3s_32_esid_to_vsid(struct kvm_vcpu *vcpu, u64 esid, | ||
319 | u64 *vsid) | ||
320 | { | ||
321 | /* In case we only have one of MSR_IR or MSR_DR set, let's put | ||
322 | that in the real-mode context (and hope RM doesn't access | ||
323 | high memory) */ | ||
324 | switch (vcpu->arch.msr & (MSR_DR|MSR_IR)) { | ||
325 | case 0: | ||
326 | *vsid = (VSID_REAL >> 16) | esid; | ||
327 | break; | ||
328 | case MSR_IR: | ||
329 | *vsid = (VSID_REAL_IR >> 16) | esid; | ||
330 | break; | ||
331 | case MSR_DR: | ||
332 | *vsid = (VSID_REAL_DR >> 16) | esid; | ||
333 | break; | ||
334 | case MSR_DR|MSR_IR: | ||
335 | { | ||
336 | ulong ea; | ||
337 | ea = esid << SID_SHIFT; | ||
338 | *vsid = find_sr(to_book3s(vcpu), ea)->vsid; | ||
339 | break; | ||
340 | } | ||
341 | default: | ||
342 | BUG(); | ||
343 | } | ||
344 | |||
345 | return 0; | ||
346 | } | ||
347 | |||
348 | static bool kvmppc_mmu_book3s_32_is_dcbz32(struct kvm_vcpu *vcpu) | ||
349 | { | ||
350 | return true; | ||
351 | } | ||
352 | |||
353 | |||
354 | void kvmppc_mmu_book3s_32_init(struct kvm_vcpu *vcpu) | ||
355 | { | ||
356 | struct kvmppc_mmu *mmu = &vcpu->arch.mmu; | ||
357 | |||
358 | mmu->mtsrin = kvmppc_mmu_book3s_32_mtsrin; | ||
359 | mmu->mfsrin = kvmppc_mmu_book3s_32_mfsrin; | ||
360 | mmu->xlate = kvmppc_mmu_book3s_32_xlate; | ||
361 | mmu->reset_msr = kvmppc_mmu_book3s_32_reset_msr; | ||
362 | mmu->tlbie = kvmppc_mmu_book3s_32_tlbie; | ||
363 | mmu->esid_to_vsid = kvmppc_mmu_book3s_32_esid_to_vsid; | ||
364 | mmu->ea_to_vp = kvmppc_mmu_book3s_32_ea_to_vp; | ||
365 | mmu->is_dcbz32 = kvmppc_mmu_book3s_32_is_dcbz32; | ||
366 | |||
367 | mmu->slbmte = NULL; | ||
368 | mmu->slbmfee = NULL; | ||
369 | mmu->slbmfev = NULL; | ||
370 | mmu->slbie = NULL; | ||
371 | mmu->slbia = NULL; | ||
372 | } | ||
diff --git a/arch/powerpc/kvm/book3s_64_emulate.c b/arch/powerpc/kvm/book3s_64_emulate.c new file mode 100644 index 000000000000..c343e67306e0 --- /dev/null +++ b/arch/powerpc/kvm/book3s_64_emulate.c | |||
@@ -0,0 +1,337 @@ | |||
1 | /* | ||
2 | * This program is free software; you can redistribute it and/or modify | ||
3 | * it under the terms of the GNU General Public License, version 2, as | ||
4 | * published by the Free Software Foundation. | ||
5 | * | ||
6 | * This program is distributed in the hope that it will be useful, | ||
7 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
8 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
9 | * GNU General Public License for more details. | ||
10 | * | ||
11 | * You should have received a copy of the GNU General Public License | ||
12 | * along with this program; if not, write to the Free Software | ||
13 | * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
14 | * | ||
15 | * Copyright SUSE Linux Products GmbH 2009 | ||
16 | * | ||
17 | * Authors: Alexander Graf <agraf@suse.de> | ||
18 | */ | ||
19 | |||
20 | #include <asm/kvm_ppc.h> | ||
21 | #include <asm/disassemble.h> | ||
22 | #include <asm/kvm_book3s.h> | ||
23 | #include <asm/reg.h> | ||
24 | |||
25 | #define OP_19_XOP_RFID 18 | ||
26 | #define OP_19_XOP_RFI 50 | ||
27 | |||
28 | #define OP_31_XOP_MFMSR 83 | ||
29 | #define OP_31_XOP_MTMSR 146 | ||
30 | #define OP_31_XOP_MTMSRD 178 | ||
31 | #define OP_31_XOP_MTSRIN 242 | ||
32 | #define OP_31_XOP_TLBIEL 274 | ||
33 | #define OP_31_XOP_TLBIE 306 | ||
34 | #define OP_31_XOP_SLBMTE 402 | ||
35 | #define OP_31_XOP_SLBIE 434 | ||
36 | #define OP_31_XOP_SLBIA 498 | ||
37 | #define OP_31_XOP_MFSRIN 659 | ||
38 | #define OP_31_XOP_SLBMFEV 851 | ||
39 | #define OP_31_XOP_EIOIO 854 | ||
40 | #define OP_31_XOP_SLBMFEE 915 | ||
41 | |||
42 | /* DCBZ is actually 1014, but we patch it to 1010 so we get a trap */ | ||
43 | #define OP_31_XOP_DCBZ 1010 | ||
44 | |||
45 | int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu, | ||
46 | unsigned int inst, int *advance) | ||
47 | { | ||
48 | int emulated = EMULATE_DONE; | ||
49 | |||
50 | switch (get_op(inst)) { | ||
51 | case 19: | ||
52 | switch (get_xop(inst)) { | ||
53 | case OP_19_XOP_RFID: | ||
54 | case OP_19_XOP_RFI: | ||
55 | vcpu->arch.pc = vcpu->arch.srr0; | ||
56 | kvmppc_set_msr(vcpu, vcpu->arch.srr1); | ||
57 | *advance = 0; | ||
58 | break; | ||
59 | |||
60 | default: | ||
61 | emulated = EMULATE_FAIL; | ||
62 | break; | ||
63 | } | ||
64 | break; | ||
65 | case 31: | ||
66 | switch (get_xop(inst)) { | ||
67 | case OP_31_XOP_MFMSR: | ||
68 | vcpu->arch.gpr[get_rt(inst)] = vcpu->arch.msr; | ||
69 | break; | ||
70 | case OP_31_XOP_MTMSRD: | ||
71 | { | ||
72 | ulong rs = vcpu->arch.gpr[get_rs(inst)]; | ||
73 | if (inst & 0x10000) { | ||
74 | vcpu->arch.msr &= ~(MSR_RI | MSR_EE); | ||
75 | vcpu->arch.msr |= rs & (MSR_RI | MSR_EE); | ||
76 | } else | ||
77 | kvmppc_set_msr(vcpu, rs); | ||
78 | break; | ||
79 | } | ||
80 | case OP_31_XOP_MTMSR: | ||
81 | kvmppc_set_msr(vcpu, vcpu->arch.gpr[get_rs(inst)]); | ||
82 | break; | ||
83 | case OP_31_XOP_MFSRIN: | ||
84 | { | ||
85 | int srnum; | ||
86 | |||
87 | srnum = (vcpu->arch.gpr[get_rb(inst)] >> 28) & 0xf; | ||
88 | if (vcpu->arch.mmu.mfsrin) { | ||
89 | u32 sr; | ||
90 | sr = vcpu->arch.mmu.mfsrin(vcpu, srnum); | ||
91 | vcpu->arch.gpr[get_rt(inst)] = sr; | ||
92 | } | ||
93 | break; | ||
94 | } | ||
95 | case OP_31_XOP_MTSRIN: | ||
96 | vcpu->arch.mmu.mtsrin(vcpu, | ||
97 | (vcpu->arch.gpr[get_rb(inst)] >> 28) & 0xf, | ||
98 | vcpu->arch.gpr[get_rs(inst)]); | ||
99 | break; | ||
100 | case OP_31_XOP_TLBIE: | ||
101 | case OP_31_XOP_TLBIEL: | ||
102 | { | ||
103 | bool large = (inst & 0x00200000) ? true : false; | ||
104 | ulong addr = vcpu->arch.gpr[get_rb(inst)]; | ||
105 | vcpu->arch.mmu.tlbie(vcpu, addr, large); | ||
106 | break; | ||
107 | } | ||
108 | case OP_31_XOP_EIOIO: | ||
109 | break; | ||
110 | case OP_31_XOP_SLBMTE: | ||
111 | if (!vcpu->arch.mmu.slbmte) | ||
112 | return EMULATE_FAIL; | ||
113 | |||
114 | vcpu->arch.mmu.slbmte(vcpu, vcpu->arch.gpr[get_rs(inst)], | ||
115 | vcpu->arch.gpr[get_rb(inst)]); | ||
116 | break; | ||
117 | case OP_31_XOP_SLBIE: | ||
118 | if (!vcpu->arch.mmu.slbie) | ||
119 | return EMULATE_FAIL; | ||
120 | |||
121 | vcpu->arch.mmu.slbie(vcpu, vcpu->arch.gpr[get_rb(inst)]); | ||
122 | break; | ||
123 | case OP_31_XOP_SLBIA: | ||
124 | if (!vcpu->arch.mmu.slbia) | ||
125 | return EMULATE_FAIL; | ||
126 | |||
127 | vcpu->arch.mmu.slbia(vcpu); | ||
128 | break; | ||
129 | case OP_31_XOP_SLBMFEE: | ||
130 | if (!vcpu->arch.mmu.slbmfee) { | ||
131 | emulated = EMULATE_FAIL; | ||
132 | } else { | ||
133 | ulong t, rb; | ||
134 | |||
135 | rb = vcpu->arch.gpr[get_rb(inst)]; | ||
136 | t = vcpu->arch.mmu.slbmfee(vcpu, rb); | ||
137 | vcpu->arch.gpr[get_rt(inst)] = t; | ||
138 | } | ||
139 | break; | ||
140 | case OP_31_XOP_SLBMFEV: | ||
141 | if (!vcpu->arch.mmu.slbmfev) { | ||
142 | emulated = EMULATE_FAIL; | ||
143 | } else { | ||
144 | ulong t, rb; | ||
145 | |||
146 | rb = vcpu->arch.gpr[get_rb(inst)]; | ||
147 | t = vcpu->arch.mmu.slbmfev(vcpu, rb); | ||
148 | vcpu->arch.gpr[get_rt(inst)] = t; | ||
149 | } | ||
150 | break; | ||
151 | case OP_31_XOP_DCBZ: | ||
152 | { | ||
153 | ulong rb = vcpu->arch.gpr[get_rb(inst)]; | ||
154 | ulong ra = 0; | ||
155 | ulong addr; | ||
156 | u32 zeros[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; | ||
157 | |||
158 | if (get_ra(inst)) | ||
159 | ra = vcpu->arch.gpr[get_ra(inst)]; | ||
160 | |||
161 | addr = (ra + rb) & ~31ULL; | ||
162 | if (!(vcpu->arch.msr & MSR_SF)) | ||
163 | addr &= 0xffffffff; | ||
164 | |||
165 | if (kvmppc_st(vcpu, addr, 32, zeros)) { | ||
166 | vcpu->arch.dear = addr; | ||
167 | vcpu->arch.fault_dear = addr; | ||
168 | to_book3s(vcpu)->dsisr = DSISR_PROTFAULT | | ||
169 | DSISR_ISSTORE; | ||
170 | kvmppc_book3s_queue_irqprio(vcpu, | ||
171 | BOOK3S_INTERRUPT_DATA_STORAGE); | ||
172 | kvmppc_mmu_pte_flush(vcpu, addr, ~0xFFFULL); | ||
173 | } | ||
174 | |||
175 | break; | ||
176 | } | ||
177 | default: | ||
178 | emulated = EMULATE_FAIL; | ||
179 | } | ||
180 | break; | ||
181 | default: | ||
182 | emulated = EMULATE_FAIL; | ||
183 | } | ||
184 | |||
185 | return emulated; | ||
186 | } | ||
187 | |||
188 | static void kvmppc_write_bat(struct kvm_vcpu *vcpu, int sprn, u64 val) | ||
189 | { | ||
190 | struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu); | ||
191 | struct kvmppc_bat *bat; | ||
192 | |||
193 | switch (sprn) { | ||
194 | case SPRN_IBAT0U ... SPRN_IBAT3L: | ||
195 | bat = &vcpu_book3s->ibat[(sprn - SPRN_IBAT0U) / 2]; | ||
196 | break; | ||
197 | case SPRN_IBAT4U ... SPRN_IBAT7L: | ||
198 | bat = &vcpu_book3s->ibat[(sprn - SPRN_IBAT4U) / 2]; | ||
199 | break; | ||
200 | case SPRN_DBAT0U ... SPRN_DBAT3L: | ||
201 | bat = &vcpu_book3s->dbat[(sprn - SPRN_DBAT0U) / 2]; | ||
202 | break; | ||
203 | case SPRN_DBAT4U ... SPRN_DBAT7L: | ||
204 | bat = &vcpu_book3s->dbat[(sprn - SPRN_DBAT4U) / 2]; | ||
205 | break; | ||
206 | default: | ||
207 | BUG(); | ||
208 | } | ||
209 | |||
210 | if (!(sprn % 2)) { | ||
211 | /* Upper BAT */ | ||
212 | u32 bl = (val >> 2) & 0x7ff; | ||
213 | bat->bepi_mask = (~bl << 17); | ||
214 | bat->bepi = val & 0xfffe0000; | ||
215 | bat->vs = (val & 2) ? 1 : 0; | ||
216 | bat->vp = (val & 1) ? 1 : 0; | ||
217 | } else { | ||
218 | /* Lower BAT */ | ||
219 | bat->brpn = val & 0xfffe0000; | ||
220 | bat->wimg = (val >> 3) & 0xf; | ||
221 | bat->pp = val & 3; | ||
222 | } | ||
223 | } | ||
224 | |||
225 | int kvmppc_core_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, int rs) | ||
226 | { | ||
227 | int emulated = EMULATE_DONE; | ||
228 | |||
229 | switch (sprn) { | ||
230 | case SPRN_SDR1: | ||
231 | to_book3s(vcpu)->sdr1 = vcpu->arch.gpr[rs]; | ||
232 | break; | ||
233 | case SPRN_DSISR: | ||
234 | to_book3s(vcpu)->dsisr = vcpu->arch.gpr[rs]; | ||
235 | break; | ||
236 | case SPRN_DAR: | ||
237 | vcpu->arch.dear = vcpu->arch.gpr[rs]; | ||
238 | break; | ||
239 | case SPRN_HIOR: | ||
240 | to_book3s(vcpu)->hior = vcpu->arch.gpr[rs]; | ||
241 | break; | ||
242 | case SPRN_IBAT0U ... SPRN_IBAT3L: | ||
243 | case SPRN_IBAT4U ... SPRN_IBAT7L: | ||
244 | case SPRN_DBAT0U ... SPRN_DBAT3L: | ||
245 | case SPRN_DBAT4U ... SPRN_DBAT7L: | ||
246 | kvmppc_write_bat(vcpu, sprn, vcpu->arch.gpr[rs]); | ||
247 | /* BAT writes happen so rarely that we're ok to flush | ||
248 | * everything here */ | ||
249 | kvmppc_mmu_pte_flush(vcpu, 0, 0); | ||
250 | break; | ||
251 | case SPRN_HID0: | ||
252 | to_book3s(vcpu)->hid[0] = vcpu->arch.gpr[rs]; | ||
253 | break; | ||
254 | case SPRN_HID1: | ||
255 | to_book3s(vcpu)->hid[1] = vcpu->arch.gpr[rs]; | ||
256 | break; | ||
257 | case SPRN_HID2: | ||
258 | to_book3s(vcpu)->hid[2] = vcpu->arch.gpr[rs]; | ||
259 | break; | ||
260 | case SPRN_HID4: | ||
261 | to_book3s(vcpu)->hid[4] = vcpu->arch.gpr[rs]; | ||
262 | break; | ||
263 | case SPRN_HID5: | ||
264 | to_book3s(vcpu)->hid[5] = vcpu->arch.gpr[rs]; | ||
265 | /* guest HID5 set can change is_dcbz32 */ | ||
266 | if (vcpu->arch.mmu.is_dcbz32(vcpu) && | ||
267 | (mfmsr() & MSR_HV)) | ||
268 | vcpu->arch.hflags |= BOOK3S_HFLAG_DCBZ32; | ||
269 | break; | ||
270 | case SPRN_ICTC: | ||
271 | case SPRN_THRM1: | ||
272 | case SPRN_THRM2: | ||
273 | case SPRN_THRM3: | ||
274 | case SPRN_CTRLF: | ||
275 | case SPRN_CTRLT: | ||
276 | break; | ||
277 | default: | ||
278 | printk(KERN_INFO "KVM: invalid SPR write: %d\n", sprn); | ||
279 | #ifndef DEBUG_SPR | ||
280 | emulated = EMULATE_FAIL; | ||
281 | #endif | ||
282 | break; | ||
283 | } | ||
284 | |||
285 | return emulated; | ||
286 | } | ||
287 | |||
288 | int kvmppc_core_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, int rt) | ||
289 | { | ||
290 | int emulated = EMULATE_DONE; | ||
291 | |||
292 | switch (sprn) { | ||
293 | case SPRN_SDR1: | ||
294 | vcpu->arch.gpr[rt] = to_book3s(vcpu)->sdr1; | ||
295 | break; | ||
296 | case SPRN_DSISR: | ||
297 | vcpu->arch.gpr[rt] = to_book3s(vcpu)->dsisr; | ||
298 | break; | ||
299 | case SPRN_DAR: | ||
300 | vcpu->arch.gpr[rt] = vcpu->arch.dear; | ||
301 | break; | ||
302 | case SPRN_HIOR: | ||
303 | vcpu->arch.gpr[rt] = to_book3s(vcpu)->hior; | ||
304 | break; | ||
305 | case SPRN_HID0: | ||
306 | vcpu->arch.gpr[rt] = to_book3s(vcpu)->hid[0]; | ||
307 | break; | ||
308 | case SPRN_HID1: | ||
309 | vcpu->arch.gpr[rt] = to_book3s(vcpu)->hid[1]; | ||
310 | break; | ||
311 | case SPRN_HID2: | ||
312 | vcpu->arch.gpr[rt] = to_book3s(vcpu)->hid[2]; | ||
313 | break; | ||
314 | case SPRN_HID4: | ||
315 | vcpu->arch.gpr[rt] = to_book3s(vcpu)->hid[4]; | ||
316 | break; | ||
317 | case SPRN_HID5: | ||
318 | vcpu->arch.gpr[rt] = to_book3s(vcpu)->hid[5]; | ||
319 | break; | ||
320 | case SPRN_THRM1: | ||
321 | case SPRN_THRM2: | ||
322 | case SPRN_THRM3: | ||
323 | case SPRN_CTRLF: | ||
324 | case SPRN_CTRLT: | ||
325 | vcpu->arch.gpr[rt] = 0; | ||
326 | break; | ||
327 | default: | ||
328 | printk(KERN_INFO "KVM: invalid SPR read: %d\n", sprn); | ||
329 | #ifndef DEBUG_SPR | ||
330 | emulated = EMULATE_FAIL; | ||
331 | #endif | ||
332 | break; | ||
333 | } | ||
334 | |||
335 | return emulated; | ||
336 | } | ||
337 | |||
diff --git a/arch/powerpc/kvm/book3s_64_exports.c b/arch/powerpc/kvm/book3s_64_exports.c new file mode 100644 index 000000000000..5b2db38ed86c --- /dev/null +++ b/arch/powerpc/kvm/book3s_64_exports.c | |||
@@ -0,0 +1,24 @@ | |||
1 | /* | ||
2 | * This program is free software; you can redistribute it and/or modify | ||
3 | * it under the terms of the GNU General Public License, version 2, as | ||
4 | * published by the Free Software Foundation. | ||
5 | * | ||
6 | * This program is distributed in the hope that it will be useful, | ||
7 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
8 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
9 | * GNU General Public License for more details. | ||
10 | * | ||
11 | * You should have received a copy of the GNU General Public License | ||
12 | * along with this program; if not, write to the Free Software | ||
13 | * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
14 | * | ||
15 | * Copyright SUSE Linux Products GmbH 2009 | ||
16 | * | ||
17 | * Authors: Alexander Graf <agraf@suse.de> | ||
18 | */ | ||
19 | |||
20 | #include <linux/module.h> | ||
21 | #include <asm/kvm_book3s.h> | ||
22 | |||
23 | EXPORT_SYMBOL_GPL(kvmppc_trampoline_enter); | ||
24 | EXPORT_SYMBOL_GPL(kvmppc_trampoline_lowmem); | ||
diff --git a/arch/powerpc/kvm/book3s_64_interrupts.S b/arch/powerpc/kvm/book3s_64_interrupts.S new file mode 100644 index 000000000000..7b55d8094c8b --- /dev/null +++ b/arch/powerpc/kvm/book3s_64_interrupts.S | |||
@@ -0,0 +1,392 @@ | |||
1 | /* | ||
2 | * This program is free software; you can redistribute it and/or modify | ||
3 | * it under the terms of the GNU General Public License, version 2, as | ||
4 | * published by the Free Software Foundation. | ||
5 | * | ||
6 | * This program is distributed in the hope that it will be useful, | ||
7 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
8 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
9 | * GNU General Public License for more details. | ||
10 | * | ||
11 | * You should have received a copy of the GNU General Public License | ||
12 | * along with this program; if not, write to the Free Software | ||
13 | * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
14 | * | ||
15 | * Copyright SUSE Linux Products GmbH 2009 | ||
16 | * | ||
17 | * Authors: Alexander Graf <agraf@suse.de> | ||
18 | */ | ||
19 | |||
20 | #include <asm/ppc_asm.h> | ||
21 | #include <asm/kvm_asm.h> | ||
22 | #include <asm/reg.h> | ||
23 | #include <asm/page.h> | ||
24 | #include <asm/asm-offsets.h> | ||
25 | #include <asm/exception-64s.h> | ||
26 | |||
27 | #define KVMPPC_HANDLE_EXIT .kvmppc_handle_exit | ||
28 | #define ULONG_SIZE 8 | ||
29 | #define VCPU_GPR(n) (VCPU_GPRS + (n * ULONG_SIZE)) | ||
30 | |||
31 | .macro mfpaca tmp_reg, src_reg, offset, vcpu_reg | ||
32 | ld \tmp_reg, (PACA_EXMC+\offset)(r13) | ||
33 | std \tmp_reg, VCPU_GPR(\src_reg)(\vcpu_reg) | ||
34 | .endm | ||
35 | |||
36 | .macro DISABLE_INTERRUPTS | ||
37 | mfmsr r0 | ||
38 | rldicl r0,r0,48,1 | ||
39 | rotldi r0,r0,16 | ||
40 | mtmsrd r0,1 | ||
41 | .endm | ||
42 | |||
43 | /***************************************************************************** | ||
44 | * * | ||
45 | * Guest entry / exit code that is in kernel module memory (highmem) * | ||
46 | * * | ||
47 | ****************************************************************************/ | ||
48 | |||
49 | /* Registers: | ||
50 | * r3: kvm_run pointer | ||
51 | * r4: vcpu pointer | ||
52 | */ | ||
53 | _GLOBAL(__kvmppc_vcpu_entry) | ||
54 | |||
55 | kvm_start_entry: | ||
56 | /* Write correct stack frame */ | ||
57 | mflr r0 | ||
58 | std r0,16(r1) | ||
59 | |||
60 | /* Save host state to the stack */ | ||
61 | stdu r1, -SWITCH_FRAME_SIZE(r1) | ||
62 | |||
63 | /* Save r3 (kvm_run) and r4 (vcpu) */ | ||
64 | SAVE_2GPRS(3, r1) | ||
65 | |||
66 | /* Save non-volatile registers (r14 - r31) */ | ||
67 | SAVE_NVGPRS(r1) | ||
68 | |||
69 | /* Save LR */ | ||
70 | mflr r14 | ||
71 | std r14, _LINK(r1) | ||
72 | |||
73 | /* XXX optimize non-volatile loading away */ | ||
74 | kvm_start_lightweight: | ||
75 | |||
76 | DISABLE_INTERRUPTS | ||
77 | |||
78 | /* Save R1/R2 in the PACA */ | ||
79 | std r1, PACAR1(r13) | ||
80 | std r2, (PACA_EXMC+EX_SRR0)(r13) | ||
81 | ld r3, VCPU_HIGHMEM_HANDLER(r4) | ||
82 | std r3, PACASAVEDMSR(r13) | ||
83 | |||
84 | /* Load non-volatile guest state from the vcpu */ | ||
85 | ld r14, VCPU_GPR(r14)(r4) | ||
86 | ld r15, VCPU_GPR(r15)(r4) | ||
87 | ld r16, VCPU_GPR(r16)(r4) | ||
88 | ld r17, VCPU_GPR(r17)(r4) | ||
89 | ld r18, VCPU_GPR(r18)(r4) | ||
90 | ld r19, VCPU_GPR(r19)(r4) | ||
91 | ld r20, VCPU_GPR(r20)(r4) | ||
92 | ld r21, VCPU_GPR(r21)(r4) | ||
93 | ld r22, VCPU_GPR(r22)(r4) | ||
94 | ld r23, VCPU_GPR(r23)(r4) | ||
95 | ld r24, VCPU_GPR(r24)(r4) | ||
96 | ld r25, VCPU_GPR(r25)(r4) | ||
97 | ld r26, VCPU_GPR(r26)(r4) | ||
98 | ld r27, VCPU_GPR(r27)(r4) | ||
99 | ld r28, VCPU_GPR(r28)(r4) | ||
100 | ld r29, VCPU_GPR(r29)(r4) | ||
101 | ld r30, VCPU_GPR(r30)(r4) | ||
102 | ld r31, VCPU_GPR(r31)(r4) | ||
103 | |||
104 | ld r9, VCPU_PC(r4) /* r9 = vcpu->arch.pc */ | ||
105 | ld r10, VCPU_SHADOW_MSR(r4) /* r10 = vcpu->arch.shadow_msr */ | ||
106 | |||
107 | ld r3, VCPU_TRAMPOLINE_ENTER(r4) | ||
108 | mtsrr0 r3 | ||
109 | |||
110 | LOAD_REG_IMMEDIATE(r3, MSR_KERNEL & ~(MSR_IR | MSR_DR)) | ||
111 | mtsrr1 r3 | ||
112 | |||
113 | /* Load guest state in the respective registers */ | ||
114 | lwz r3, VCPU_CR(r4) /* r3 = vcpu->arch.cr */ | ||
115 | stw r3, (PACA_EXMC + EX_CCR)(r13) | ||
116 | |||
117 | ld r3, VCPU_CTR(r4) /* r3 = vcpu->arch.ctr */ | ||
118 | mtctr r3 /* CTR = r3 */ | ||
119 | |||
120 | ld r3, VCPU_LR(r4) /* r3 = vcpu->arch.lr */ | ||
121 | mtlr r3 /* LR = r3 */ | ||
122 | |||
123 | ld r3, VCPU_XER(r4) /* r3 = vcpu->arch.xer */ | ||
124 | std r3, (PACA_EXMC + EX_R3)(r13) | ||
125 | |||
126 | /* Some guests may need to have dcbz set to 32 byte length. | ||
127 | * | ||
128 | * Usually we ensure that by patching the guest's instructions | ||
129 | * to trap on dcbz and emulate it in the hypervisor. | ||
130 | * | ||
131 | * If we can, we should tell the CPU to use 32 byte dcbz though, | ||
132 | * because that's a lot faster. | ||
133 | */ | ||
134 | |||
135 | ld r3, VCPU_HFLAGS(r4) | ||
136 | rldicl. r3, r3, 0, 63 /* CR = ((r3 & 1) == 0) */ | ||
137 | beq no_dcbz32_on | ||
138 | |||
139 | mfspr r3,SPRN_HID5 | ||
140 | ori r3, r3, 0x80 /* XXX HID5_dcbz32 = 0x80 */ | ||
141 | mtspr SPRN_HID5,r3 | ||
142 | |||
143 | no_dcbz32_on: | ||
144 | /* Load guest GPRs */ | ||
145 | |||
146 | ld r3, VCPU_GPR(r9)(r4) | ||
147 | std r3, (PACA_EXMC + EX_R9)(r13) | ||
148 | ld r3, VCPU_GPR(r10)(r4) | ||
149 | std r3, (PACA_EXMC + EX_R10)(r13) | ||
150 | ld r3, VCPU_GPR(r11)(r4) | ||
151 | std r3, (PACA_EXMC + EX_R11)(r13) | ||
152 | ld r3, VCPU_GPR(r12)(r4) | ||
153 | std r3, (PACA_EXMC + EX_R12)(r13) | ||
154 | ld r3, VCPU_GPR(r13)(r4) | ||
155 | std r3, (PACA_EXMC + EX_R13)(r13) | ||
156 | |||
157 | ld r0, VCPU_GPR(r0)(r4) | ||
158 | ld r1, VCPU_GPR(r1)(r4) | ||
159 | ld r2, VCPU_GPR(r2)(r4) | ||
160 | ld r3, VCPU_GPR(r3)(r4) | ||
161 | ld r5, VCPU_GPR(r5)(r4) | ||
162 | ld r6, VCPU_GPR(r6)(r4) | ||
163 | ld r7, VCPU_GPR(r7)(r4) | ||
164 | ld r8, VCPU_GPR(r8)(r4) | ||
165 | ld r4, VCPU_GPR(r4)(r4) | ||
166 | |||
167 | /* This sets the Magic value for the trampoline */ | ||
168 | |||
169 | li r11, 1 | ||
170 | stb r11, PACA_KVM_IN_GUEST(r13) | ||
171 | |||
172 | /* Jump to SLB patching handlder and into our guest */ | ||
173 | RFI | ||
174 | |||
175 | /* | ||
176 | * This is the handler in module memory. It gets jumped at from the | ||
177 | * lowmem trampoline code, so it's basically the guest exit code. | ||
178 | * | ||
179 | */ | ||
180 | |||
181 | .global kvmppc_handler_highmem | ||
182 | kvmppc_handler_highmem: | ||
183 | |||
184 | /* | ||
185 | * Register usage at this point: | ||
186 | * | ||
187 | * R00 = guest R13 | ||
188 | * R01 = host R1 | ||
189 | * R02 = host R2 | ||
190 | * R10 = guest PC | ||
191 | * R11 = guest MSR | ||
192 | * R12 = exit handler id | ||
193 | * R13 = PACA | ||
194 | * PACA.exmc.R9 = guest R1 | ||
195 | * PACA.exmc.R10 = guest R10 | ||
196 | * PACA.exmc.R11 = guest R11 | ||
197 | * PACA.exmc.R12 = guest R12 | ||
198 | * PACA.exmc.R13 = guest R2 | ||
199 | * PACA.exmc.DAR = guest DAR | ||
200 | * PACA.exmc.DSISR = guest DSISR | ||
201 | * PACA.exmc.LR = guest instruction | ||
202 | * PACA.exmc.CCR = guest CR | ||
203 | * PACA.exmc.SRR0 = guest R0 | ||
204 | * | ||
205 | */ | ||
206 | |||
207 | std r3, (PACA_EXMC+EX_R3)(r13) | ||
208 | |||
209 | /* save the exit id in R3 */ | ||
210 | mr r3, r12 | ||
211 | |||
212 | /* R12 = vcpu */ | ||
213 | ld r12, GPR4(r1) | ||
214 | |||
215 | /* Now save the guest state */ | ||
216 | |||
217 | std r0, VCPU_GPR(r13)(r12) | ||
218 | std r4, VCPU_GPR(r4)(r12) | ||
219 | std r5, VCPU_GPR(r5)(r12) | ||
220 | std r6, VCPU_GPR(r6)(r12) | ||
221 | std r7, VCPU_GPR(r7)(r12) | ||
222 | std r8, VCPU_GPR(r8)(r12) | ||
223 | std r9, VCPU_GPR(r9)(r12) | ||
224 | |||
225 | /* get registers from PACA */ | ||
226 | mfpaca r5, r0, EX_SRR0, r12 | ||
227 | mfpaca r5, r3, EX_R3, r12 | ||
228 | mfpaca r5, r1, EX_R9, r12 | ||
229 | mfpaca r5, r10, EX_R10, r12 | ||
230 | mfpaca r5, r11, EX_R11, r12 | ||
231 | mfpaca r5, r12, EX_R12, r12 | ||
232 | mfpaca r5, r2, EX_R13, r12 | ||
233 | |||
234 | lwz r5, (PACA_EXMC+EX_LR)(r13) | ||
235 | stw r5, VCPU_LAST_INST(r12) | ||
236 | |||
237 | lwz r5, (PACA_EXMC+EX_CCR)(r13) | ||
238 | stw r5, VCPU_CR(r12) | ||
239 | |||
240 | ld r5, VCPU_HFLAGS(r12) | ||
241 | rldicl. r5, r5, 0, 63 /* CR = ((r5 & 1) == 0) */ | ||
242 | beq no_dcbz32_off | ||
243 | |||
244 | mfspr r5,SPRN_HID5 | ||
245 | rldimi r5,r5,6,56 | ||
246 | mtspr SPRN_HID5,r5 | ||
247 | |||
248 | no_dcbz32_off: | ||
249 | |||
250 | /* XXX maybe skip on lightweight? */ | ||
251 | std r14, VCPU_GPR(r14)(r12) | ||
252 | std r15, VCPU_GPR(r15)(r12) | ||
253 | std r16, VCPU_GPR(r16)(r12) | ||
254 | std r17, VCPU_GPR(r17)(r12) | ||
255 | std r18, VCPU_GPR(r18)(r12) | ||
256 | std r19, VCPU_GPR(r19)(r12) | ||
257 | std r20, VCPU_GPR(r20)(r12) | ||
258 | std r21, VCPU_GPR(r21)(r12) | ||
259 | std r22, VCPU_GPR(r22)(r12) | ||
260 | std r23, VCPU_GPR(r23)(r12) | ||
261 | std r24, VCPU_GPR(r24)(r12) | ||
262 | std r25, VCPU_GPR(r25)(r12) | ||
263 | std r26, VCPU_GPR(r26)(r12) | ||
264 | std r27, VCPU_GPR(r27)(r12) | ||
265 | std r28, VCPU_GPR(r28)(r12) | ||
266 | std r29, VCPU_GPR(r29)(r12) | ||
267 | std r30, VCPU_GPR(r30)(r12) | ||
268 | std r31, VCPU_GPR(r31)(r12) | ||
269 | |||
270 | /* Restore non-volatile host registers (r14 - r31) */ | ||
271 | REST_NVGPRS(r1) | ||
272 | |||
273 | /* Save guest PC (R10) */ | ||
274 | std r10, VCPU_PC(r12) | ||
275 | |||
276 | /* Save guest msr (R11) */ | ||
277 | std r11, VCPU_SHADOW_MSR(r12) | ||
278 | |||
279 | /* Save guest CTR (in R12) */ | ||
280 | mfctr r5 | ||
281 | std r5, VCPU_CTR(r12) | ||
282 | |||
283 | /* Save guest LR */ | ||
284 | mflr r5 | ||
285 | std r5, VCPU_LR(r12) | ||
286 | |||
287 | /* Save guest XER */ | ||
288 | mfxer r5 | ||
289 | std r5, VCPU_XER(r12) | ||
290 | |||
291 | /* Save guest DAR */ | ||
292 | ld r5, (PACA_EXMC+EX_DAR)(r13) | ||
293 | std r5, VCPU_FAULT_DEAR(r12) | ||
294 | |||
295 | /* Save guest DSISR */ | ||
296 | lwz r5, (PACA_EXMC+EX_DSISR)(r13) | ||
297 | std r5, VCPU_FAULT_DSISR(r12) | ||
298 | |||
299 | /* Restore host msr -> SRR1 */ | ||
300 | ld r7, VCPU_HOST_MSR(r12) | ||
301 | mtsrr1 r7 | ||
302 | |||
303 | /* Restore host IP -> SRR0 */ | ||
304 | ld r6, VCPU_HOST_RETIP(r12) | ||
305 | mtsrr0 r6 | ||
306 | |||
307 | /* | ||
308 | * For some interrupts, we need to call the real Linux | ||
309 | * handler, so it can do work for us. This has to happen | ||
310 | * as if the interrupt arrived from the kernel though, | ||
311 | * so let's fake it here where most state is restored. | ||
312 | * | ||
313 | * Call Linux for hardware interrupts/decrementer | ||
314 | * r3 = address of interrupt handler (exit reason) | ||
315 | */ | ||
316 | |||
317 | cmpwi r3, BOOK3S_INTERRUPT_EXTERNAL | ||
318 | beq call_linux_handler | ||
319 | cmpwi r3, BOOK3S_INTERRUPT_DECREMENTER | ||
320 | beq call_linux_handler | ||
321 | |||
322 | /* Back to Interruptable Mode! (goto kvm_return_point) */ | ||
323 | RFI | ||
324 | |||
325 | call_linux_handler: | ||
326 | |||
327 | /* | ||
328 | * If we land here we need to jump back to the handler we | ||
329 | * came from. | ||
330 | * | ||
331 | * We have a page that we can access from real mode, so let's | ||
332 | * jump back to that and use it as a trampoline to get back into the | ||
333 | * interrupt handler! | ||
334 | * | ||
335 | * R3 still contains the exit code, | ||
336 | * R6 VCPU_HOST_RETIP and | ||
337 | * R7 VCPU_HOST_MSR | ||
338 | */ | ||
339 | |||
340 | mtlr r3 | ||
341 | |||
342 | ld r5, VCPU_TRAMPOLINE_LOWMEM(r12) | ||
343 | mtsrr0 r5 | ||
344 | LOAD_REG_IMMEDIATE(r5, MSR_KERNEL & ~(MSR_IR | MSR_DR)) | ||
345 | mtsrr1 r5 | ||
346 | |||
347 | RFI | ||
348 | |||
349 | .global kvm_return_point | ||
350 | kvm_return_point: | ||
351 | |||
352 | /* Jump back to lightweight entry if we're supposed to */ | ||
353 | /* go back into the guest */ | ||
354 | mr r5, r3 | ||
355 | /* Restore r3 (kvm_run) and r4 (vcpu) */ | ||
356 | REST_2GPRS(3, r1) | ||
357 | bl KVMPPC_HANDLE_EXIT | ||
358 | |||
359 | #if 0 /* XXX get lightweight exits back */ | ||
360 | cmpwi r3, RESUME_GUEST | ||
361 | bne kvm_exit_heavyweight | ||
362 | |||
363 | /* put VCPU and KVM_RUN back into place and roll again! */ | ||
364 | REST_2GPRS(3, r1) | ||
365 | b kvm_start_lightweight | ||
366 | |||
367 | kvm_exit_heavyweight: | ||
368 | /* Restore non-volatile host registers */ | ||
369 | ld r14, _LINK(r1) | ||
370 | mtlr r14 | ||
371 | REST_NVGPRS(r1) | ||
372 | |||
373 | addi r1, r1, SWITCH_FRAME_SIZE | ||
374 | #else | ||
375 | ld r4, _LINK(r1) | ||
376 | mtlr r4 | ||
377 | |||
378 | cmpwi r3, RESUME_GUEST | ||
379 | bne kvm_exit_heavyweight | ||
380 | |||
381 | REST_2GPRS(3, r1) | ||
382 | |||
383 | addi r1, r1, SWITCH_FRAME_SIZE | ||
384 | |||
385 | b kvm_start_entry | ||
386 | |||
387 | kvm_exit_heavyweight: | ||
388 | |||
389 | addi r1, r1, SWITCH_FRAME_SIZE | ||
390 | #endif | ||
391 | |||
392 | blr | ||
diff --git a/arch/powerpc/kvm/book3s_64_mmu.c b/arch/powerpc/kvm/book3s_64_mmu.c new file mode 100644 index 000000000000..a31f9c677d23 --- /dev/null +++ b/arch/powerpc/kvm/book3s_64_mmu.c | |||
@@ -0,0 +1,476 @@ | |||
1 | /* | ||
2 | * This program is free software; you can redistribute it and/or modify | ||
3 | * it under the terms of the GNU General Public License, version 2, as | ||
4 | * published by the Free Software Foundation. | ||
5 | * | ||
6 | * This program is distributed in the hope that it will be useful, | ||
7 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
8 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
9 | * GNU General Public License for more details. | ||
10 | * | ||
11 | * You should have received a copy of the GNU General Public License | ||
12 | * along with this program; if not, write to the Free Software | ||
13 | * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
14 | * | ||
15 | * Copyright SUSE Linux Products GmbH 2009 | ||
16 | * | ||
17 | * Authors: Alexander Graf <agraf@suse.de> | ||
18 | */ | ||
19 | |||
20 | #include <linux/types.h> | ||
21 | #include <linux/string.h> | ||
22 | #include <linux/kvm.h> | ||
23 | #include <linux/kvm_host.h> | ||
24 | #include <linux/highmem.h> | ||
25 | |||
26 | #include <asm/tlbflush.h> | ||
27 | #include <asm/kvm_ppc.h> | ||
28 | #include <asm/kvm_book3s.h> | ||
29 | |||
30 | /* #define DEBUG_MMU */ | ||
31 | |||
32 | #ifdef DEBUG_MMU | ||
33 | #define dprintk(X...) printk(KERN_INFO X) | ||
34 | #else | ||
35 | #define dprintk(X...) do { } while(0) | ||
36 | #endif | ||
37 | |||
38 | static void kvmppc_mmu_book3s_64_reset_msr(struct kvm_vcpu *vcpu) | ||
39 | { | ||
40 | kvmppc_set_msr(vcpu, MSR_SF); | ||
41 | } | ||
42 | |||
43 | static struct kvmppc_slb *kvmppc_mmu_book3s_64_find_slbe( | ||
44 | struct kvmppc_vcpu_book3s *vcpu_book3s, | ||
45 | gva_t eaddr) | ||
46 | { | ||
47 | int i; | ||
48 | u64 esid = GET_ESID(eaddr); | ||
49 | u64 esid_1t = GET_ESID_1T(eaddr); | ||
50 | |||
51 | for (i = 0; i < vcpu_book3s->slb_nr; i++) { | ||
52 | u64 cmp_esid = esid; | ||
53 | |||
54 | if (!vcpu_book3s->slb[i].valid) | ||
55 | continue; | ||
56 | |||
57 | if (vcpu_book3s->slb[i].large) | ||
58 | cmp_esid = esid_1t; | ||
59 | |||
60 | if (vcpu_book3s->slb[i].esid == cmp_esid) | ||
61 | return &vcpu_book3s->slb[i]; | ||
62 | } | ||
63 | |||
64 | dprintk("KVM: No SLB entry found for 0x%lx [%llx | %llx]\n", | ||
65 | eaddr, esid, esid_1t); | ||
66 | for (i = 0; i < vcpu_book3s->slb_nr; i++) { | ||
67 | if (vcpu_book3s->slb[i].vsid) | ||
68 | dprintk(" %d: %c%c %llx %llx\n", i, | ||
69 | vcpu_book3s->slb[i].valid ? 'v' : ' ', | ||
70 | vcpu_book3s->slb[i].large ? 'l' : ' ', | ||
71 | vcpu_book3s->slb[i].esid, | ||
72 | vcpu_book3s->slb[i].vsid); | ||
73 | } | ||
74 | |||
75 | return NULL; | ||
76 | } | ||
77 | |||
78 | static u64 kvmppc_mmu_book3s_64_ea_to_vp(struct kvm_vcpu *vcpu, gva_t eaddr, | ||
79 | bool data) | ||
80 | { | ||
81 | struct kvmppc_slb *slb; | ||
82 | |||
83 | slb = kvmppc_mmu_book3s_64_find_slbe(to_book3s(vcpu), eaddr); | ||
84 | if (!slb) | ||
85 | return 0; | ||
86 | |||
87 | if (slb->large) | ||
88 | return (((u64)eaddr >> 12) & 0xfffffff) | | ||
89 | (((u64)slb->vsid) << 28); | ||
90 | |||
91 | return (((u64)eaddr >> 12) & 0xffff) | (((u64)slb->vsid) << 16); | ||
92 | } | ||
93 | |||
94 | static int kvmppc_mmu_book3s_64_get_pagesize(struct kvmppc_slb *slbe) | ||
95 | { | ||
96 | return slbe->large ? 24 : 12; | ||
97 | } | ||
98 | |||
99 | static u32 kvmppc_mmu_book3s_64_get_page(struct kvmppc_slb *slbe, gva_t eaddr) | ||
100 | { | ||
101 | int p = kvmppc_mmu_book3s_64_get_pagesize(slbe); | ||
102 | return ((eaddr & 0xfffffff) >> p); | ||
103 | } | ||
104 | |||
105 | static hva_t kvmppc_mmu_book3s_64_get_pteg( | ||
106 | struct kvmppc_vcpu_book3s *vcpu_book3s, | ||
107 | struct kvmppc_slb *slbe, gva_t eaddr, | ||
108 | bool second) | ||
109 | { | ||
110 | u64 hash, pteg, htabsize; | ||
111 | u32 page; | ||
112 | hva_t r; | ||
113 | |||
114 | page = kvmppc_mmu_book3s_64_get_page(slbe, eaddr); | ||
115 | htabsize = ((1 << ((vcpu_book3s->sdr1 & 0x1f) + 11)) - 1); | ||
116 | |||
117 | hash = slbe->vsid ^ page; | ||
118 | if (second) | ||
119 | hash = ~hash; | ||
120 | hash &= ((1ULL << 39ULL) - 1ULL); | ||
121 | hash &= htabsize; | ||
122 | hash <<= 7ULL; | ||
123 | |||
124 | pteg = vcpu_book3s->sdr1 & 0xfffffffffffc0000ULL; | ||
125 | pteg |= hash; | ||
126 | |||
127 | dprintk("MMU: page=0x%x sdr1=0x%llx pteg=0x%llx vsid=0x%llx\n", | ||
128 | page, vcpu_book3s->sdr1, pteg, slbe->vsid); | ||
129 | |||
130 | r = gfn_to_hva(vcpu_book3s->vcpu.kvm, pteg >> PAGE_SHIFT); | ||
131 | if (kvm_is_error_hva(r)) | ||
132 | return r; | ||
133 | return r | (pteg & ~PAGE_MASK); | ||
134 | } | ||
135 | |||
136 | static u64 kvmppc_mmu_book3s_64_get_avpn(struct kvmppc_slb *slbe, gva_t eaddr) | ||
137 | { | ||
138 | int p = kvmppc_mmu_book3s_64_get_pagesize(slbe); | ||
139 | u64 avpn; | ||
140 | |||
141 | avpn = kvmppc_mmu_book3s_64_get_page(slbe, eaddr); | ||
142 | avpn |= slbe->vsid << (28 - p); | ||
143 | |||
144 | if (p < 24) | ||
145 | avpn >>= ((80 - p) - 56) - 8; | ||
146 | else | ||
147 | avpn <<= 8; | ||
148 | |||
149 | return avpn; | ||
150 | } | ||
151 | |||
152 | static int kvmppc_mmu_book3s_64_xlate(struct kvm_vcpu *vcpu, gva_t eaddr, | ||
153 | struct kvmppc_pte *gpte, bool data) | ||
154 | { | ||
155 | struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu); | ||
156 | struct kvmppc_slb *slbe; | ||
157 | hva_t ptegp; | ||
158 | u64 pteg[16]; | ||
159 | u64 avpn = 0; | ||
160 | int i; | ||
161 | u8 key = 0; | ||
162 | bool found = false; | ||
163 | bool perm_err = false; | ||
164 | int second = 0; | ||
165 | |||
166 | slbe = kvmppc_mmu_book3s_64_find_slbe(vcpu_book3s, eaddr); | ||
167 | if (!slbe) | ||
168 | goto no_seg_found; | ||
169 | |||
170 | do_second: | ||
171 | ptegp = kvmppc_mmu_book3s_64_get_pteg(vcpu_book3s, slbe, eaddr, second); | ||
172 | if (kvm_is_error_hva(ptegp)) | ||
173 | goto no_page_found; | ||
174 | |||
175 | avpn = kvmppc_mmu_book3s_64_get_avpn(slbe, eaddr); | ||
176 | |||
177 | if(copy_from_user(pteg, (void __user *)ptegp, sizeof(pteg))) { | ||
178 | printk(KERN_ERR "KVM can't copy data from 0x%lx!\n", ptegp); | ||
179 | goto no_page_found; | ||
180 | } | ||
181 | |||
182 | if ((vcpu->arch.msr & MSR_PR) && slbe->Kp) | ||
183 | key = 4; | ||
184 | else if (!(vcpu->arch.msr & MSR_PR) && slbe->Ks) | ||
185 | key = 4; | ||
186 | |||
187 | for (i=0; i<16; i+=2) { | ||
188 | u64 v = pteg[i]; | ||
189 | u64 r = pteg[i+1]; | ||
190 | |||
191 | /* Valid check */ | ||
192 | if (!(v & HPTE_V_VALID)) | ||
193 | continue; | ||
194 | /* Hash check */ | ||
195 | if ((v & HPTE_V_SECONDARY) != second) | ||
196 | continue; | ||
197 | |||
198 | /* AVPN compare */ | ||
199 | if (HPTE_V_AVPN_VAL(avpn) == HPTE_V_AVPN_VAL(v)) { | ||
200 | u8 pp = (r & HPTE_R_PP) | key; | ||
201 | int eaddr_mask = 0xFFF; | ||
202 | |||
203 | gpte->eaddr = eaddr; | ||
204 | gpte->vpage = kvmppc_mmu_book3s_64_ea_to_vp(vcpu, | ||
205 | eaddr, | ||
206 | data); | ||
207 | if (slbe->large) | ||
208 | eaddr_mask = 0xFFFFFF; | ||
209 | gpte->raddr = (r & HPTE_R_RPN) | (eaddr & eaddr_mask); | ||
210 | gpte->may_execute = ((r & HPTE_R_N) ? false : true); | ||
211 | gpte->may_read = false; | ||
212 | gpte->may_write = false; | ||
213 | |||
214 | switch (pp) { | ||
215 | case 0: | ||
216 | case 1: | ||
217 | case 2: | ||
218 | case 6: | ||
219 | gpte->may_write = true; | ||
220 | /* fall through */ | ||
221 | case 3: | ||
222 | case 5: | ||
223 | case 7: | ||
224 | gpte->may_read = true; | ||
225 | break; | ||
226 | } | ||
227 | |||
228 | if (!gpte->may_read) { | ||
229 | perm_err = true; | ||
230 | continue; | ||
231 | } | ||
232 | |||
233 | dprintk("KVM MMU: Translated 0x%lx [0x%llx] -> 0x%llx " | ||
234 | "-> 0x%llx\n", | ||
235 | eaddr, avpn, gpte->vpage, gpte->raddr); | ||
236 | found = true; | ||
237 | break; | ||
238 | } | ||
239 | } | ||
240 | |||
241 | /* Update PTE R and C bits, so the guest's swapper knows we used the | ||
242 | * page */ | ||
243 | if (found) { | ||
244 | u32 oldr = pteg[i+1]; | ||
245 | |||
246 | if (gpte->may_read) { | ||
247 | /* Set the accessed flag */ | ||
248 | pteg[i+1] |= HPTE_R_R; | ||
249 | } | ||
250 | if (gpte->may_write) { | ||
251 | /* Set the dirty flag */ | ||
252 | pteg[i+1] |= HPTE_R_C; | ||
253 | } else { | ||
254 | dprintk("KVM: Mapping read-only page!\n"); | ||
255 | } | ||
256 | |||
257 | /* Write back into the PTEG */ | ||
258 | if (pteg[i+1] != oldr) | ||
259 | copy_to_user((void __user *)ptegp, pteg, sizeof(pteg)); | ||
260 | |||
261 | return 0; | ||
262 | } else { | ||
263 | dprintk("KVM MMU: No PTE found (ea=0x%lx sdr1=0x%llx " | ||
264 | "ptegp=0x%lx)\n", | ||
265 | eaddr, to_book3s(vcpu)->sdr1, ptegp); | ||
266 | for (i = 0; i < 16; i += 2) | ||
267 | dprintk(" %02d: 0x%llx - 0x%llx (0x%llx)\n", | ||
268 | i, pteg[i], pteg[i+1], avpn); | ||
269 | |||
270 | if (!second) { | ||
271 | second = HPTE_V_SECONDARY; | ||
272 | goto do_second; | ||
273 | } | ||
274 | } | ||
275 | |||
276 | |||
277 | no_page_found: | ||
278 | |||
279 | |||
280 | if (perm_err) | ||
281 | return -EPERM; | ||
282 | |||
283 | return -ENOENT; | ||
284 | |||
285 | no_seg_found: | ||
286 | |||
287 | dprintk("KVM MMU: Trigger segment fault\n"); | ||
288 | return -EINVAL; | ||
289 | } | ||
290 | |||
291 | static void kvmppc_mmu_book3s_64_slbmte(struct kvm_vcpu *vcpu, u64 rs, u64 rb) | ||
292 | { | ||
293 | struct kvmppc_vcpu_book3s *vcpu_book3s; | ||
294 | u64 esid, esid_1t; | ||
295 | int slb_nr; | ||
296 | struct kvmppc_slb *slbe; | ||
297 | |||
298 | dprintk("KVM MMU: slbmte(0x%llx, 0x%llx)\n", rs, rb); | ||
299 | |||
300 | vcpu_book3s = to_book3s(vcpu); | ||
301 | |||
302 | esid = GET_ESID(rb); | ||
303 | esid_1t = GET_ESID_1T(rb); | ||
304 | slb_nr = rb & 0xfff; | ||
305 | |||
306 | if (slb_nr > vcpu_book3s->slb_nr) | ||
307 | return; | ||
308 | |||
309 | slbe = &vcpu_book3s->slb[slb_nr]; | ||
310 | |||
311 | slbe->large = (rs & SLB_VSID_L) ? 1 : 0; | ||
312 | slbe->esid = slbe->large ? esid_1t : esid; | ||
313 | slbe->vsid = rs >> 12; | ||
314 | slbe->valid = (rb & SLB_ESID_V) ? 1 : 0; | ||
315 | slbe->Ks = (rs & SLB_VSID_KS) ? 1 : 0; | ||
316 | slbe->Kp = (rs & SLB_VSID_KP) ? 1 : 0; | ||
317 | slbe->nx = (rs & SLB_VSID_N) ? 1 : 0; | ||
318 | slbe->class = (rs & SLB_VSID_C) ? 1 : 0; | ||
319 | |||
320 | slbe->orige = rb & (ESID_MASK | SLB_ESID_V); | ||
321 | slbe->origv = rs; | ||
322 | |||
323 | /* Map the new segment */ | ||
324 | kvmppc_mmu_map_segment(vcpu, esid << SID_SHIFT); | ||
325 | } | ||
326 | |||
327 | static u64 kvmppc_mmu_book3s_64_slbmfee(struct kvm_vcpu *vcpu, u64 slb_nr) | ||
328 | { | ||
329 | struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu); | ||
330 | struct kvmppc_slb *slbe; | ||
331 | |||
332 | if (slb_nr > vcpu_book3s->slb_nr) | ||
333 | return 0; | ||
334 | |||
335 | slbe = &vcpu_book3s->slb[slb_nr]; | ||
336 | |||
337 | return slbe->orige; | ||
338 | } | ||
339 | |||
340 | static u64 kvmppc_mmu_book3s_64_slbmfev(struct kvm_vcpu *vcpu, u64 slb_nr) | ||
341 | { | ||
342 | struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu); | ||
343 | struct kvmppc_slb *slbe; | ||
344 | |||
345 | if (slb_nr > vcpu_book3s->slb_nr) | ||
346 | return 0; | ||
347 | |||
348 | slbe = &vcpu_book3s->slb[slb_nr]; | ||
349 | |||
350 | return slbe->origv; | ||
351 | } | ||
352 | |||
353 | static void kvmppc_mmu_book3s_64_slbie(struct kvm_vcpu *vcpu, u64 ea) | ||
354 | { | ||
355 | struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu); | ||
356 | struct kvmppc_slb *slbe; | ||
357 | |||
358 | dprintk("KVM MMU: slbie(0x%llx)\n", ea); | ||
359 | |||
360 | slbe = kvmppc_mmu_book3s_64_find_slbe(vcpu_book3s, ea); | ||
361 | |||
362 | if (!slbe) | ||
363 | return; | ||
364 | |||
365 | dprintk("KVM MMU: slbie(0x%llx, 0x%llx)\n", ea, slbe->esid); | ||
366 | |||
367 | slbe->valid = false; | ||
368 | |||
369 | kvmppc_mmu_map_segment(vcpu, ea); | ||
370 | } | ||
371 | |||
372 | static void kvmppc_mmu_book3s_64_slbia(struct kvm_vcpu *vcpu) | ||
373 | { | ||
374 | struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu); | ||
375 | int i; | ||
376 | |||
377 | dprintk("KVM MMU: slbia()\n"); | ||
378 | |||
379 | for (i = 1; i < vcpu_book3s->slb_nr; i++) | ||
380 | vcpu_book3s->slb[i].valid = false; | ||
381 | |||
382 | if (vcpu->arch.msr & MSR_IR) { | ||
383 | kvmppc_mmu_flush_segments(vcpu); | ||
384 | kvmppc_mmu_map_segment(vcpu, vcpu->arch.pc); | ||
385 | } | ||
386 | } | ||
387 | |||
388 | static void kvmppc_mmu_book3s_64_mtsrin(struct kvm_vcpu *vcpu, u32 srnum, | ||
389 | ulong value) | ||
390 | { | ||
391 | u64 rb = 0, rs = 0; | ||
392 | |||
393 | /* ESID = srnum */ | ||
394 | rb |= (srnum & 0xf) << 28; | ||
395 | /* Set the valid bit */ | ||
396 | rb |= 1 << 27; | ||
397 | /* Index = ESID */ | ||
398 | rb |= srnum; | ||
399 | |||
400 | /* VSID = VSID */ | ||
401 | rs |= (value & 0xfffffff) << 12; | ||
402 | /* flags = flags */ | ||
403 | rs |= ((value >> 27) & 0xf) << 9; | ||
404 | |||
405 | kvmppc_mmu_book3s_64_slbmte(vcpu, rs, rb); | ||
406 | } | ||
407 | |||
408 | static void kvmppc_mmu_book3s_64_tlbie(struct kvm_vcpu *vcpu, ulong va, | ||
409 | bool large) | ||
410 | { | ||
411 | u64 mask = 0xFFFFFFFFFULL; | ||
412 | |||
413 | dprintk("KVM MMU: tlbie(0x%lx)\n", va); | ||
414 | |||
415 | if (large) | ||
416 | mask = 0xFFFFFF000ULL; | ||
417 | kvmppc_mmu_pte_vflush(vcpu, va >> 12, mask); | ||
418 | } | ||
419 | |||
420 | static int kvmppc_mmu_book3s_64_esid_to_vsid(struct kvm_vcpu *vcpu, u64 esid, | ||
421 | u64 *vsid) | ||
422 | { | ||
423 | switch (vcpu->arch.msr & (MSR_DR|MSR_IR)) { | ||
424 | case 0: | ||
425 | *vsid = (VSID_REAL >> 16) | esid; | ||
426 | break; | ||
427 | case MSR_IR: | ||
428 | *vsid = (VSID_REAL_IR >> 16) | esid; | ||
429 | break; | ||
430 | case MSR_DR: | ||
431 | *vsid = (VSID_REAL_DR >> 16) | esid; | ||
432 | break; | ||
433 | case MSR_DR|MSR_IR: | ||
434 | { | ||
435 | ulong ea; | ||
436 | struct kvmppc_slb *slb; | ||
437 | ea = esid << SID_SHIFT; | ||
438 | slb = kvmppc_mmu_book3s_64_find_slbe(to_book3s(vcpu), ea); | ||
439 | if (slb) | ||
440 | *vsid = slb->vsid; | ||
441 | else | ||
442 | return -ENOENT; | ||
443 | |||
444 | break; | ||
445 | } | ||
446 | default: | ||
447 | BUG(); | ||
448 | break; | ||
449 | } | ||
450 | |||
451 | return 0; | ||
452 | } | ||
453 | |||
454 | static bool kvmppc_mmu_book3s_64_is_dcbz32(struct kvm_vcpu *vcpu) | ||
455 | { | ||
456 | return (to_book3s(vcpu)->hid[5] & 0x80); | ||
457 | } | ||
458 | |||
459 | void kvmppc_mmu_book3s_64_init(struct kvm_vcpu *vcpu) | ||
460 | { | ||
461 | struct kvmppc_mmu *mmu = &vcpu->arch.mmu; | ||
462 | |||
463 | mmu->mfsrin = NULL; | ||
464 | mmu->mtsrin = kvmppc_mmu_book3s_64_mtsrin; | ||
465 | mmu->slbmte = kvmppc_mmu_book3s_64_slbmte; | ||
466 | mmu->slbmfee = kvmppc_mmu_book3s_64_slbmfee; | ||
467 | mmu->slbmfev = kvmppc_mmu_book3s_64_slbmfev; | ||
468 | mmu->slbie = kvmppc_mmu_book3s_64_slbie; | ||
469 | mmu->slbia = kvmppc_mmu_book3s_64_slbia; | ||
470 | mmu->xlate = kvmppc_mmu_book3s_64_xlate; | ||
471 | mmu->reset_msr = kvmppc_mmu_book3s_64_reset_msr; | ||
472 | mmu->tlbie = kvmppc_mmu_book3s_64_tlbie; | ||
473 | mmu->esid_to_vsid = kvmppc_mmu_book3s_64_esid_to_vsid; | ||
474 | mmu->ea_to_vp = kvmppc_mmu_book3s_64_ea_to_vp; | ||
475 | mmu->is_dcbz32 = kvmppc_mmu_book3s_64_is_dcbz32; | ||
476 | } | ||
diff --git a/arch/powerpc/kvm/book3s_64_mmu_host.c b/arch/powerpc/kvm/book3s_64_mmu_host.c new file mode 100644 index 000000000000..f2899b297ffd --- /dev/null +++ b/arch/powerpc/kvm/book3s_64_mmu_host.c | |||
@@ -0,0 +1,408 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2009 SUSE Linux Products GmbH. All rights reserved. | ||
3 | * | ||
4 | * Authors: | ||
5 | * Alexander Graf <agraf@suse.de> | ||
6 | * Kevin Wolf <mail@kevin-wolf.de> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License, version 2, as | ||
10 | * published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
20 | */ | ||
21 | |||
22 | #include <linux/kvm_host.h> | ||
23 | |||
24 | #include <asm/kvm_ppc.h> | ||
25 | #include <asm/kvm_book3s.h> | ||
26 | #include <asm/mmu-hash64.h> | ||
27 | #include <asm/machdep.h> | ||
28 | #include <asm/mmu_context.h> | ||
29 | #include <asm/hw_irq.h> | ||
30 | |||
31 | #define PTE_SIZE 12 | ||
32 | #define VSID_ALL 0 | ||
33 | |||
34 | /* #define DEBUG_MMU */ | ||
35 | /* #define DEBUG_SLB */ | ||
36 | |||
37 | #ifdef DEBUG_MMU | ||
38 | #define dprintk_mmu(a, ...) printk(KERN_INFO a, __VA_ARGS__) | ||
39 | #else | ||
40 | #define dprintk_mmu(a, ...) do { } while(0) | ||
41 | #endif | ||
42 | |||
43 | #ifdef DEBUG_SLB | ||
44 | #define dprintk_slb(a, ...) printk(KERN_INFO a, __VA_ARGS__) | ||
45 | #else | ||
46 | #define dprintk_slb(a, ...) do { } while(0) | ||
47 | #endif | ||
48 | |||
49 | static void invalidate_pte(struct hpte_cache *pte) | ||
50 | { | ||
51 | dprintk_mmu("KVM: Flushing SPT %d: 0x%llx (0x%llx) -> 0x%llx\n", | ||
52 | i, pte->pte.eaddr, pte->pte.vpage, pte->host_va); | ||
53 | |||
54 | ppc_md.hpte_invalidate(pte->slot, pte->host_va, | ||
55 | MMU_PAGE_4K, MMU_SEGSIZE_256M, | ||
56 | false); | ||
57 | pte->host_va = 0; | ||
58 | kvm_release_pfn_dirty(pte->pfn); | ||
59 | } | ||
60 | |||
61 | void kvmppc_mmu_pte_flush(struct kvm_vcpu *vcpu, u64 guest_ea, u64 ea_mask) | ||
62 | { | ||
63 | int i; | ||
64 | |||
65 | dprintk_mmu("KVM: Flushing %d Shadow PTEs: 0x%llx & 0x%llx\n", | ||
66 | vcpu->arch.hpte_cache_offset, guest_ea, ea_mask); | ||
67 | BUG_ON(vcpu->arch.hpte_cache_offset > HPTEG_CACHE_NUM); | ||
68 | |||
69 | guest_ea &= ea_mask; | ||
70 | for (i = 0; i < vcpu->arch.hpte_cache_offset; i++) { | ||
71 | struct hpte_cache *pte; | ||
72 | |||
73 | pte = &vcpu->arch.hpte_cache[i]; | ||
74 | if (!pte->host_va) | ||
75 | continue; | ||
76 | |||
77 | if ((pte->pte.eaddr & ea_mask) == guest_ea) { | ||
78 | invalidate_pte(pte); | ||
79 | } | ||
80 | } | ||
81 | |||
82 | /* Doing a complete flush -> start from scratch */ | ||
83 | if (!ea_mask) | ||
84 | vcpu->arch.hpte_cache_offset = 0; | ||
85 | } | ||
86 | |||
87 | void kvmppc_mmu_pte_vflush(struct kvm_vcpu *vcpu, u64 guest_vp, u64 vp_mask) | ||
88 | { | ||
89 | int i; | ||
90 | |||
91 | dprintk_mmu("KVM: Flushing %d Shadow vPTEs: 0x%llx & 0x%llx\n", | ||
92 | vcpu->arch.hpte_cache_offset, guest_vp, vp_mask); | ||
93 | BUG_ON(vcpu->arch.hpte_cache_offset > HPTEG_CACHE_NUM); | ||
94 | |||
95 | guest_vp &= vp_mask; | ||
96 | for (i = 0; i < vcpu->arch.hpte_cache_offset; i++) { | ||
97 | struct hpte_cache *pte; | ||
98 | |||
99 | pte = &vcpu->arch.hpte_cache[i]; | ||
100 | if (!pte->host_va) | ||
101 | continue; | ||
102 | |||
103 | if ((pte->pte.vpage & vp_mask) == guest_vp) { | ||
104 | invalidate_pte(pte); | ||
105 | } | ||
106 | } | ||
107 | } | ||
108 | |||
109 | void kvmppc_mmu_pte_pflush(struct kvm_vcpu *vcpu, u64 pa_start, u64 pa_end) | ||
110 | { | ||
111 | int i; | ||
112 | |||
113 | dprintk_mmu("KVM: Flushing %d Shadow pPTEs: 0x%llx & 0x%llx\n", | ||
114 | vcpu->arch.hpte_cache_offset, guest_pa, pa_mask); | ||
115 | BUG_ON(vcpu->arch.hpte_cache_offset > HPTEG_CACHE_NUM); | ||
116 | |||
117 | for (i = 0; i < vcpu->arch.hpte_cache_offset; i++) { | ||
118 | struct hpte_cache *pte; | ||
119 | |||
120 | pte = &vcpu->arch.hpte_cache[i]; | ||
121 | if (!pte->host_va) | ||
122 | continue; | ||
123 | |||
124 | if ((pte->pte.raddr >= pa_start) && | ||
125 | (pte->pte.raddr < pa_end)) { | ||
126 | invalidate_pte(pte); | ||
127 | } | ||
128 | } | ||
129 | } | ||
130 | |||
131 | struct kvmppc_pte *kvmppc_mmu_find_pte(struct kvm_vcpu *vcpu, u64 ea, bool data) | ||
132 | { | ||
133 | int i; | ||
134 | u64 guest_vp; | ||
135 | |||
136 | guest_vp = vcpu->arch.mmu.ea_to_vp(vcpu, ea, false); | ||
137 | for (i=0; i<vcpu->arch.hpte_cache_offset; i++) { | ||
138 | struct hpte_cache *pte; | ||
139 | |||
140 | pte = &vcpu->arch.hpte_cache[i]; | ||
141 | if (!pte->host_va) | ||
142 | continue; | ||
143 | |||
144 | if (pte->pte.vpage == guest_vp) | ||
145 | return &pte->pte; | ||
146 | } | ||
147 | |||
148 | return NULL; | ||
149 | } | ||
150 | |||
151 | static int kvmppc_mmu_hpte_cache_next(struct kvm_vcpu *vcpu) | ||
152 | { | ||
153 | if (vcpu->arch.hpte_cache_offset == HPTEG_CACHE_NUM) | ||
154 | kvmppc_mmu_pte_flush(vcpu, 0, 0); | ||
155 | |||
156 | return vcpu->arch.hpte_cache_offset++; | ||
157 | } | ||
158 | |||
159 | /* We keep 512 gvsid->hvsid entries, mapping the guest ones to the array using | ||
160 | * a hash, so we don't waste cycles on looping */ | ||
161 | static u16 kvmppc_sid_hash(struct kvm_vcpu *vcpu, u64 gvsid) | ||
162 | { | ||
163 | return (u16)(((gvsid >> (SID_MAP_BITS * 7)) & SID_MAP_MASK) ^ | ||
164 | ((gvsid >> (SID_MAP_BITS * 6)) & SID_MAP_MASK) ^ | ||
165 | ((gvsid >> (SID_MAP_BITS * 5)) & SID_MAP_MASK) ^ | ||
166 | ((gvsid >> (SID_MAP_BITS * 4)) & SID_MAP_MASK) ^ | ||
167 | ((gvsid >> (SID_MAP_BITS * 3)) & SID_MAP_MASK) ^ | ||
168 | ((gvsid >> (SID_MAP_BITS * 2)) & SID_MAP_MASK) ^ | ||
169 | ((gvsid >> (SID_MAP_BITS * 1)) & SID_MAP_MASK) ^ | ||
170 | ((gvsid >> (SID_MAP_BITS * 0)) & SID_MAP_MASK)); | ||
171 | } | ||
172 | |||
173 | |||
174 | static struct kvmppc_sid_map *find_sid_vsid(struct kvm_vcpu *vcpu, u64 gvsid) | ||
175 | { | ||
176 | struct kvmppc_sid_map *map; | ||
177 | u16 sid_map_mask; | ||
178 | |||
179 | if (vcpu->arch.msr & MSR_PR) | ||
180 | gvsid |= VSID_PR; | ||
181 | |||
182 | sid_map_mask = kvmppc_sid_hash(vcpu, gvsid); | ||
183 | map = &to_book3s(vcpu)->sid_map[sid_map_mask]; | ||
184 | if (map->guest_vsid == gvsid) { | ||
185 | dprintk_slb("SLB: Searching 0x%llx -> 0x%llx\n", | ||
186 | gvsid, map->host_vsid); | ||
187 | return map; | ||
188 | } | ||
189 | |||
190 | map = &to_book3s(vcpu)->sid_map[SID_MAP_MASK - sid_map_mask]; | ||
191 | if (map->guest_vsid == gvsid) { | ||
192 | dprintk_slb("SLB: Searching 0x%llx -> 0x%llx\n", | ||
193 | gvsid, map->host_vsid); | ||
194 | return map; | ||
195 | } | ||
196 | |||
197 | dprintk_slb("SLB: Searching 0x%llx -> not found\n", gvsid); | ||
198 | return NULL; | ||
199 | } | ||
200 | |||
201 | int kvmppc_mmu_map_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *orig_pte) | ||
202 | { | ||
203 | pfn_t hpaddr; | ||
204 | ulong hash, hpteg, va; | ||
205 | u64 vsid; | ||
206 | int ret; | ||
207 | int rflags = 0x192; | ||
208 | int vflags = 0; | ||
209 | int attempt = 0; | ||
210 | struct kvmppc_sid_map *map; | ||
211 | |||
212 | /* Get host physical address for gpa */ | ||
213 | hpaddr = gfn_to_pfn(vcpu->kvm, orig_pte->raddr >> PAGE_SHIFT); | ||
214 | if (kvm_is_error_hva(hpaddr)) { | ||
215 | printk(KERN_INFO "Couldn't get guest page for gfn %llx!\n", orig_pte->eaddr); | ||
216 | return -EINVAL; | ||
217 | } | ||
218 | hpaddr <<= PAGE_SHIFT; | ||
219 | #if PAGE_SHIFT == 12 | ||
220 | #elif PAGE_SHIFT == 16 | ||
221 | hpaddr |= orig_pte->raddr & 0xf000; | ||
222 | #else | ||
223 | #error Unknown page size | ||
224 | #endif | ||
225 | |||
226 | /* and write the mapping ea -> hpa into the pt */ | ||
227 | vcpu->arch.mmu.esid_to_vsid(vcpu, orig_pte->eaddr >> SID_SHIFT, &vsid); | ||
228 | map = find_sid_vsid(vcpu, vsid); | ||
229 | if (!map) { | ||
230 | kvmppc_mmu_map_segment(vcpu, orig_pte->eaddr); | ||
231 | map = find_sid_vsid(vcpu, vsid); | ||
232 | } | ||
233 | BUG_ON(!map); | ||
234 | |||
235 | vsid = map->host_vsid; | ||
236 | va = hpt_va(orig_pte->eaddr, vsid, MMU_SEGSIZE_256M); | ||
237 | |||
238 | if (!orig_pte->may_write) | ||
239 | rflags |= HPTE_R_PP; | ||
240 | else | ||
241 | mark_page_dirty(vcpu->kvm, orig_pte->raddr >> PAGE_SHIFT); | ||
242 | |||
243 | if (!orig_pte->may_execute) | ||
244 | rflags |= HPTE_R_N; | ||
245 | |||
246 | hash = hpt_hash(va, PTE_SIZE, MMU_SEGSIZE_256M); | ||
247 | |||
248 | map_again: | ||
249 | hpteg = ((hash & htab_hash_mask) * HPTES_PER_GROUP); | ||
250 | |||
251 | /* In case we tried normal mapping already, let's nuke old entries */ | ||
252 | if (attempt > 1) | ||
253 | if (ppc_md.hpte_remove(hpteg) < 0) | ||
254 | return -1; | ||
255 | |||
256 | ret = ppc_md.hpte_insert(hpteg, va, hpaddr, rflags, vflags, MMU_PAGE_4K, MMU_SEGSIZE_256M); | ||
257 | |||
258 | if (ret < 0) { | ||
259 | /* If we couldn't map a primary PTE, try a secondary */ | ||
260 | #ifdef USE_SECONDARY | ||
261 | hash = ~hash; | ||
262 | attempt++; | ||
263 | if (attempt % 2) | ||
264 | vflags = HPTE_V_SECONDARY; | ||
265 | else | ||
266 | vflags = 0; | ||
267 | #else | ||
268 | attempt = 2; | ||
269 | #endif | ||
270 | goto map_again; | ||
271 | } else { | ||
272 | int hpte_id = kvmppc_mmu_hpte_cache_next(vcpu); | ||
273 | struct hpte_cache *pte = &vcpu->arch.hpte_cache[hpte_id]; | ||
274 | |||
275 | dprintk_mmu("KVM: %c%c Map 0x%llx: [%lx] 0x%lx (0x%llx) -> %lx\n", | ||
276 | ((rflags & HPTE_R_PP) == 3) ? '-' : 'w', | ||
277 | (rflags & HPTE_R_N) ? '-' : 'x', | ||
278 | orig_pte->eaddr, hpteg, va, orig_pte->vpage, hpaddr); | ||
279 | |||
280 | pte->slot = hpteg + (ret & 7); | ||
281 | pte->host_va = va; | ||
282 | pte->pte = *orig_pte; | ||
283 | pte->pfn = hpaddr >> PAGE_SHIFT; | ||
284 | } | ||
285 | |||
286 | return 0; | ||
287 | } | ||
288 | |||
289 | static struct kvmppc_sid_map *create_sid_map(struct kvm_vcpu *vcpu, u64 gvsid) | ||
290 | { | ||
291 | struct kvmppc_sid_map *map; | ||
292 | struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu); | ||
293 | u16 sid_map_mask; | ||
294 | static int backwards_map = 0; | ||
295 | |||
296 | if (vcpu->arch.msr & MSR_PR) | ||
297 | gvsid |= VSID_PR; | ||
298 | |||
299 | /* We might get collisions that trap in preceding order, so let's | ||
300 | map them differently */ | ||
301 | |||
302 | sid_map_mask = kvmppc_sid_hash(vcpu, gvsid); | ||
303 | if (backwards_map) | ||
304 | sid_map_mask = SID_MAP_MASK - sid_map_mask; | ||
305 | |||
306 | map = &to_book3s(vcpu)->sid_map[sid_map_mask]; | ||
307 | |||
308 | /* Make sure we're taking the other map next time */ | ||
309 | backwards_map = !backwards_map; | ||
310 | |||
311 | /* Uh-oh ... out of mappings. Let's flush! */ | ||
312 | if (vcpu_book3s->vsid_next == vcpu_book3s->vsid_max) { | ||
313 | vcpu_book3s->vsid_next = vcpu_book3s->vsid_first; | ||
314 | memset(vcpu_book3s->sid_map, 0, | ||
315 | sizeof(struct kvmppc_sid_map) * SID_MAP_NUM); | ||
316 | kvmppc_mmu_pte_flush(vcpu, 0, 0); | ||
317 | kvmppc_mmu_flush_segments(vcpu); | ||
318 | } | ||
319 | map->host_vsid = vcpu_book3s->vsid_next++; | ||
320 | |||
321 | map->guest_vsid = gvsid; | ||
322 | map->valid = true; | ||
323 | |||
324 | return map; | ||
325 | } | ||
326 | |||
327 | static int kvmppc_mmu_next_segment(struct kvm_vcpu *vcpu, ulong esid) | ||
328 | { | ||
329 | int i; | ||
330 | int max_slb_size = 64; | ||
331 | int found_inval = -1; | ||
332 | int r; | ||
333 | |||
334 | if (!get_paca()->kvm_slb_max) | ||
335 | get_paca()->kvm_slb_max = 1; | ||
336 | |||
337 | /* Are we overwriting? */ | ||
338 | for (i = 1; i < get_paca()->kvm_slb_max; i++) { | ||
339 | if (!(get_paca()->kvm_slb[i].esid & SLB_ESID_V)) | ||
340 | found_inval = i; | ||
341 | else if ((get_paca()->kvm_slb[i].esid & ESID_MASK) == esid) | ||
342 | return i; | ||
343 | } | ||
344 | |||
345 | /* Found a spare entry that was invalidated before */ | ||
346 | if (found_inval > 0) | ||
347 | return found_inval; | ||
348 | |||
349 | /* No spare invalid entry, so create one */ | ||
350 | |||
351 | if (mmu_slb_size < 64) | ||
352 | max_slb_size = mmu_slb_size; | ||
353 | |||
354 | /* Overflowing -> purge */ | ||
355 | if ((get_paca()->kvm_slb_max) == max_slb_size) | ||
356 | kvmppc_mmu_flush_segments(vcpu); | ||
357 | |||
358 | r = get_paca()->kvm_slb_max; | ||
359 | get_paca()->kvm_slb_max++; | ||
360 | |||
361 | return r; | ||
362 | } | ||
363 | |||
364 | int kvmppc_mmu_map_segment(struct kvm_vcpu *vcpu, ulong eaddr) | ||
365 | { | ||
366 | u64 esid = eaddr >> SID_SHIFT; | ||
367 | u64 slb_esid = (eaddr & ESID_MASK) | SLB_ESID_V; | ||
368 | u64 slb_vsid = SLB_VSID_USER; | ||
369 | u64 gvsid; | ||
370 | int slb_index; | ||
371 | struct kvmppc_sid_map *map; | ||
372 | |||
373 | slb_index = kvmppc_mmu_next_segment(vcpu, eaddr & ESID_MASK); | ||
374 | |||
375 | if (vcpu->arch.mmu.esid_to_vsid(vcpu, esid, &gvsid)) { | ||
376 | /* Invalidate an entry */ | ||
377 | get_paca()->kvm_slb[slb_index].esid = 0; | ||
378 | return -ENOENT; | ||
379 | } | ||
380 | |||
381 | map = find_sid_vsid(vcpu, gvsid); | ||
382 | if (!map) | ||
383 | map = create_sid_map(vcpu, gvsid); | ||
384 | |||
385 | map->guest_esid = esid; | ||
386 | |||
387 | slb_vsid |= (map->host_vsid << 12); | ||
388 | slb_vsid &= ~SLB_VSID_KP; | ||
389 | slb_esid |= slb_index; | ||
390 | |||
391 | get_paca()->kvm_slb[slb_index].esid = slb_esid; | ||
392 | get_paca()->kvm_slb[slb_index].vsid = slb_vsid; | ||
393 | |||
394 | dprintk_slb("slbmte %#llx, %#llx\n", slb_vsid, slb_esid); | ||
395 | |||
396 | return 0; | ||
397 | } | ||
398 | |||
399 | void kvmppc_mmu_flush_segments(struct kvm_vcpu *vcpu) | ||
400 | { | ||
401 | get_paca()->kvm_slb_max = 1; | ||
402 | get_paca()->kvm_slb[0].esid = 0; | ||
403 | } | ||
404 | |||
405 | void kvmppc_mmu_destroy(struct kvm_vcpu *vcpu) | ||
406 | { | ||
407 | kvmppc_mmu_pte_flush(vcpu, 0, 0); | ||
408 | } | ||
diff --git a/arch/powerpc/kvm/book3s_64_rmhandlers.S b/arch/powerpc/kvm/book3s_64_rmhandlers.S new file mode 100644 index 000000000000..fb7dd2e9ac88 --- /dev/null +++ b/arch/powerpc/kvm/book3s_64_rmhandlers.S | |||
@@ -0,0 +1,131 @@ | |||
1 | /* | ||
2 | * This program is free software; you can redistribute it and/or modify | ||
3 | * it under the terms of the GNU General Public License, version 2, as | ||
4 | * published by the Free Software Foundation. | ||
5 | * | ||
6 | * This program is distributed in the hope that it will be useful, | ||
7 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
8 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
9 | * GNU General Public License for more details. | ||
10 | * | ||
11 | * You should have received a copy of the GNU General Public License | ||
12 | * along with this program; if not, write to the Free Software | ||
13 | * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
14 | * | ||
15 | * Copyright SUSE Linux Products GmbH 2009 | ||
16 | * | ||
17 | * Authors: Alexander Graf <agraf@suse.de> | ||
18 | */ | ||
19 | |||
20 | #include <asm/ppc_asm.h> | ||
21 | #include <asm/kvm_asm.h> | ||
22 | #include <asm/reg.h> | ||
23 | #include <asm/page.h> | ||
24 | #include <asm/asm-offsets.h> | ||
25 | #include <asm/exception-64s.h> | ||
26 | |||
27 | /***************************************************************************** | ||
28 | * * | ||
29 | * Real Mode handlers that need to be in low physical memory * | ||
30 | * * | ||
31 | ****************************************************************************/ | ||
32 | |||
33 | |||
34 | .macro INTERRUPT_TRAMPOLINE intno | ||
35 | |||
36 | .global kvmppc_trampoline_\intno | ||
37 | kvmppc_trampoline_\intno: | ||
38 | |||
39 | mtspr SPRN_SPRG_SCRATCH0, r13 /* Save r13 */ | ||
40 | |||
41 | /* | ||
42 | * First thing to do is to find out if we're coming | ||
43 | * from a KVM guest or a Linux process. | ||
44 | * | ||
45 | * To distinguish, we check a magic byte in the PACA | ||
46 | */ | ||
47 | mfspr r13, SPRN_SPRG_PACA /* r13 = PACA */ | ||
48 | std r12, (PACA_EXMC + EX_R12)(r13) | ||
49 | mfcr r12 | ||
50 | stw r12, (PACA_EXMC + EX_CCR)(r13) | ||
51 | lbz r12, PACA_KVM_IN_GUEST(r13) | ||
52 | cmpwi r12, 0 | ||
53 | bne ..kvmppc_handler_hasmagic_\intno | ||
54 | /* No KVM guest? Then jump back to the Linux handler! */ | ||
55 | lwz r12, (PACA_EXMC + EX_CCR)(r13) | ||
56 | mtcr r12 | ||
57 | ld r12, (PACA_EXMC + EX_R12)(r13) | ||
58 | mfspr r13, SPRN_SPRG_SCRATCH0 /* r13 = original r13 */ | ||
59 | b kvmppc_resume_\intno /* Get back original handler */ | ||
60 | |||
61 | /* Now we know we're handling a KVM guest */ | ||
62 | ..kvmppc_handler_hasmagic_\intno: | ||
63 | /* Unset guest state */ | ||
64 | li r12, 0 | ||
65 | stb r12, PACA_KVM_IN_GUEST(r13) | ||
66 | |||
67 | std r1, (PACA_EXMC+EX_R9)(r13) | ||
68 | std r10, (PACA_EXMC+EX_R10)(r13) | ||
69 | std r11, (PACA_EXMC+EX_R11)(r13) | ||
70 | std r2, (PACA_EXMC+EX_R13)(r13) | ||
71 | |||
72 | mfsrr0 r10 | ||
73 | mfsrr1 r11 | ||
74 | |||
75 | /* Restore R1/R2 so we can handle faults */ | ||
76 | ld r1, PACAR1(r13) | ||
77 | ld r2, (PACA_EXMC+EX_SRR0)(r13) | ||
78 | |||
79 | /* Let's store which interrupt we're handling */ | ||
80 | li r12, \intno | ||
81 | |||
82 | /* Jump into the SLB exit code that goes to the highmem handler */ | ||
83 | b kvmppc_handler_trampoline_exit | ||
84 | |||
85 | .endm | ||
86 | |||
87 | INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_SYSTEM_RESET | ||
88 | INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_MACHINE_CHECK | ||
89 | INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_DATA_STORAGE | ||
90 | INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_DATA_SEGMENT | ||
91 | INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_INST_STORAGE | ||
92 | INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_INST_SEGMENT | ||
93 | INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_EXTERNAL | ||
94 | INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_ALIGNMENT | ||
95 | INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_PROGRAM | ||
96 | INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_FP_UNAVAIL | ||
97 | INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_DECREMENTER | ||
98 | INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_SYSCALL | ||
99 | INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_TRACE | ||
100 | INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_PERFMON | ||
101 | INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_ALTIVEC | ||
102 | INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_VSX | ||
103 | |||
104 | /* | ||
105 | * This trampoline brings us back to a real mode handler | ||
106 | * | ||
107 | * Input Registers: | ||
108 | * | ||
109 | * R6 = SRR0 | ||
110 | * R7 = SRR1 | ||
111 | * LR = real-mode IP | ||
112 | * | ||
113 | */ | ||
114 | .global kvmppc_handler_lowmem_trampoline | ||
115 | kvmppc_handler_lowmem_trampoline: | ||
116 | |||
117 | mtsrr0 r6 | ||
118 | mtsrr1 r7 | ||
119 | blr | ||
120 | kvmppc_handler_lowmem_trampoline_end: | ||
121 | |||
122 | .global kvmppc_trampoline_lowmem | ||
123 | kvmppc_trampoline_lowmem: | ||
124 | .long kvmppc_handler_lowmem_trampoline - _stext | ||
125 | |||
126 | .global kvmppc_trampoline_enter | ||
127 | kvmppc_trampoline_enter: | ||
128 | .long kvmppc_handler_trampoline_enter - _stext | ||
129 | |||
130 | #include "book3s_64_slb.S" | ||
131 | |||
diff --git a/arch/powerpc/kvm/book3s_64_slb.S b/arch/powerpc/kvm/book3s_64_slb.S new file mode 100644 index 000000000000..ecd237a03fd0 --- /dev/null +++ b/arch/powerpc/kvm/book3s_64_slb.S | |||
@@ -0,0 +1,262 @@ | |||
1 | /* | ||
2 | * This program is free software; you can redistribute it and/or modify | ||
3 | * it under the terms of the GNU General Public License, version 2, as | ||
4 | * published by the Free Software Foundation. | ||
5 | * | ||
6 | * This program is distributed in the hope that it will be useful, | ||
7 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
8 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
9 | * GNU General Public License for more details. | ||
10 | * | ||
11 | * You should have received a copy of the GNU General Public License | ||
12 | * along with this program; if not, write to the Free Software | ||
13 | * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
14 | * | ||
15 | * Copyright SUSE Linux Products GmbH 2009 | ||
16 | * | ||
17 | * Authors: Alexander Graf <agraf@suse.de> | ||
18 | */ | ||
19 | |||
20 | #define SHADOW_SLB_ESID(num) (SLBSHADOW_SAVEAREA + (num * 0x10)) | ||
21 | #define SHADOW_SLB_VSID(num) (SLBSHADOW_SAVEAREA + (num * 0x10) + 0x8) | ||
22 | #define UNBOLT_SLB_ENTRY(num) \ | ||
23 | ld r9, SHADOW_SLB_ESID(num)(r12); \ | ||
24 | /* Invalid? Skip. */; \ | ||
25 | rldicl. r0, r9, 37, 63; \ | ||
26 | beq slb_entry_skip_ ## num; \ | ||
27 | xoris r9, r9, SLB_ESID_V@h; \ | ||
28 | std r9, SHADOW_SLB_ESID(num)(r12); \ | ||
29 | slb_entry_skip_ ## num: | ||
30 | |||
31 | #define REBOLT_SLB_ENTRY(num) \ | ||
32 | ld r10, SHADOW_SLB_ESID(num)(r11); \ | ||
33 | cmpdi r10, 0; \ | ||
34 | beq slb_exit_skip_1; \ | ||
35 | oris r10, r10, SLB_ESID_V@h; \ | ||
36 | ld r9, SHADOW_SLB_VSID(num)(r11); \ | ||
37 | slbmte r9, r10; \ | ||
38 | std r10, SHADOW_SLB_ESID(num)(r11); \ | ||
39 | slb_exit_skip_ ## num: | ||
40 | |||
41 | /****************************************************************************** | ||
42 | * * | ||
43 | * Entry code * | ||
44 | * * | ||
45 | *****************************************************************************/ | ||
46 | |||
47 | .global kvmppc_handler_trampoline_enter | ||
48 | kvmppc_handler_trampoline_enter: | ||
49 | |||
50 | /* Required state: | ||
51 | * | ||
52 | * MSR = ~IR|DR | ||
53 | * R13 = PACA | ||
54 | * R9 = guest IP | ||
55 | * R10 = guest MSR | ||
56 | * R11 = free | ||
57 | * R12 = free | ||
58 | * PACA[PACA_EXMC + EX_R9] = guest R9 | ||
59 | * PACA[PACA_EXMC + EX_R10] = guest R10 | ||
60 | * PACA[PACA_EXMC + EX_R11] = guest R11 | ||
61 | * PACA[PACA_EXMC + EX_R12] = guest R12 | ||
62 | * PACA[PACA_EXMC + EX_R13] = guest R13 | ||
63 | * PACA[PACA_EXMC + EX_CCR] = guest CR | ||
64 | * PACA[PACA_EXMC + EX_R3] = guest XER | ||
65 | */ | ||
66 | |||
67 | mtsrr0 r9 | ||
68 | mtsrr1 r10 | ||
69 | |||
70 | mtspr SPRN_SPRG_SCRATCH0, r0 | ||
71 | |||
72 | /* Remove LPAR shadow entries */ | ||
73 | |||
74 | #if SLB_NUM_BOLTED == 3 | ||
75 | |||
76 | ld r12, PACA_SLBSHADOWPTR(r13) | ||
77 | |||
78 | /* Save off the first entry so we can slbie it later */ | ||
79 | ld r10, SHADOW_SLB_ESID(0)(r12) | ||
80 | ld r11, SHADOW_SLB_VSID(0)(r12) | ||
81 | |||
82 | /* Remove bolted entries */ | ||
83 | UNBOLT_SLB_ENTRY(0) | ||
84 | UNBOLT_SLB_ENTRY(1) | ||
85 | UNBOLT_SLB_ENTRY(2) | ||
86 | |||
87 | #else | ||
88 | #error unknown number of bolted entries | ||
89 | #endif | ||
90 | |||
91 | /* Flush SLB */ | ||
92 | |||
93 | slbia | ||
94 | |||
95 | /* r0 = esid & ESID_MASK */ | ||
96 | rldicr r10, r10, 0, 35 | ||
97 | /* r0 |= CLASS_BIT(VSID) */ | ||
98 | rldic r12, r11, 56 - 36, 36 | ||
99 | or r10, r10, r12 | ||
100 | slbie r10 | ||
101 | |||
102 | isync | ||
103 | |||
104 | /* Fill SLB with our shadow */ | ||
105 | |||
106 | lbz r12, PACA_KVM_SLB_MAX(r13) | ||
107 | mulli r12, r12, 16 | ||
108 | addi r12, r12, PACA_KVM_SLB | ||
109 | add r12, r12, r13 | ||
110 | |||
111 | /* for (r11 = kvm_slb; r11 < kvm_slb + kvm_slb_size; r11+=slb_entry) */ | ||
112 | li r11, PACA_KVM_SLB | ||
113 | add r11, r11, r13 | ||
114 | |||
115 | slb_loop_enter: | ||
116 | |||
117 | ld r10, 0(r11) | ||
118 | |||
119 | rldicl. r0, r10, 37, 63 | ||
120 | beq slb_loop_enter_skip | ||
121 | |||
122 | ld r9, 8(r11) | ||
123 | slbmte r9, r10 | ||
124 | |||
125 | slb_loop_enter_skip: | ||
126 | addi r11, r11, 16 | ||
127 | cmpd cr0, r11, r12 | ||
128 | blt slb_loop_enter | ||
129 | |||
130 | slb_do_enter: | ||
131 | |||
132 | /* Enter guest */ | ||
133 | |||
134 | mfspr r0, SPRN_SPRG_SCRATCH0 | ||
135 | |||
136 | ld r9, (PACA_EXMC+EX_R9)(r13) | ||
137 | ld r10, (PACA_EXMC+EX_R10)(r13) | ||
138 | ld r12, (PACA_EXMC+EX_R12)(r13) | ||
139 | |||
140 | lwz r11, (PACA_EXMC+EX_CCR)(r13) | ||
141 | mtcr r11 | ||
142 | |||
143 | ld r11, (PACA_EXMC+EX_R3)(r13) | ||
144 | mtxer r11 | ||
145 | |||
146 | ld r11, (PACA_EXMC+EX_R11)(r13) | ||
147 | ld r13, (PACA_EXMC+EX_R13)(r13) | ||
148 | |||
149 | RFI | ||
150 | kvmppc_handler_trampoline_enter_end: | ||
151 | |||
152 | |||
153 | |||
154 | /****************************************************************************** | ||
155 | * * | ||
156 | * Exit code * | ||
157 | * * | ||
158 | *****************************************************************************/ | ||
159 | |||
160 | .global kvmppc_handler_trampoline_exit | ||
161 | kvmppc_handler_trampoline_exit: | ||
162 | |||
163 | /* Register usage at this point: | ||
164 | * | ||
165 | * SPRG_SCRATCH0 = guest R13 | ||
166 | * R01 = host R1 | ||
167 | * R02 = host R2 | ||
168 | * R10 = guest PC | ||
169 | * R11 = guest MSR | ||
170 | * R12 = exit handler id | ||
171 | * R13 = PACA | ||
172 | * PACA.exmc.CCR = guest CR | ||
173 | * PACA.exmc.R9 = guest R1 | ||
174 | * PACA.exmc.R10 = guest R10 | ||
175 | * PACA.exmc.R11 = guest R11 | ||
176 | * PACA.exmc.R12 = guest R12 | ||
177 | * PACA.exmc.R13 = guest R2 | ||
178 | * | ||
179 | */ | ||
180 | |||
181 | /* Save registers */ | ||
182 | |||
183 | std r0, (PACA_EXMC+EX_SRR0)(r13) | ||
184 | std r9, (PACA_EXMC+EX_R3)(r13) | ||
185 | std r10, (PACA_EXMC+EX_LR)(r13) | ||
186 | std r11, (PACA_EXMC+EX_DAR)(r13) | ||
187 | |||
188 | /* | ||
189 | * In order for us to easily get the last instruction, | ||
190 | * we got the #vmexit at, we exploit the fact that the | ||
191 | * virtual layout is still the same here, so we can just | ||
192 | * ld from the guest's PC address | ||
193 | */ | ||
194 | |||
195 | /* We only load the last instruction when it's safe */ | ||
196 | cmpwi r12, BOOK3S_INTERRUPT_DATA_STORAGE | ||
197 | beq ld_last_inst | ||
198 | cmpwi r12, BOOK3S_INTERRUPT_PROGRAM | ||
199 | beq ld_last_inst | ||
200 | |||
201 | b no_ld_last_inst | ||
202 | |||
203 | ld_last_inst: | ||
204 | /* Save off the guest instruction we're at */ | ||
205 | /* 1) enable paging for data */ | ||
206 | mfmsr r9 | ||
207 | ori r11, r9, MSR_DR /* Enable paging for data */ | ||
208 | mtmsr r11 | ||
209 | /* 2) fetch the instruction */ | ||
210 | lwz r0, 0(r10) | ||
211 | /* 3) disable paging again */ | ||
212 | mtmsr r9 | ||
213 | |||
214 | no_ld_last_inst: | ||
215 | |||
216 | /* Restore bolted entries from the shadow and fix it along the way */ | ||
217 | |||
218 | /* We don't store anything in entry 0, so we don't need to take care of it */ | ||
219 | slbia | ||
220 | isync | ||
221 | |||
222 | #if SLB_NUM_BOLTED == 3 | ||
223 | |||
224 | ld r11, PACA_SLBSHADOWPTR(r13) | ||
225 | |||
226 | REBOLT_SLB_ENTRY(0) | ||
227 | REBOLT_SLB_ENTRY(1) | ||
228 | REBOLT_SLB_ENTRY(2) | ||
229 | |||
230 | #else | ||
231 | #error unknown number of bolted entries | ||
232 | #endif | ||
233 | |||
234 | slb_do_exit: | ||
235 | |||
236 | /* Restore registers */ | ||
237 | |||
238 | ld r11, (PACA_EXMC+EX_DAR)(r13) | ||
239 | ld r10, (PACA_EXMC+EX_LR)(r13) | ||
240 | ld r9, (PACA_EXMC+EX_R3)(r13) | ||
241 | |||
242 | /* Save last inst */ | ||
243 | stw r0, (PACA_EXMC+EX_LR)(r13) | ||
244 | |||
245 | /* Save DAR and DSISR before going to paged mode */ | ||
246 | mfdar r0 | ||
247 | std r0, (PACA_EXMC+EX_DAR)(r13) | ||
248 | mfdsisr r0 | ||
249 | stw r0, (PACA_EXMC+EX_DSISR)(r13) | ||
250 | |||
251 | /* RFI into the highmem handler */ | ||
252 | mfmsr r0 | ||
253 | ori r0, r0, MSR_IR|MSR_DR|MSR_RI /* Enable paging */ | ||
254 | mtsrr1 r0 | ||
255 | ld r0, PACASAVEDMSR(r13) /* Highmem handler address */ | ||
256 | mtsrr0 r0 | ||
257 | |||
258 | mfspr r0, SPRN_SPRG_SCRATCH0 | ||
259 | |||
260 | RFI | ||
261 | kvmppc_handler_trampoline_exit_end: | ||
262 | |||
diff --git a/arch/powerpc/kvm/booke.c b/arch/powerpc/kvm/booke.c index e7bf4d029484..06f5a9ecc42c 100644 --- a/arch/powerpc/kvm/booke.c +++ b/arch/powerpc/kvm/booke.c | |||
@@ -520,6 +520,11 @@ int kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu, | |||
520 | return kvmppc_core_vcpu_translate(vcpu, tr); | 520 | return kvmppc_core_vcpu_translate(vcpu, tr); |
521 | } | 521 | } |
522 | 522 | ||
523 | int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm, struct kvm_dirty_log *log) | ||
524 | { | ||
525 | return -ENOTSUPP; | ||
526 | } | ||
527 | |||
523 | int __init kvmppc_booke_init(void) | 528 | int __init kvmppc_booke_init(void) |
524 | { | 529 | { |
525 | unsigned long ivor[16]; | 530 | unsigned long ivor[16]; |
diff --git a/arch/powerpc/kvm/emulate.c b/arch/powerpc/kvm/emulate.c index 7737146af3fb..4a9ac6640fad 100644 --- a/arch/powerpc/kvm/emulate.c +++ b/arch/powerpc/kvm/emulate.c | |||
@@ -18,7 +18,7 @@ | |||
18 | */ | 18 | */ |
19 | 19 | ||
20 | #include <linux/jiffies.h> | 20 | #include <linux/jiffies.h> |
21 | #include <linux/timer.h> | 21 | #include <linux/hrtimer.h> |
22 | #include <linux/types.h> | 22 | #include <linux/types.h> |
23 | #include <linux/string.h> | 23 | #include <linux/string.h> |
24 | #include <linux/kvm_host.h> | 24 | #include <linux/kvm_host.h> |
@@ -32,6 +32,7 @@ | |||
32 | #include "trace.h" | 32 | #include "trace.h" |
33 | 33 | ||
34 | #define OP_TRAP 3 | 34 | #define OP_TRAP 3 |
35 | #define OP_TRAP_64 2 | ||
35 | 36 | ||
36 | #define OP_31_XOP_LWZX 23 | 37 | #define OP_31_XOP_LWZX 23 |
37 | #define OP_31_XOP_LBZX 87 | 38 | #define OP_31_XOP_LBZX 87 |
@@ -64,19 +65,45 @@ | |||
64 | #define OP_STH 44 | 65 | #define OP_STH 44 |
65 | #define OP_STHU 45 | 66 | #define OP_STHU 45 |
66 | 67 | ||
68 | #ifdef CONFIG_PPC64 | ||
69 | static int kvmppc_dec_enabled(struct kvm_vcpu *vcpu) | ||
70 | { | ||
71 | return 1; | ||
72 | } | ||
73 | #else | ||
74 | static int kvmppc_dec_enabled(struct kvm_vcpu *vcpu) | ||
75 | { | ||
76 | return vcpu->arch.tcr & TCR_DIE; | ||
77 | } | ||
78 | #endif | ||
79 | |||
67 | void kvmppc_emulate_dec(struct kvm_vcpu *vcpu) | 80 | void kvmppc_emulate_dec(struct kvm_vcpu *vcpu) |
68 | { | 81 | { |
69 | if (vcpu->arch.tcr & TCR_DIE) { | 82 | unsigned long dec_nsec; |
83 | |||
84 | pr_debug("mtDEC: %x\n", vcpu->arch.dec); | ||
85 | #ifdef CONFIG_PPC64 | ||
86 | /* POWER4+ triggers a dec interrupt if the value is < 0 */ | ||
87 | if (vcpu->arch.dec & 0x80000000) { | ||
88 | hrtimer_try_to_cancel(&vcpu->arch.dec_timer); | ||
89 | kvmppc_core_queue_dec(vcpu); | ||
90 | return; | ||
91 | } | ||
92 | #endif | ||
93 | if (kvmppc_dec_enabled(vcpu)) { | ||
70 | /* The decrementer ticks at the same rate as the timebase, so | 94 | /* The decrementer ticks at the same rate as the timebase, so |
71 | * that's how we convert the guest DEC value to the number of | 95 | * that's how we convert the guest DEC value to the number of |
72 | * host ticks. */ | 96 | * host ticks. */ |
73 | unsigned long nr_jiffies; | ||
74 | 97 | ||
75 | nr_jiffies = vcpu->arch.dec / tb_ticks_per_jiffy; | 98 | hrtimer_try_to_cancel(&vcpu->arch.dec_timer); |
76 | mod_timer(&vcpu->arch.dec_timer, | 99 | dec_nsec = vcpu->arch.dec; |
77 | get_jiffies_64() + nr_jiffies); | 100 | dec_nsec *= 1000; |
101 | dec_nsec /= tb_ticks_per_usec; | ||
102 | hrtimer_start(&vcpu->arch.dec_timer, ktime_set(0, dec_nsec), | ||
103 | HRTIMER_MODE_REL); | ||
104 | vcpu->arch.dec_jiffies = get_tb(); | ||
78 | } else { | 105 | } else { |
79 | del_timer(&vcpu->arch.dec_timer); | 106 | hrtimer_try_to_cancel(&vcpu->arch.dec_timer); |
80 | } | 107 | } |
81 | } | 108 | } |
82 | 109 | ||
@@ -111,9 +138,15 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu) | |||
111 | /* this default type might be overwritten by subcategories */ | 138 | /* this default type might be overwritten by subcategories */ |
112 | kvmppc_set_exit_type(vcpu, EMULATED_INST_EXITS); | 139 | kvmppc_set_exit_type(vcpu, EMULATED_INST_EXITS); |
113 | 140 | ||
141 | pr_debug(KERN_INFO "Emulating opcode %d / %d\n", get_op(inst), get_xop(inst)); | ||
142 | |||
114 | switch (get_op(inst)) { | 143 | switch (get_op(inst)) { |
115 | case OP_TRAP: | 144 | case OP_TRAP: |
145 | #ifdef CONFIG_PPC64 | ||
146 | case OP_TRAP_64: | ||
147 | #else | ||
116 | vcpu->arch.esr |= ESR_PTR; | 148 | vcpu->arch.esr |= ESR_PTR; |
149 | #endif | ||
117 | kvmppc_core_queue_program(vcpu); | 150 | kvmppc_core_queue_program(vcpu); |
118 | advance = 0; | 151 | advance = 0; |
119 | break; | 152 | break; |
@@ -188,17 +221,19 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu) | |||
188 | case SPRN_SRR1: | 221 | case SPRN_SRR1: |
189 | vcpu->arch.gpr[rt] = vcpu->arch.srr1; break; | 222 | vcpu->arch.gpr[rt] = vcpu->arch.srr1; break; |
190 | case SPRN_PVR: | 223 | case SPRN_PVR: |
191 | vcpu->arch.gpr[rt] = mfspr(SPRN_PVR); break; | 224 | vcpu->arch.gpr[rt] = vcpu->arch.pvr; break; |
192 | case SPRN_PIR: | 225 | case SPRN_PIR: |
193 | vcpu->arch.gpr[rt] = mfspr(SPRN_PIR); break; | 226 | vcpu->arch.gpr[rt] = vcpu->vcpu_id; break; |
227 | case SPRN_MSSSR0: | ||
228 | vcpu->arch.gpr[rt] = 0; break; | ||
194 | 229 | ||
195 | /* Note: mftb and TBRL/TBWL are user-accessible, so | 230 | /* Note: mftb and TBRL/TBWL are user-accessible, so |
196 | * the guest can always access the real TB anyways. | 231 | * the guest can always access the real TB anyways. |
197 | * In fact, we probably will never see these traps. */ | 232 | * In fact, we probably will never see these traps. */ |
198 | case SPRN_TBWL: | 233 | case SPRN_TBWL: |
199 | vcpu->arch.gpr[rt] = mftbl(); break; | 234 | vcpu->arch.gpr[rt] = get_tb() >> 32; break; |
200 | case SPRN_TBWU: | 235 | case SPRN_TBWU: |
201 | vcpu->arch.gpr[rt] = mftbu(); break; | 236 | vcpu->arch.gpr[rt] = get_tb(); break; |
202 | 237 | ||
203 | case SPRN_SPRG0: | 238 | case SPRN_SPRG0: |
204 | vcpu->arch.gpr[rt] = vcpu->arch.sprg0; break; | 239 | vcpu->arch.gpr[rt] = vcpu->arch.sprg0; break; |
@@ -211,6 +246,13 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu) | |||
211 | /* Note: SPRG4-7 are user-readable, so we don't get | 246 | /* Note: SPRG4-7 are user-readable, so we don't get |
212 | * a trap. */ | 247 | * a trap. */ |
213 | 248 | ||
249 | case SPRN_DEC: | ||
250 | { | ||
251 | u64 jd = get_tb() - vcpu->arch.dec_jiffies; | ||
252 | vcpu->arch.gpr[rt] = vcpu->arch.dec - jd; | ||
253 | pr_debug(KERN_INFO "mfDEC: %x - %llx = %lx\n", vcpu->arch.dec, jd, vcpu->arch.gpr[rt]); | ||
254 | break; | ||
255 | } | ||
214 | default: | 256 | default: |
215 | emulated = kvmppc_core_emulate_mfspr(vcpu, sprn, rt); | 257 | emulated = kvmppc_core_emulate_mfspr(vcpu, sprn, rt); |
216 | if (emulated == EMULATE_FAIL) { | 258 | if (emulated == EMULATE_FAIL) { |
@@ -260,6 +302,8 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu) | |||
260 | case SPRN_TBWL: break; | 302 | case SPRN_TBWL: break; |
261 | case SPRN_TBWU: break; | 303 | case SPRN_TBWU: break; |
262 | 304 | ||
305 | case SPRN_MSSSR0: break; | ||
306 | |||
263 | case SPRN_DEC: | 307 | case SPRN_DEC: |
264 | vcpu->arch.dec = vcpu->arch.gpr[rs]; | 308 | vcpu->arch.dec = vcpu->arch.gpr[rs]; |
265 | kvmppc_emulate_dec(vcpu); | 309 | kvmppc_emulate_dec(vcpu); |
diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c index 2a4551f78f60..692c3709011e 100644 --- a/arch/powerpc/kvm/powerpc.c +++ b/arch/powerpc/kvm/powerpc.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/kvm_host.h> | 23 | #include <linux/kvm_host.h> |
24 | #include <linux/module.h> | 24 | #include <linux/module.h> |
25 | #include <linux/vmalloc.h> | 25 | #include <linux/vmalloc.h> |
26 | #include <linux/hrtimer.h> | ||
26 | #include <linux/fs.h> | 27 | #include <linux/fs.h> |
27 | #include <asm/cputable.h> | 28 | #include <asm/cputable.h> |
28 | #include <asm/uaccess.h> | 29 | #include <asm/uaccess.h> |
@@ -208,10 +209,25 @@ static void kvmppc_decrementer_func(unsigned long data) | |||
208 | } | 209 | } |
209 | } | 210 | } |
210 | 211 | ||
212 | /* | ||
213 | * low level hrtimer wake routine. Because this runs in hardirq context | ||
214 | * we schedule a tasklet to do the real work. | ||
215 | */ | ||
216 | enum hrtimer_restart kvmppc_decrementer_wakeup(struct hrtimer *timer) | ||
217 | { | ||
218 | struct kvm_vcpu *vcpu; | ||
219 | |||
220 | vcpu = container_of(timer, struct kvm_vcpu, arch.dec_timer); | ||
221 | tasklet_schedule(&vcpu->arch.tasklet); | ||
222 | |||
223 | return HRTIMER_NORESTART; | ||
224 | } | ||
225 | |||
211 | int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu) | 226 | int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu) |
212 | { | 227 | { |
213 | setup_timer(&vcpu->arch.dec_timer, kvmppc_decrementer_func, | 228 | hrtimer_init(&vcpu->arch.dec_timer, CLOCK_REALTIME, HRTIMER_MODE_ABS); |
214 | (unsigned long)vcpu); | 229 | tasklet_init(&vcpu->arch.tasklet, kvmppc_decrementer_func, (ulong)vcpu); |
230 | vcpu->arch.dec_timer.function = kvmppc_decrementer_wakeup; | ||
215 | 231 | ||
216 | return 0; | 232 | return 0; |
217 | } | 233 | } |
@@ -409,11 +425,6 @@ out: | |||
409 | return r; | 425 | return r; |
410 | } | 426 | } |
411 | 427 | ||
412 | int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm, struct kvm_dirty_log *log) | ||
413 | { | ||
414 | return -ENOTSUPP; | ||
415 | } | ||
416 | |||
417 | long kvm_arch_vm_ioctl(struct file *filp, | 428 | long kvm_arch_vm_ioctl(struct file *filp, |
418 | unsigned int ioctl, unsigned long arg) | 429 | unsigned int ioctl, unsigned long arg) |
419 | { | 430 | { |
diff --git a/arch/powerpc/kvm/trace.h b/arch/powerpc/kvm/trace.h index 67f219de0455..a8e840018052 100644 --- a/arch/powerpc/kvm/trace.h +++ b/arch/powerpc/kvm/trace.h | |||
@@ -12,8 +12,8 @@ | |||
12 | * Tracepoint for guest mode entry. | 12 | * Tracepoint for guest mode entry. |
13 | */ | 13 | */ |
14 | TRACE_EVENT(kvm_ppc_instr, | 14 | TRACE_EVENT(kvm_ppc_instr, |
15 | TP_PROTO(unsigned int inst, unsigned long pc, unsigned int emulate), | 15 | TP_PROTO(unsigned int inst, unsigned long _pc, unsigned int emulate), |
16 | TP_ARGS(inst, pc, emulate), | 16 | TP_ARGS(inst, _pc, emulate), |
17 | 17 | ||
18 | TP_STRUCT__entry( | 18 | TP_STRUCT__entry( |
19 | __field( unsigned int, inst ) | 19 | __field( unsigned int, inst ) |
@@ -23,7 +23,7 @@ TRACE_EVENT(kvm_ppc_instr, | |||
23 | 23 | ||
24 | TP_fast_assign( | 24 | TP_fast_assign( |
25 | __entry->inst = inst; | 25 | __entry->inst = inst; |
26 | __entry->pc = pc; | 26 | __entry->pc = _pc; |
27 | __entry->emulate = emulate; | 27 | __entry->emulate = emulate; |
28 | ), | 28 | ), |
29 | 29 | ||
diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c index fa251f8c2f82..6810128aba30 100644 --- a/arch/powerpc/mm/hash_utils_64.c +++ b/arch/powerpc/mm/hash_utils_64.c | |||
@@ -92,6 +92,7 @@ struct mmu_psize_def mmu_psize_defs[MMU_PAGE_COUNT]; | |||
92 | struct hash_pte *htab_address; | 92 | struct hash_pte *htab_address; |
93 | unsigned long htab_size_bytes; | 93 | unsigned long htab_size_bytes; |
94 | unsigned long htab_hash_mask; | 94 | unsigned long htab_hash_mask; |
95 | EXPORT_SYMBOL_GPL(htab_hash_mask); | ||
95 | int mmu_linear_psize = MMU_PAGE_4K; | 96 | int mmu_linear_psize = MMU_PAGE_4K; |
96 | int mmu_virtual_psize = MMU_PAGE_4K; | 97 | int mmu_virtual_psize = MMU_PAGE_4K; |
97 | int mmu_vmalloc_psize = MMU_PAGE_4K; | 98 | int mmu_vmalloc_psize = MMU_PAGE_4K; |
@@ -102,6 +103,7 @@ int mmu_io_psize = MMU_PAGE_4K; | |||
102 | int mmu_kernel_ssize = MMU_SEGSIZE_256M; | 103 | int mmu_kernel_ssize = MMU_SEGSIZE_256M; |
103 | int mmu_highuser_ssize = MMU_SEGSIZE_256M; | 104 | int mmu_highuser_ssize = MMU_SEGSIZE_256M; |
104 | u16 mmu_slb_size = 64; | 105 | u16 mmu_slb_size = 64; |
106 | EXPORT_SYMBOL_GPL(mmu_slb_size); | ||
105 | #ifdef CONFIG_HUGETLB_PAGE | 107 | #ifdef CONFIG_HUGETLB_PAGE |
106 | unsigned int HPAGE_SHIFT; | 108 | unsigned int HPAGE_SHIFT; |
107 | #endif | 109 | #endif |
diff --git a/arch/powerpc/mm/mmu_context_hash64.c b/arch/powerpc/mm/mmu_context_hash64.c index dbeb86ac90cd..b9e4cc2c2057 100644 --- a/arch/powerpc/mm/mmu_context_hash64.c +++ b/arch/powerpc/mm/mmu_context_hash64.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/mm.h> | 18 | #include <linux/mm.h> |
19 | #include <linux/spinlock.h> | 19 | #include <linux/spinlock.h> |
20 | #include <linux/idr.h> | 20 | #include <linux/idr.h> |
21 | #include <linux/module.h> | ||
21 | 22 | ||
22 | #include <asm/mmu_context.h> | 23 | #include <asm/mmu_context.h> |
23 | 24 | ||
@@ -32,7 +33,7 @@ static DEFINE_IDR(mmu_context_idr); | |||
32 | #define NO_CONTEXT 0 | 33 | #define NO_CONTEXT 0 |
33 | #define MAX_CONTEXT ((1UL << 19) - 1) | 34 | #define MAX_CONTEXT ((1UL << 19) - 1) |
34 | 35 | ||
35 | int init_new_context(struct task_struct *tsk, struct mm_struct *mm) | 36 | int __init_new_context(void) |
36 | { | 37 | { |
37 | int index; | 38 | int index; |
38 | int err; | 39 | int err; |
@@ -57,6 +58,18 @@ again: | |||
57 | return -ENOMEM; | 58 | return -ENOMEM; |
58 | } | 59 | } |
59 | 60 | ||
61 | return index; | ||
62 | } | ||
63 | EXPORT_SYMBOL_GPL(__init_new_context); | ||
64 | |||
65 | int init_new_context(struct task_struct *tsk, struct mm_struct *mm) | ||
66 | { | ||
67 | int index; | ||
68 | |||
69 | index = __init_new_context(); | ||
70 | if (index < 0) | ||
71 | return index; | ||
72 | |||
60 | /* The old code would re-promote on fork, we don't do that | 73 | /* The old code would re-promote on fork, we don't do that |
61 | * when using slices as it could cause problem promoting slices | 74 | * when using slices as it could cause problem promoting slices |
62 | * that have been forced down to 4K | 75 | * that have been forced down to 4K |
@@ -68,11 +81,16 @@ again: | |||
68 | return 0; | 81 | return 0; |
69 | } | 82 | } |
70 | 83 | ||
71 | void destroy_context(struct mm_struct *mm) | 84 | void __destroy_context(int context_id) |
72 | { | 85 | { |
73 | spin_lock(&mmu_context_lock); | 86 | spin_lock(&mmu_context_lock); |
74 | idr_remove(&mmu_context_idr, mm->context.id); | 87 | idr_remove(&mmu_context_idr, context_id); |
75 | spin_unlock(&mmu_context_lock); | 88 | spin_unlock(&mmu_context_lock); |
89 | } | ||
90 | EXPORT_SYMBOL_GPL(__destroy_context); | ||
76 | 91 | ||
92 | void destroy_context(struct mm_struct *mm) | ||
93 | { | ||
94 | __destroy_context(mm->context.id); | ||
77 | mm->context.id = NO_CONTEXT; | 95 | mm->context.id = NO_CONTEXT; |
78 | } | 96 | } |