Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

KVM: PPC: booke: Allow multiple exception types

Current kvmppc_booke_handlers uses the same macro (KVM_HANDLER) and
all handlers are considered to be the same size. This will not be
the case if we want to use different macros for different handlers.

This patch improves the kvmppc_booke_handler so that it can
support different macros for different handlers.

Signed-off-by: Liu Yu <yu.liu@freescale.com>
[bharat.bhushan@freescale.com: Substantial changes]
Signed-off-by: Bharat Bhushan <bharat.bhushan@freescale.com>
Signed-off-by: Alexander Graf <agraf@suse.de>

authored by

Bharat Bhushan and committed by
Alexander Graf
1d542d9c ffe129ec

+54 -16
-2
arch/powerpc/include/asm/kvm_ppc.h
··· 49 49 50 50 extern int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu); 51 51 extern int __kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu); 52 - extern char kvmppc_handlers_start[]; 53 - extern unsigned long kvmppc_handler_len; 54 52 extern void kvmppc_handler_highmem(void); 55 53 56 54 extern void kvmppc_dump_vcpu(struct kvm_vcpu *vcpu);
+9 -5
arch/powerpc/kvm/booke.c
··· 1594 1594 { 1595 1595 #ifndef CONFIG_KVM_BOOKE_HV 1596 1596 unsigned long ivor[16]; 1597 + unsigned long *handler = kvmppc_booke_handler_addr; 1597 1598 unsigned long max_ivor = 0; 1599 + unsigned long handler_len; 1598 1600 int i; 1599 1601 1600 1602 /* We install our own exception handlers by hijacking IVPR. IVPR must ··· 1629 1627 1630 1628 for (i = 0; i < 16; i++) { 1631 1629 if (ivor[i] > max_ivor) 1632 - max_ivor = ivor[i]; 1630 + max_ivor = i; 1633 1631 1632 + handler_len = handler[i + 1] - handler[i]; 1634 1633 memcpy((void *)kvmppc_booke_handlers + ivor[i], 1635 - kvmppc_handlers_start + i * kvmppc_handler_len, 1636 - kvmppc_handler_len); 1634 + (void *)handler[i], handler_len); 1637 1635 } 1638 - flush_icache_range(kvmppc_booke_handlers, 1639 - kvmppc_booke_handlers + max_ivor + kvmppc_handler_len); 1636 + 1637 + handler_len = handler[max_ivor + 1] - handler[max_ivor]; 1638 + flush_icache_range(kvmppc_booke_handlers, kvmppc_booke_handlers + 1639 + ivor[max_ivor] + handler_len); 1640 1640 #endif /* !BOOKE_HV */ 1641 1641 return 0; 1642 1642 }
+1
arch/powerpc/kvm/booke.h
··· 65 65 (1 << BOOKE_IRQPRIO_CRITICAL)) 66 66 67 67 extern unsigned long kvmppc_booke_handlers; 68 + extern unsigned long kvmppc_booke_handler_addr[]; 68 69 69 70 void kvmppc_set_msr(struct kvm_vcpu *vcpu, u32 new_msr); 70 71 void kvmppc_mmu_msr_notify(struct kvm_vcpu *vcpu, u32 old_msr);
+34 -3
arch/powerpc/kvm/booke_interrupts.S
··· 74 74 bctr 75 75 .endm 76 76 77 + .macro KVM_HANDLER_ADDR ivor_nr 78 + .long kvmppc_handler_\ivor_nr 79 + .endm 80 + 81 + .macro KVM_HANDLER_END 82 + .long kvmppc_handlers_end 83 + .endm 84 + 77 85 _GLOBAL(kvmppc_handlers_start) 78 86 KVM_HANDLER BOOKE_INTERRUPT_CRITICAL SPRN_SPRG_RSCRATCH_CRIT SPRN_CSRR0 79 87 KVM_HANDLER BOOKE_INTERRUPT_MACHINE_CHECK SPRN_SPRG_RSCRATCH_MC SPRN_MCSRR0 ··· 102 94 KVM_HANDLER BOOKE_INTERRUPT_SPE_UNAVAIL SPRN_SPRG_RSCRATCH0 SPRN_SRR0 103 95 KVM_HANDLER BOOKE_INTERRUPT_SPE_FP_DATA SPRN_SPRG_RSCRATCH0 SPRN_SRR0 104 96 KVM_HANDLER BOOKE_INTERRUPT_SPE_FP_ROUND SPRN_SPRG_RSCRATCH0 SPRN_SRR0 105 - 106 - _GLOBAL(kvmppc_handler_len) 107 - .long kvmppc_handler_1 - kvmppc_handler_0 97 + _GLOBAL(kvmppc_handlers_end) 108 98 109 99 /* Registers: 110 100 * SPRG_SCRATCH0: guest r4 ··· 466 460 lwz r3, VCPU_GPR(R3)(r4) 467 461 lwz r4, VCPU_GPR(R4)(r4) 468 462 rfi 463 + 464 + .data 465 + .align 4 466 + .globl kvmppc_booke_handler_addr 467 + kvmppc_booke_handler_addr: 468 + KVM_HANDLER_ADDR BOOKE_INTERRUPT_CRITICAL 469 + KVM_HANDLER_ADDR BOOKE_INTERRUPT_MACHINE_CHECK 470 + KVM_HANDLER_ADDR BOOKE_INTERRUPT_DATA_STORAGE 471 + KVM_HANDLER_ADDR BOOKE_INTERRUPT_INST_STORAGE 472 + KVM_HANDLER_ADDR BOOKE_INTERRUPT_EXTERNAL 473 + KVM_HANDLER_ADDR BOOKE_INTERRUPT_ALIGNMENT 474 + KVM_HANDLER_ADDR BOOKE_INTERRUPT_PROGRAM 475 + KVM_HANDLER_ADDR BOOKE_INTERRUPT_FP_UNAVAIL 476 + KVM_HANDLER_ADDR BOOKE_INTERRUPT_SYSCALL 477 + KVM_HANDLER_ADDR BOOKE_INTERRUPT_AP_UNAVAIL 478 + KVM_HANDLER_ADDR BOOKE_INTERRUPT_DECREMENTER 479 + KVM_HANDLER_ADDR BOOKE_INTERRUPT_FIT 480 + KVM_HANDLER_ADDR BOOKE_INTERRUPT_WATCHDOG 481 + KVM_HANDLER_ADDR BOOKE_INTERRUPT_DTLB_MISS 482 + KVM_HANDLER_ADDR BOOKE_INTERRUPT_ITLB_MISS 483 + KVM_HANDLER_ADDR BOOKE_INTERRUPT_DEBUG 484 + KVM_HANDLER_ADDR BOOKE_INTERRUPT_SPE_UNAVAIL 485 + KVM_HANDLER_ADDR BOOKE_INTERRUPT_SPE_FP_DATA 486 + KVM_HANDLER_ADDR BOOKE_INTERRUPT_SPE_FP_ROUND 487 + KVM_HANDLER_END /*Always keep this in end*/ 469 488 470 489 #ifdef CONFIG_SPE 471 490 _GLOBAL(kvmppc_save_guest_spe)
+10 -6
arch/powerpc/kvm/e500.c
··· 491 491 { 492 492 int r, i; 493 493 unsigned long ivor[3]; 494 + /* Process remaining handlers above the generic first 16 */ 495 + unsigned long *handler = &kvmppc_booke_handler_addr[16]; 496 + unsigned long handler_len; 494 497 unsigned long max_ivor = 0; 495 498 496 499 r = kvmppc_core_check_processor_compat(); ··· 509 506 ivor[1] = mfspr(SPRN_IVOR33); 510 507 ivor[2] = mfspr(SPRN_IVOR34); 511 508 for (i = 0; i < 3; i++) { 512 - if (ivor[i] > max_ivor) 513 - max_ivor = ivor[i]; 509 + if (ivor[i] > ivor[max_ivor]) 510 + max_ivor = i; 514 511 512 + handler_len = handler[i + 1] - handler[i]; 515 513 memcpy((void *)kvmppc_booke_handlers + ivor[i], 516 - kvmppc_handlers_start + (i + 16) * kvmppc_handler_len, 517 - kvmppc_handler_len); 514 + (void *)handler[i], handler_len); 518 515 } 519 - flush_icache_range(kvmppc_booke_handlers, 520 - kvmppc_booke_handlers + max_ivor + kvmppc_handler_len); 516 + handler_len = handler[max_ivor + 1] - handler[max_ivor]; 517 + flush_icache_range(kvmppc_booke_handlers, kvmppc_booke_handlers + 518 + ivor[max_ivor] + handler_len); 521 519 522 520 return kvm_init(NULL, sizeof(struct kvmppc_vcpu_e500), 0, THIS_MODULE); 523 521 }