diff options
author | Alexander Graf <agraf@suse.de> | 2010-08-03 04:39:35 -0400 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2010-10-24 04:52:12 -0400 |
commit | cbe487fac7fc016dbabbcbe83f11384e1803a56d (patch) | |
tree | 7144ae2f0b5a920aba061c101b9a0ac8305d5e31 /arch/powerpc/kernel/kvm.c | |
parent | df1bfa25d81f9451715ccbbb67551e0f792ceec8 (diff) |
KVM: PPC: Add mtsrin PV code
This is the guest side of the mtsr acceleration. Using this a guest can now
call mtsrin with almost no overhead as long as it ensures that it only uses
it with (MSR_IR|MSR_DR) == 0. Linux does that, so we're good.
Signed-off-by: Alexander Graf <agraf@suse.de>
Diffstat (limited to 'arch/powerpc/kernel/kvm.c')
-rw-r--r-- | arch/powerpc/kernel/kvm.c | 60 |
1 files changed, 60 insertions, 0 deletions
diff --git a/arch/powerpc/kernel/kvm.c b/arch/powerpc/kernel/kvm.c index 226882fe85a6..c8bab24ff8ac 100644 --- a/arch/powerpc/kernel/kvm.c +++ b/arch/powerpc/kernel/kvm.c | |||
@@ -42,6 +42,7 @@ | |||
42 | #define KVM_INST_B_MAX 0x01ffffff | 42 | #define KVM_INST_B_MAX 0x01ffffff |
43 | 43 | ||
44 | #define KVM_MASK_RT 0x03e00000 | 44 | #define KVM_MASK_RT 0x03e00000 |
45 | #define KVM_MASK_RB 0x0000f800 | ||
45 | #define KVM_INST_MFMSR 0x7c0000a6 | 46 | #define KVM_INST_MFMSR 0x7c0000a6 |
46 | #define KVM_INST_MFSPR_SPRG0 0x7c1042a6 | 47 | #define KVM_INST_MFSPR_SPRG0 0x7c1042a6 |
47 | #define KVM_INST_MFSPR_SPRG1 0x7c1142a6 | 48 | #define KVM_INST_MFSPR_SPRG1 0x7c1142a6 |
@@ -69,6 +70,8 @@ | |||
69 | #define KVM_INST_WRTEEI_0 0x7c000146 | 70 | #define KVM_INST_WRTEEI_0 0x7c000146 |
70 | #define KVM_INST_WRTEEI_1 0x7c008146 | 71 | #define KVM_INST_WRTEEI_1 0x7c008146 |
71 | 72 | ||
73 | #define KVM_INST_MTSRIN 0x7c0001e4 | ||
74 | |||
72 | static bool kvm_patching_worked = true; | 75 | static bool kvm_patching_worked = true; |
73 | static char kvm_tmp[1024 * 1024]; | 76 | static char kvm_tmp[1024 * 1024]; |
74 | static int kvm_tmp_index; | 77 | static int kvm_tmp_index; |
@@ -264,6 +267,51 @@ static void kvm_patch_ins_wrteei(u32 *inst) | |||
264 | 267 | ||
265 | #endif | 268 | #endif |
266 | 269 | ||
270 | #ifdef CONFIG_PPC_BOOK3S_32 | ||
271 | |||
272 | extern u32 kvm_emulate_mtsrin_branch_offs; | ||
273 | extern u32 kvm_emulate_mtsrin_reg1_offs; | ||
274 | extern u32 kvm_emulate_mtsrin_reg2_offs; | ||
275 | extern u32 kvm_emulate_mtsrin_orig_ins_offs; | ||
276 | extern u32 kvm_emulate_mtsrin_len; | ||
277 | extern u32 kvm_emulate_mtsrin[]; | ||
278 | |||
279 | static void kvm_patch_ins_mtsrin(u32 *inst, u32 rt, u32 rb) | ||
280 | { | ||
281 | u32 *p; | ||
282 | int distance_start; | ||
283 | int distance_end; | ||
284 | ulong next_inst; | ||
285 | |||
286 | p = kvm_alloc(kvm_emulate_mtsrin_len * 4); | ||
287 | if (!p) | ||
288 | return; | ||
289 | |||
290 | /* Find out where we are and put everything there */ | ||
291 | distance_start = (ulong)p - (ulong)inst; | ||
292 | next_inst = ((ulong)inst + 4); | ||
293 | distance_end = next_inst - (ulong)&p[kvm_emulate_mtsrin_branch_offs]; | ||
294 | |||
295 | /* Make sure we only write valid b instructions */ | ||
296 | if (distance_start > KVM_INST_B_MAX) { | ||
297 | kvm_patching_worked = false; | ||
298 | return; | ||
299 | } | ||
300 | |||
301 | /* Modify the chunk to fit the invocation */ | ||
302 | memcpy(p, kvm_emulate_mtsrin, kvm_emulate_mtsrin_len * 4); | ||
303 | p[kvm_emulate_mtsrin_branch_offs] |= distance_end & KVM_INST_B_MASK; | ||
304 | p[kvm_emulate_mtsrin_reg1_offs] |= (rb << 10); | ||
305 | p[kvm_emulate_mtsrin_reg2_offs] |= rt; | ||
306 | p[kvm_emulate_mtsrin_orig_ins_offs] = *inst; | ||
307 | flush_icache_range((ulong)p, (ulong)p + kvm_emulate_mtsrin_len * 4); | ||
308 | |||
309 | /* Patch the invocation */ | ||
310 | kvm_patch_ins_b(inst, distance_start); | ||
311 | } | ||
312 | |||
313 | #endif | ||
314 | |||
267 | static void kvm_map_magic_page(void *data) | 315 | static void kvm_map_magic_page(void *data) |
268 | { | 316 | { |
269 | u32 *features = data; | 317 | u32 *features = data; |
@@ -360,6 +408,18 @@ static void kvm_check_ins(u32 *inst, u32 features) | |||
360 | break; | 408 | break; |
361 | } | 409 | } |
362 | 410 | ||
411 | switch (inst_no_rt & ~KVM_MASK_RB) { | ||
412 | #ifdef CONFIG_PPC_BOOK3S_32 | ||
413 | case KVM_INST_MTSRIN: | ||
414 | if (features & KVM_MAGIC_FEAT_SR) { | ||
415 | u32 inst_rb = _inst & KVM_MASK_RB; | ||
416 | kvm_patch_ins_mtsrin(inst, inst_rt, inst_rb); | ||
417 | } | ||
418 | break; | ||
419 | break; | ||
420 | #endif | ||
421 | } | ||
422 | |||
363 | switch (_inst) { | 423 | switch (_inst) { |
364 | #ifdef CONFIG_BOOKE | 424 | #ifdef CONFIG_BOOKE |
365 | case KVM_INST_WRTEEI_0: | 425 | case KVM_INST_WRTEEI_0: |