aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/powerpc/kernel/kvm.c50
-rw-r--r--arch/powerpc/kernel/kvm_emul.S41
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
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
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
205kvm_emulate_mtmsr_len: 205kvm_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
211kvm_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 */
224kvm_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 */
233kvm_emulate_wrteei_branch:
234 b .
235kvm_emulate_wrteei_end:
236
237.global kvm_emulate_wrteei_branch_offs
238kvm_emulate_wrteei_branch_offs:
239 .long (kvm_emulate_wrteei_branch - kvm_emulate_wrteei) / 4
240
241.global kvm_emulate_wrteei_ee_offs
242kvm_emulate_wrteei_ee_offs:
243 .long (kvm_emulate_wrteei_ee - kvm_emulate_wrteei) / 4
244
245.global kvm_emulate_wrteei_len
246kvm_emulate_wrteei_len:
247 .long (kvm_emulate_wrteei_end - kvm_emulate_wrteei) / 4