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 | |
| 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>
| -rw-r--r-- | Documentation/kvm/ppc-pv.txt | 3 | ||||
| -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 |
4 files changed, 114 insertions, 0 deletions
diff --git a/Documentation/kvm/ppc-pv.txt b/Documentation/kvm/ppc-pv.txt index 41ee16d954d7..922cf954bd99 100644 --- a/Documentation/kvm/ppc-pv.txt +++ b/Documentation/kvm/ppc-pv.txt | |||
| @@ -160,6 +160,9 @@ mtmsr rX b <special mtmsr section> | |||
| 160 | 160 | ||
| 161 | mtmsrd rX, 1 b <special mtmsrd section> | 161 | mtmsrd rX, 1 b <special mtmsrd section> |
| 162 | 162 | ||
| 163 | [Book3S only] | ||
| 164 | mtsrin rX, rY b <special mtsrin section> | ||
| 165 | |||
| 163 | [BookE only] | 166 | [BookE only] |
| 164 | wrteei [0|1] b <special wrteei section> | 167 | wrteei [0|1] b <special wrteei section> |
| 165 | 168 | ||
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 | ||
