aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/kvm.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/kernel/kvm.c')
-rw-r--r--arch/powerpc/kernel/kvm.c45
1 files changed, 45 insertions, 0 deletions
diff --git a/arch/powerpc/kernel/kvm.c b/arch/powerpc/kernel/kvm.c
index 239a70d750a..717ab0dded2 100644
--- a/arch/powerpc/kernel/kvm.c
+++ b/arch/powerpc/kernel/kvm.c
@@ -63,6 +63,7 @@
63#define KVM_INST_MTSPR_DSISR 0x7c1203a6 63#define KVM_INST_MTSPR_DSISR 0x7c1203a6
64 64
65#define KVM_INST_TLBSYNC 0x7c00046c 65#define KVM_INST_TLBSYNC 0x7c00046c
66#define KVM_INST_MTMSRD_L1 0x7c010164
66 67
67static bool kvm_patching_worked = true; 68static bool kvm_patching_worked = true;
68static char kvm_tmp[1024 * 1024]; 69static char kvm_tmp[1024 * 1024];
@@ -138,6 +139,43 @@ static u32 *kvm_alloc(int len)
138 return p; 139 return p;
139} 140}
140 141
142extern u32 kvm_emulate_mtmsrd_branch_offs;
143extern u32 kvm_emulate_mtmsrd_reg_offs;
144extern u32 kvm_emulate_mtmsrd_len;
145extern u32 kvm_emulate_mtmsrd[];
146
147static void kvm_patch_ins_mtmsrd(u32 *inst, u32 rt)
148{
149 u32 *p;
150 int distance_start;
151 int distance_end;
152 ulong next_inst;
153
154 p = kvm_alloc(kvm_emulate_mtmsrd_len * 4);
155 if (!p)
156 return;
157
158 /* Find out where we are and put everything there */
159 distance_start = (ulong)p - (ulong)inst;
160 next_inst = ((ulong)inst + 4);
161 distance_end = next_inst - (ulong)&p[kvm_emulate_mtmsrd_branch_offs];
162
163 /* Make sure we only write valid b instructions */
164 if (distance_start > KVM_INST_B_MAX) {
165 kvm_patching_worked = false;
166 return;
167 }
168
169 /* Modify the chunk to fit the invocation */
170 memcpy(p, kvm_emulate_mtmsrd, kvm_emulate_mtmsrd_len * 4);
171 p[kvm_emulate_mtmsrd_branch_offs] |= distance_end & KVM_INST_B_MASK;
172 p[kvm_emulate_mtmsrd_reg_offs] |= rt;
173 flush_icache_range((ulong)p, (ulong)p + kvm_emulate_mtmsrd_len * 4);
174
175 /* Patch the invocation */
176 kvm_patch_ins_b(inst, distance_start);
177}
178
141static void kvm_map_magic_page(void *data) 179static void kvm_map_magic_page(void *data)
142{ 180{
143 kvm_hypercall2(KVM_HC_PPC_MAP_MAGIC_PAGE, 181 kvm_hypercall2(KVM_HC_PPC_MAP_MAGIC_PAGE,
@@ -211,6 +249,13 @@ static void kvm_check_ins(u32 *inst)
211 case KVM_INST_TLBSYNC: 249 case KVM_INST_TLBSYNC:
212 kvm_patch_ins_nop(inst); 250 kvm_patch_ins_nop(inst);
213 break; 251 break;
252
253 /* Rewrites */
254 case KVM_INST_MTMSRD_L1:
255 /* We use r30 and r31 during the hook */
256 if (get_rt(inst_rt) < 30)
257 kvm_patch_ins_mtmsrd(inst, inst_rt);
258 break;
214 } 259 }
215 260
216 switch (_inst) { 261 switch (_inst) {