diff options
Diffstat (limited to 'arch/powerpc/kernel/kvm.c')
-rw-r--r-- | arch/powerpc/kernel/kvm.c | 50 |
1 files changed, 50 insertions, 0 deletions
diff --git a/arch/powerpc/kernel/kvm.c b/arch/powerpc/kernel/kvm.c index 8ac57e2c52f..e93681753de 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 | ||