/* $NetBSD: vector.S,v 1.89 2022/09/07 00:40:18 knakahara Exp $ */ /* * Copyright 2002 (c) Wasabi Systems, Inc. * All rights reserved. * * Written by Frank van der Linden for Wasabi Systems, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed for the NetBSD Project by * Wasabi Systems, Inc. * 4. The name of Wasabi Systems, Inc. may not be used to endorse * or promote products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /*- * Copyright (c) 1998, 2007, 2009 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Charles M. Hannum, and by Andrew Doran. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include __KERNEL_RCSID(0, "$NetBSD: vector.S,v 1.89 2022/09/07 00:40:18 knakahara Exp $"); #include "opt_ddb.h" #include "opt_multiprocessor.h" #include "opt_xen.h" #include "opt_dtrace.h" #include #include #include #include #include #include #include #ifdef XEN #include #endif #include "ioapic.h" #include "lapic.h" #ifndef XENPV #include "hyperv.h" #endif #include "assym.h" /* * Macros for interrupt entry, call to handler, and exit. * * XXX * The interrupt frame is set up to look like a trap frame. This may be a * waste. The only handler which needs a frame is the clock handler, and it * only needs a few bits. Xdoreti() needs a trap frame for handling ASTs, but * it could easily convert the frame on demand. * * The direct costs of setting up a trap frame are two pushl's (error code and * trap number), an addl to get rid of these, and pushing and popping the * callee-saved registers %esi, %edi, %ebx, and %ebp twice. * * If the interrupt frame is made more flexible, INTR can push %eax first and * decide the ipending case with less overhead, e.g., by avoiding loading the * segment registers. */ /* * Store address of TSS in %eax, given a selector in %eax. * Clobbers %eax, %ecx, %edx, but that's ok for its usage. * This is a bit complicated, but it's done to make as few * assumptions as possible about the validity of the environment. * The GDT and the current and previous TSS are known to be OK, * otherwise we would not be here. The only other thing that needs * to be OK is the cpu_info structure for the current CPU. */ #define GET_TSS \ andl $0xfff8,%eax ;\ addl CPUVAR(GDT),%eax ;\ movl 2(%eax),%edx ;\ andl $0xffffff,%edx ;\ movzbl 7(%eax),%eax ;\ shl $24,%eax ;\ orl %edx,%eax #ifdef KDTRACE_HOOKS .bss .globl dtrace_invop_jump_addr .align 4 .type dtrace_invop_jump_addr, @object .size dtrace_invop_jump_addr, 4 dtrace_invop_jump_addr: .zero 4 .globl dtrace_invop_calltrap_addr .align 4 .type dtrace_invop_calltrap_addr, @object .size dtrace_invop_calltrap_addr, 4 dtrace_invop_calltrap_addr: .zero 8 .text #endif #ifndef XENPV #if NLAPIC > 0 #ifdef MULTIPROCESSOR /* * General purpose IPI handler. */ IDTVEC(recurse_lapic_ipi) INTR_RECURSE_HWFRAME pushl $0 pushl $T_ASTFLT INTRENTRY jmp 1f IDTVEC_END(recurse_lapic_ipi) IDTVEC(intr_x2apic_ipi) pushl $0 pushl $T_ASTFLT INTRENTRY movl $(MSR_X2APIC_BASE + MSR_X2APIC_EOI),%ecx xorl %eax,%eax xorl %edx,%edx wrmsr movzbl CPUVAR(ILEVEL),%ebx cmpl $IPL_HIGH,%ebx jae 2f jmp 1f IDTVEC_END(intr_x2apic_ipi) IDTVEC(intr_lapic_ipi) pushl $0 pushl $T_ASTFLT INTRENTRY movl _C_LABEL(local_apic_va),%ebx movl $0,LAPIC_EOI(%ebx) movzbl CPUVAR(ILEVEL),%ebx cmpl $IPL_HIGH,%ebx jae 2f IDTVEC_END(intr_lapic_ipi) IDTVEC(resume_lapic_ipi) 1: pushl %ebx IDEPTH_INCR movb $IPL_HIGH,CPUVAR(ILEVEL) sti call _C_LABEL(x86_ipi_handler) cli jmp _C_LABEL(Xdoreti) 2: btsl $(LIR_IPI - 32),CPUVAR(IPENDING)+4 INTRFASTEXIT IDTVEC_END(resume_lapic_ipi) /* * TLB shootdown handler. */ IDTVEC(intr_lapic_tlb) pushl $0 pushl $T_ASTFLT INTRENTRY call _C_LABEL(pmap_tlb_intr) movl _C_LABEL(local_apic_va),%eax movl $0,LAPIC_EOI(%eax) INTRFASTEXIT IDTVEC_END(intr_lapic_tlb) IDTVEC(intr_x2apic_tlb) pushl $0 pushl $T_ASTFLT INTRENTRY call _C_LABEL(pmap_tlb_intr) movl $(MSR_X2APIC_BASE + MSR_X2APIC_EOI),%ecx xorl %eax,%eax xorl %edx,%edx wrmsr INTRFASTEXIT IDTVEC_END(intr_x2apic_tlb) #if defined(DDB) /* * No need to use INTRENTRY, since we were brought here through a task-gate * which triggered a hardware context switch and saved the GPRs in the TSS. */ IDTVEC(intr_ddbipi) 1: str %ax GET_TSS movzwl (%eax),%eax GET_TSS pushl %eax movl _C_LABEL(local_apic_va),%ebx movl $0xff,LAPIC_TPRI(%ebx) movl _C_LABEL(local_apic_va),%ebx movl $0,LAPIC_EOI(%ebx) sti call _C_LABEL(ddb_ipi_tss) addl $4,%esp movl _C_LABEL(local_apic_va),%ebx movl $0,LAPIC_TPRI(%ebx) iret jmp 1b IDTVEC_END(intr_ddbipi) IDTVEC(intr_x2apic_ddbipi) 1: str %ax GET_TSS movzwl (%eax),%eax GET_TSS pushl %eax movl $(MSR_X2APIC_BASE + MSR_X2APIC_TPRI),%ecx movl 0xff,%eax xorl %edx,%edx wrmsr movl $(MSR_X2APIC_BASE + MSR_X2APIC_EOI),%ecx xorl %eax,%eax xorl %edx,%edx wrmsr sti call _C_LABEL(ddb_ipi_tss) addl $4,%esp movl $(MSR_X2APIC_BASE + MSR_X2APIC_TPRI),%ecx xorl %eax,%eax xorl %edx,%edx wrmsr iret jmp 1b IDTVEC_END(intr_x2apic_ddbipi) #endif /* DDB */ #endif /* MULTIPROCESSOR */ /* * Interrupt from the local APIC timer. */ IDTVEC(recurse_lapic_ltimer) INTR_RECURSE_HWFRAME pushl $0 pushl $T_ASTFLT INTRENTRY jmp 1f IDTVEC_END(recurse_lapic_ltimer) IDTVEC(intr_x2apic_ltimer) pushl $0 pushl $T_ASTFLT INTRENTRY movl $(MSR_X2APIC_BASE + MSR_X2APIC_EOI),%ecx xorl %eax,%eax xorl %edx,%edx wrmsr movzbl CPUVAR(ILEVEL),%ebx cmpl $IPL_CLOCK,%ebx jae 2f jmp 1f IDTVEC_END(intr_x2apic_ltimer) IDTVEC(intr_lapic_ltimer) pushl $0 pushl $T_ASTFLT INTRENTRY movl _C_LABEL(local_apic_va),%ebx movl $0,LAPIC_EOI(%ebx) movzbl CPUVAR(ILEVEL),%ebx cmpl $IPL_CLOCK,%ebx jae 2f IDTVEC_END(intr_lapic_ltimer) IDTVEC(resume_lapic_ltimer) 1: pushl %ebx IDEPTH_INCR movb $IPL_CLOCK,CPUVAR(ILEVEL) sti pushl $0 call _C_LABEL(lapic_clockintr) addl $4,%esp cli jmp _C_LABEL(Xdoreti) 2: btsl $(LIR_TIMER - 32),CPUVAR(IPENDING)+4 INTRFASTEXIT IDTVEC_END(resume_lapic_ltimer) #if NHYPERV > 0 /* * Hyper-V event channel upcall interrupt handler. * Only used when the hypervisor supports direct vector callbacks. */ IDTVEC(recurse_hyperv_hypercall) INTR_RECURSE_HWFRAME pushl $0 pushl $T_ASTFLT INTRENTRY jmp 1f IDTVEC_END(recurse_hyperv_hypercall) IDTVEC(intr_hyperv_hypercall) pushl $0 pushl $T_ASTFLT INTRENTRY movzbl CPUVAR(ILEVEL),%ebx cmpl $IPL_NET,%ebx jae 2f jmp 1f IDTVEC_END(intr_hyperv_hypercall) IDTVEC(resume_hyperv_hypercall) 1: pushl %ebx IDEPTH_INCR movb $IPL_NET,CPUVAR(ILEVEL) sti pushl %esp call _C_LABEL(hyperv_hypercall_intr) addl $4,%esp cli jmp _C_LABEL(Xdoreti) 2: btsl $(LIR_HV - 32),CPUVAR(IPENDING)+4 INTRFASTEXIT IDTVEC_END(resume_hyperv_hypercall) #endif /* NHYPERV > 0 */ #endif /* NLAPIC > 0 */ #define voidop(num) /* * This macro defines the generic stub code. Its arguments modifiy it * for specific PICs. */ #define INTRSTUB1(name, num, sub, off, early_ack, late_ack, mask, unmask, level_mask) \ IDTVEC(recurse_ ## name ## num) ;\ INTR_RECURSE_HWFRAME ;\ subl $4,%esp ;\ pushl $T_ASTFLT /* trap # for doing ASTs */ ;\ INTRENTRY ;\ IDTVEC_END(recurse_ ## name ## num) ;\ IDTVEC(resume_ ## name ## num) \ movl $IREENT_MAGIC,TF_ERR(%esp) ;\ movl %ebx,%esi ;\ movl CPUVAR(ISOURCES) + (num) * 4,%ebp ;\ movl IS_MAXLEVEL(%ebp),%ebx ;\ jmp 1f ;\ IDTVEC_END(resume_ ## name ## num) ;\ IDTVEC(intr_ ## name ## num) ;\ pushl $0 /* dummy error code */ ;\ pushl $T_ASTFLT /* trap # for doing ASTs */ ;\ INTRENTRY ;\ movl CPUVAR(ISOURCES) + (num) * 4,%ebp ;\ mask(num) /* mask it in hardware */ ;\ early_ack(num) /* and allow other intrs */ ;\ testl %ebp,%ebp ;\ jz 9f /* stray */ ;\ movl IS_MAXLEVEL(%ebp),%ebx ;\ movzbl CPUVAR(ILEVEL),%esi ;\ cmpl %ebx,%esi ;\ jae 10f /* currently masked; hold it */ ;\ addl $1,CPUVAR(NINTR) /* statistical info */ ;\ adcl $0,CPUVAR(NINTR)+4 ;\ addl $1,IS_EVCNTLO(%ebp) /* inc event counter */ ;\ adcl $0,IS_EVCNTHI(%ebp) ;\ 1: \ pushl %esi /* if_ppi */ ;\ movb %bl,CPUVAR(ILEVEL) ;\ /* switch stack if necessary, and push a ptr to our intrframe */ \ IDEPTH_INCR ;\ sti ;\ movl IS_HANDLERS(%ebp),%ebx ;\ cmpl $0,IS_MASK_COUNT(%ebp) /* source currently masked? */ ;\ jne 12f /* yes, hold it */ ;\ 6: \ movl IH_LEVEL(%ebx),%eax ;\ cmpl %esi,%eax ;\ jle 7f ;\ pushl IH_ARG(%ebx) ;\ movl IH_FUN(%ebx),%edi ;\ movb %al,CPUVAR(ILEVEL) ;\ movl IH_NEXT(%ebx),%ebx /* next handler in chain */ ;\ call *%edi /* call it */ ;\ addl $4,%esp /* toss the arg */ ;\ testl %ebx,%ebx ;\ jnz 6b ;\ cmpl $0,IS_MASK_COUNT(%ebp) /* source now masked? */ ;\ jne 12f /* yes, deal */ ;\ cli ;\ unmask(num) /* unmask it in hardware */ ;\ late_ack(num) ;\ jmp _C_LABEL(Xdoreti) /* lower spl and do ASTs */ ;\ 7: \ cli ;\ btsl $(num - sub),CPUVAR(IPENDING) + off ;\ 8: level_mask(num) ;\ late_ack(num) ;\ jmp _C_LABEL(Xdoreti) /* lower spl and do ASTs */ ;\ 12: \ cli ;\ btsl $(num - sub),CPUVAR(IMASKED) + off ;\ btrl $(num - sub),CPUVAR(IPENDING) + off ;\ jmp 8b ;\ 10: \ btsl $(num - sub),CPUVAR(IPENDING) + off ;\ level_mask(num) ;\ late_ack(num) ;\ INTRFASTEXIT ;\ 9: \ pushl %esp /* for unmask */ ;\ unmask(num) ;\ late_ack(num) ;\ addl $4,%esp ;\ INTRFASTEXIT ;\ IDTVEC_END(intr_ ## name ## num) #define INTRSTUB(name, num, early_ack, late_ack, mask, unmask, level_mask) \ INTRSTUB1(name, num, 0, 0, early_ack, late_ack, mask, unmask, level_mask) #define INTRSTUB32(name, num, early_ack, late_ack, mask, unmask, level_mask) \ INTRSTUB1(name, num, 32, 4, early_ack, late_ack, mask, unmask, level_mask) #define ICUADDR IO_ICU1 INTRSTUB(legacy,0,i8259_asm_ack1,voidop,i8259_asm_mask,i8259_asm_unmask, voidop) INTRSTUB(legacy,1,i8259_asm_ack1,voidop,i8259_asm_mask,i8259_asm_unmask, voidop) INTRSTUB(legacy,2,i8259_asm_ack1,voidop,i8259_asm_mask,i8259_asm_unmask, voidop) INTRSTUB(legacy,3,i8259_asm_ack1,voidop,i8259_asm_mask,i8259_asm_unmask, voidop) INTRSTUB(legacy,4,i8259_asm_ack1,voidop,i8259_asm_mask,i8259_asm_unmask, voidop) INTRSTUB(legacy,5,i8259_asm_ack1,voidop,i8259_asm_mask,i8259_asm_unmask, voidop) INTRSTUB(legacy,6,i8259_asm_ack1,voidop,i8259_asm_mask,i8259_asm_unmask, voidop) INTRSTUB(legacy,7,i8259_asm_ack1,voidop,i8259_asm_mask,i8259_asm_unmask, voidop) #undef ICUADDR #define ICUADDR IO_ICU2 INTRSTUB(legacy,8,i8259_asm_ack2,voidop,i8259_asm_mask,i8259_asm_unmask, voidop) INTRSTUB(legacy,9,i8259_asm_ack2,voidop,i8259_asm_mask,i8259_asm_unmask, voidop) INTRSTUB(legacy,10,i8259_asm_ack2,voidop,i8259_asm_mask,i8259_asm_unmask, voidop) INTRSTUB(legacy,11,i8259_asm_ack2,voidop,i8259_asm_mask,i8259_asm_unmask, voidop) INTRSTUB(legacy,12,i8259_asm_ack2,voidop,i8259_asm_mask,i8259_asm_unmask, voidop) INTRSTUB(legacy,13,i8259_asm_ack2,voidop,i8259_asm_mask,i8259_asm_unmask, voidop) INTRSTUB(legacy,14,i8259_asm_ack2,voidop,i8259_asm_mask,i8259_asm_unmask, voidop) INTRSTUB(legacy,15,i8259_asm_ack2,voidop,i8259_asm_mask,i8259_asm_unmask, voidop) #if NIOAPIC > 0 #define INTRSTUB_56(name,early_ack,late_ack,mask,unmask,level_mask) ;\ INTRSTUB(name,0,early_ack,late_ack,mask,unmask,level_mask) ;\ INTRSTUB(name,1,early_ack,late_ack,mask,unmask,level_mask) ;\ INTRSTUB(name,2,early_ack,late_ack,mask,unmask,level_mask) ;\ INTRSTUB(name,3,early_ack,late_ack,mask,unmask,level_mask) ;\ INTRSTUB(name,4,early_ack,late_ack,mask,unmask,level_mask) ;\ INTRSTUB(name,5,early_ack,late_ack,mask,unmask,level_mask) ;\ INTRSTUB(name,6,early_ack,late_ack,mask,unmask,level_mask) ;\ INTRSTUB(name,7,early_ack,late_ack,mask,unmask,level_mask) ;\ INTRSTUB(name,8,early_ack,late_ack,mask,unmask,level_mask) ;\ INTRSTUB(name,9,early_ack,late_ack,mask,unmask,level_mask) ;\ INTRSTUB(name,10,early_ack,late_ack,mask,unmask,level_mask) ;\ INTRSTUB(name,11,early_ack,late_ack,mask,unmask,level_mask) ;\ INTRSTUB(name,12,early_ack,late_ack,mask,unmask,level_mask) ;\ INTRSTUB(name,13,early_ack,late_ack,mask,unmask,level_mask) ;\ INTRSTUB(name,14,early_ack,late_ack,mask,unmask,level_mask) ;\ INTRSTUB(name,15,early_ack,late_ack,mask,unmask,level_mask) ;\ INTRSTUB(name,16,early_ack,late_ack,mask,unmask,level_mask) ;\ INTRSTUB(name,17,early_ack,late_ack,mask,unmask,level_mask) ;\ INTRSTUB(name,18,early_ack,late_ack,mask,unmask,level_mask) ;\ INTRSTUB(name,19,early_ack,late_ack,mask,unmask,level_mask) ;\ INTRSTUB(name,20,early_ack,late_ack,mask,unmask,level_mask) ;\ INTRSTUB(name,21,early_ack,late_ack,mask,unmask,level_mask) ;\ INTRSTUB(name,22,early_ack,late_ack,mask,unmask,level_mask) ;\ INTRSTUB(name,23,early_ack,late_ack,mask,unmask,level_mask) ;\ INTRSTUB(name,24,early_ack,late_ack,mask,unmask,level_mask) ;\ INTRSTUB(name,25,early_ack,late_ack,mask,unmask,level_mask) ;\ INTRSTUB(name,26,early_ack,late_ack,mask,unmask,level_mask) ;\ INTRSTUB(name,27,early_ack,late_ack,mask,unmask,level_mask) ;\ INTRSTUB(name,28,early_ack,late_ack,mask,unmask,level_mask) ;\ INTRSTUB(name,29,early_ack,late_ack,mask,unmask,level_mask) ;\ INTRSTUB(name,30,early_ack,late_ack,mask,unmask,level_mask) ;\ INTRSTUB(name,31,early_ack,late_ack,mask,unmask,level_mask) ;\ INTRSTUB32(name,32,early_ack,late_ack,mask,unmask,level_mask) ;\ INTRSTUB32(name,33,early_ack,late_ack,mask,unmask,level_mask) ;\ INTRSTUB32(name,34,early_ack,late_ack,mask,unmask,level_mask) ;\ INTRSTUB32(name,35,early_ack,late_ack,mask,unmask,level_mask) ;\ INTRSTUB32(name,36,early_ack,late_ack,mask,unmask,level_mask) ;\ INTRSTUB32(name,37,early_ack,late_ack,mask,unmask,level_mask) ;\ INTRSTUB32(name,38,early_ack,late_ack,mask,unmask,level_mask) ;\ INTRSTUB32(name,39,early_ack,late_ack,mask,unmask,level_mask) ;\ INTRSTUB32(name,40,early_ack,late_ack,mask,unmask,level_mask) ;\ INTRSTUB32(name,41,early_ack,late_ack,mask,unmask,level_mask) ;\ INTRSTUB32(name,42,early_ack,late_ack,mask,unmask,level_mask) ;\ INTRSTUB32(name,43,early_ack,late_ack,mask,unmask,level_mask) ;\ INTRSTUB32(name,44,early_ack,late_ack,mask,unmask,level_mask) ;\ INTRSTUB32(name,45,early_ack,late_ack,mask,unmask,level_mask) ;\ INTRSTUB32(name,46,early_ack,late_ack,mask,unmask,level_mask) ;\ INTRSTUB32(name,47,early_ack,late_ack,mask,unmask,level_mask) ;\ INTRSTUB32(name,48,early_ack,late_ack,mask,unmask,level_mask) ;\ INTRSTUB32(name,49,early_ack,late_ack,mask,unmask,level_mask) ;\ INTRSTUB32(name,50,early_ack,late_ack,mask,unmask,level_mask) ;\ INTRSTUB32(name,51,early_ack,late_ack,mask,unmask,level_mask) ;\ INTRSTUB32(name,52,early_ack,late_ack,mask,unmask,level_mask) ;\ INTRSTUB32(name,53,early_ack,late_ack,mask,unmask,level_mask) ;\ INTRSTUB32(name,54,early_ack,late_ack,mask,unmask,level_mask) ;\ INTRSTUB32(name,55,early_ack,late_ack,mask,unmask,level_mask) INTRSTUB_56(ioapic_edge,voidop,ioapic_asm_ack,voidop,voidop,voidop) INTRSTUB_56(ioapic_level,voidop,ioapic_asm_ack,voidop,ioapic_unmask,ioapic_mask) INTRSTUB_56(x2apic_edge,voidop,x2apic_asm_ack,voidop,voidop,voidop) INTRSTUB_56(x2apic_level,voidop,x2apic_asm_ack,voidop,ioapic_unmask,ioapic_mask) #endif /* * Create a struct intrstub. */ #define INTRSTUB_ENTRY(name) \ .long _C_LABEL(Xintr_ ## name ), _C_LABEL(Xrecurse_ ## name ) ; \ .long _C_LABEL(Xresume_ ## name ) ; /* * Create an array of structs intrstub (16 entries). */ #define INTRSTUB_ARRAY_16(name) ; \ .type _C_LABEL(name ## _stubs), @object ; \ LABEL(name ## _stubs) ; \ INTRSTUB_ENTRY(name ## 0) ; \ INTRSTUB_ENTRY(name ## 1) ; \ INTRSTUB_ENTRY(name ## 2) ; \ INTRSTUB_ENTRY(name ## 3) ; \ INTRSTUB_ENTRY(name ## 4) ; \ INTRSTUB_ENTRY(name ## 5) ; \ INTRSTUB_ENTRY(name ## 6) ; \ INTRSTUB_ENTRY(name ## 7) ; \ INTRSTUB_ENTRY(name ## 8) ; \ INTRSTUB_ENTRY(name ## 9) ; \ INTRSTUB_ENTRY(name ## 10) ; \ INTRSTUB_ENTRY(name ## 11) ; \ INTRSTUB_ENTRY(name ## 12) ; \ INTRSTUB_ENTRY(name ## 13) ; \ INTRSTUB_ENTRY(name ## 14) ; \ INTRSTUB_ENTRY(name ## 15) ; \ END(name ## _stubs) /* * Create an array of structs intrstub (56 entries). */ #define INTRSTUB_ARRAY_56(name) ; \ .type _C_LABEL(name ## _stubs), @object ; \ LABEL(name ## _stubs) ; \ INTRSTUB_ENTRY(name ## 0) ; \ INTRSTUB_ENTRY(name ## 1) ; \ INTRSTUB_ENTRY(name ## 2) ; \ INTRSTUB_ENTRY(name ## 3) ; \ INTRSTUB_ENTRY(name ## 4) ; \ INTRSTUB_ENTRY(name ## 5) ; \ INTRSTUB_ENTRY(name ## 6) ; \ INTRSTUB_ENTRY(name ## 7) ; \ INTRSTUB_ENTRY(name ## 8) ; \ INTRSTUB_ENTRY(name ## 9) ; \ INTRSTUB_ENTRY(name ## 10) ; \ INTRSTUB_ENTRY(name ## 11) ; \ INTRSTUB_ENTRY(name ## 12) ; \ INTRSTUB_ENTRY(name ## 13) ; \ INTRSTUB_ENTRY(name ## 14) ; \ INTRSTUB_ENTRY(name ## 15) ; \ INTRSTUB_ENTRY(name ## 16) ; \ INTRSTUB_ENTRY(name ## 17) ; \ INTRSTUB_ENTRY(name ## 18) ; \ INTRSTUB_ENTRY(name ## 19) ; \ INTRSTUB_ENTRY(name ## 20) ; \ INTRSTUB_ENTRY(name ## 21) ; \ INTRSTUB_ENTRY(name ## 22) ; \ INTRSTUB_ENTRY(name ## 23) ; \ INTRSTUB_ENTRY(name ## 24) ; \ INTRSTUB_ENTRY(name ## 25) ; \ INTRSTUB_ENTRY(name ## 26) ; \ INTRSTUB_ENTRY(name ## 27) ; \ INTRSTUB_ENTRY(name ## 28) ; \ INTRSTUB_ENTRY(name ## 29) ; \ INTRSTUB_ENTRY(name ## 30) ; \ INTRSTUB_ENTRY(name ## 31) ; \ INTRSTUB_ENTRY(name ## 32) ; \ INTRSTUB_ENTRY(name ## 33) ; \ INTRSTUB_ENTRY(name ## 34) ; \ INTRSTUB_ENTRY(name ## 35) ; \ INTRSTUB_ENTRY(name ## 36) ; \ INTRSTUB_ENTRY(name ## 37) ; \ INTRSTUB_ENTRY(name ## 38) ; \ INTRSTUB_ENTRY(name ## 39) ; \ INTRSTUB_ENTRY(name ## 40) ; \ INTRSTUB_ENTRY(name ## 41) ; \ INTRSTUB_ENTRY(name ## 42) ; \ INTRSTUB_ENTRY(name ## 43) ; \ INTRSTUB_ENTRY(name ## 44) ; \ INTRSTUB_ENTRY(name ## 45) ; \ INTRSTUB_ENTRY(name ## 46) ; \ INTRSTUB_ENTRY(name ## 47) ; \ INTRSTUB_ENTRY(name ## 48) ; \ INTRSTUB_ENTRY(name ## 49) ; \ INTRSTUB_ENTRY(name ## 50) ; \ INTRSTUB_ENTRY(name ## 51) ; \ INTRSTUB_ENTRY(name ## 52) ; \ INTRSTUB_ENTRY(name ## 53) ; \ INTRSTUB_ENTRY(name ## 54) ; \ INTRSTUB_ENTRY(name ## 55) ; \ END(name ## _stubs) #endif /* XENPV */ #if defined(XEN) #define voidop(num) #define XENINTRSTUB(name, sir, level, unmask) \ IDTVEC(recurse_ ## name ## sir) ;\ INTR_RECURSE_HWFRAME ;\ subl $4,%esp ;\ pushl $T_ASTFLT /* trap # for doing ASTs */ ;\ INTRENTRY ;\ IDTVEC(resume_ ## name ## sir) \ movl $IREENT_MAGIC,TF_ERR(%esp) ;\ pushl %ebx ;\ movl CPUVAR(ISOURCES) + (sir) * 4,%ebp ;\ movb $level,CPUVAR(ILEVEL) ;\ IDEPTH_INCR /* leaves old %esp on stack */ ;\ STI(%eax) ;\ movl IS_HANDLERS(%ebp),%ebx ;\ 6: \ cmpl $0, IH_PENDING(%ebx) /* is handler pending ? */ ;\ je 7f /* no */ ;\ movl $0, IH_PENDING(%ebx) ;\ pushl IH_ARG(%ebx) ;\ call *IH_FUN(%ebx) /* call it */ ;\ addl $4,%esp /* toss the arg */ ;\ 7: \ movl IH_NEXT(%ebx),%ebx /* next handler in chain */ ;\ testl %ebx,%ebx ;\ jnz 6b ;\ \ CLI(%eax) ;\ unmask(sir) /* unmask it in hardware */ ;\ jmp _C_LABEL(Xdoreti) /* lower spl and do ASTs */ ;\ /* * Just unmasking the event isn't enough, we also need to * reassert the event pending bit if needed. For now just call * the C function doing it, maybe rewrite in inline assembly ? */ #define hypervisor_asm_unmask(sir) \ pushl $sir ;\ call _C_LABEL(hypervisor_enable_sir) ;\ addl $4,%esp XENINTRSTUB(xenev,SIR_XENIPL_VM,IPL_VM,hypervisor_asm_unmask) XENINTRSTUB(xenev,SIR_XENIPL_SCHED,IPL_SCHED,hypervisor_asm_unmask) XENINTRSTUB(xenev,SIR_XENIPL_HIGH,IPL_HIGH,hypervisor_asm_unmask) /* On Xen, the xenev_stubs are purely for spl entry, since there is no * vector based mechanism. We however provide the entrypoint to ensure * that native and Xen struct intrstub ; definitions are uniform. */ panicmsg: .ascii "vector Xen event entry path entered." LABEL(entry_xenev) pushl $panicmsg call _C_LABEL(panic) END(entry_xenev) #define XENINTRSTUB_ENTRY(name, sir) \ .long entry_xenev , _C_LABEL(Xrecurse_ ## name ## sir); \ .long _C_LABEL(Xresume_ ## name ## sir); .type _C_LABEL(xenev_stubs), @object LABEL(xenev_stubs) XENINTRSTUB_ENTRY(xenev, SIR_XENIPL_VM) ; XENINTRSTUB_ENTRY(xenev, SIR_XENIPL_SCHED) ; XENINTRSTUB_ENTRY(xenev, SIR_XENIPL_HIGH) ; END(xenev_stubs) #endif /* XEN */ #include "i386_trap.S" #ifdef XEN ENTRY(hypervisor_callback) IDTVEC(hypervisor_pvhvm_callback) pushl $0 /* dummy error code */ pushl $T_ASTFLT INTRENTRY movzbl CPUVAR(ILEVEL),%eax pushl %eax IDEPTH_INCR /* IDEPTH_INCR puts %esp on stack; we use it as argument to * do_hypervisor_callback. But don't restore the stack after, * Xdoreti needs it too. */ call do_hypervisor_callback #ifndef XENPV movzbl _C_LABEL(xenhvm_use_percpu_callback),%eax testl %eax, %eax jz 1f movl _C_LABEL(local_apic_va),%eax movl $0, LAPIC_EOI(%eax) 1: #endif jmp _C_LABEL(Xdoreti) IDTVEC_END(hypervisor_pvhvm_callback) END(hypervisor_callback) #endif /* XEN */ #ifdef XENPV /* * Hypervisor uses this for application faults while it executes. */ ENTRY(failsafe_callback) pop %ds pop %es pop %fs pop %gs call _C_LABEL(xen_failsafe_handler) iret END(failsafe_callback) #else /* XENPV */ .section .rodata INTRSTUB_ARRAY_16(legacy) #if NIOAPIC > 0 INTRSTUB_ARRAY_56(ioapic_edge) INTRSTUB_ARRAY_56(ioapic_level) INTRSTUB_ARRAY_56(x2apic_edge) INTRSTUB_ARRAY_56(x2apic_level) #endif #endif /* XENPV */