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 | |
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')
-rw-r--r-- | arch/powerpc/kernel/asm-offsets.c | 1 | ||||
-rw-r--r-- | arch/powerpc/kernel/kvm.c | 60 | ||||
-rw-r--r-- | arch/powerpc/kernel/kvm_emul.S | 50 |
3 files changed, 111 insertions, 0 deletions
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index 6d92b4e13ebf..7f0d6fcc28a3 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c | |||
@@ -478,6 +478,7 @@ int main(void) | |||
478 | DEFINE(KVM_MAGIC_MSR, offsetof(struct kvm_vcpu_arch_shared, msr)); | 478 | DEFINE(KVM_MAGIC_MSR, offsetof(struct kvm_vcpu_arch_shared, msr)); |
479 | DEFINE(KVM_MAGIC_CRITICAL, offsetof(struct kvm_vcpu_arch_shared, | 479 | DEFINE(KVM_MAGIC_CRITICAL, offsetof(struct kvm_vcpu_arch_shared, |
480 | critical)); | 480 | critical)); |
481 | DEFINE(KVM_MAGIC_SR, offsetof(struct kvm_vcpu_arch_shared, sr)); | ||
481 | #endif | 482 | #endif |
482 | 483 | ||
483 | #ifdef CONFIG_44x | 484 | #ifdef CONFIG_44x |
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: |
diff --git a/arch/powerpc/kernel/kvm_emul.S b/arch/powerpc/kernel/kvm_emul.S index 3199f65ede2c..a6e97e7a55e0 100644 --- a/arch/powerpc/kernel/kvm_emul.S +++ b/arch/powerpc/kernel/kvm_emul.S | |||
@@ -245,3 +245,53 @@ kvm_emulate_wrteei_ee_offs: | |||
245 | .global kvm_emulate_wrteei_len | 245 | .global kvm_emulate_wrteei_len |
246 | kvm_emulate_wrteei_len: | 246 | kvm_emulate_wrteei_len: |
247 | .long (kvm_emulate_wrteei_end - kvm_emulate_wrteei) / 4 | 247 | .long (kvm_emulate_wrteei_end - kvm_emulate_wrteei) / 4 |
248 | |||
249 | |||
250 | .global kvm_emulate_mtsrin | ||
251 | kvm_emulate_mtsrin: | ||
252 | |||
253 | SCRATCH_SAVE | ||
254 | |||
255 | LL64(r31, KVM_MAGIC_PAGE + KVM_MAGIC_MSR, 0) | ||
256 | andi. r31, r31, MSR_DR | MSR_IR | ||
257 | beq kvm_emulate_mtsrin_reg1 | ||
258 | |||
259 | SCRATCH_RESTORE | ||
260 | |||
261 | kvm_emulate_mtsrin_orig_ins: | ||
262 | nop | ||
263 | b kvm_emulate_mtsrin_branch | ||
264 | |||
265 | kvm_emulate_mtsrin_reg1: | ||
266 | /* rX >> 26 */ | ||
267 | rlwinm r30,r0,6,26,29 | ||
268 | |||
269 | kvm_emulate_mtsrin_reg2: | ||
270 | stw r0, (KVM_MAGIC_PAGE + KVM_MAGIC_SR)(r30) | ||
271 | |||
272 | SCRATCH_RESTORE | ||
273 | |||
274 | /* Go back to caller */ | ||
275 | kvm_emulate_mtsrin_branch: | ||
276 | b . | ||
277 | kvm_emulate_mtsrin_end: | ||
278 | |||
279 | .global kvm_emulate_mtsrin_branch_offs | ||
280 | kvm_emulate_mtsrin_branch_offs: | ||
281 | .long (kvm_emulate_mtsrin_branch - kvm_emulate_mtsrin) / 4 | ||
282 | |||
283 | .global kvm_emulate_mtsrin_reg1_offs | ||
284 | kvm_emulate_mtsrin_reg1_offs: | ||
285 | .long (kvm_emulate_mtsrin_reg1 - kvm_emulate_mtsrin) / 4 | ||
286 | |||
287 | .global kvm_emulate_mtsrin_reg2_offs | ||
288 | kvm_emulate_mtsrin_reg2_offs: | ||
289 | .long (kvm_emulate_mtsrin_reg2 - kvm_emulate_mtsrin) / 4 | ||
290 | |||
291 | .global kvm_emulate_mtsrin_orig_ins_offs | ||
292 | kvm_emulate_mtsrin_orig_ins_offs: | ||
293 | .long (kvm_emulate_mtsrin_orig_ins - kvm_emulate_mtsrin) / 4 | ||
294 | |||
295 | .global kvm_emulate_mtsrin_len | ||
296 | kvm_emulate_mtsrin_len: | ||
297 | .long (kvm_emulate_mtsrin_end - kvm_emulate_mtsrin) / 4 | ||