aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/kvm.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/kernel/kvm.c')
-rw-r--r--arch/powerpc/kernel/kvm.c50
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
70static bool kvm_patching_worked = true; 73static bool kvm_patching_worked = true;
71static char kvm_tmp[1024 * 1024]; 74static char kvm_tmp[1024 * 1024];
72static int kvm_tmp_index; 75static 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
229extern u32 kvm_emulate_wrteei_branch_offs;
230extern u32 kvm_emulate_wrteei_ee_offs;
231extern u32 kvm_emulate_wrteei_len;
232extern u32 kvm_emulate_wrteei[];
233
234static 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
224static void kvm_map_magic_page(void *data) 268static 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