# HG changeset patch # User Wei Huang # Date 1333061476 18000 # Node ID d7fdc948f6540427c4c20da216b304fc7a11cd76 # Parent 86fac5ca5d9234d293047fc7b310127f7eaa91f3 x86: add cpu affiliated interrupt delegate for guest VM This patch adds a delegate on-behalf-of guest VM for interrupts which are initiated by CPU. When this interrupt is triggered, hypervisor calls registered interrupt handler to notify guest that the interrupt has arrived. Guest VM can disable receiving this notification by setting handler as NULL. Signed-off-by: Wei Huang diff -r 86fac5ca5d92 -r d7fdc948f654 xen/arch/x86/apic.c --- a/xen/arch/x86/apic.c Thu Mar 29 17:46:18 2012 -0500 +++ b/xen/arch/x86/apic.c Thu Mar 29 17:51:16 2012 -0500 @@ -111,6 +111,13 @@ BUILD_SMP_INTERRUPT(thermal_interrupt,THERMAL_APIC_VECTOR) #endif +/* The following vector is received on-behalf-of guest VM for interrupts which + * are initiated by CPU locally. One example is light-weight profiling (LWP), + * which can trigger an interrupt when event buffer overflows. Hypervisor will + * notify guest VM about the arrival of interrupts. + */ +BUILD_SMP_INTERRUPT(cpu_affiliate_interrupt, CPU_AFFILIATE_VECTOR) + static int modern_apic(void) { unsigned int lvr, version; diff -r 86fac5ca5d92 -r d7fdc948f654 xen/arch/x86/hvm/hvm.c --- a/xen/arch/x86/hvm/hvm.c Thu Mar 29 17:46:18 2012 -0500 +++ b/xen/arch/x86/hvm/hvm.c Thu Mar 29 17:51:16 2012 -0500 @@ -1438,6 +1438,19 @@ return -1; } +int hvm_handle_affiliate_intr(struct cpu_user_regs *regs) +{ + struct vcpu *curr = current; + + if ( !curr->arch.hvm_vcpu.affiliate_intr_handler ) + { + printk("HVM: received an unregistered CPU affiliated interrupt!\n"); + return 0; + } + else + return curr->arch.hvm_vcpu.affiliate_intr_handler(regs); +} + int hvm_set_efer(uint64_t value) { struct vcpu *v = current; diff -r 86fac5ca5d92 -r d7fdc948f654 xen/arch/x86/irq.c --- a/xen/arch/x86/irq.c Thu Mar 29 17:46:18 2012 -0500 +++ b/xen/arch/x86/irq.c Thu Mar 29 17:51:16 2012 -0500 @@ -608,6 +608,16 @@ desc->handler->enable(desc); } +fastcall void smp_cpu_affiliate_interrupt(struct cpu_user_regs *regs) +{ + struct cpu_user_regs *old_regs = set_irq_regs(regs); + + ack_APIC_irq(); + this_cpu(irq_count)++; + hvm_handle_affiliate_intr(regs); + set_irq_regs(old_regs); +} + static void dump_irqs(unsigned char key); fastcall void smp_irq_move_cleanup_interrupt(struct cpu_user_regs *regs) diff -r 86fac5ca5d92 -r d7fdc948f654 xen/arch/x86/smpboot.c --- a/xen/arch/x86/smpboot.c Thu Mar 29 17:46:18 2012 -0500 +++ b/xen/arch/x86/smpboot.c Thu Mar 29 17:51:16 2012 -0500 @@ -1037,4 +1037,7 @@ /* IPI for generic function call */ set_intr_gate(CALL_FUNCTION_VECTOR, call_function_interrupt); + + /* CPU affiliate interrupt delegate */ + set_intr_gate(CPU_AFFILIATE_VECTOR, cpu_affiliate_interrupt); } diff -r 86fac5ca5d92 -r d7fdc948f654 xen/include/asm-x86/hvm/hvm.h --- a/xen/include/asm-x86/hvm/hvm.h Thu Mar 29 17:46:18 2012 -0500 +++ b/xen/include/asm-x86/hvm/hvm.h Thu Mar 29 17:51:16 2012 -0500 @@ -309,6 +309,7 @@ void hvm_migrate_pirqs(struct vcpu *v); void hvm_inject_exception(unsigned int trapnr, int errcode, unsigned long cr2); +int hvm_handle_affiliate_intr(struct cpu_user_regs *regs); static inline int hvm_event_pending(struct vcpu *v) { diff -r 86fac5ca5d92 -r d7fdc948f654 xen/include/asm-x86/hvm/vcpu.h --- a/xen/include/asm-x86/hvm/vcpu.h Thu Mar 29 17:46:18 2012 -0500 +++ b/xen/include/asm-x86/hvm/vcpu.h Thu Mar 29 17:51:16 2012 -0500 @@ -170,6 +170,10 @@ unsigned long inject_cr2; struct viridian_vcpu viridian; + + /* callback handler for CPU affiliated interrupt. Guest VM can setup this + * handler if it wants to receive notification. NULL means no handler. */ + int (*affiliate_intr_handler)(struct cpu_user_regs *regs); }; #endif /* __ASM_X86_HVM_VCPU_H__ */ diff -r 86fac5ca5d92 -r d7fdc948f654 xen/include/asm-x86/irq.h --- a/xen/include/asm-x86/irq.h Thu Mar 29 17:46:18 2012 -0500 +++ b/xen/include/asm-x86/irq.h Thu Mar 29 17:51:16 2012 -0500 @@ -89,6 +89,7 @@ fastcall void thermal_interrupt(void); fastcall void cmci_interrupt(void); fastcall void irq_move_cleanup_interrupt(void); +fastcall void cpu_affiliate_interrupt(void); fastcall void smp_event_check_interrupt(struct cpu_user_regs *regs); fastcall void smp_invalidate_interrupt(void); @@ -100,6 +101,7 @@ fastcall void smp_thermal_interrupt(struct cpu_user_regs *regs); fastcall void smp_cmci_interrupt(struct cpu_user_regs *regs); fastcall void smp_irq_move_cleanup_interrupt(struct cpu_user_regs *regs); +fastcall void smp_cpu_affiliate_interrupt(struct cpu_user_regs *regs); void do_IRQ(struct cpu_user_regs *regs); diff -r 86fac5ca5d92 -r d7fdc948f654 xen/include/asm-x86/mach-default/irq_vectors.h --- a/xen/include/asm-x86/mach-default/irq_vectors.h Thu Mar 29 17:46:18 2012 -0500 +++ b/xen/include/asm-x86/mach-default/irq_vectors.h Thu Mar 29 17:51:16 2012 -0500 @@ -11,12 +11,18 @@ #define LOCAL_TIMER_VECTOR 0xf9 #define PMU_APIC_VECTOR 0xf8 #define CMCI_APIC_VECTOR 0xf7 + +/* CPU affiliate interrupt vector, which is used for interrupts that are + * initiated by CPU locally. Hypervisor receives on-behalf-of guest VM. + */ +#define CPU_AFFILIATE_VECTOR 0xf6 + /* * High-priority dynamically-allocated vectors. For interrupts that * must be higher priority than any guest-bound interrupt. */ #define FIRST_HIPRIORITY_VECTOR 0xf0 -#define LAST_HIPRIORITY_VECTOR 0xf6 +#define LAST_HIPRIORITY_VECTOR 0xf5 /* Legacy PIC uses vectors 0xe0-0xef. */ #define FIRST_LEGACY_VECTOR 0xe0