diff options
-rw-r--r-- | arch/powerpc/kernel/kvm.c | 92 | ||||
-rw-r--r-- | arch/powerpc/kernel/kvm_emul.S | 96 |
2 files changed, 154 insertions, 34 deletions
diff --git a/arch/powerpc/kernel/kvm.c b/arch/powerpc/kernel/kvm.c index 2985338d0e10..06b15ee997f7 100644 --- a/arch/powerpc/kernel/kvm.c +++ b/arch/powerpc/kernel/kvm.c | |||
@@ -1,5 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2010 SUSE Linux Products GmbH. All rights reserved. | 2 | * Copyright (C) 2010 SUSE Linux Products GmbH. All rights reserved. |
3 | * Copyright 2010-2011 Freescale Semiconductor, Inc. | ||
3 | * | 4 | * |
4 | * Authors: | 5 | * Authors: |
5 | * Alexander Graf <agraf@suse.de> | 6 | * Alexander Graf <agraf@suse.de> |
@@ -29,6 +30,7 @@ | |||
29 | #include <asm/sections.h> | 30 | #include <asm/sections.h> |
30 | #include <asm/cacheflush.h> | 31 | #include <asm/cacheflush.h> |
31 | #include <asm/disassemble.h> | 32 | #include <asm/disassemble.h> |
33 | #include <asm/ppc-opcode.h> | ||
32 | 34 | ||
33 | #define KVM_MAGIC_PAGE (-4096L) | 35 | #define KVM_MAGIC_PAGE (-4096L) |
34 | #define magic_var(x) KVM_MAGIC_PAGE + offsetof(struct kvm_vcpu_arch_shared, x) | 36 | #define magic_var(x) KVM_MAGIC_PAGE + offsetof(struct kvm_vcpu_arch_shared, x) |
@@ -41,6 +43,7 @@ | |||
41 | #define KVM_INST_B 0x48000000 | 43 | #define KVM_INST_B 0x48000000 |
42 | #define KVM_INST_B_MASK 0x03ffffff | 44 | #define KVM_INST_B_MASK 0x03ffffff |
43 | #define KVM_INST_B_MAX 0x01ffffff | 45 | #define KVM_INST_B_MAX 0x01ffffff |
46 | #define KVM_INST_LI 0x38000000 | ||
44 | 47 | ||
45 | #define KVM_MASK_RT 0x03e00000 | 48 | #define KVM_MASK_RT 0x03e00000 |
46 | #define KVM_RT_30 0x03c00000 | 49 | #define KVM_RT_30 0x03c00000 |
@@ -69,6 +72,7 @@ | |||
69 | #define KVM_INST_MTMSRD_L1 0x7c010164 | 72 | #define KVM_INST_MTMSRD_L1 0x7c010164 |
70 | #define KVM_INST_MTMSR 0x7c000124 | 73 | #define KVM_INST_MTMSR 0x7c000124 |
71 | 74 | ||
75 | #define KVM_INST_WRTEE 0x7c000106 | ||
72 | #define KVM_INST_WRTEEI_0 0x7c000146 | 76 | #define KVM_INST_WRTEEI_0 0x7c000146 |
73 | #define KVM_INST_WRTEEI_1 0x7c008146 | 77 | #define KVM_INST_WRTEEI_1 0x7c008146 |
74 | 78 | ||
@@ -270,26 +274,27 @@ static void kvm_patch_ins_mtmsr(u32 *inst, u32 rt) | |||
270 | 274 | ||
271 | #ifdef CONFIG_BOOKE | 275 | #ifdef CONFIG_BOOKE |
272 | 276 | ||
273 | extern u32 kvm_emulate_wrteei_branch_offs; | 277 | extern u32 kvm_emulate_wrtee_branch_offs; |
274 | extern u32 kvm_emulate_wrteei_ee_offs; | 278 | extern u32 kvm_emulate_wrtee_reg_offs; |
275 | extern u32 kvm_emulate_wrteei_len; | 279 | extern u32 kvm_emulate_wrtee_orig_ins_offs; |
276 | extern u32 kvm_emulate_wrteei[]; | 280 | extern u32 kvm_emulate_wrtee_len; |
281 | extern u32 kvm_emulate_wrtee[]; | ||
277 | 282 | ||
278 | static void kvm_patch_ins_wrteei(u32 *inst) | 283 | static void kvm_patch_ins_wrtee(u32 *inst, u32 rt, int imm_one) |
279 | { | 284 | { |
280 | u32 *p; | 285 | u32 *p; |
281 | int distance_start; | 286 | int distance_start; |
282 | int distance_end; | 287 | int distance_end; |
283 | ulong next_inst; | 288 | ulong next_inst; |
284 | 289 | ||
285 | p = kvm_alloc(kvm_emulate_wrteei_len * 4); | 290 | p = kvm_alloc(kvm_emulate_wrtee_len * 4); |
286 | if (!p) | 291 | if (!p) |
287 | return; | 292 | return; |
288 | 293 | ||
289 | /* Find out where we are and put everything there */ | 294 | /* Find out where we are and put everything there */ |
290 | distance_start = (ulong)p - (ulong)inst; | 295 | distance_start = (ulong)p - (ulong)inst; |
291 | next_inst = ((ulong)inst + 4); | 296 | next_inst = ((ulong)inst + 4); |
292 | distance_end = next_inst - (ulong)&p[kvm_emulate_wrteei_branch_offs]; | 297 | distance_end = next_inst - (ulong)&p[kvm_emulate_wrtee_branch_offs]; |
293 | 298 | ||
294 | /* Make sure we only write valid b instructions */ | 299 | /* Make sure we only write valid b instructions */ |
295 | if (distance_start > KVM_INST_B_MAX) { | 300 | if (distance_start > KVM_INST_B_MAX) { |
@@ -298,10 +303,65 @@ static void kvm_patch_ins_wrteei(u32 *inst) | |||
298 | } | 303 | } |
299 | 304 | ||
300 | /* Modify the chunk to fit the invocation */ | 305 | /* Modify the chunk to fit the invocation */ |
301 | memcpy(p, kvm_emulate_wrteei, kvm_emulate_wrteei_len * 4); | 306 | memcpy(p, kvm_emulate_wrtee, kvm_emulate_wrtee_len * 4); |
302 | p[kvm_emulate_wrteei_branch_offs] |= distance_end & KVM_INST_B_MASK; | 307 | p[kvm_emulate_wrtee_branch_offs] |= distance_end & KVM_INST_B_MASK; |
303 | p[kvm_emulate_wrteei_ee_offs] |= (*inst & MSR_EE); | 308 | |
304 | flush_icache_range((ulong)p, (ulong)p + kvm_emulate_wrteei_len * 4); | 309 | if (imm_one) { |
310 | p[kvm_emulate_wrtee_reg_offs] = | ||
311 | KVM_INST_LI | __PPC_RT(30) | MSR_EE; | ||
312 | } else { | ||
313 | /* Make clobbered registers work too */ | ||
314 | switch (get_rt(rt)) { | ||
315 | case 30: | ||
316 | kvm_patch_ins_ll(&p[kvm_emulate_wrtee_reg_offs], | ||
317 | magic_var(scratch2), KVM_RT_30); | ||
318 | break; | ||
319 | case 31: | ||
320 | kvm_patch_ins_ll(&p[kvm_emulate_wrtee_reg_offs], | ||
321 | magic_var(scratch1), KVM_RT_30); | ||
322 | break; | ||
323 | default: | ||
324 | p[kvm_emulate_wrtee_reg_offs] |= rt; | ||
325 | break; | ||
326 | } | ||
327 | } | ||
328 | |||
329 | p[kvm_emulate_wrtee_orig_ins_offs] = *inst; | ||
330 | flush_icache_range((ulong)p, (ulong)p + kvm_emulate_wrtee_len * 4); | ||
331 | |||
332 | /* Patch the invocation */ | ||
333 | kvm_patch_ins_b(inst, distance_start); | ||
334 | } | ||
335 | |||
336 | extern u32 kvm_emulate_wrteei_0_branch_offs; | ||
337 | extern u32 kvm_emulate_wrteei_0_len; | ||
338 | extern u32 kvm_emulate_wrteei_0[]; | ||
339 | |||
340 | static void kvm_patch_ins_wrteei_0(u32 *inst) | ||
341 | { | ||
342 | u32 *p; | ||
343 | int distance_start; | ||
344 | int distance_end; | ||
345 | ulong next_inst; | ||
346 | |||
347 | p = kvm_alloc(kvm_emulate_wrteei_0_len * 4); | ||
348 | if (!p) | ||
349 | return; | ||
350 | |||
351 | /* Find out where we are and put everything there */ | ||
352 | distance_start = (ulong)p - (ulong)inst; | ||
353 | next_inst = ((ulong)inst + 4); | ||
354 | distance_end = next_inst - (ulong)&p[kvm_emulate_wrteei_0_branch_offs]; | ||
355 | |||
356 | /* Make sure we only write valid b instructions */ | ||
357 | if (distance_start > KVM_INST_B_MAX) { | ||
358 | kvm_patching_worked = false; | ||
359 | return; | ||
360 | } | ||
361 | |||
362 | memcpy(p, kvm_emulate_wrteei_0, kvm_emulate_wrteei_0_len * 4); | ||
363 | p[kvm_emulate_wrteei_0_branch_offs] |= distance_end & KVM_INST_B_MASK; | ||
364 | flush_icache_range((ulong)p, (ulong)p + kvm_emulate_wrteei_0_len * 4); | ||
305 | 365 | ||
306 | /* Patch the invocation */ | 366 | /* Patch the invocation */ |
307 | kvm_patch_ins_b(inst, distance_start); | 367 | kvm_patch_ins_b(inst, distance_start); |
@@ -444,6 +504,11 @@ static void kvm_check_ins(u32 *inst, u32 features) | |||
444 | case KVM_INST_MTMSRD_L0: | 504 | case KVM_INST_MTMSRD_L0: |
445 | kvm_patch_ins_mtmsr(inst, inst_rt); | 505 | kvm_patch_ins_mtmsr(inst, inst_rt); |
446 | break; | 506 | break; |
507 | #ifdef CONFIG_BOOKE | ||
508 | case KVM_INST_WRTEE: | ||
509 | kvm_patch_ins_wrtee(inst, inst_rt, 0); | ||
510 | break; | ||
511 | #endif | ||
447 | } | 512 | } |
448 | 513 | ||
449 | switch (inst_no_rt & ~KVM_MASK_RB) { | 514 | switch (inst_no_rt & ~KVM_MASK_RB) { |
@@ -461,8 +526,11 @@ static void kvm_check_ins(u32 *inst, u32 features) | |||
461 | switch (_inst) { | 526 | switch (_inst) { |
462 | #ifdef CONFIG_BOOKE | 527 | #ifdef CONFIG_BOOKE |
463 | case KVM_INST_WRTEEI_0: | 528 | case KVM_INST_WRTEEI_0: |
529 | kvm_patch_ins_wrteei_0(inst); | ||
530 | break; | ||
531 | |||
464 | case KVM_INST_WRTEEI_1: | 532 | case KVM_INST_WRTEEI_1: |
465 | kvm_patch_ins_wrteei(inst); | 533 | kvm_patch_ins_wrtee(inst, 0, 1); |
466 | break; | 534 | break; |
467 | #endif | 535 | #endif |
468 | } | 536 | } |
diff --git a/arch/powerpc/kernel/kvm_emul.S b/arch/powerpc/kernel/kvm_emul.S index 3d64c5704fd5..801058dd74db 100644 --- a/arch/powerpc/kernel/kvm_emul.S +++ b/arch/powerpc/kernel/kvm_emul.S | |||
@@ -13,6 +13,7 @@ | |||
13 | * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | 13 | * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
14 | * | 14 | * |
15 | * Copyright SUSE Linux Products GmbH 2010 | 15 | * Copyright SUSE Linux Products GmbH 2010 |
16 | * Copyright 2010-2011 Freescale Semiconductor, Inc. | ||
16 | * | 17 | * |
17 | * Authors: Alexander Graf <agraf@suse.de> | 18 | * Authors: Alexander Graf <agraf@suse.de> |
18 | */ | 19 | */ |
@@ -208,24 +209,80 @@ kvm_emulate_mtmsr_orig_ins_offs: | |||
208 | kvm_emulate_mtmsr_len: | 209 | kvm_emulate_mtmsr_len: |
209 | .long (kvm_emulate_mtmsr_end - kvm_emulate_mtmsr) / 4 | 210 | .long (kvm_emulate_mtmsr_end - kvm_emulate_mtmsr) / 4 |
210 | 211 | ||
212 | /* also used for wrteei 1 */ | ||
213 | .global kvm_emulate_wrtee | ||
214 | kvm_emulate_wrtee: | ||
211 | 215 | ||
216 | SCRATCH_SAVE | ||
217 | |||
218 | /* Fetch old MSR in r31 */ | ||
219 | LL64(r31, KVM_MAGIC_PAGE + KVM_MAGIC_MSR, 0) | ||
212 | 220 | ||
213 | .global kvm_emulate_wrteei | 221 | /* Insert new MSR[EE] */ |
214 | kvm_emulate_wrteei: | 222 | kvm_emulate_wrtee_reg: |
223 | ori r30, r0, 0 | ||
224 | rlwimi r31, r30, 0, MSR_EE | ||
225 | |||
226 | /* | ||
227 | * If MSR[EE] is now set, check for a pending interrupt. | ||
228 | * We could skip this if MSR[EE] was already on, but that | ||
229 | * should be rare, so don't bother. | ||
230 | */ | ||
231 | andi. r30, r30, MSR_EE | ||
215 | 232 | ||
233 | /* Put MSR into magic page because we don't call wrtee */ | ||
234 | STL64(r31, KVM_MAGIC_PAGE + KVM_MAGIC_MSR, 0) | ||
235 | |||
236 | beq no_wrtee | ||
237 | |||
238 | /* Check if we have to fetch an interrupt */ | ||
239 | lwz r30, (KVM_MAGIC_PAGE + KVM_MAGIC_INT)(0) | ||
240 | cmpwi r30, 0 | ||
241 | bne do_wrtee | ||
242 | |||
243 | no_wrtee: | ||
244 | SCRATCH_RESTORE | ||
245 | |||
246 | /* Go back to caller */ | ||
247 | kvm_emulate_wrtee_branch: | ||
248 | b . | ||
249 | |||
250 | do_wrtee: | ||
251 | SCRATCH_RESTORE | ||
252 | |||
253 | /* Just fire off the wrtee if it's critical */ | ||
254 | kvm_emulate_wrtee_orig_ins: | ||
255 | wrtee r0 | ||
256 | |||
257 | b kvm_emulate_wrtee_branch | ||
258 | |||
259 | kvm_emulate_wrtee_end: | ||
260 | |||
261 | .global kvm_emulate_wrtee_branch_offs | ||
262 | kvm_emulate_wrtee_branch_offs: | ||
263 | .long (kvm_emulate_wrtee_branch - kvm_emulate_wrtee) / 4 | ||
264 | |||
265 | .global kvm_emulate_wrtee_reg_offs | ||
266 | kvm_emulate_wrtee_reg_offs: | ||
267 | .long (kvm_emulate_wrtee_reg - kvm_emulate_wrtee) / 4 | ||
268 | |||
269 | .global kvm_emulate_wrtee_orig_ins_offs | ||
270 | kvm_emulate_wrtee_orig_ins_offs: | ||
271 | .long (kvm_emulate_wrtee_orig_ins - kvm_emulate_wrtee) / 4 | ||
272 | |||
273 | .global kvm_emulate_wrtee_len | ||
274 | kvm_emulate_wrtee_len: | ||
275 | .long (kvm_emulate_wrtee_end - kvm_emulate_wrtee) / 4 | ||
276 | |||
277 | .global kvm_emulate_wrteei_0 | ||
278 | kvm_emulate_wrteei_0: | ||
216 | SCRATCH_SAVE | 279 | SCRATCH_SAVE |
217 | 280 | ||
218 | /* Fetch old MSR in r31 */ | 281 | /* Fetch old MSR in r31 */ |
219 | LL64(r31, KVM_MAGIC_PAGE + KVM_MAGIC_MSR, 0) | 282 | LL64(r31, KVM_MAGIC_PAGE + KVM_MAGIC_MSR, 0) |
220 | 283 | ||
221 | /* Remove MSR_EE from old MSR */ | 284 | /* Remove MSR_EE from old MSR */ |
222 | li r30, 0 | 285 | rlwinm r31, r31, 0, ~MSR_EE |
223 | ori r30, r30, MSR_EE | ||
224 | andc r31, r31, r30 | ||
225 | |||
226 | /* OR new MSR_EE onto the old MSR */ | ||
227 | kvm_emulate_wrteei_ee: | ||
228 | ori r31, r31, 0 | ||
229 | 286 | ||
230 | /* Write new MSR value back */ | 287 | /* Write new MSR value back */ |
231 | STL64(r31, KVM_MAGIC_PAGE + KVM_MAGIC_MSR, 0) | 288 | STL64(r31, KVM_MAGIC_PAGE + KVM_MAGIC_MSR, 0) |
@@ -233,22 +290,17 @@ kvm_emulate_wrteei_ee: | |||
233 | SCRATCH_RESTORE | 290 | SCRATCH_RESTORE |
234 | 291 | ||
235 | /* Go back to caller */ | 292 | /* Go back to caller */ |
236 | kvm_emulate_wrteei_branch: | 293 | kvm_emulate_wrteei_0_branch: |
237 | b . | 294 | b . |
238 | kvm_emulate_wrteei_end: | 295 | kvm_emulate_wrteei_0_end: |
239 | |||
240 | .global kvm_emulate_wrteei_branch_offs | ||
241 | kvm_emulate_wrteei_branch_offs: | ||
242 | .long (kvm_emulate_wrteei_branch - kvm_emulate_wrteei) / 4 | ||
243 | |||
244 | .global kvm_emulate_wrteei_ee_offs | ||
245 | kvm_emulate_wrteei_ee_offs: | ||
246 | .long (kvm_emulate_wrteei_ee - kvm_emulate_wrteei) / 4 | ||
247 | 296 | ||
248 | .global kvm_emulate_wrteei_len | 297 | .global kvm_emulate_wrteei_0_branch_offs |
249 | kvm_emulate_wrteei_len: | 298 | kvm_emulate_wrteei_0_branch_offs: |
250 | .long (kvm_emulate_wrteei_end - kvm_emulate_wrteei) / 4 | 299 | .long (kvm_emulate_wrteei_0_branch - kvm_emulate_wrteei_0) / 4 |
251 | 300 | ||
301 | .global kvm_emulate_wrteei_0_len | ||
302 | kvm_emulate_wrteei_0_len: | ||
303 | .long (kvm_emulate_wrteei_0_end - kvm_emulate_wrteei_0) / 4 | ||
252 | 304 | ||
253 | .global kvm_emulate_mtsrin | 305 | .global kvm_emulate_mtsrin |
254 | kvm_emulate_mtsrin: | 306 | kvm_emulate_mtsrin: |