Commit 512ba59e authored by Alexander Graf's avatar Alexander Graf Committed by Avi Kivity

KVM: PPC: Make PV mtmsr work with r30 and r31

So far we've been restricting ourselves to r0-r29 as registers an mtmsr
instruction could use. This was bad, as there are some code paths in
Linux actually using r30.

So let's instead handle all registers gracefully and get rid of that
stupid limitation
Signed-off-by: default avatarAlexander Graf <agraf@suse.de>
parent cbe487fa
...@@ -42,6 +42,7 @@ ...@@ -42,6 +42,7 @@
#define KVM_INST_B_MAX 0x01ffffff #define KVM_INST_B_MAX 0x01ffffff
#define KVM_MASK_RT 0x03e00000 #define KVM_MASK_RT 0x03e00000
#define KVM_RT_30 0x03c00000
#define KVM_MASK_RB 0x0000f800 #define KVM_MASK_RB 0x0000f800
#define KVM_INST_MFMSR 0x7c0000a6 #define KVM_INST_MFMSR 0x7c0000a6
#define KVM_INST_MFSPR_SPRG0 0x7c1042a6 #define KVM_INST_MFSPR_SPRG0 0x7c1042a6
...@@ -82,6 +83,15 @@ static inline void kvm_patch_ins(u32 *inst, u32 new_inst) ...@@ -82,6 +83,15 @@ static inline void kvm_patch_ins(u32 *inst, u32 new_inst)
flush_icache_range((ulong)inst, (ulong)inst + 4); flush_icache_range((ulong)inst, (ulong)inst + 4);
} }
static void kvm_patch_ins_ll(u32 *inst, long addr, u32 rt)
{
#ifdef CONFIG_64BIT
kvm_patch_ins(inst, KVM_INST_LD | rt | (addr & 0x0000fffc));
#else
kvm_patch_ins(inst, KVM_INST_LWZ | rt | (addr & 0x0000fffc));
#endif
}
static void kvm_patch_ins_ld(u32 *inst, long addr, u32 rt) static void kvm_patch_ins_ld(u32 *inst, long addr, u32 rt)
{ {
#ifdef CONFIG_64BIT #ifdef CONFIG_64BIT
...@@ -186,7 +196,6 @@ static void kvm_patch_ins_mtmsrd(u32 *inst, u32 rt) ...@@ -186,7 +196,6 @@ static void kvm_patch_ins_mtmsrd(u32 *inst, u32 rt)
extern u32 kvm_emulate_mtmsr_branch_offs; extern u32 kvm_emulate_mtmsr_branch_offs;
extern u32 kvm_emulate_mtmsr_reg1_offs; extern u32 kvm_emulate_mtmsr_reg1_offs;
extern u32 kvm_emulate_mtmsr_reg2_offs; extern u32 kvm_emulate_mtmsr_reg2_offs;
extern u32 kvm_emulate_mtmsr_reg3_offs;
extern u32 kvm_emulate_mtmsr_orig_ins_offs; extern u32 kvm_emulate_mtmsr_orig_ins_offs;
extern u32 kvm_emulate_mtmsr_len; extern u32 kvm_emulate_mtmsr_len;
extern u32 kvm_emulate_mtmsr[]; extern u32 kvm_emulate_mtmsr[];
...@@ -216,9 +225,27 @@ static void kvm_patch_ins_mtmsr(u32 *inst, u32 rt) ...@@ -216,9 +225,27 @@ static void kvm_patch_ins_mtmsr(u32 *inst, u32 rt)
/* Modify the chunk to fit the invocation */ /* Modify the chunk to fit the invocation */
memcpy(p, kvm_emulate_mtmsr, kvm_emulate_mtmsr_len * 4); memcpy(p, kvm_emulate_mtmsr, kvm_emulate_mtmsr_len * 4);
p[kvm_emulate_mtmsr_branch_offs] |= distance_end & KVM_INST_B_MASK; p[kvm_emulate_mtmsr_branch_offs] |= distance_end & KVM_INST_B_MASK;
p[kvm_emulate_mtmsr_reg1_offs] |= rt;
p[kvm_emulate_mtmsr_reg2_offs] |= rt; /* Make clobbered registers work too */
p[kvm_emulate_mtmsr_reg3_offs] |= rt; switch (get_rt(rt)) {
case 30:
kvm_patch_ins_ll(&p[kvm_emulate_mtmsr_reg1_offs],
magic_var(scratch2), KVM_RT_30);
kvm_patch_ins_ll(&p[kvm_emulate_mtmsr_reg2_offs],
magic_var(scratch2), KVM_RT_30);
break;
case 31:
kvm_patch_ins_ll(&p[kvm_emulate_mtmsr_reg1_offs],
magic_var(scratch1), KVM_RT_30);
kvm_patch_ins_ll(&p[kvm_emulate_mtmsr_reg2_offs],
magic_var(scratch1), KVM_RT_30);
break;
default:
p[kvm_emulate_mtmsr_reg1_offs] |= rt;
p[kvm_emulate_mtmsr_reg2_offs] |= rt;
break;
}
p[kvm_emulate_mtmsr_orig_ins_offs] = *inst; p[kvm_emulate_mtmsr_orig_ins_offs] = *inst;
flush_icache_range((ulong)p, (ulong)p + kvm_emulate_mtmsr_len * 4); flush_icache_range((ulong)p, (ulong)p + kvm_emulate_mtmsr_len * 4);
...@@ -402,9 +429,7 @@ static void kvm_check_ins(u32 *inst, u32 features) ...@@ -402,9 +429,7 @@ static void kvm_check_ins(u32 *inst, u32 features)
break; break;
case KVM_INST_MTMSR: case KVM_INST_MTMSR:
case KVM_INST_MTMSRD_L0: case KVM_INST_MTMSRD_L0:
/* We use r30 and r31 during the hook */ kvm_patch_ins_mtmsr(inst, inst_rt);
if (get_rt(inst_rt) < 30)
kvm_patch_ins_mtmsr(inst, inst_rt);
break; break;
} }
......
...@@ -135,7 +135,8 @@ kvm_emulate_mtmsr: ...@@ -135,7 +135,8 @@ kvm_emulate_mtmsr:
/* Find the changed bits between old and new MSR */ /* Find the changed bits between old and new MSR */
kvm_emulate_mtmsr_reg1: kvm_emulate_mtmsr_reg1:
xor r31, r0, r31 ori r30, r0, 0
xor r31, r30, r31
/* Check if we need to really do mtmsr */ /* Check if we need to really do mtmsr */
LOAD_REG_IMMEDIATE(r30, MSR_CRITICAL_BITS) LOAD_REG_IMMEDIATE(r30, MSR_CRITICAL_BITS)
...@@ -156,14 +157,17 @@ kvm_emulate_mtmsr_orig_ins: ...@@ -156,14 +157,17 @@ kvm_emulate_mtmsr_orig_ins:
maybe_stay_in_guest: maybe_stay_in_guest:
/* Get the target register in r30 */
kvm_emulate_mtmsr_reg2:
ori r30, r0, 0
/* Check if we have to fetch an interrupt */ /* Check if we have to fetch an interrupt */
lwz r31, (KVM_MAGIC_PAGE + KVM_MAGIC_INT)(0) lwz r31, (KVM_MAGIC_PAGE + KVM_MAGIC_INT)(0)
cmpwi r31, 0 cmpwi r31, 0
beq+ no_mtmsr beq+ no_mtmsr
/* Check if we may trigger an interrupt */ /* Check if we may trigger an interrupt */
kvm_emulate_mtmsr_reg2: andi. r31, r30, MSR_EE
andi. r31, r0, MSR_EE
beq no_mtmsr beq no_mtmsr
b do_mtmsr b do_mtmsr
...@@ -171,8 +175,7 @@ kvm_emulate_mtmsr_reg2: ...@@ -171,8 +175,7 @@ kvm_emulate_mtmsr_reg2:
no_mtmsr: no_mtmsr:
/* Put MSR into magic page because we don't call mtmsr */ /* Put MSR into magic page because we don't call mtmsr */
kvm_emulate_mtmsr_reg3: STL64(r30, KVM_MAGIC_PAGE + KVM_MAGIC_MSR, 0)
STL64(r0, KVM_MAGIC_PAGE + KVM_MAGIC_MSR, 0)
SCRATCH_RESTORE SCRATCH_RESTORE
...@@ -193,10 +196,6 @@ kvm_emulate_mtmsr_reg1_offs: ...@@ -193,10 +196,6 @@ kvm_emulate_mtmsr_reg1_offs:
kvm_emulate_mtmsr_reg2_offs: kvm_emulate_mtmsr_reg2_offs:
.long (kvm_emulate_mtmsr_reg2 - kvm_emulate_mtmsr) / 4 .long (kvm_emulate_mtmsr_reg2 - kvm_emulate_mtmsr) / 4
.global kvm_emulate_mtmsr_reg3_offs
kvm_emulate_mtmsr_reg3_offs:
.long (kvm_emulate_mtmsr_reg3 - kvm_emulate_mtmsr) / 4
.global kvm_emulate_mtmsr_orig_ins_offs .global kvm_emulate_mtmsr_orig_ins_offs
kvm_emulate_mtmsr_orig_ins_offs: kvm_emulate_mtmsr_orig_ins_offs:
.long (kvm_emulate_mtmsr_orig_ins - kvm_emulate_mtmsr) / 4 .long (kvm_emulate_mtmsr_orig_ins - kvm_emulate_mtmsr) / 4
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment