diff options
-rw-r--r-- | arch/powerpc/kernel/kvm.c | 50 | ||||
-rw-r--r-- | arch/powerpc/kernel/kvm_emul.S | 41 |
2 files changed, 91 insertions, 0 deletions
diff --git a/arch/powerpc/kernel/kvm.c b/arch/powerpc/kernel/kvm.c index 8ac57e2c52fa..e93681753deb 100644 --- a/arch/powerpc/kernel/kvm.c +++ b/arch/powerpc/kernel/kvm.c | |||
@@ -67,6 +67,9 @@ | |||
67 | #define KVM_INST_MTMSRD_L1 0x7c010164 | 67 | #define KVM_INST_MTMSRD_L1 0x7c010164 |
68 | #define KVM_INST_MTMSR 0x7c000124 | 68 | #define KVM_INST_MTMSR 0x7c000124 |
69 | 69 | ||
70 | #define KVM_INST_WRTEEI_0 0x7c000146 | ||
71 | #define KVM_INST_WRTEEI_1 0x7c008146 | ||
72 | |||
70 | static bool kvm_patching_worked = true; | 73 | static bool kvm_patching_worked = true; |
71 | static char kvm_tmp[1024 * 1024]; | 74 | static char kvm_tmp[1024 * 1024]; |
72 | static int kvm_tmp_index; | 75 | static int kvm_tmp_index; |
@@ -221,6 +224,47 @@ static void kvm_patch_ins_mtmsr(u32 *inst, u32 rt) | |||
221 | kvm_patch_ins_b(inst, distance_start); | 224 | kvm_patch_ins_b(inst, distance_start); |
222 | } | 225 | } |
223 | 226 | ||
227 | #ifdef CONFIG_BOOKE | ||
228 | |||
229 | extern u32 kvm_emulate_wrteei_branch_offs; | ||
230 | extern u32 kvm_emulate_wrteei_ee_offs; | ||
231 | extern u32 kvm_emulate_wrteei_len; | ||
232 | extern u32 kvm_emulate_wrteei[]; | ||
233 | |||
234 | static void kvm_patch_ins_wrteei(u32 *inst) | ||
235 | { | ||
236 | u32 *p; | ||
237 | int distance_start; | ||
238 | int distance_end; | ||
239 | ulong next_inst; | ||
240 | |||
241 | p = kvm_alloc(kvm_emulate_wrteei_len * 4); | ||
242 | if (!p) | ||
243 | return; | ||
244 | |||
245 | /* Find out where we are and put everything there */ | ||
246 | distance_start = (ulong)p - (ulong)inst; | ||
247 | next_inst = ((ulong)inst + 4); | ||
248 | distance_end = next_inst - (ulong)&p[kvm_emulate_wrteei_branch_offs]; | ||
249 | |||
250 | /* Make sure we only write valid b instructions */ | ||
251 | if (distance_start > KVM_INST_B_MAX) { | ||
252 | kvm_patching_worked = false; | ||
253 | return; | ||
254 | } | ||
255 | |||
256 | /* Modify the chunk to fit the invocation */ | ||
257 | memcpy(p, kvm_emulate_wrteei, kvm_emulate_wrteei_len * 4); | ||
258 | p[kvm_emulate_wrteei_branch_offs] |= distance_end & KVM_INST_B_MASK; | ||
259 | p[kvm_emulate_wrteei_ee_offs] |= (*inst & MSR_EE); | ||
260 | flush_icache_range((ulong)p, (ulong)p + kvm_emulate_wrteei_len * 4); | ||
261 | |||
262 | /* Patch the invocation */ | ||
263 | kvm_patch_ins_b(inst, distance_start); | ||
264 | } | ||
265 | |||
266 | #endif | ||
267 | |||
224 | static void kvm_map_magic_page(void *data) | 268 | static void kvm_map_magic_page(void *data) |
225 | { | 269 | { |
226 | kvm_hypercall2(KVM_HC_PPC_MAP_MAGIC_PAGE, | 270 | kvm_hypercall2(KVM_HC_PPC_MAP_MAGIC_PAGE, |
@@ -310,6 +354,12 @@ static void kvm_check_ins(u32 *inst) | |||
310 | } | 354 | } |
311 | 355 | ||
312 | switch (_inst) { | 356 | switch (_inst) { |
357 | #ifdef CONFIG_BOOKE | ||
358 | case KVM_INST_WRTEEI_0: | ||
359 | case KVM_INST_WRTEEI_1: | ||
360 | kvm_patch_ins_wrteei(inst); | ||
361 | break; | ||
362 | #endif | ||
313 | } | 363 | } |
314 | } | 364 | } |
315 | 365 | ||
diff --git a/arch/powerpc/kernel/kvm_emul.S b/arch/powerpc/kernel/kvm_emul.S index 8cd22f47dd01..3199f65ede2c 100644 --- a/arch/powerpc/kernel/kvm_emul.S +++ b/arch/powerpc/kernel/kvm_emul.S | |||
@@ -204,3 +204,44 @@ kvm_emulate_mtmsr_orig_ins_offs: | |||
204 | .global kvm_emulate_mtmsr_len | 204 | .global kvm_emulate_mtmsr_len |
205 | kvm_emulate_mtmsr_len: | 205 | kvm_emulate_mtmsr_len: |
206 | .long (kvm_emulate_mtmsr_end - kvm_emulate_mtmsr) / 4 | 206 | .long (kvm_emulate_mtmsr_end - kvm_emulate_mtmsr) / 4 |
207 | |||
208 | |||
209 | |||
210 | .global kvm_emulate_wrteei | ||
211 | kvm_emulate_wrteei: | ||
212 | |||
213 | SCRATCH_SAVE | ||
214 | |||
215 | /* Fetch old MSR in r31 */ | ||
216 | LL64(r31, KVM_MAGIC_PAGE + KVM_MAGIC_MSR, 0) | ||
217 | |||
218 | /* Remove MSR_EE from old MSR */ | ||
219 | li r30, 0 | ||
220 | ori r30, r30, MSR_EE | ||
221 | andc r31, r31, r30 | ||
222 | |||
223 | /* OR new MSR_EE onto the old MSR */ | ||
224 | kvm_emulate_wrteei_ee: | ||
225 | ori r31, r31, 0 | ||
226 | |||
227 | /* Write new MSR value back */ | ||
228 | STL64(r31, KVM_MAGIC_PAGE + KVM_MAGIC_MSR, 0) | ||
229 | |||
230 | SCRATCH_RESTORE | ||
231 | |||
232 | /* Go back to caller */ | ||
233 | kvm_emulate_wrteei_branch: | ||
234 | b . | ||
235 | kvm_emulate_wrteei_end: | ||
236 | |||
237 | .global kvm_emulate_wrteei_branch_offs | ||
238 | kvm_emulate_wrteei_branch_offs: | ||
239 | .long (kvm_emulate_wrteei_branch - kvm_emulate_wrteei) / 4 | ||
240 | |||
241 | .global kvm_emulate_wrteei_ee_offs | ||
242 | kvm_emulate_wrteei_ee_offs: | ||
243 | .long (kvm_emulate_wrteei_ee - kvm_emulate_wrteei) / 4 | ||
244 | |||
245 | .global kvm_emulate_wrteei_len | ||
246 | kvm_emulate_wrteei_len: | ||
247 | .long (kvm_emulate_wrteei_end - kvm_emulate_wrteei) / 4 | ||