diff options
author | Scott Wood <scottwood@freescale.com> | 2011-11-08 19:23:28 -0500 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2012-03-05 07:52:26 -0500 |
commit | 940b45ec18cf00046b8b28299d97066a2c43d559 (patch) | |
tree | a3a768ff3b6fcda9cbed00d93dac1bbf2b95f20c /arch/powerpc/kernel/kvm.c | |
parent | 29ac26efbdc651303643025c83009ce5766c1676 (diff) |
KVM: PPC: booke: Paravirtualize wrtee
Also fix wrteei 1 paravirt to check for a pending interrupt.
Signed-off-by: Scott Wood <scottwood@freescale.com>
Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Avi Kivity <avi@redhat.com>
Diffstat (limited to 'arch/powerpc/kernel/kvm.c')
-rw-r--r-- | arch/powerpc/kernel/kvm.c | 92 |
1 files changed, 80 insertions, 12 deletions
diff --git a/arch/powerpc/kernel/kvm.c b/arch/powerpc/kernel/kvm.c index 2985338d0e10..06b15ee997f7 100644 --- a/arch/powerpc/kernel/kvm.c +++ b/arch/powerpc/kernel/kvm.c | |||
@@ -1,5 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2010 SUSE Linux Products GmbH. All rights reserved. | 2 | * Copyright (C) 2010 SUSE Linux Products GmbH. All rights reserved. |
3 | * Copyright 2010-2011 Freescale Semiconductor, Inc. | ||
3 | * | 4 | * |
4 | * Authors: | 5 | * Authors: |
5 | * Alexander Graf <agraf@suse.de> | 6 | * Alexander Graf <agraf@suse.de> |
@@ -29,6 +30,7 @@ | |||
29 | #include <asm/sections.h> | 30 | #include <asm/sections.h> |
30 | #include <asm/cacheflush.h> | 31 | #include <asm/cacheflush.h> |
31 | #include <asm/disassemble.h> | 32 | #include <asm/disassemble.h> |
33 | #include <asm/ppc-opcode.h> | ||
32 | 34 | ||
33 | #define KVM_MAGIC_PAGE (-4096L) | 35 | #define KVM_MAGIC_PAGE (-4096L) |
34 | #define magic_var(x) KVM_MAGIC_PAGE + offsetof(struct kvm_vcpu_arch_shared, x) | 36 | #define magic_var(x) KVM_MAGIC_PAGE + offsetof(struct kvm_vcpu_arch_shared, x) |
@@ -41,6 +43,7 @@ | |||
41 | #define KVM_INST_B 0x48000000 | 43 | #define KVM_INST_B 0x48000000 |
42 | #define KVM_INST_B_MASK 0x03ffffff | 44 | #define KVM_INST_B_MASK 0x03ffffff |
43 | #define KVM_INST_B_MAX 0x01ffffff | 45 | #define KVM_INST_B_MAX 0x01ffffff |
46 | #define KVM_INST_LI 0x38000000 | ||
44 | 47 | ||
45 | #define KVM_MASK_RT 0x03e00000 | 48 | #define KVM_MASK_RT 0x03e00000 |
46 | #define KVM_RT_30 0x03c00000 | 49 | #define KVM_RT_30 0x03c00000 |
@@ -69,6 +72,7 @@ | |||
69 | #define KVM_INST_MTMSRD_L1 0x7c010164 | 72 | #define KVM_INST_MTMSRD_L1 0x7c010164 |
70 | #define KVM_INST_MTMSR 0x7c000124 | 73 | #define KVM_INST_MTMSR 0x7c000124 |
71 | 74 | ||
75 | #define KVM_INST_WRTEE 0x7c000106 | ||
72 | #define KVM_INST_WRTEEI_0 0x7c000146 | 76 | #define KVM_INST_WRTEEI_0 0x7c000146 |
73 | #define KVM_INST_WRTEEI_1 0x7c008146 | 77 | #define KVM_INST_WRTEEI_1 0x7c008146 |
74 | 78 | ||
@@ -270,26 +274,27 @@ static void kvm_patch_ins_mtmsr(u32 *inst, u32 rt) | |||
270 | 274 | ||
271 | #ifdef CONFIG_BOOKE | 275 | #ifdef CONFIG_BOOKE |
272 | 276 | ||
273 | extern u32 kvm_emulate_wrteei_branch_offs; | 277 | extern u32 kvm_emulate_wrtee_branch_offs; |
274 | extern u32 kvm_emulate_wrteei_ee_offs; | 278 | extern u32 kvm_emulate_wrtee_reg_offs; |
275 | extern u32 kvm_emulate_wrteei_len; | 279 | extern u32 kvm_emulate_wrtee_orig_ins_offs; |
276 | extern u32 kvm_emulate_wrteei[]; | 280 | extern u32 kvm_emulate_wrtee_len; |
281 | extern u32 kvm_emulate_wrtee[]; | ||
277 | 282 | ||
278 | static void kvm_patch_ins_wrteei(u32 *inst) | 283 | static void kvm_patch_ins_wrtee(u32 *inst, u32 rt, int imm_one) |
279 | { | 284 | { |
280 | u32 *p; | 285 | u32 *p; |
281 | int distance_start; | 286 | int distance_start; |
282 | int distance_end; | 287 | int distance_end; |
283 | ulong next_inst; | 288 | ulong next_inst; |
284 | 289 | ||
285 | p = kvm_alloc(kvm_emulate_wrteei_len * 4); | 290 | p = kvm_alloc(kvm_emulate_wrtee_len * 4); |
286 | if (!p) | 291 | if (!p) |
287 | return; | 292 | return; |
288 | 293 | ||
289 | /* Find out where we are and put everything there */ | 294 | /* Find out where we are and put everything there */ |
290 | distance_start = (ulong)p - (ulong)inst; | 295 | distance_start = (ulong)p - (ulong)inst; |
291 | next_inst = ((ulong)inst + 4); | 296 | next_inst = ((ulong)inst + 4); |
292 | distance_end = next_inst - (ulong)&p[kvm_emulate_wrteei_branch_offs]; | 297 | distance_end = next_inst - (ulong)&p[kvm_emulate_wrtee_branch_offs]; |
293 | 298 | ||
294 | /* Make sure we only write valid b instructions */ | 299 | /* Make sure we only write valid b instructions */ |
295 | if (distance_start > KVM_INST_B_MAX) { | 300 | if (distance_start > KVM_INST_B_MAX) { |
@@ -298,10 +303,65 @@ static void kvm_patch_ins_wrteei(u32 *inst) | |||
298 | } | 303 | } |
299 | 304 | ||
300 | /* Modify the chunk to fit the invocation */ | 305 | /* Modify the chunk to fit the invocation */ |
301 | memcpy(p, kvm_emulate_wrteei, kvm_emulate_wrteei_len * 4); | 306 | memcpy(p, kvm_emulate_wrtee, kvm_emulate_wrtee_len * 4); |
302 | p[kvm_emulate_wrteei_branch_offs] |= distance_end & KVM_INST_B_MASK; | 307 | p[kvm_emulate_wrtee_branch_offs] |= distance_end & KVM_INST_B_MASK; |
303 | p[kvm_emulate_wrteei_ee_offs] |= (*inst & MSR_EE); | 308 | |
304 | flush_icache_range((ulong)p, (ulong)p + kvm_emulate_wrteei_len * 4); | 309 | if (imm_one) { |
310 | p[kvm_emulate_wrtee_reg_offs] = | ||
311 | KVM_INST_LI | __PPC_RT(30) | MSR_EE; | ||
312 | } else { | ||
313 | /* Make clobbered registers work too */ | ||
314 | switch (get_rt(rt)) { | ||
315 | case 30: | ||
316 | kvm_patch_ins_ll(&p[kvm_emulate_wrtee_reg_offs], | ||
317 | magic_var(scratch2), KVM_RT_30); | ||
318 | break; | ||
319 | case 31: | ||
320 | kvm_patch_ins_ll(&p[kvm_emulate_wrtee_reg_offs], | ||
321 | magic_var(scratch1), KVM_RT_30); | ||
322 | break; | ||
323 | default: | ||
324 | p[kvm_emulate_wrtee_reg_offs] |= rt; | ||
325 | break; | ||
326 | } | ||
327 | } | ||
328 | |||
329 | p[kvm_emulate_wrtee_orig_ins_offs] = *inst; | ||
330 | flush_icache_range((ulong)p, (ulong)p + kvm_emulate_wrtee_len * 4); | ||
331 | |||
332 | /* Patch the invocation */ | ||
333 | kvm_patch_ins_b(inst, distance_start); | ||
334 | } | ||
335 | |||
336 | extern u32 kvm_emulate_wrteei_0_branch_offs; | ||
337 | extern u32 kvm_emulate_wrteei_0_len; | ||
338 | extern u32 kvm_emulate_wrteei_0[]; | ||
339 | |||
340 | static void kvm_patch_ins_wrteei_0(u32 *inst) | ||
341 | { | ||
342 | u32 *p; | ||
343 | int distance_start; | ||
344 | int distance_end; | ||
345 | ulong next_inst; | ||
346 | |||
347 | p = kvm_alloc(kvm_emulate_wrteei_0_len * 4); | ||
348 | if (!p) | ||
349 | return; | ||
350 | |||
351 | /* Find out where we are and put everything there */ | ||
352 | distance_start = (ulong)p - (ulong)inst; | ||
353 | next_inst = ((ulong)inst + 4); | ||
354 | distance_end = next_inst - (ulong)&p[kvm_emulate_wrteei_0_branch_offs]; | ||
355 | |||
356 | /* Make sure we only write valid b instructions */ | ||
357 | if (distance_start > KVM_INST_B_MAX) { | ||
358 | kvm_patching_worked = false; | ||
359 | return; | ||
360 | } | ||
361 | |||
362 | memcpy(p, kvm_emulate_wrteei_0, kvm_emulate_wrteei_0_len * 4); | ||
363 | p[kvm_emulate_wrteei_0_branch_offs] |= distance_end & KVM_INST_B_MASK; | ||
364 | flush_icache_range((ulong)p, (ulong)p + kvm_emulate_wrteei_0_len * 4); | ||
305 | 365 | ||
306 | /* Patch the invocation */ | 366 | /* Patch the invocation */ |
307 | kvm_patch_ins_b(inst, distance_start); | 367 | kvm_patch_ins_b(inst, distance_start); |
@@ -444,6 +504,11 @@ static void kvm_check_ins(u32 *inst, u32 features) | |||
444 | case KVM_INST_MTMSRD_L0: | 504 | case KVM_INST_MTMSRD_L0: |
445 | kvm_patch_ins_mtmsr(inst, inst_rt); | 505 | kvm_patch_ins_mtmsr(inst, inst_rt); |
446 | break; | 506 | break; |
507 | #ifdef CONFIG_BOOKE | ||
508 | case KVM_INST_WRTEE: | ||
509 | kvm_patch_ins_wrtee(inst, inst_rt, 0); | ||
510 | break; | ||
511 | #endif | ||
447 | } | 512 | } |
448 | 513 | ||
449 | switch (inst_no_rt & ~KVM_MASK_RB) { | 514 | switch (inst_no_rt & ~KVM_MASK_RB) { |
@@ -461,8 +526,11 @@ static void kvm_check_ins(u32 *inst, u32 features) | |||
461 | switch (_inst) { | 526 | switch (_inst) { |
462 | #ifdef CONFIG_BOOKE | 527 | #ifdef CONFIG_BOOKE |
463 | case KVM_INST_WRTEEI_0: | 528 | case KVM_INST_WRTEEI_0: |
529 | kvm_patch_ins_wrteei_0(inst); | ||
530 | break; | ||
531 | |||
464 | case KVM_INST_WRTEEI_1: | 532 | case KVM_INST_WRTEEI_1: |
465 | kvm_patch_ins_wrteei(inst); | 533 | kvm_patch_ins_wrtee(inst, 0, 1); |
466 | break; | 534 | break; |
467 | #endif | 535 | #endif |
468 | } | 536 | } |