Index: head/sys/amd64/amd64/apic_vector.S =================================================================== --- head/sys/amd64/amd64/apic_vector.S (revision 38243) +++ head/sys/amd64/amd64/apic_vector.S (revision 38244) @@ -1,1052 +1,1047 @@ /* * from: vector.s, 386BSD 0.1 unknown origin - * $Id: apic_vector.s,v 1.29 1998/04/22 22:49:27 tegge Exp $ + * $Id: apic_vector.s,v 1.30 1998/05/17 22:12:04 tegge Exp $ */ #include #include #include "i386/isa/intr_machdep.h" #ifdef FAST_SIMPLELOCK #define GET_FAST_INTR_LOCK \ pushl $_fast_intr_lock ; /* address of lock */ \ call _s_lock ; /* MP-safe */ \ addl $4,%esp #define REL_FAST_INTR_LOCK \ pushl $_fast_intr_lock ; /* address of lock */ \ call _s_unlock ; /* MP-safe */ \ addl $4,%esp #else /* FAST_SIMPLELOCK */ #define GET_FAST_INTR_LOCK \ call _get_isrlock #define REL_FAST_INTR_LOCK \ pushl $_mp_lock ; /* GIANT_LOCK */ \ call _MPrellock ; \ add $4, %esp #endif /* FAST_SIMPLELOCK */ /* convert an absolute IRQ# into a bitmask */ #define IRQ_BIT(irq_num) (1 << (irq_num)) /* make an index into the IO APIC from the IRQ# */ #define REDTBL_IDX(irq_num) (0x10 + ((irq_num) * 2)) /* * Macros for interrupt interrupt entry, call to handler, and exit. */ #ifdef FAST_WITHOUTCPL /* */ #define FAST_INTR(irq_num, vec_name) \ .text ; \ SUPERALIGN_TEXT ; \ IDTVEC(vec_name) ; \ pushl %eax ; /* save only call-used registers */ \ pushl %ecx ; \ pushl %edx ; \ pushl %ds ; \ MAYBE_PUSHL_ES ; \ movl $KDSEL,%eax ; \ movl %ax,%ds ; \ MAYBE_MOVW_AX_ES ; \ FAKE_MCOUNT((4+ACTUALLY_PUSHED)*4(%esp)) ; \ pushl _intr_unit + (irq_num) * 4 ; \ GET_FAST_INTR_LOCK ; \ call *_intr_handler + (irq_num) * 4 ; /* do the work ASAP */ \ REL_FAST_INTR_LOCK ; \ addl $4, %esp ; \ movl $0, lapic_eoi ; \ lock ; \ incl _cnt+V_INTR ; /* book-keeping can wait */ \ movl _intr_countp + (irq_num) * 4, %eax ; \ lock ; \ incl (%eax) ; \ MEXITCOUNT ; \ MAYBE_POPL_ES ; \ popl %ds ; \ popl %edx ; \ popl %ecx ; \ popl %eax ; \ iret #else /* FAST_WITHOUTCPL */ #define FAST_INTR(irq_num, vec_name) \ .text ; \ SUPERALIGN_TEXT ; \ IDTVEC(vec_name) ; \ pushl %eax ; /* save only call-used registers */ \ pushl %ecx ; \ pushl %edx ; \ pushl %ds ; \ MAYBE_PUSHL_ES ; \ movl $KDSEL, %eax ; \ movl %ax, %ds ; \ MAYBE_MOVW_AX_ES ; \ FAKE_MCOUNT((4+ACTUALLY_PUSHED)*4(%esp)) ; \ GET_FAST_INTR_LOCK ; \ pushl _intr_unit + (irq_num) * 4 ; \ call *_intr_handler + (irq_num) * 4 ; /* do the work ASAP */ \ addl $4, %esp ; \ movl $0, lapic_eoi ; \ lock ; \ incl _cnt+V_INTR ; /* book-keeping can wait */ \ movl _intr_countp + (irq_num) * 4,%eax ; \ lock ; \ incl (%eax) ; \ movl _cpl, %eax ; /* unmasking pending HWIs or SWIs? */ \ notl %eax ; \ andl _ipending, %eax ; \ jne 2f ; /* yes, maybe handle them */ \ 1: ; \ MEXITCOUNT ; \ REL_FAST_INTR_LOCK ; \ MAYBE_POPL_ES ; \ popl %ds ; \ popl %edx ; \ popl %ecx ; \ popl %eax ; \ iret ; \ ; \ ALIGN_TEXT ; \ 2: ; \ cmpb $3, _intr_nesting_level ; /* enough stack? */ \ jae 1b ; /* no, return */ \ movl _cpl, %eax ; \ /* XXX next line is probably unnecessary now. */ \ movl $HWI_MASK|SWI_MASK, _cpl ; /* limit nesting ... */ \ lock ; \ incb _intr_nesting_level ; /* ... really limit it ... */ \ sti ; /* to do this as early as possible */ \ MAYBE_POPL_ES ; /* discard most of thin frame ... */ \ popl %ecx ; /* ... original %ds ... */ \ popl %edx ; \ xchgl %eax, 4(%esp) ; /* orig %eax; save cpl */ \ pushal ; /* build fat frame (grrr) ... */ \ pushl %ecx ; /* ... actually %ds ... */ \ pushl %es ; \ movl $KDSEL, %eax ; \ movl %ax, %es ; \ movl (2+8+0)*4(%esp), %ecx ; /* %ecx from thin frame ... */ \ movl %ecx, (2+6)*4(%esp) ; /* ... to fat frame ... */ \ movl (2+8+1)*4(%esp), %eax ; /* ... cpl from thin frame */ \ pushl %eax ; \ subl $4, %esp ; /* junk for unit number */ \ MEXITCOUNT ; \ jmp _doreti #endif /** FAST_WITHOUTCPL */ /* * */ #define PUSH_FRAME \ pushl $0 ; /* dummy error code */ \ pushl $0 ; /* dummy trap type */ \ pushal ; \ pushl %ds ; /* save data and extra segments ... */ \ pushl %es #define POP_FRAME \ popl %es ; \ popl %ds ; \ popal ; \ addl $4+4,%esp #define MASK_IRQ(irq_num) \ IMASK_LOCK ; /* into critical reg */ \ testl $IRQ_BIT(irq_num), _apic_imen ; \ jne 7f ; /* masked, don't mask */ \ orl $IRQ_BIT(irq_num), _apic_imen ; /* set the mask bit */ \ movl _ioapic, %ecx ; /* ioapic[0] addr */ \ movl $REDTBL_IDX(irq_num), (%ecx) ; /* write the index */ \ movl IOAPIC_WINDOW(%ecx), %eax ; /* current value */ \ orl $IOART_INTMASK, %eax ; /* set the mask */ \ movl %eax, IOAPIC_WINDOW(%ecx) ; /* new value */ \ 7: ; /* already masked */ \ IMASK_UNLOCK /* * Test to see whether we are handling an edge or level triggered INT. * Level-triggered INTs must still be masked as we don't clear the source, * and the EOI cycle would cause redundant INTs to occur. */ #define MASK_LEVEL_IRQ(irq_num) \ testl $IRQ_BIT(irq_num), _apic_pin_trigger ; \ jz 9f ; /* edge, don't mask */ \ MASK_IRQ(irq_num) ; \ 9: #ifdef APIC_INTR_REORDER #define EOI_IRQ(irq_num) \ movl _apic_isrbit_location + 8 * (irq_num), %eax ; \ movl (%eax), %eax ; \ testl _apic_isrbit_location + 4 + 8 * (irq_num), %eax ; \ jz 9f ; /* not active */ \ movl $0, lapic_eoi ; \ APIC_ITRACE(apic_itrace_eoi, irq_num, APIC_ITRACE_EOI) ; \ 9: #else #define EOI_IRQ(irq_num) \ testl $IRQ_BIT(irq_num), lapic_isr1; \ jz 9f ; /* not active */ \ movl $0, lapic_eoi; \ APIC_ITRACE(apic_itrace_eoi, irq_num, APIC_ITRACE_EOI) ; \ 9: #endif /* * Test to see if the source is currntly masked, clear if so. */ #define UNMASK_IRQ(irq_num) \ IMASK_LOCK ; /* into critical reg */ \ testl $IRQ_BIT(irq_num), _apic_imen ; \ je 7f ; /* bit clear, not masked */ \ andl $~IRQ_BIT(irq_num), _apic_imen ;/* clear mask bit */ \ movl _ioapic,%ecx ; /* ioapic[0]addr */ \ movl $REDTBL_IDX(irq_num),(%ecx) ; /* write the index */ \ movl IOAPIC_WINDOW(%ecx),%eax ; /* current value */ \ andl $~IOART_INTMASK,%eax ; /* clear the mask */ \ movl %eax,IOAPIC_WINDOW(%ecx) ; /* new value */ \ 7: ; \ IMASK_UNLOCK #ifdef INTR_SIMPLELOCK #define ENLOCK #define DELOCK #define LATELOCK call _get_isrlock #else #define ENLOCK \ ISR_TRYLOCK ; /* XXX this is going away... */ \ testl %eax, %eax ; /* did we get it? */ \ jz 3f #define DELOCK ISR_RELLOCK #define LATELOCK #endif #ifdef APIC_INTR_DIAGNOSTIC #ifdef APIC_INTR_DIAGNOSTIC_IRQ log_intr_event: pushf cli pushl $CNAME(apic_itrace_debuglock) call _s_lock_np addl $4, %esp movl CNAME(apic_itrace_debugbuffer_idx), %ecx andl $32767, %ecx movl _cpuid, %eax shll $8, %eax orl 8(%esp), %eax movw %ax, CNAME(apic_itrace_debugbuffer)(,%ecx,2) incl %ecx andl $32767, %ecx movl %ecx, CNAME(apic_itrace_debugbuffer_idx) pushl $CNAME(apic_itrace_debuglock) call _s_unlock_np addl $4, %esp popf ret #define APIC_ITRACE(name, irq_num, id) \ lock ; /* MP-safe */ \ incl CNAME(name) + (irq_num) * 4 ; \ pushl %eax ; \ pushl %ecx ; \ pushl %edx ; \ movl $(irq_num), %eax ; \ cmpl $APIC_INTR_DIAGNOSTIC_IRQ, %eax ; \ jne 7f ; \ pushl $id ; \ call log_intr_event ; \ addl $4, %esp ; \ 7: ; \ popl %edx ; \ popl %ecx ; \ popl %eax #else #define APIC_ITRACE(name, irq_num, id) \ lock ; /* MP-safe */ \ incl CNAME(name) + (irq_num) * 4 #endif #define APIC_ITRACE_ENTER 1 #define APIC_ITRACE_EOI 2 #define APIC_ITRACE_TRYISRLOCK 3 #define APIC_ITRACE_GOTISRLOCK 4 #define APIC_ITRACE_ENTER2 5 #define APIC_ITRACE_LEAVE 6 #define APIC_ITRACE_UNMASK 7 #define APIC_ITRACE_ACTIVE 8 #define APIC_ITRACE_MASKED 9 #define APIC_ITRACE_NOISRLOCK 10 #define APIC_ITRACE_MASKED2 11 #define APIC_ITRACE_SPLZ 12 #define APIC_ITRACE_DORETI 13 #else #define APIC_ITRACE(name, irq_num, id) #endif #ifdef CPL_AND_CML #define INTR(irq_num, vec_name) \ .text ; \ SUPERALIGN_TEXT ; \ /* _XintrNN: entry point used by IDT/HWIs & splz_unpend via _vec[]. */ \ IDTVEC(vec_name) ; \ PUSH_FRAME ; \ movl $KDSEL, %eax ; /* reload with kernel's data segment */ \ movl %ax, %ds ; \ movl %ax, %es ; \ ; \ APIC_ITRACE(apic_itrace_enter, irq_num, APIC_ITRACE_ENTER) ; \ lock ; /* MP-safe */ \ btsl $(irq_num), iactive ; /* lazy masking */ \ jc 1f ; /* already active */ \ ; \ MASK_LEVEL_IRQ(irq_num) ; \ EOI_IRQ(irq_num) ; \ 0: ; \ APIC_ITRACE(apic_itrace_tryisrlock, irq_num, APIC_ITRACE_TRYISRLOCK) ;\ ENLOCK ; \ ; \ APIC_ITRACE(apic_itrace_gotisrlock, irq_num, APIC_ITRACE_GOTISRLOCK) ;\ AVCPL_LOCK ; /* MP-safe */ \ testl $IRQ_BIT(irq_num), _cpl ; \ jne 2f ; /* this INT masked */ \ testl $IRQ_BIT(irq_num), _cml ; \ jne 2f ; /* this INT masked */ \ orl $IRQ_BIT(irq_num), _cil ; \ AVCPL_UNLOCK ; \ ; \ incb _intr_nesting_level ; \ ; \ /* entry point used by doreti_unpend for HWIs. */ \ __CONCAT(Xresume,irq_num): ; \ FAKE_MCOUNT(12*4(%esp)) ; /* XXX avoid dbl cnt */ \ lock ; incl _cnt+V_INTR ; /* tally interrupts */ \ movl _intr_countp + (irq_num) * 4, %eax ; \ lock ; incl (%eax) ; \ ; \ AVCPL_LOCK ; /* MP-safe */ \ movl _cml, %eax ; \ pushl %eax ; \ orl _intr_mask + (irq_num) * 4, %eax ; \ movl %eax, _cml ; \ AVCPL_UNLOCK ; \ ; \ pushl _intr_unit + (irq_num) * 4 ; \ incl _inside_intr ; \ APIC_ITRACE(apic_itrace_enter2, irq_num, APIC_ITRACE_ENTER2) ; \ sti ; \ call *_intr_handler + (irq_num) * 4 ; \ cli ; \ APIC_ITRACE(apic_itrace_leave, irq_num, APIC_ITRACE_LEAVE) ; \ decl _inside_intr ; \ ; \ lock ; andl $~IRQ_BIT(irq_num), iactive ; \ lock ; andl $~IRQ_BIT(irq_num), _cil ; \ UNMASK_IRQ(irq_num) ; \ APIC_ITRACE(apic_itrace_unmask, irq_num, APIC_ITRACE_UNMASK) ; \ sti ; /* doreti repeats cli/sti */ \ MEXITCOUNT ; \ LATELOCK ; \ jmp _doreti ; \ ; \ ALIGN_TEXT ; \ 1: ; /* active */ \ APIC_ITRACE(apic_itrace_active, irq_num, APIC_ITRACE_ACTIVE) ; \ MASK_IRQ(irq_num) ; \ EOI_IRQ(irq_num) ; \ AVCPL_LOCK ; /* MP-safe */ \ orl $IRQ_BIT(irq_num), _ipending ; \ AVCPL_UNLOCK ; \ lock ; \ btsl $(irq_num), iactive ; /* still active */ \ jnc 0b ; /* retry */ \ POP_FRAME ; \ iret ; \ ; \ ALIGN_TEXT ; \ 2: ; /* masked by cpl|cml */ \ APIC_ITRACE(apic_itrace_masked, irq_num, APIC_ITRACE_MASKED) ; \ orl $IRQ_BIT(irq_num), _ipending ; \ AVCPL_UNLOCK ; \ DELOCK ; /* XXX this is going away... */ \ POP_FRAME ; \ iret ; \ ALIGN_TEXT ; \ 3: ; /* other cpu has isr lock */ \ APIC_ITRACE(apic_itrace_noisrlock, irq_num, APIC_ITRACE_NOISRLOCK) ;\ AVCPL_LOCK ; /* MP-safe */ \ orl $IRQ_BIT(irq_num), _ipending ; \ testl $IRQ_BIT(irq_num), _cpl ; \ jne 4f ; /* this INT masked */ \ testl $IRQ_BIT(irq_num), _cml ; \ jne 4f ; /* this INT masked */ \ orl $IRQ_BIT(irq_num), _cil ; \ AVCPL_UNLOCK ; \ call forward_irq ; /* forward irq to lock holder */ \ POP_FRAME ; /* and return */ \ iret ; \ ALIGN_TEXT ; \ 4: ; /* blocked */ \ APIC_ITRACE(apic_itrace_masked2, irq_num, APIC_ITRACE_MASKED2) ;\ AVCPL_UNLOCK ; \ POP_FRAME ; /* and return */ \ iret #else /* CPL_AND_CML */ #define INTR(irq_num, vec_name) \ .text ; \ SUPERALIGN_TEXT ; \ /* _XintrNN: entry point used by IDT/HWIs & splz_unpend via _vec[]. */ \ IDTVEC(vec_name) ; \ PUSH_FRAME ; \ movl $KDSEL, %eax ; /* reload with kernel's data segment */ \ movl %ax, %ds ; \ movl %ax, %es ; \ ; \ APIC_ITRACE(apic_itrace_enter, irq_num, APIC_ITRACE_ENTER) ; \ lock ; /* MP-safe */ \ btsl $(irq_num), iactive ; /* lazy masking */ \ jc 1f ; /* already active */ \ ; \ MASK_LEVEL_IRQ(irq_num) ; \ EOI_IRQ(irq_num) ; \ 0: ; \ APIC_ITRACE(apic_itrace_tryisrlock, irq_num, APIC_ITRACE_TRYISRLOCK) ;\ ISR_TRYLOCK ; /* XXX this is going away... */ \ testl %eax, %eax ; /* did we get it? */ \ jz 3f ; /* no */ \ ; \ APIC_ITRACE(apic_itrace_gotisrlock, irq_num, APIC_ITRACE_GOTISRLOCK) ;\ AVCPL_LOCK ; /* MP-safe */ \ testl $IRQ_BIT(irq_num), _cpl ; \ jne 2f ; /* this INT masked */ \ AVCPL_UNLOCK ; \ ; \ incb _intr_nesting_level ; \ ; \ /* entry point used by doreti_unpend for HWIs. */ \ __CONCAT(Xresume,irq_num): ; \ FAKE_MCOUNT(12*4(%esp)) ; /* XXX avoid dbl cnt */ \ lock ; incl _cnt+V_INTR ; /* tally interrupts */ \ movl _intr_countp + (irq_num) * 4, %eax ; \ lock ; incl (%eax) ; \ ; \ AVCPL_LOCK ; /* MP-safe */ \ movl _cpl, %eax ; \ pushl %eax ; \ orl _intr_mask + (irq_num) * 4, %eax ; \ movl %eax, _cpl ; \ andl $~IRQ_BIT(irq_num), _ipending ; \ AVCPL_UNLOCK ; \ ; \ pushl _intr_unit + (irq_num) * 4 ; \ APIC_ITRACE(apic_itrace_enter2, irq_num, APIC_ITRACE_ENTER2) ; \ sti ; \ call *_intr_handler + (irq_num) * 4 ; \ cli ; \ APIC_ITRACE(apic_itrace_leave, irq_num, APIC_ITRACE_LEAVE) ; \ ; \ lock ; andl $~IRQ_BIT(irq_num), iactive ; \ UNMASK_IRQ(irq_num) ; \ APIC_ITRACE(apic_itrace_unmask, irq_num, APIC_ITRACE_UNMASK) ; \ sti ; /* doreti repeats cli/sti */ \ MEXITCOUNT ; \ jmp _doreti ; \ ; \ ALIGN_TEXT ; \ 1: ; /* active */ \ APIC_ITRACE(apic_itrace_active, irq_num, APIC_ITRACE_ACTIVE) ; \ MASK_IRQ(irq_num) ; \ EOI_IRQ(irq_num) ; \ AVCPL_LOCK ; /* MP-safe */ \ orl $IRQ_BIT(irq_num), _ipending ; \ AVCPL_UNLOCK ; \ lock ; \ btsl $(irq_num), iactive ; /* still active */ \ jnc 0b ; /* retry */ \ POP_FRAME ; \ iret ; /* XXX: iactive bit might be 0 now */ \ ALIGN_TEXT ; \ 2: ; /* masked by cpl, leave iactive set */ \ APIC_ITRACE(apic_itrace_masked, irq_num, APIC_ITRACE_MASKED) ; \ orl $IRQ_BIT(irq_num), _ipending ; \ AVCPL_UNLOCK ; \ ISR_RELLOCK ; /* XXX this is going away... */ \ POP_FRAME ; \ iret ; \ ALIGN_TEXT ; \ 3: ; /* other cpu has isr lock */ \ APIC_ITRACE(apic_itrace_noisrlock, irq_num, APIC_ITRACE_NOISRLOCK) ;\ AVCPL_LOCK ; /* MP-safe */ \ orl $IRQ_BIT(irq_num), _ipending ; \ testl $IRQ_BIT(irq_num), _cpl ; \ jne 4f ; /* this INT masked */ \ AVCPL_UNLOCK ; \ call forward_irq ; /* forward irq to lock holder */ \ POP_FRAME ; /* and return */ \ iret ; \ ALIGN_TEXT ; \ 4: ; /* blocked */ \ APIC_ITRACE(apic_itrace_masked2, irq_num, APIC_ITRACE_MASKED2) ;\ AVCPL_UNLOCK ; \ POP_FRAME ; /* and return */ \ iret #endif /* CPL_AND_CML */ /* * Handle "spurious INTerrupts". * Notes: * This is different than the "spurious INTerrupt" generated by an * 8259 PIC for missing INTs. See the APIC documentation for details. * This routine should NOT do an 'EOI' cycle. */ .text SUPERALIGN_TEXT .globl _Xspuriousint _Xspuriousint: /* No EOI cycle used here */ iret /* * Handle TLB shootdowns. */ .text SUPERALIGN_TEXT .globl _Xinvltlb _Xinvltlb: pushl %eax #ifdef COUNT_XINVLTLB_HITS ss movl _cpuid, %eax ss incl _xhits(,%eax,4) #endif /* COUNT_XINVLTLB_HITS */ movl %cr3, %eax /* invalidate the TLB */ movl %eax, %cr3 ss /* stack segment, avoid %ds load */ movl $0, lapic_eoi /* End Of Interrupt to APIC */ popl %eax iret #ifdef BETTER_CLOCK /* * Executed by a CPU when it receives an Xcpucheckstate IPI from another CPU, * * - Stores current cpu state in checkstate_cpustate[cpuid] * 0 == user, 1 == sys, 2 == intr * - Stores current process in checkstate_curproc[cpuid] * * - Signals its receipt by setting bit cpuid in checkstate_probed_cpus. * * stack: 0 -> ds, 4 -> ebx, 8 -> eax, 12 -> eip, 16 -> cs, 20 -> eflags */ .text SUPERALIGN_TEXT .globl _Xcpucheckstate .globl _checkstate_cpustate .globl _checkstate_curproc .globl _checkstate_pc _Xcpucheckstate: pushl %eax pushl %ebx pushl %ds /* save current data segment */ movl $KDSEL, %eax movl %ax, %ds /* use KERNEL data segment */ movl $0, lapic_eoi /* End Of Interrupt to APIC */ movl $0, %ebx movl 16(%esp), %eax andl $3, %eax cmpl $3, %eax je 1f #ifdef VM86 testl $PSL_VM, 20(%esp) jne 1f #endif incl %ebx /* system or interrupt */ #ifdef CPL_AND_CML cmpl $0, _inside_intr je 1f incl %ebx /* interrupt */ #endif 1: movl _cpuid, %eax movl %ebx, _checkstate_cpustate(,%eax,4) movl _curproc, %ebx movl %ebx, _checkstate_curproc(,%eax,4) movl 12(%esp), %ebx movl %ebx, _checkstate_pc(,%eax,4) lock /* checkstate_probed_cpus |= (1<> 3) #ifdef AUTO_EOI_1 #define ENABLE_ICU1 /* use auto-EOI to reduce i/o */ #define OUTB_ICU1 #else #define ENABLE_ICU1 \ movb $ICU_EOI,%al ; /* as soon as possible send EOI ... */ \ OUTB_ICU1 /* ... to clear in service bit */ #define OUTB_ICU1 \ outb %al,$IO_ICU1 #endif #ifdef AUTO_EOI_2 /* * The data sheet says no auto-EOI on slave, but it sometimes works. */ #define ENABLE_ICU1_AND_2 ENABLE_ICU1 #else #define ENABLE_ICU1_AND_2 \ movb $ICU_EOI,%al ; /* as above */ \ outb %al,$IO_ICU2 ; /* but do second icu first ... */ \ OUTB_ICU1 /* ... then first icu (if !AUTO_EOI_1) */ #endif /* * Macros for interrupt interrupt entry, call to handler, and exit. */ #define FAST_INTR(irq_num, vec_name, enable_icus) \ .text ; \ SUPERALIGN_TEXT ; \ IDTVEC(vec_name) ; \ pushl %eax ; /* save only call-used registers */ \ pushl %ecx ; \ pushl %edx ; \ pushl %ds ; \ MAYBE_PUSHL_ES ; \ movl $KDSEL,%eax ; \ movl %ax,%ds ; \ MAYBE_MOVW_AX_ES ; \ FAKE_MCOUNT((4+ACTUALLY_PUSHED)*4(%esp)) ; \ pushl _intr_unit + (irq_num) * 4 ; \ call *_intr_handler + (irq_num) * 4 ; /* do the work ASAP */ \ enable_icus ; /* (re)enable ASAP (helps edge trigger?) */ \ addl $4,%esp ; \ incl _cnt+V_INTR ; /* book-keeping can wait */ \ movl _intr_countp + (irq_num) * 4,%eax ; \ incl (%eax) ; \ movl _cpl,%eax ; /* are we unmasking pending HWIs or SWIs? */ \ notl %eax ; \ andl _ipending,%eax ; \ jne 2f ; /* yes, maybe handle them */ \ 1: ; \ MEXITCOUNT ; \ MAYBE_POPL_ES ; \ popl %ds ; \ popl %edx ; \ popl %ecx ; \ popl %eax ; \ iret ; \ ; \ ALIGN_TEXT ; \ 2: ; \ cmpb $3,_intr_nesting_level ; /* is there enough stack? */ \ jae 1b ; /* no, return */ \ movl _cpl,%eax ; \ /* XXX next line is probably unnecessary now. */ \ movl $HWI_MASK|SWI_MASK,_cpl ; /* limit nesting ... */ \ incb _intr_nesting_level ; /* ... really limit it ... */ \ sti ; /* ... to do this as early as possible */ \ MAYBE_POPL_ES ; /* discard most of thin frame ... */ \ popl %ecx ; /* ... original %ds ... */ \ popl %edx ; \ xchgl %eax,4(%esp) ; /* orig %eax; save cpl */ \ pushal ; /* build fat frame (grrr) ... */ \ pushl %ecx ; /* ... actually %ds ... */ \ pushl %es ; \ movl $KDSEL,%eax ; \ movl %ax,%es ; \ movl (2+8+0)*4(%esp),%ecx ; /* ... %ecx from thin frame ... */ \ movl %ecx,(2+6)*4(%esp) ; /* ... to fat frame ... */ \ movl (2+8+1)*4(%esp),%eax ; /* ... cpl from thin frame */ \ pushl %eax ; \ subl $4,%esp ; /* junk for unit number */ \ MEXITCOUNT ; \ jmp _doreti #define INTR(irq_num, vec_name, icu, enable_icus, reg) \ .text ; \ SUPERALIGN_TEXT ; \ IDTVEC(vec_name) ; \ pushl $0 ; /* dummy error code */ \ pushl $0 ; /* dummy trap type */ \ pushal ; \ pushl %ds ; /* save our data and extra segments ... */ \ pushl %es ; \ movl $KDSEL,%eax ; /* ... and reload with kernel's own ... */ \ movl %ax,%ds ; /* ... early for obsolete reasons */ \ movl %ax,%es ; \ movb _imen + IRQ_BYTE(irq_num),%al ; \ orb $IRQ_BIT(irq_num),%al ; \ movb %al,_imen + IRQ_BYTE(irq_num) ; \ outb %al,$icu+ICU_IMR_OFFSET ; \ enable_icus ; \ movl _cpl,%eax ; \ testb $IRQ_BIT(irq_num),%reg ; \ jne 2f ; \ incb _intr_nesting_level ; \ __CONCAT(Xresume,irq_num): ; \ FAKE_MCOUNT(12*4(%esp)) ; /* XXX late to avoid double count */ \ incl _cnt+V_INTR ; /* tally interrupts */ \ movl _intr_countp + (irq_num) * 4,%eax ; \ incl (%eax) ; \ movl _cpl,%eax ; \ pushl %eax ; \ pushl _intr_unit + (irq_num) * 4 ; \ orl _intr_mask + (irq_num) * 4,%eax ; \ movl %eax,_cpl ; \ sti ; \ call *_intr_handler + (irq_num) * 4 ; \ cli ; /* must unmask _imen and icu atomically */ \ movb _imen + IRQ_BYTE(irq_num),%al ; \ andb $~IRQ_BIT(irq_num),%al ; \ movb %al,_imen + IRQ_BYTE(irq_num) ; \ outb %al,$icu+ICU_IMR_OFFSET ; \ sti ; /* XXX _doreti repeats the cli/sti */ \ MEXITCOUNT ; \ /* We could usually avoid the following jmp by inlining some of */ \ /* _doreti, but it's probably better to use less cache. */ \ jmp _doreti ; \ ; \ ALIGN_TEXT ; \ 2: ; \ /* XXX skip mcounting here to avoid double count */ \ orb $IRQ_BIT(irq_num),_ipending + IRQ_BYTE(irq_num) ; \ popl %es ; \ popl %ds ; \ popal ; \ addl $4+4,%esp ; \ iret MCOUNT_LABEL(bintr) FAST_INTR(0,fastintr0, ENABLE_ICU1) FAST_INTR(1,fastintr1, ENABLE_ICU1) FAST_INTR(2,fastintr2, ENABLE_ICU1) FAST_INTR(3,fastintr3, ENABLE_ICU1) FAST_INTR(4,fastintr4, ENABLE_ICU1) FAST_INTR(5,fastintr5, ENABLE_ICU1) FAST_INTR(6,fastintr6, ENABLE_ICU1) FAST_INTR(7,fastintr7, ENABLE_ICU1) FAST_INTR(8,fastintr8, ENABLE_ICU1_AND_2) FAST_INTR(9,fastintr9, ENABLE_ICU1_AND_2) FAST_INTR(10,fastintr10, ENABLE_ICU1_AND_2) FAST_INTR(11,fastintr11, ENABLE_ICU1_AND_2) FAST_INTR(12,fastintr12, ENABLE_ICU1_AND_2) FAST_INTR(13,fastintr13, ENABLE_ICU1_AND_2) FAST_INTR(14,fastintr14, ENABLE_ICU1_AND_2) FAST_INTR(15,fastintr15, ENABLE_ICU1_AND_2) INTR(0,intr0, IO_ICU1, ENABLE_ICU1, al) INTR(1,intr1, IO_ICU1, ENABLE_ICU1, al) INTR(2,intr2, IO_ICU1, ENABLE_ICU1, al) INTR(3,intr3, IO_ICU1, ENABLE_ICU1, al) INTR(4,intr4, IO_ICU1, ENABLE_ICU1, al) INTR(5,intr5, IO_ICU1, ENABLE_ICU1, al) INTR(6,intr6, IO_ICU1, ENABLE_ICU1, al) INTR(7,intr7, IO_ICU1, ENABLE_ICU1, al) INTR(8,intr8, IO_ICU2, ENABLE_ICU1_AND_2, ah) INTR(9,intr9, IO_ICU2, ENABLE_ICU1_AND_2, ah) INTR(10,intr10, IO_ICU2, ENABLE_ICU1_AND_2, ah) INTR(11,intr11, IO_ICU2, ENABLE_ICU1_AND_2, ah) INTR(12,intr12, IO_ICU2, ENABLE_ICU1_AND_2, ah) INTR(13,intr13, IO_ICU2, ENABLE_ICU1_AND_2, ah) INTR(14,intr14, IO_ICU2, ENABLE_ICU1_AND_2, ah) INTR(15,intr15, IO_ICU2, ENABLE_ICU1_AND_2, ah) MCOUNT_LABEL(eintr) .data .globl _ihandlers -_ihandlers: -ihandlers: /* addresses of interrupt handlers */ +_ihandlers: /* addresses of interrupt handlers */ /* actually resumption addresses for HWI's */ .long Xresume0, Xresume1, Xresume2, Xresume3 .long Xresume4, Xresume5, Xresume6, Xresume7 .long Xresume8, Xresume9, Xresume10, Xresume11 .long Xresume12, Xresume13, Xresume14, Xresume15 .long swi_tty, swi_net, dummycamisr, dummycamisr - .long _swi_vm, 0, 0, 0 - .long 0, 0, 0, 0 - .long 0, 0, _softclock, swi_ast + .long _swi_vm, _swi_null, _swi_null, _swi_null + .long _swi_null, _swi_null, _swi_null, _swi_null + .long _swi_null, _swi_null, _softclock, swi_ast imasks: /* masks for interrupt handlers */ .space NHWI*4 /* padding; HWI masks are elsewhere */ .long SWI_TTY_MASK, SWI_NET_MASK, SWI_CAMNET_MASK, SWI_CAMBIO_MASK .long SWI_VM_MASK, 0, 0, 0 .long 0, 0, 0, 0 .long 0, 0, SWI_CLOCK_MASK, SWI_AST_MASK /* * Interrupt counters and names. The format of these and the label names * must agree with what vmstat expects. The tables are indexed by device * ids so that we don't have to move the names around as devices are * attached. */ #include "vector.h" .globl _intrcnt, _eintrcnt _intrcnt: .space (NR_DEVICES + ICU_LEN) * 4 _eintrcnt: .globl _intrnames, _eintrnames _intrnames: .ascii DEVICE_NAMES .asciz "stray irq0" .asciz "stray irq1" .asciz "stray irq2" .asciz "stray irq3" .asciz "stray irq4" .asciz "stray irq5" .asciz "stray irq6" .asciz "stray irq7" .asciz "stray irq8" .asciz "stray irq9" .asciz "stray irq10" .asciz "stray irq11" .asciz "stray irq12" .asciz "stray irq13" .asciz "stray irq14" .asciz "stray irq15" _eintrnames: .text Index: head/sys/amd64/isa/icu_ipl.S =================================================================== --- head/sys/amd64/isa/icu_ipl.S (revision 38243) +++ head/sys/amd64/isa/icu_ipl.S (revision 38244) @@ -1,173 +1,170 @@ /*- * Copyright (c) 1989, 1990 William F. Jolitz. * Copyright (c) 1990 The Regents of the University of California. * All rights reserved. * * This code is derived from software contributed to Berkeley by * William Jolitz. * * 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 by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. * - * $Id: icu_ipl.s,v 1.2 1997/08/24 00:05:13 fsmp Exp $ + * $Id: icu_ipl.s,v 1.3 1997/09/02 19:40:13 fsmp Exp $ */ .data ALIGN_DATA vec: .long vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7 .long vec8, vec9, vec10, vec11, vec12, vec13, vec14, vec15 /* interrupt mask enable (all h/w off) */ .globl _imen _imen: .long HWI_MASK /* * */ .text SUPERALIGN_TEXT /* * Interrupt priority mechanism * -- soft splXX masks with group mechanism (cpl) * -- h/w masks for currently active or unused interrupts (imen) * -- ipending = active interrupts currently masked by cpl */ ENTRY(splz) /* * The caller has restored cpl and checked that (ipending & ~cpl) * is nonzero. We have to repeat the check since if there is an * interrupt while we're looking, _doreti processing for the * interrupt will handle all the unmasked pending interrupts * because we restored early. We're repeating the calculation * of (ipending & ~cpl) anyway so that the caller doesn't have * to pass it, so this only costs one "jne". "bsfl %ecx,%ecx" * is undefined when %ecx is 0 so we can't rely on the secondary * btrl tests. */ movl _cpl,%eax splz_next: /* * We don't need any locking here. (ipending & ~cpl) cannot grow * while we're looking at it - any interrupt will shrink it to 0. */ movl %eax,%ecx notl %ecx andl _ipending,%ecx jne splz_unpend ret ALIGN_TEXT splz_unpend: bsfl %ecx,%ecx btrl %ecx,_ipending jnc splz_next - movl ihandlers(,%ecx,4),%edx - testl %edx,%edx - je splz_next /* "can't happen" */ cmpl $NHWI,%ecx jae splz_swi /* * We would prefer to call the intr handler directly here but that * doesn't work for badly behaved handlers that want the interrupt * frame. Also, there's a problem determining the unit number. * We should change the interface so that the unit number is not * determined at config time. */ jmp *vec(,%ecx,4) ALIGN_TEXT splz_swi: cmpl $SWI_AST,%ecx je splz_next /* "can't happen" */ pushl %eax orl imasks(,%ecx,4),%eax movl %eax,_cpl - call %edx + call *_ihandlers(,%ecx,4) popl %eax movl %eax,_cpl jmp splz_next /* * Fake clock interrupt(s) so that they appear to come from our caller instead * of from here, so that system profiling works. * XXX do this more generally (for all vectors; look up the C entry point). * XXX frame bogusness stops us from just jumping to the C entry point. */ ALIGN_TEXT vec0: popl %eax /* return address */ pushfl pushl $KCSEL pushl %eax cli MEXITCOUNT jmp _Xintr0 /* XXX might need _Xfastintr0 */ #ifndef PC98 ALIGN_TEXT vec8: popl %eax pushfl pushl $KCSEL pushl %eax cli MEXITCOUNT jmp _Xintr8 /* XXX might need _Xfastintr8 */ #endif /* PC98 */ /* * The 'generic' vector stubs. */ #define BUILD_VEC(irq_num) \ ALIGN_TEXT ; \ __CONCAT(vec,irq_num): ; \ int $ICU_OFFSET + (irq_num) ; \ ret BUILD_VEC(1) BUILD_VEC(2) BUILD_VEC(3) BUILD_VEC(4) BUILD_VEC(5) BUILD_VEC(6) BUILD_VEC(7) #ifdef PC98 BUILD_VEC(8) #endif BUILD_VEC(9) BUILD_VEC(10) BUILD_VEC(11) BUILD_VEC(12) BUILD_VEC(13) BUILD_VEC(14) BUILD_VEC(15) Index: head/sys/amd64/isa/icu_ipl.s =================================================================== --- head/sys/amd64/isa/icu_ipl.s (revision 38243) +++ head/sys/amd64/isa/icu_ipl.s (revision 38244) @@ -1,173 +1,170 @@ /*- * Copyright (c) 1989, 1990 William F. Jolitz. * Copyright (c) 1990 The Regents of the University of California. * All rights reserved. * * This code is derived from software contributed to Berkeley by * William Jolitz. * * 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 by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. * - * $Id: icu_ipl.s,v 1.2 1997/08/24 00:05:13 fsmp Exp $ + * $Id: icu_ipl.s,v 1.3 1997/09/02 19:40:13 fsmp Exp $ */ .data ALIGN_DATA vec: .long vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7 .long vec8, vec9, vec10, vec11, vec12, vec13, vec14, vec15 /* interrupt mask enable (all h/w off) */ .globl _imen _imen: .long HWI_MASK /* * */ .text SUPERALIGN_TEXT /* * Interrupt priority mechanism * -- soft splXX masks with group mechanism (cpl) * -- h/w masks for currently active or unused interrupts (imen) * -- ipending = active interrupts currently masked by cpl */ ENTRY(splz) /* * The caller has restored cpl and checked that (ipending & ~cpl) * is nonzero. We have to repeat the check since if there is an * interrupt while we're looking, _doreti processing for the * interrupt will handle all the unmasked pending interrupts * because we restored early. We're repeating the calculation * of (ipending & ~cpl) anyway so that the caller doesn't have * to pass it, so this only costs one "jne". "bsfl %ecx,%ecx" * is undefined when %ecx is 0 so we can't rely on the secondary * btrl tests. */ movl _cpl,%eax splz_next: /* * We don't need any locking here. (ipending & ~cpl) cannot grow * while we're looking at it - any interrupt will shrink it to 0. */ movl %eax,%ecx notl %ecx andl _ipending,%ecx jne splz_unpend ret ALIGN_TEXT splz_unpend: bsfl %ecx,%ecx btrl %ecx,_ipending jnc splz_next - movl ihandlers(,%ecx,4),%edx - testl %edx,%edx - je splz_next /* "can't happen" */ cmpl $NHWI,%ecx jae splz_swi /* * We would prefer to call the intr handler directly here but that * doesn't work for badly behaved handlers that want the interrupt * frame. Also, there's a problem determining the unit number. * We should change the interface so that the unit number is not * determined at config time. */ jmp *vec(,%ecx,4) ALIGN_TEXT splz_swi: cmpl $SWI_AST,%ecx je splz_next /* "can't happen" */ pushl %eax orl imasks(,%ecx,4),%eax movl %eax,_cpl - call %edx + call *_ihandlers(,%ecx,4) popl %eax movl %eax,_cpl jmp splz_next /* * Fake clock interrupt(s) so that they appear to come from our caller instead * of from here, so that system profiling works. * XXX do this more generally (for all vectors; look up the C entry point). * XXX frame bogusness stops us from just jumping to the C entry point. */ ALIGN_TEXT vec0: popl %eax /* return address */ pushfl pushl $KCSEL pushl %eax cli MEXITCOUNT jmp _Xintr0 /* XXX might need _Xfastintr0 */ #ifndef PC98 ALIGN_TEXT vec8: popl %eax pushfl pushl $KCSEL pushl %eax cli MEXITCOUNT jmp _Xintr8 /* XXX might need _Xfastintr8 */ #endif /* PC98 */ /* * The 'generic' vector stubs. */ #define BUILD_VEC(irq_num) \ ALIGN_TEXT ; \ __CONCAT(vec,irq_num): ; \ int $ICU_OFFSET + (irq_num) ; \ ret BUILD_VEC(1) BUILD_VEC(2) BUILD_VEC(3) BUILD_VEC(4) BUILD_VEC(5) BUILD_VEC(6) BUILD_VEC(7) #ifdef PC98 BUILD_VEC(8) #endif BUILD_VEC(9) BUILD_VEC(10) BUILD_VEC(11) BUILD_VEC(12) BUILD_VEC(13) BUILD_VEC(14) BUILD_VEC(15) Index: head/sys/amd64/isa/icu_vector.S =================================================================== --- head/sys/amd64/isa/icu_vector.S (revision 38243) +++ head/sys/amd64/isa/icu_vector.S (revision 38244) @@ -1,251 +1,250 @@ /* * from: vector.s, 386BSD 0.1 unknown origin - * $Id: icu_vector.s,v 1.6 1997/09/28 19:30:01 gibbs Exp $ + * $Id: icu_vector.s,v 1.7 1998/01/15 07:33:59 gibbs Exp $ */ /* * modified for PC98 by Kakefuda */ #ifdef PC98 #define ICU_IMR_OFFSET 2 /* IO_ICU{1,2} + 2 */ #else #define ICU_IMR_OFFSET 1 /* IO_ICU{1,2} + 1 */ #endif #define ICU_EOI 0x20 /* XXX - define elsewhere */ #define IRQ_BIT(irq_num) (1 << ((irq_num) % 8)) #define IRQ_BYTE(irq_num) ((irq_num) >> 3) #ifdef AUTO_EOI_1 #define ENABLE_ICU1 /* use auto-EOI to reduce i/o */ #define OUTB_ICU1 #else #define ENABLE_ICU1 \ movb $ICU_EOI,%al ; /* as soon as possible send EOI ... */ \ OUTB_ICU1 /* ... to clear in service bit */ #define OUTB_ICU1 \ outb %al,$IO_ICU1 #endif #ifdef AUTO_EOI_2 /* * The data sheet says no auto-EOI on slave, but it sometimes works. */ #define ENABLE_ICU1_AND_2 ENABLE_ICU1 #else #define ENABLE_ICU1_AND_2 \ movb $ICU_EOI,%al ; /* as above */ \ outb %al,$IO_ICU2 ; /* but do second icu first ... */ \ OUTB_ICU1 /* ... then first icu (if !AUTO_EOI_1) */ #endif /* * Macros for interrupt interrupt entry, call to handler, and exit. */ #define FAST_INTR(irq_num, vec_name, enable_icus) \ .text ; \ SUPERALIGN_TEXT ; \ IDTVEC(vec_name) ; \ pushl %eax ; /* save only call-used registers */ \ pushl %ecx ; \ pushl %edx ; \ pushl %ds ; \ MAYBE_PUSHL_ES ; \ movl $KDSEL,%eax ; \ movl %ax,%ds ; \ MAYBE_MOVW_AX_ES ; \ FAKE_MCOUNT((4+ACTUALLY_PUSHED)*4(%esp)) ; \ pushl _intr_unit + (irq_num) * 4 ; \ call *_intr_handler + (irq_num) * 4 ; /* do the work ASAP */ \ enable_icus ; /* (re)enable ASAP (helps edge trigger?) */ \ addl $4,%esp ; \ incl _cnt+V_INTR ; /* book-keeping can wait */ \ movl _intr_countp + (irq_num) * 4,%eax ; \ incl (%eax) ; \ movl _cpl,%eax ; /* are we unmasking pending HWIs or SWIs? */ \ notl %eax ; \ andl _ipending,%eax ; \ jne 2f ; /* yes, maybe handle them */ \ 1: ; \ MEXITCOUNT ; \ MAYBE_POPL_ES ; \ popl %ds ; \ popl %edx ; \ popl %ecx ; \ popl %eax ; \ iret ; \ ; \ ALIGN_TEXT ; \ 2: ; \ cmpb $3,_intr_nesting_level ; /* is there enough stack? */ \ jae 1b ; /* no, return */ \ movl _cpl,%eax ; \ /* XXX next line is probably unnecessary now. */ \ movl $HWI_MASK|SWI_MASK,_cpl ; /* limit nesting ... */ \ incb _intr_nesting_level ; /* ... really limit it ... */ \ sti ; /* ... to do this as early as possible */ \ MAYBE_POPL_ES ; /* discard most of thin frame ... */ \ popl %ecx ; /* ... original %ds ... */ \ popl %edx ; \ xchgl %eax,4(%esp) ; /* orig %eax; save cpl */ \ pushal ; /* build fat frame (grrr) ... */ \ pushl %ecx ; /* ... actually %ds ... */ \ pushl %es ; \ movl $KDSEL,%eax ; \ movl %ax,%es ; \ movl (2+8+0)*4(%esp),%ecx ; /* ... %ecx from thin frame ... */ \ movl %ecx,(2+6)*4(%esp) ; /* ... to fat frame ... */ \ movl (2+8+1)*4(%esp),%eax ; /* ... cpl from thin frame */ \ pushl %eax ; \ subl $4,%esp ; /* junk for unit number */ \ MEXITCOUNT ; \ jmp _doreti #define INTR(irq_num, vec_name, icu, enable_icus, reg) \ .text ; \ SUPERALIGN_TEXT ; \ IDTVEC(vec_name) ; \ pushl $0 ; /* dummy error code */ \ pushl $0 ; /* dummy trap type */ \ pushal ; \ pushl %ds ; /* save our data and extra segments ... */ \ pushl %es ; \ movl $KDSEL,%eax ; /* ... and reload with kernel's own ... */ \ movl %ax,%ds ; /* ... early for obsolete reasons */ \ movl %ax,%es ; \ movb _imen + IRQ_BYTE(irq_num),%al ; \ orb $IRQ_BIT(irq_num),%al ; \ movb %al,_imen + IRQ_BYTE(irq_num) ; \ outb %al,$icu+ICU_IMR_OFFSET ; \ enable_icus ; \ movl _cpl,%eax ; \ testb $IRQ_BIT(irq_num),%reg ; \ jne 2f ; \ incb _intr_nesting_level ; \ __CONCAT(Xresume,irq_num): ; \ FAKE_MCOUNT(12*4(%esp)) ; /* XXX late to avoid double count */ \ incl _cnt+V_INTR ; /* tally interrupts */ \ movl _intr_countp + (irq_num) * 4,%eax ; \ incl (%eax) ; \ movl _cpl,%eax ; \ pushl %eax ; \ pushl _intr_unit + (irq_num) * 4 ; \ orl _intr_mask + (irq_num) * 4,%eax ; \ movl %eax,_cpl ; \ sti ; \ call *_intr_handler + (irq_num) * 4 ; \ cli ; /* must unmask _imen and icu atomically */ \ movb _imen + IRQ_BYTE(irq_num),%al ; \ andb $~IRQ_BIT(irq_num),%al ; \ movb %al,_imen + IRQ_BYTE(irq_num) ; \ outb %al,$icu+ICU_IMR_OFFSET ; \ sti ; /* XXX _doreti repeats the cli/sti */ \ MEXITCOUNT ; \ /* We could usually avoid the following jmp by inlining some of */ \ /* _doreti, but it's probably better to use less cache. */ \ jmp _doreti ; \ ; \ ALIGN_TEXT ; \ 2: ; \ /* XXX skip mcounting here to avoid double count */ \ orb $IRQ_BIT(irq_num),_ipending + IRQ_BYTE(irq_num) ; \ popl %es ; \ popl %ds ; \ popal ; \ addl $4+4,%esp ; \ iret MCOUNT_LABEL(bintr) FAST_INTR(0,fastintr0, ENABLE_ICU1) FAST_INTR(1,fastintr1, ENABLE_ICU1) FAST_INTR(2,fastintr2, ENABLE_ICU1) FAST_INTR(3,fastintr3, ENABLE_ICU1) FAST_INTR(4,fastintr4, ENABLE_ICU1) FAST_INTR(5,fastintr5, ENABLE_ICU1) FAST_INTR(6,fastintr6, ENABLE_ICU1) FAST_INTR(7,fastintr7, ENABLE_ICU1) FAST_INTR(8,fastintr8, ENABLE_ICU1_AND_2) FAST_INTR(9,fastintr9, ENABLE_ICU1_AND_2) FAST_INTR(10,fastintr10, ENABLE_ICU1_AND_2) FAST_INTR(11,fastintr11, ENABLE_ICU1_AND_2) FAST_INTR(12,fastintr12, ENABLE_ICU1_AND_2) FAST_INTR(13,fastintr13, ENABLE_ICU1_AND_2) FAST_INTR(14,fastintr14, ENABLE_ICU1_AND_2) FAST_INTR(15,fastintr15, ENABLE_ICU1_AND_2) INTR(0,intr0, IO_ICU1, ENABLE_ICU1, al) INTR(1,intr1, IO_ICU1, ENABLE_ICU1, al) INTR(2,intr2, IO_ICU1, ENABLE_ICU1, al) INTR(3,intr3, IO_ICU1, ENABLE_ICU1, al) INTR(4,intr4, IO_ICU1, ENABLE_ICU1, al) INTR(5,intr5, IO_ICU1, ENABLE_ICU1, al) INTR(6,intr6, IO_ICU1, ENABLE_ICU1, al) INTR(7,intr7, IO_ICU1, ENABLE_ICU1, al) INTR(8,intr8, IO_ICU2, ENABLE_ICU1_AND_2, ah) INTR(9,intr9, IO_ICU2, ENABLE_ICU1_AND_2, ah) INTR(10,intr10, IO_ICU2, ENABLE_ICU1_AND_2, ah) INTR(11,intr11, IO_ICU2, ENABLE_ICU1_AND_2, ah) INTR(12,intr12, IO_ICU2, ENABLE_ICU1_AND_2, ah) INTR(13,intr13, IO_ICU2, ENABLE_ICU1_AND_2, ah) INTR(14,intr14, IO_ICU2, ENABLE_ICU1_AND_2, ah) INTR(15,intr15, IO_ICU2, ENABLE_ICU1_AND_2, ah) MCOUNT_LABEL(eintr) .data .globl _ihandlers -_ihandlers: -ihandlers: /* addresses of interrupt handlers */ +_ihandlers: /* addresses of interrupt handlers */ /* actually resumption addresses for HWI's */ .long Xresume0, Xresume1, Xresume2, Xresume3 .long Xresume4, Xresume5, Xresume6, Xresume7 .long Xresume8, Xresume9, Xresume10, Xresume11 .long Xresume12, Xresume13, Xresume14, Xresume15 .long swi_tty, swi_net, dummycamisr, dummycamisr - .long _swi_vm, 0, 0, 0 - .long 0, 0, 0, 0 - .long 0, 0, _softclock, swi_ast + .long _swi_vm, _swi_null, _swi_null, _swi_null + .long _swi_null, _swi_null, _swi_null, _swi_null + .long _swi_null, _swi_null, _softclock, swi_ast imasks: /* masks for interrupt handlers */ .space NHWI*4 /* padding; HWI masks are elsewhere */ .long SWI_TTY_MASK, SWI_NET_MASK, SWI_CAMNET_MASK, SWI_CAMBIO_MASK .long SWI_VM_MASK, 0, 0, 0 .long 0, 0, 0, 0 .long 0, 0, SWI_CLOCK_MASK, SWI_AST_MASK /* * Interrupt counters and names. The format of these and the label names * must agree with what vmstat expects. The tables are indexed by device * ids so that we don't have to move the names around as devices are * attached. */ #include "vector.h" .globl _intrcnt, _eintrcnt _intrcnt: .space (NR_DEVICES + ICU_LEN) * 4 _eintrcnt: .globl _intrnames, _eintrnames _intrnames: .ascii DEVICE_NAMES .asciz "stray irq0" .asciz "stray irq1" .asciz "stray irq2" .asciz "stray irq3" .asciz "stray irq4" .asciz "stray irq5" .asciz "stray irq6" .asciz "stray irq7" .asciz "stray irq8" .asciz "stray irq9" .asciz "stray irq10" .asciz "stray irq11" .asciz "stray irq12" .asciz "stray irq13" .asciz "stray irq14" .asciz "stray irq15" _eintrnames: .text Index: head/sys/amd64/isa/icu_vector.s =================================================================== --- head/sys/amd64/isa/icu_vector.s (revision 38243) +++ head/sys/amd64/isa/icu_vector.s (revision 38244) @@ -1,251 +1,250 @@ /* * from: vector.s, 386BSD 0.1 unknown origin - * $Id: icu_vector.s,v 1.6 1997/09/28 19:30:01 gibbs Exp $ + * $Id: icu_vector.s,v 1.7 1998/01/15 07:33:59 gibbs Exp $ */ /* * modified for PC98 by Kakefuda */ #ifdef PC98 #define ICU_IMR_OFFSET 2 /* IO_ICU{1,2} + 2 */ #else #define ICU_IMR_OFFSET 1 /* IO_ICU{1,2} + 1 */ #endif #define ICU_EOI 0x20 /* XXX - define elsewhere */ #define IRQ_BIT(irq_num) (1 << ((irq_num) % 8)) #define IRQ_BYTE(irq_num) ((irq_num) >> 3) #ifdef AUTO_EOI_1 #define ENABLE_ICU1 /* use auto-EOI to reduce i/o */ #define OUTB_ICU1 #else #define ENABLE_ICU1 \ movb $ICU_EOI,%al ; /* as soon as possible send EOI ... */ \ OUTB_ICU1 /* ... to clear in service bit */ #define OUTB_ICU1 \ outb %al,$IO_ICU1 #endif #ifdef AUTO_EOI_2 /* * The data sheet says no auto-EOI on slave, but it sometimes works. */ #define ENABLE_ICU1_AND_2 ENABLE_ICU1 #else #define ENABLE_ICU1_AND_2 \ movb $ICU_EOI,%al ; /* as above */ \ outb %al,$IO_ICU2 ; /* but do second icu first ... */ \ OUTB_ICU1 /* ... then first icu (if !AUTO_EOI_1) */ #endif /* * Macros for interrupt interrupt entry, call to handler, and exit. */ #define FAST_INTR(irq_num, vec_name, enable_icus) \ .text ; \ SUPERALIGN_TEXT ; \ IDTVEC(vec_name) ; \ pushl %eax ; /* save only call-used registers */ \ pushl %ecx ; \ pushl %edx ; \ pushl %ds ; \ MAYBE_PUSHL_ES ; \ movl $KDSEL,%eax ; \ movl %ax,%ds ; \ MAYBE_MOVW_AX_ES ; \ FAKE_MCOUNT((4+ACTUALLY_PUSHED)*4(%esp)) ; \ pushl _intr_unit + (irq_num) * 4 ; \ call *_intr_handler + (irq_num) * 4 ; /* do the work ASAP */ \ enable_icus ; /* (re)enable ASAP (helps edge trigger?) */ \ addl $4,%esp ; \ incl _cnt+V_INTR ; /* book-keeping can wait */ \ movl _intr_countp + (irq_num) * 4,%eax ; \ incl (%eax) ; \ movl _cpl,%eax ; /* are we unmasking pending HWIs or SWIs? */ \ notl %eax ; \ andl _ipending,%eax ; \ jne 2f ; /* yes, maybe handle them */ \ 1: ; \ MEXITCOUNT ; \ MAYBE_POPL_ES ; \ popl %ds ; \ popl %edx ; \ popl %ecx ; \ popl %eax ; \ iret ; \ ; \ ALIGN_TEXT ; \ 2: ; \ cmpb $3,_intr_nesting_level ; /* is there enough stack? */ \ jae 1b ; /* no, return */ \ movl _cpl,%eax ; \ /* XXX next line is probably unnecessary now. */ \ movl $HWI_MASK|SWI_MASK,_cpl ; /* limit nesting ... */ \ incb _intr_nesting_level ; /* ... really limit it ... */ \ sti ; /* ... to do this as early as possible */ \ MAYBE_POPL_ES ; /* discard most of thin frame ... */ \ popl %ecx ; /* ... original %ds ... */ \ popl %edx ; \ xchgl %eax,4(%esp) ; /* orig %eax; save cpl */ \ pushal ; /* build fat frame (grrr) ... */ \ pushl %ecx ; /* ... actually %ds ... */ \ pushl %es ; \ movl $KDSEL,%eax ; \ movl %ax,%es ; \ movl (2+8+0)*4(%esp),%ecx ; /* ... %ecx from thin frame ... */ \ movl %ecx,(2+6)*4(%esp) ; /* ... to fat frame ... */ \ movl (2+8+1)*4(%esp),%eax ; /* ... cpl from thin frame */ \ pushl %eax ; \ subl $4,%esp ; /* junk for unit number */ \ MEXITCOUNT ; \ jmp _doreti #define INTR(irq_num, vec_name, icu, enable_icus, reg) \ .text ; \ SUPERALIGN_TEXT ; \ IDTVEC(vec_name) ; \ pushl $0 ; /* dummy error code */ \ pushl $0 ; /* dummy trap type */ \ pushal ; \ pushl %ds ; /* save our data and extra segments ... */ \ pushl %es ; \ movl $KDSEL,%eax ; /* ... and reload with kernel's own ... */ \ movl %ax,%ds ; /* ... early for obsolete reasons */ \ movl %ax,%es ; \ movb _imen + IRQ_BYTE(irq_num),%al ; \ orb $IRQ_BIT(irq_num),%al ; \ movb %al,_imen + IRQ_BYTE(irq_num) ; \ outb %al,$icu+ICU_IMR_OFFSET ; \ enable_icus ; \ movl _cpl,%eax ; \ testb $IRQ_BIT(irq_num),%reg ; \ jne 2f ; \ incb _intr_nesting_level ; \ __CONCAT(Xresume,irq_num): ; \ FAKE_MCOUNT(12*4(%esp)) ; /* XXX late to avoid double count */ \ incl _cnt+V_INTR ; /* tally interrupts */ \ movl _intr_countp + (irq_num) * 4,%eax ; \ incl (%eax) ; \ movl _cpl,%eax ; \ pushl %eax ; \ pushl _intr_unit + (irq_num) * 4 ; \ orl _intr_mask + (irq_num) * 4,%eax ; \ movl %eax,_cpl ; \ sti ; \ call *_intr_handler + (irq_num) * 4 ; \ cli ; /* must unmask _imen and icu atomically */ \ movb _imen + IRQ_BYTE(irq_num),%al ; \ andb $~IRQ_BIT(irq_num),%al ; \ movb %al,_imen + IRQ_BYTE(irq_num) ; \ outb %al,$icu+ICU_IMR_OFFSET ; \ sti ; /* XXX _doreti repeats the cli/sti */ \ MEXITCOUNT ; \ /* We could usually avoid the following jmp by inlining some of */ \ /* _doreti, but it's probably better to use less cache. */ \ jmp _doreti ; \ ; \ ALIGN_TEXT ; \ 2: ; \ /* XXX skip mcounting here to avoid double count */ \ orb $IRQ_BIT(irq_num),_ipending + IRQ_BYTE(irq_num) ; \ popl %es ; \ popl %ds ; \ popal ; \ addl $4+4,%esp ; \ iret MCOUNT_LABEL(bintr) FAST_INTR(0,fastintr0, ENABLE_ICU1) FAST_INTR(1,fastintr1, ENABLE_ICU1) FAST_INTR(2,fastintr2, ENABLE_ICU1) FAST_INTR(3,fastintr3, ENABLE_ICU1) FAST_INTR(4,fastintr4, ENABLE_ICU1) FAST_INTR(5,fastintr5, ENABLE_ICU1) FAST_INTR(6,fastintr6, ENABLE_ICU1) FAST_INTR(7,fastintr7, ENABLE_ICU1) FAST_INTR(8,fastintr8, ENABLE_ICU1_AND_2) FAST_INTR(9,fastintr9, ENABLE_ICU1_AND_2) FAST_INTR(10,fastintr10, ENABLE_ICU1_AND_2) FAST_INTR(11,fastintr11, ENABLE_ICU1_AND_2) FAST_INTR(12,fastintr12, ENABLE_ICU1_AND_2) FAST_INTR(13,fastintr13, ENABLE_ICU1_AND_2) FAST_INTR(14,fastintr14, ENABLE_ICU1_AND_2) FAST_INTR(15,fastintr15, ENABLE_ICU1_AND_2) INTR(0,intr0, IO_ICU1, ENABLE_ICU1, al) INTR(1,intr1, IO_ICU1, ENABLE_ICU1, al) INTR(2,intr2, IO_ICU1, ENABLE_ICU1, al) INTR(3,intr3, IO_ICU1, ENABLE_ICU1, al) INTR(4,intr4, IO_ICU1, ENABLE_ICU1, al) INTR(5,intr5, IO_ICU1, ENABLE_ICU1, al) INTR(6,intr6, IO_ICU1, ENABLE_ICU1, al) INTR(7,intr7, IO_ICU1, ENABLE_ICU1, al) INTR(8,intr8, IO_ICU2, ENABLE_ICU1_AND_2, ah) INTR(9,intr9, IO_ICU2, ENABLE_ICU1_AND_2, ah) INTR(10,intr10, IO_ICU2, ENABLE_ICU1_AND_2, ah) INTR(11,intr11, IO_ICU2, ENABLE_ICU1_AND_2, ah) INTR(12,intr12, IO_ICU2, ENABLE_ICU1_AND_2, ah) INTR(13,intr13, IO_ICU2, ENABLE_ICU1_AND_2, ah) INTR(14,intr14, IO_ICU2, ENABLE_ICU1_AND_2, ah) INTR(15,intr15, IO_ICU2, ENABLE_ICU1_AND_2, ah) MCOUNT_LABEL(eintr) .data .globl _ihandlers -_ihandlers: -ihandlers: /* addresses of interrupt handlers */ +_ihandlers: /* addresses of interrupt handlers */ /* actually resumption addresses for HWI's */ .long Xresume0, Xresume1, Xresume2, Xresume3 .long Xresume4, Xresume5, Xresume6, Xresume7 .long Xresume8, Xresume9, Xresume10, Xresume11 .long Xresume12, Xresume13, Xresume14, Xresume15 .long swi_tty, swi_net, dummycamisr, dummycamisr - .long _swi_vm, 0, 0, 0 - .long 0, 0, 0, 0 - .long 0, 0, _softclock, swi_ast + .long _swi_vm, _swi_null, _swi_null, _swi_null + .long _swi_null, _swi_null, _swi_null, _swi_null + .long _swi_null, _swi_null, _softclock, swi_ast imasks: /* masks for interrupt handlers */ .space NHWI*4 /* padding; HWI masks are elsewhere */ .long SWI_TTY_MASK, SWI_NET_MASK, SWI_CAMNET_MASK, SWI_CAMBIO_MASK .long SWI_VM_MASK, 0, 0, 0 .long 0, 0, 0, 0 .long 0, 0, SWI_CLOCK_MASK, SWI_AST_MASK /* * Interrupt counters and names. The format of these and the label names * must agree with what vmstat expects. The tables are indexed by device * ids so that we don't have to move the names around as devices are * attached. */ #include "vector.h" .globl _intrcnt, _eintrcnt _intrcnt: .space (NR_DEVICES + ICU_LEN) * 4 _eintrcnt: .globl _intrnames, _eintrnames _intrnames: .ascii DEVICE_NAMES .asciz "stray irq0" .asciz "stray irq1" .asciz "stray irq2" .asciz "stray irq3" .asciz "stray irq4" .asciz "stray irq5" .asciz "stray irq6" .asciz "stray irq7" .asciz "stray irq8" .asciz "stray irq9" .asciz "stray irq10" .asciz "stray irq11" .asciz "stray irq12" .asciz "stray irq13" .asciz "stray irq14" .asciz "stray irq15" _eintrnames: .text Index: head/sys/i386/i386/apic_vector.s =================================================================== --- head/sys/i386/i386/apic_vector.s (revision 38243) +++ head/sys/i386/i386/apic_vector.s (revision 38244) @@ -1,1052 +1,1047 @@ /* * from: vector.s, 386BSD 0.1 unknown origin - * $Id: apic_vector.s,v 1.29 1998/04/22 22:49:27 tegge Exp $ + * $Id: apic_vector.s,v 1.30 1998/05/17 22:12:04 tegge Exp $ */ #include #include #include "i386/isa/intr_machdep.h" #ifdef FAST_SIMPLELOCK #define GET_FAST_INTR_LOCK \ pushl $_fast_intr_lock ; /* address of lock */ \ call _s_lock ; /* MP-safe */ \ addl $4,%esp #define REL_FAST_INTR_LOCK \ pushl $_fast_intr_lock ; /* address of lock */ \ call _s_unlock ; /* MP-safe */ \ addl $4,%esp #else /* FAST_SIMPLELOCK */ #define GET_FAST_INTR_LOCK \ call _get_isrlock #define REL_FAST_INTR_LOCK \ pushl $_mp_lock ; /* GIANT_LOCK */ \ call _MPrellock ; \ add $4, %esp #endif /* FAST_SIMPLELOCK */ /* convert an absolute IRQ# into a bitmask */ #define IRQ_BIT(irq_num) (1 << (irq_num)) /* make an index into the IO APIC from the IRQ# */ #define REDTBL_IDX(irq_num) (0x10 + ((irq_num) * 2)) /* * Macros for interrupt interrupt entry, call to handler, and exit. */ #ifdef FAST_WITHOUTCPL /* */ #define FAST_INTR(irq_num, vec_name) \ .text ; \ SUPERALIGN_TEXT ; \ IDTVEC(vec_name) ; \ pushl %eax ; /* save only call-used registers */ \ pushl %ecx ; \ pushl %edx ; \ pushl %ds ; \ MAYBE_PUSHL_ES ; \ movl $KDSEL,%eax ; \ movl %ax,%ds ; \ MAYBE_MOVW_AX_ES ; \ FAKE_MCOUNT((4+ACTUALLY_PUSHED)*4(%esp)) ; \ pushl _intr_unit + (irq_num) * 4 ; \ GET_FAST_INTR_LOCK ; \ call *_intr_handler + (irq_num) * 4 ; /* do the work ASAP */ \ REL_FAST_INTR_LOCK ; \ addl $4, %esp ; \ movl $0, lapic_eoi ; \ lock ; \ incl _cnt+V_INTR ; /* book-keeping can wait */ \ movl _intr_countp + (irq_num) * 4, %eax ; \ lock ; \ incl (%eax) ; \ MEXITCOUNT ; \ MAYBE_POPL_ES ; \ popl %ds ; \ popl %edx ; \ popl %ecx ; \ popl %eax ; \ iret #else /* FAST_WITHOUTCPL */ #define FAST_INTR(irq_num, vec_name) \ .text ; \ SUPERALIGN_TEXT ; \ IDTVEC(vec_name) ; \ pushl %eax ; /* save only call-used registers */ \ pushl %ecx ; \ pushl %edx ; \ pushl %ds ; \ MAYBE_PUSHL_ES ; \ movl $KDSEL, %eax ; \ movl %ax, %ds ; \ MAYBE_MOVW_AX_ES ; \ FAKE_MCOUNT((4+ACTUALLY_PUSHED)*4(%esp)) ; \ GET_FAST_INTR_LOCK ; \ pushl _intr_unit + (irq_num) * 4 ; \ call *_intr_handler + (irq_num) * 4 ; /* do the work ASAP */ \ addl $4, %esp ; \ movl $0, lapic_eoi ; \ lock ; \ incl _cnt+V_INTR ; /* book-keeping can wait */ \ movl _intr_countp + (irq_num) * 4,%eax ; \ lock ; \ incl (%eax) ; \ movl _cpl, %eax ; /* unmasking pending HWIs or SWIs? */ \ notl %eax ; \ andl _ipending, %eax ; \ jne 2f ; /* yes, maybe handle them */ \ 1: ; \ MEXITCOUNT ; \ REL_FAST_INTR_LOCK ; \ MAYBE_POPL_ES ; \ popl %ds ; \ popl %edx ; \ popl %ecx ; \ popl %eax ; \ iret ; \ ; \ ALIGN_TEXT ; \ 2: ; \ cmpb $3, _intr_nesting_level ; /* enough stack? */ \ jae 1b ; /* no, return */ \ movl _cpl, %eax ; \ /* XXX next line is probably unnecessary now. */ \ movl $HWI_MASK|SWI_MASK, _cpl ; /* limit nesting ... */ \ lock ; \ incb _intr_nesting_level ; /* ... really limit it ... */ \ sti ; /* to do this as early as possible */ \ MAYBE_POPL_ES ; /* discard most of thin frame ... */ \ popl %ecx ; /* ... original %ds ... */ \ popl %edx ; \ xchgl %eax, 4(%esp) ; /* orig %eax; save cpl */ \ pushal ; /* build fat frame (grrr) ... */ \ pushl %ecx ; /* ... actually %ds ... */ \ pushl %es ; \ movl $KDSEL, %eax ; \ movl %ax, %es ; \ movl (2+8+0)*4(%esp), %ecx ; /* %ecx from thin frame ... */ \ movl %ecx, (2+6)*4(%esp) ; /* ... to fat frame ... */ \ movl (2+8+1)*4(%esp), %eax ; /* ... cpl from thin frame */ \ pushl %eax ; \ subl $4, %esp ; /* junk for unit number */ \ MEXITCOUNT ; \ jmp _doreti #endif /** FAST_WITHOUTCPL */ /* * */ #define PUSH_FRAME \ pushl $0 ; /* dummy error code */ \ pushl $0 ; /* dummy trap type */ \ pushal ; \ pushl %ds ; /* save data and extra segments ... */ \ pushl %es #define POP_FRAME \ popl %es ; \ popl %ds ; \ popal ; \ addl $4+4,%esp #define MASK_IRQ(irq_num) \ IMASK_LOCK ; /* into critical reg */ \ testl $IRQ_BIT(irq_num), _apic_imen ; \ jne 7f ; /* masked, don't mask */ \ orl $IRQ_BIT(irq_num), _apic_imen ; /* set the mask bit */ \ movl _ioapic, %ecx ; /* ioapic[0] addr */ \ movl $REDTBL_IDX(irq_num), (%ecx) ; /* write the index */ \ movl IOAPIC_WINDOW(%ecx), %eax ; /* current value */ \ orl $IOART_INTMASK, %eax ; /* set the mask */ \ movl %eax, IOAPIC_WINDOW(%ecx) ; /* new value */ \ 7: ; /* already masked */ \ IMASK_UNLOCK /* * Test to see whether we are handling an edge or level triggered INT. * Level-triggered INTs must still be masked as we don't clear the source, * and the EOI cycle would cause redundant INTs to occur. */ #define MASK_LEVEL_IRQ(irq_num) \ testl $IRQ_BIT(irq_num), _apic_pin_trigger ; \ jz 9f ; /* edge, don't mask */ \ MASK_IRQ(irq_num) ; \ 9: #ifdef APIC_INTR_REORDER #define EOI_IRQ(irq_num) \ movl _apic_isrbit_location + 8 * (irq_num), %eax ; \ movl (%eax), %eax ; \ testl _apic_isrbit_location + 4 + 8 * (irq_num), %eax ; \ jz 9f ; /* not active */ \ movl $0, lapic_eoi ; \ APIC_ITRACE(apic_itrace_eoi, irq_num, APIC_ITRACE_EOI) ; \ 9: #else #define EOI_IRQ(irq_num) \ testl $IRQ_BIT(irq_num), lapic_isr1; \ jz 9f ; /* not active */ \ movl $0, lapic_eoi; \ APIC_ITRACE(apic_itrace_eoi, irq_num, APIC_ITRACE_EOI) ; \ 9: #endif /* * Test to see if the source is currntly masked, clear if so. */ #define UNMASK_IRQ(irq_num) \ IMASK_LOCK ; /* into critical reg */ \ testl $IRQ_BIT(irq_num), _apic_imen ; \ je 7f ; /* bit clear, not masked */ \ andl $~IRQ_BIT(irq_num), _apic_imen ;/* clear mask bit */ \ movl _ioapic,%ecx ; /* ioapic[0]addr */ \ movl $REDTBL_IDX(irq_num),(%ecx) ; /* write the index */ \ movl IOAPIC_WINDOW(%ecx),%eax ; /* current value */ \ andl $~IOART_INTMASK,%eax ; /* clear the mask */ \ movl %eax,IOAPIC_WINDOW(%ecx) ; /* new value */ \ 7: ; \ IMASK_UNLOCK #ifdef INTR_SIMPLELOCK #define ENLOCK #define DELOCK #define LATELOCK call _get_isrlock #else #define ENLOCK \ ISR_TRYLOCK ; /* XXX this is going away... */ \ testl %eax, %eax ; /* did we get it? */ \ jz 3f #define DELOCK ISR_RELLOCK #define LATELOCK #endif #ifdef APIC_INTR_DIAGNOSTIC #ifdef APIC_INTR_DIAGNOSTIC_IRQ log_intr_event: pushf cli pushl $CNAME(apic_itrace_debuglock) call _s_lock_np addl $4, %esp movl CNAME(apic_itrace_debugbuffer_idx), %ecx andl $32767, %ecx movl _cpuid, %eax shll $8, %eax orl 8(%esp), %eax movw %ax, CNAME(apic_itrace_debugbuffer)(,%ecx,2) incl %ecx andl $32767, %ecx movl %ecx, CNAME(apic_itrace_debugbuffer_idx) pushl $CNAME(apic_itrace_debuglock) call _s_unlock_np addl $4, %esp popf ret #define APIC_ITRACE(name, irq_num, id) \ lock ; /* MP-safe */ \ incl CNAME(name) + (irq_num) * 4 ; \ pushl %eax ; \ pushl %ecx ; \ pushl %edx ; \ movl $(irq_num), %eax ; \ cmpl $APIC_INTR_DIAGNOSTIC_IRQ, %eax ; \ jne 7f ; \ pushl $id ; \ call log_intr_event ; \ addl $4, %esp ; \ 7: ; \ popl %edx ; \ popl %ecx ; \ popl %eax #else #define APIC_ITRACE(name, irq_num, id) \ lock ; /* MP-safe */ \ incl CNAME(name) + (irq_num) * 4 #endif #define APIC_ITRACE_ENTER 1 #define APIC_ITRACE_EOI 2 #define APIC_ITRACE_TRYISRLOCK 3 #define APIC_ITRACE_GOTISRLOCK 4 #define APIC_ITRACE_ENTER2 5 #define APIC_ITRACE_LEAVE 6 #define APIC_ITRACE_UNMASK 7 #define APIC_ITRACE_ACTIVE 8 #define APIC_ITRACE_MASKED 9 #define APIC_ITRACE_NOISRLOCK 10 #define APIC_ITRACE_MASKED2 11 #define APIC_ITRACE_SPLZ 12 #define APIC_ITRACE_DORETI 13 #else #define APIC_ITRACE(name, irq_num, id) #endif #ifdef CPL_AND_CML #define INTR(irq_num, vec_name) \ .text ; \ SUPERALIGN_TEXT ; \ /* _XintrNN: entry point used by IDT/HWIs & splz_unpend via _vec[]. */ \ IDTVEC(vec_name) ; \ PUSH_FRAME ; \ movl $KDSEL, %eax ; /* reload with kernel's data segment */ \ movl %ax, %ds ; \ movl %ax, %es ; \ ; \ APIC_ITRACE(apic_itrace_enter, irq_num, APIC_ITRACE_ENTER) ; \ lock ; /* MP-safe */ \ btsl $(irq_num), iactive ; /* lazy masking */ \ jc 1f ; /* already active */ \ ; \ MASK_LEVEL_IRQ(irq_num) ; \ EOI_IRQ(irq_num) ; \ 0: ; \ APIC_ITRACE(apic_itrace_tryisrlock, irq_num, APIC_ITRACE_TRYISRLOCK) ;\ ENLOCK ; \ ; \ APIC_ITRACE(apic_itrace_gotisrlock, irq_num, APIC_ITRACE_GOTISRLOCK) ;\ AVCPL_LOCK ; /* MP-safe */ \ testl $IRQ_BIT(irq_num), _cpl ; \ jne 2f ; /* this INT masked */ \ testl $IRQ_BIT(irq_num), _cml ; \ jne 2f ; /* this INT masked */ \ orl $IRQ_BIT(irq_num), _cil ; \ AVCPL_UNLOCK ; \ ; \ incb _intr_nesting_level ; \ ; \ /* entry point used by doreti_unpend for HWIs. */ \ __CONCAT(Xresume,irq_num): ; \ FAKE_MCOUNT(12*4(%esp)) ; /* XXX avoid dbl cnt */ \ lock ; incl _cnt+V_INTR ; /* tally interrupts */ \ movl _intr_countp + (irq_num) * 4, %eax ; \ lock ; incl (%eax) ; \ ; \ AVCPL_LOCK ; /* MP-safe */ \ movl _cml, %eax ; \ pushl %eax ; \ orl _intr_mask + (irq_num) * 4, %eax ; \ movl %eax, _cml ; \ AVCPL_UNLOCK ; \ ; \ pushl _intr_unit + (irq_num) * 4 ; \ incl _inside_intr ; \ APIC_ITRACE(apic_itrace_enter2, irq_num, APIC_ITRACE_ENTER2) ; \ sti ; \ call *_intr_handler + (irq_num) * 4 ; \ cli ; \ APIC_ITRACE(apic_itrace_leave, irq_num, APIC_ITRACE_LEAVE) ; \ decl _inside_intr ; \ ; \ lock ; andl $~IRQ_BIT(irq_num), iactive ; \ lock ; andl $~IRQ_BIT(irq_num), _cil ; \ UNMASK_IRQ(irq_num) ; \ APIC_ITRACE(apic_itrace_unmask, irq_num, APIC_ITRACE_UNMASK) ; \ sti ; /* doreti repeats cli/sti */ \ MEXITCOUNT ; \ LATELOCK ; \ jmp _doreti ; \ ; \ ALIGN_TEXT ; \ 1: ; /* active */ \ APIC_ITRACE(apic_itrace_active, irq_num, APIC_ITRACE_ACTIVE) ; \ MASK_IRQ(irq_num) ; \ EOI_IRQ(irq_num) ; \ AVCPL_LOCK ; /* MP-safe */ \ orl $IRQ_BIT(irq_num), _ipending ; \ AVCPL_UNLOCK ; \ lock ; \ btsl $(irq_num), iactive ; /* still active */ \ jnc 0b ; /* retry */ \ POP_FRAME ; \ iret ; \ ; \ ALIGN_TEXT ; \ 2: ; /* masked by cpl|cml */ \ APIC_ITRACE(apic_itrace_masked, irq_num, APIC_ITRACE_MASKED) ; \ orl $IRQ_BIT(irq_num), _ipending ; \ AVCPL_UNLOCK ; \ DELOCK ; /* XXX this is going away... */ \ POP_FRAME ; \ iret ; \ ALIGN_TEXT ; \ 3: ; /* other cpu has isr lock */ \ APIC_ITRACE(apic_itrace_noisrlock, irq_num, APIC_ITRACE_NOISRLOCK) ;\ AVCPL_LOCK ; /* MP-safe */ \ orl $IRQ_BIT(irq_num), _ipending ; \ testl $IRQ_BIT(irq_num), _cpl ; \ jne 4f ; /* this INT masked */ \ testl $IRQ_BIT(irq_num), _cml ; \ jne 4f ; /* this INT masked */ \ orl $IRQ_BIT(irq_num), _cil ; \ AVCPL_UNLOCK ; \ call forward_irq ; /* forward irq to lock holder */ \ POP_FRAME ; /* and return */ \ iret ; \ ALIGN_TEXT ; \ 4: ; /* blocked */ \ APIC_ITRACE(apic_itrace_masked2, irq_num, APIC_ITRACE_MASKED2) ;\ AVCPL_UNLOCK ; \ POP_FRAME ; /* and return */ \ iret #else /* CPL_AND_CML */ #define INTR(irq_num, vec_name) \ .text ; \ SUPERALIGN_TEXT ; \ /* _XintrNN: entry point used by IDT/HWIs & splz_unpend via _vec[]. */ \ IDTVEC(vec_name) ; \ PUSH_FRAME ; \ movl $KDSEL, %eax ; /* reload with kernel's data segment */ \ movl %ax, %ds ; \ movl %ax, %es ; \ ; \ APIC_ITRACE(apic_itrace_enter, irq_num, APIC_ITRACE_ENTER) ; \ lock ; /* MP-safe */ \ btsl $(irq_num), iactive ; /* lazy masking */ \ jc 1f ; /* already active */ \ ; \ MASK_LEVEL_IRQ(irq_num) ; \ EOI_IRQ(irq_num) ; \ 0: ; \ APIC_ITRACE(apic_itrace_tryisrlock, irq_num, APIC_ITRACE_TRYISRLOCK) ;\ ISR_TRYLOCK ; /* XXX this is going away... */ \ testl %eax, %eax ; /* did we get it? */ \ jz 3f ; /* no */ \ ; \ APIC_ITRACE(apic_itrace_gotisrlock, irq_num, APIC_ITRACE_GOTISRLOCK) ;\ AVCPL_LOCK ; /* MP-safe */ \ testl $IRQ_BIT(irq_num), _cpl ; \ jne 2f ; /* this INT masked */ \ AVCPL_UNLOCK ; \ ; \ incb _intr_nesting_level ; \ ; \ /* entry point used by doreti_unpend for HWIs. */ \ __CONCAT(Xresume,irq_num): ; \ FAKE_MCOUNT(12*4(%esp)) ; /* XXX avoid dbl cnt */ \ lock ; incl _cnt+V_INTR ; /* tally interrupts */ \ movl _intr_countp + (irq_num) * 4, %eax ; \ lock ; incl (%eax) ; \ ; \ AVCPL_LOCK ; /* MP-safe */ \ movl _cpl, %eax ; \ pushl %eax ; \ orl _intr_mask + (irq_num) * 4, %eax ; \ movl %eax, _cpl ; \ andl $~IRQ_BIT(irq_num), _ipending ; \ AVCPL_UNLOCK ; \ ; \ pushl _intr_unit + (irq_num) * 4 ; \ APIC_ITRACE(apic_itrace_enter2, irq_num, APIC_ITRACE_ENTER2) ; \ sti ; \ call *_intr_handler + (irq_num) * 4 ; \ cli ; \ APIC_ITRACE(apic_itrace_leave, irq_num, APIC_ITRACE_LEAVE) ; \ ; \ lock ; andl $~IRQ_BIT(irq_num), iactive ; \ UNMASK_IRQ(irq_num) ; \ APIC_ITRACE(apic_itrace_unmask, irq_num, APIC_ITRACE_UNMASK) ; \ sti ; /* doreti repeats cli/sti */ \ MEXITCOUNT ; \ jmp _doreti ; \ ; \ ALIGN_TEXT ; \ 1: ; /* active */ \ APIC_ITRACE(apic_itrace_active, irq_num, APIC_ITRACE_ACTIVE) ; \ MASK_IRQ(irq_num) ; \ EOI_IRQ(irq_num) ; \ AVCPL_LOCK ; /* MP-safe */ \ orl $IRQ_BIT(irq_num), _ipending ; \ AVCPL_UNLOCK ; \ lock ; \ btsl $(irq_num), iactive ; /* still active */ \ jnc 0b ; /* retry */ \ POP_FRAME ; \ iret ; /* XXX: iactive bit might be 0 now */ \ ALIGN_TEXT ; \ 2: ; /* masked by cpl, leave iactive set */ \ APIC_ITRACE(apic_itrace_masked, irq_num, APIC_ITRACE_MASKED) ; \ orl $IRQ_BIT(irq_num), _ipending ; \ AVCPL_UNLOCK ; \ ISR_RELLOCK ; /* XXX this is going away... */ \ POP_FRAME ; \ iret ; \ ALIGN_TEXT ; \ 3: ; /* other cpu has isr lock */ \ APIC_ITRACE(apic_itrace_noisrlock, irq_num, APIC_ITRACE_NOISRLOCK) ;\ AVCPL_LOCK ; /* MP-safe */ \ orl $IRQ_BIT(irq_num), _ipending ; \ testl $IRQ_BIT(irq_num), _cpl ; \ jne 4f ; /* this INT masked */ \ AVCPL_UNLOCK ; \ call forward_irq ; /* forward irq to lock holder */ \ POP_FRAME ; /* and return */ \ iret ; \ ALIGN_TEXT ; \ 4: ; /* blocked */ \ APIC_ITRACE(apic_itrace_masked2, irq_num, APIC_ITRACE_MASKED2) ;\ AVCPL_UNLOCK ; \ POP_FRAME ; /* and return */ \ iret #endif /* CPL_AND_CML */ /* * Handle "spurious INTerrupts". * Notes: * This is different than the "spurious INTerrupt" generated by an * 8259 PIC for missing INTs. See the APIC documentation for details. * This routine should NOT do an 'EOI' cycle. */ .text SUPERALIGN_TEXT .globl _Xspuriousint _Xspuriousint: /* No EOI cycle used here */ iret /* * Handle TLB shootdowns. */ .text SUPERALIGN_TEXT .globl _Xinvltlb _Xinvltlb: pushl %eax #ifdef COUNT_XINVLTLB_HITS ss movl _cpuid, %eax ss incl _xhits(,%eax,4) #endif /* COUNT_XINVLTLB_HITS */ movl %cr3, %eax /* invalidate the TLB */ movl %eax, %cr3 ss /* stack segment, avoid %ds load */ movl $0, lapic_eoi /* End Of Interrupt to APIC */ popl %eax iret #ifdef BETTER_CLOCK /* * Executed by a CPU when it receives an Xcpucheckstate IPI from another CPU, * * - Stores current cpu state in checkstate_cpustate[cpuid] * 0 == user, 1 == sys, 2 == intr * - Stores current process in checkstate_curproc[cpuid] * * - Signals its receipt by setting bit cpuid in checkstate_probed_cpus. * * stack: 0 -> ds, 4 -> ebx, 8 -> eax, 12 -> eip, 16 -> cs, 20 -> eflags */ .text SUPERALIGN_TEXT .globl _Xcpucheckstate .globl _checkstate_cpustate .globl _checkstate_curproc .globl _checkstate_pc _Xcpucheckstate: pushl %eax pushl %ebx pushl %ds /* save current data segment */ movl $KDSEL, %eax movl %ax, %ds /* use KERNEL data segment */ movl $0, lapic_eoi /* End Of Interrupt to APIC */ movl $0, %ebx movl 16(%esp), %eax andl $3, %eax cmpl $3, %eax je 1f #ifdef VM86 testl $PSL_VM, 20(%esp) jne 1f #endif incl %ebx /* system or interrupt */ #ifdef CPL_AND_CML cmpl $0, _inside_intr je 1f incl %ebx /* interrupt */ #endif 1: movl _cpuid, %eax movl %ebx, _checkstate_cpustate(,%eax,4) movl _curproc, %ebx movl %ebx, _checkstate_curproc(,%eax,4) movl 12(%esp), %ebx movl %ebx, _checkstate_pc(,%eax,4) lock /* checkstate_probed_cpus |= (1<, and it is OK to rely * on that. */ #ifdef __ELF__ #define _APTD APTD #define _APTDpde APTDpde #define _APTmap APTmap #define _CONST_QNaN CONST_QNaN #define _IdlePTD IdlePTD #define _KPTphys KPTphys #define _MP_GDT MP_GDT #define _MPgetlock MPgetlock #define _MPrellock MPrellock #define _MPtrylock MPtrylock #define _PTD PTD #define _PTDpde PTDpde #define _PTmap PTmap #define _SMP_ioapic SMP_ioapic #define _SMP_prvpt SMP_prvpt #define _Xalign Xalign #define _Xbnd Xbnd #define _Xbpt Xbpt #define _Xcpuast Xcpuast #define _Xcpucheckstate Xcpucheckstate #define _Xcpustop Xcpustop #define _Xdbg Xdbg #define _Xdiv Xdiv #define _Xdna Xdna #define _Xfastintr0 Xfastintr0 #define _Xfastintr1 Xfastintr1 #define _Xfastintr10 Xfastintr10 #define _Xfastintr11 Xfastintr11 #define _Xfastintr12 Xfastintr12 #define _Xfastintr13 Xfastintr13 #define _Xfastintr14 Xfastintr14 #define _Xfastintr15 Xfastintr15 #define _Xfastintr16 Xfastintr16 #define _Xfastintr17 Xfastintr17 #define _Xfastintr18 Xfastintr18 #define _Xfastintr19 Xfastintr19 #define _Xfastintr2 Xfastintr2 #define _Xfastintr20 Xfastintr20 #define _Xfastintr21 Xfastintr21 #define _Xfastintr22 Xfastintr22 #define _Xfastintr23 Xfastintr23 #define _Xfastintr3 Xfastintr3 #define _Xfastintr4 Xfastintr4 #define _Xfastintr5 Xfastintr5 #define _Xfastintr6 Xfastintr6 #define _Xfastintr7 Xfastintr7 #define _Xfastintr8 Xfastintr8 #define _Xfastintr9 Xfastintr9 #define _Xforward_irq Xforward_irq #define _Xfpu Xfpu #define _Xfpusegm Xfpusegm #define _Xill Xill #define _Xint0x80_syscall Xint0x80_syscall #define _Xintr0 Xintr0 #define _Xintr1 Xintr1 #define _Xintr10 Xintr10 #define _Xintr11 Xintr11 #define _Xintr12 Xintr12 #define _Xintr13 Xintr13 #define _Xintr14 Xintr14 #define _Xintr15 Xintr15 #define _Xintr16 Xintr16 #define _Xintr17 Xintr17 #define _Xintr18 Xintr18 #define _Xintr19 Xintr19 #define _Xintr2 Xintr2 #define _Xintr20 Xintr20 #define _Xintr21 Xintr21 #define _Xintr22 Xintr22 #define _Xintr23 Xintr23 #define _Xintr3 Xintr3 #define _Xintr4 Xintr4 #define _Xintr5 Xintr5 #define _Xintr6 Xintr6 #define _Xintr7 Xintr7 #define _Xintr8 Xintr8 #define _Xintr8254 Xintr8254 #define _Xintr9 Xintr9 #define _XintrRTC XintrRTC #define _Xinvltlb Xinvltlb #define _Xmchk Xmchk #define _Xmissing Xmissing #define _Xnmi Xnmi #define _Xofl Xofl #define _Xpage Xpage #define _Xprot Xprot #define _Xrsvd Xrsvd #define _Xspuriousint Xspuriousint #define _Xstk Xstk #define _Xsyscall Xsyscall #define _Xtss Xtss #define __default_ldt _default_ldt #define __ucodesel _ucodesel #define __udatasel _udatasel #define _alltraps alltraps #define _ap_init ap_init #define _apic_base apic_base #define _apic_id_to_logical apic_id_to_logical #define _apic_imen apic_imen #define _apic_isrbit_location apic_isrbit_location #define _apic_pin_trigger apic_pin_trigger #define _apm_addr apm_addr #define _apm_bios_call apm_bios_call #define _apm_cs16_base apm_cs16_base #define _apm_cs32_base apm_cs32_base #define _apm_cs_entry apm_cs_entry #define _apm_cs_limit apm_cs_limit #define _apm_current_gdt_pdesc apm_current_gdt_pdesc #define _apm_ds_base apm_ds_base #define _apm_ds_limit apm_ds_limit #define _apm_flags apm_flags #define _apm_init_image apm_init_image #define _apm_init_image_size apm_init_image_size #define _apm_setup apm_setup #define _apm_version apm_version #define _arith_invalid arith_invalid #define _arith_overflow arith_overflow #define _arith_underflow arith_underflow #define _bcopy bcopy #define _bcopy_vector bcopy_vector #define _bigJump bigJump #define _bio_imask bio_imask #define _bluetrap bluetrap #define _bootCodeSeg bootCodeSeg #define _bootDataSeg bootDataSeg #define _bootMP bootMP #define _bootMP_size bootMP_size #define _bootPTD bootPTD #define _boot_get_mplock boot_get_mplock #define _bootdev bootdev #define _boothowto boothowto #define _bootinfo bootinfo #define _bootstrap_gdt bootstrap_gdt #define _bzero bzero #define _cam_imask cam_imask #define _checkstate_cpus checkstate_cpus #define _checkstate_cpustate checkstate_cpustate #define _checkstate_curproc checkstate_curproc #define _checkstate_need_ast checkstate_need_ast #define _checkstate_pc checkstate_pc #define _checkstate_pending_ast checkstate_pending_ast #define _checkstate_probed_cpus checkstate_probed_cpus #define _clock_lock clock_lock #define _cnt cnt #define _common_tss common_tss #define _common_tssd common_tssd #define _copyin_vector copyin_vector #define _copyout_vector copyout_vector #define _cpl cpl #define _cpl_lock cpl_lock #define _cpu cpu #define _cpu0prvpage cpu0prvpage #define _cpu0prvpt cpu0prvpt #define _cpu_apic_versions cpu_apic_versions #define _cpu_class cpu_class #define _cpu_feature cpu_feature #define _cpu_high cpu_high #define _cpu_id cpu_id #define _cpu_num_to_apic_id cpu_num_to_apic_id #define _cpu_switch cpu_switch #define _cpu_vendor cpu_vendor #define _cpuid cpuid #define _curpcb curpcb #define _curproc curproc #define _currentldt currentldt #define _cypoll cypoll #define _default_halt default_halt #define _denormal_operand denormal_operand #define _div_small div_small #define _divide_by_zero divide_by_zero #define _divide_kernel divide_kernel #define _do_page_zero_idle do_page_zero_idle #define _edata edata #define _eintrcnt eintrcnt #define _eintrnames eintrnames #define _end end #define _etext etext #define _exception exception #define _fast_intr_lock fast_intr_lock #define _fastmove fastmove #define _gdt gdt #define _generic_bcopy generic_bcopy #define _generic_bzero generic_bzero #define _generic_copyin generic_copyin #define _generic_copyout generic_copyout #define _get_align_lock get_align_lock #define _get_altsyscall_lock get_altsyscall_lock #define _get_fpu_lock get_fpu_lock #define _get_isrlock get_isrlock #define _get_mplock get_mplock #define _get_syscall_lock get_syscall_lock #define _getmicrouptime getmicrouptime #define _idqs idqs +#define _ihandlers ihandlers #define _imen imen #define _imen_lock imen_lock #define _in_vm86call in_vm86call #define _init386 init386 #define _init_secondary init_secondary #define _initial_bioscalls initial_bioscalls #define _inside_intr inside_intr #define _intr_countp intr_countp #define _intr_handler intr_handler #define _intr_mask intr_mask #define _intr_nesting_level intr_nesting_level #define _intr_unit intr_unit #define _intrcnt intrcnt #define _intrnames intrnames #define _invltlb_ok invltlb_ok #define _ioapic ioapic #define _ipending ipending #define _isr_lock isr_lock #define _ivectors ivectors #define _kernelname kernelname #define _kstack kstack #define _lapic lapic #define _linux_sigcode linux_sigcode #define _linux_szsigcode linux_szsigcode #define _main main #define _mask8254 mask8254 #define _maskRTC maskRTC #define _microuptime microuptime #define _mp_gdtbase mp_gdtbase #define _mp_lock mp_lock #define _mp_ncpus mp_ncpus #define _mul64 mul64 #define _my_idlePTD my_idlePTD #define _my_tr my_tr #define _net_imask net_imask #define _netisr netisr #define _netisrs netisrs #define _nfs_diskless nfs_diskless #define _nfs_diskless_valid nfs_diskless_valid #define _normalize normalize #define _normalize_nuo normalize_nuo #define _npx_intrs_while_probing npx_intrs_while_probing #define _npx_traps_while_probing npx_traps_while_probing #define _npxintr npxintr #define _npxproc npxproc #define _npxsave npxsave #define _other_cpus other_cpus #define _ovbcopy_vector ovbcopy_vector #define _panic panic #define _poly_div16 poly_div16 #define _poly_div2 poly_div2 #define _poly_div4 poly_div4 #define _polynomial polynomial #define _private_tss private_tss #define _probeintr probeintr #define _probetrap probetrap #define _proc0 proc0 #define _proc0paddr proc0paddr #define _prv_CMAP1 prv_CMAP1 #define _prv_CMAP2 prv_CMAP2 #define _prv_CMAP3 prv_CMAP3 #define _prv_PMAP1 prv_PMAP1 #define _prv_CPAGE1 prv_CPAGE1 #define _prv_CPAGE2 prv_CPAGE2 #define _prv_CPAGE3 prv_CPAGE3 #define _prv_PPAGE1 prv_PPAGE1 #define _qs qs #define _rcpoll rcpoll #define _real_2op_NaN real_2op_NaN #define _reg_div reg_div #define _reg_u_add reg_u_add #define _reg_u_div reg_u_div #define _reg_u_mul reg_u_mul #define _reg_u_sub reg_u_sub #define _rel_mplock rel_mplock #define _round_reg round_reg #define _rtqs rtqs #define _s_lock s_lock #define _s_unlock s_unlock #define _secondary_main secondary_main #define _set_precision_flag_down set_precision_flag_down #define _set_precision_flag_up set_precision_flag_up #define _set_user_ldt set_user_ldt #define _shrx shrx #define _shrxs shrxs #define _sigcode sigcode #define _siopoll siopoll #define _smp_active smp_active #define _soft_imask soft_imask #define _softclock softclock #define _softnet_imask softnet_imask #define _softtty_imask softtty_imask #define _spl0 spl0 #define _splz splz #define _ss_lock ss_lock #define _ss_unlock ss_unlock #define _started_cpus started_cpus #define _stopped_cpus stopped_cpus +#define _swi_generic swi_generic +#define _swi_null swi_null #define _swi_vm swi_vm #define _syscall syscall #define _szsigcode szsigcode #define _time time #define _timer0_max_count timer0_max_count #define _timer0_overflow_threshold timer0_overflow_threshold #define _timer0_prescaler_count timer0_prescaler_count #define _trap trap #define _trap_by_wrmsr trap_by_wrmsr #define _trapwrite trapwrite #define _tsc_bias tsc_bias #define _tsc_freq tsc_freq #define _tsc_multiplier tsc_multiplier #define _tty_imask tty_imask #define _userconfig_from_boot userconfig_from_boot #define _vec vec #define _vec8254 vec8254 #define _vecRTC vecRTC #define _vm86_emulate vm86_emulate #define _vm86_prepcall vm86_prepcall #define _vm86_sysarch vm86_sysarch #define _vm86_trap vm86_trap #define _vm86pa vm86pa #define _vm86paddr vm86paddr #define _vm86pcb vm86pcb #define _vm_page_zero_idle vm_page_zero_idle #define _want_resched want_resched #define _whichidqs whichidqs #define _whichqs whichqs #define _whichrtqs whichrtqs #define _wm_sqrt wm_sqrt #endif /* __ELF__ */ #endif /* !_MACHINE_ASNAMES_H_ */ Index: head/sys/i386/include/ipl.h =================================================================== --- head/sys/i386/include/ipl.h (revision 38243) +++ head/sys/i386/include/ipl.h (revision 38244) @@ -1,118 +1,119 @@ /*- * Copyright (c) 1993 The Regents of the University of California. * All rights reserved. * * 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 by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. * - * $Id: ipl.h,v 1.12 1997/09/21 21:38:53 gibbs Exp $ + * $Id: ipl.h,v 1.13 1998/01/15 07:32:56 gibbs Exp $ */ #ifndef _MACHINE_IPL_H_ #define _MACHINE_IPL_H_ #if defined(KERNEL) && !defined(ACTUALLY_LKM_NOT_KERNEL) #ifdef APIC_IO #include #else #include #endif /* * Software interrupt bit numbers in priority order. The priority only * determines which swi will be dispatched next; a higher priority swi * may be dispatched when a nested h/w interrupt handler returns. */ #define SWI_TTY (NHWI + 0) #define SWI_NET (NHWI + 1) #define SWI_CAMNET (NHWI + 2) #define SWI_CAMBIO (NHWI + 3) #define SWI_VM (NHWI + 4) #define SWI_CLOCK 30 #define SWI_AST 31 +#define NSWI (32 - NHWI) /* * Corresponding interrupt-pending bits for ipending. */ #define SWI_TTY_PENDING (1 << SWI_TTY) #define SWI_NET_PENDING (1 << SWI_NET) #define SWI_CAMNET_PENDING (1 << SWI_CAMNET) #define SWI_CAMBIO_PENDING (1 << SWI_CAMBIO) #define SWI_VM_PENDING (1 << SWI_VM) #define SWI_CLOCK_PENDING (1 << SWI_CLOCK) #define SWI_AST_PENDING (1 << SWI_AST) /* * Corresponding interrupt-disable masks for cpl. The ordering is now by * inclusion (where each mask is considered as a set of bits). Everything * except SWI_AST_MASK includes SWI_CLOCK_MASK so that softclock() doesn't * run while other swi handlers are running and timeout routines can call * swi handlers. Everything includes SWI_AST_MASK so that AST's are masked * until just before return to user mode. SWI_TTY_MASK includes SWI_NET_MASK * in case tty interrupts are processed at splsofttty() for a tty that is in * SLIP or PPP line discipline (this is weaker than merging net_imask with * tty_imask in isa.c - splimp() must mask hard and soft tty interrupts, but * spltty() apparently only needs to mask soft net interrupts). */ #define SWI_TTY_MASK (SWI_TTY_PENDING | SWI_CLOCK_MASK | SWI_NET_MASK) #define SWI_CAMNET_MASK (SWI_CAMNET_PENDING | SWI_CLOCK_MASK) #define SWI_CAMBIO_MASK (SWI_CAMBIO_PENDING | SWI_CLOCK_MASK) #define SWI_NET_MASK (SWI_NET_PENDING | SWI_CLOCK_MASK) #define SWI_VM_MASK (SWI_VM_PENDING | SWI_CLOCK_MASK) #define SWI_CLOCK_MASK (SWI_CLOCK_PENDING | SWI_AST_MASK) #define SWI_AST_MASK SWI_AST_PENDING #define SWI_MASK (~HWI_MASK) #endif /* KERNEL && !ACTUALLY_LKM_NOT_KERNEL */ #ifndef LOCORE /* * cpl is preserved by interrupt handlers so it is effectively nonvolatile. * ipending and idelayed are changed by interrupt handlers so they are * volatile. */ #ifdef notyet /* in until pci drivers stop hacking on them */ extern unsigned bio_imask; /* group of interrupts masked with splbio() */ #endif extern unsigned cpl; /* current priority level mask */ #ifdef SMP extern unsigned cil; /* current INTerrupt level mask */ #endif extern volatile unsigned idelayed; /* interrupts to become pending */ extern volatile unsigned ipending; /* active interrupts masked by cpl */ #ifdef notyet /* in until pci drivers stop hacking on them */ extern unsigned net_imask; /* group of interrupts masked with splimp() */ extern unsigned stat_imask; /* interrupts masked with splstatclock() */ extern unsigned tty_imask; /* group of interrupts masked with spltty() */ #endif #endif /* !LOCORE */ #endif /* !_MACHINE_IPL_H_ */ Index: head/sys/i386/isa/apic_ipl.s =================================================================== --- head/sys/i386/isa/apic_ipl.s (revision 38243) +++ head/sys/i386/isa/apic_ipl.s (revision 38244) @@ -1,474 +1,466 @@ /*- * Copyright (c) 1997, by Steve Passe * All rights reserved. * * 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. The name of the developer may NOT be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. * - * $Id: apic_ipl.s,v 1.19 1998/03/05 21:45:50 tegge Exp $ + * $Id: apic_ipl.s,v 1.20 1998/04/22 22:49:29 tegge Exp $ */ .data ALIGN_DATA /* current INTerrupt level */ .globl _cil _cil: .long 0 /* current INTerrupt level mask */ .globl _cml _cml: .long 0 /* * Routines used by splz_unpend to build an interrupt frame from a * trap frame. The _vec[] routines build the proper frame on the stack, * then call one of _Xintr0 thru _XintrNN. * * used by: * i386/isa/apic_ipl.s (this file): splz_unpend JUMPs to HWIs. * i386/isa/clock.c: setup _vec[clock] to point at _vec8254. */ .globl _vec _vec: .long vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7 .long vec8, vec9, vec10, vec11, vec12, vec13, vec14, vec15 .long vec16, vec17, vec18, vec19, vec20, vec21, vec22, vec23 /* * Note: * This is the UP equivilant of _imen. * It is OPAQUE, and must NOT be accessed directly. * It MUST be accessed along with the IO APIC as a 'critical region'. * Accessed by: * INTREN() * INTRDIS() * MAYBE_MASK_IRQ * MAYBE_UNMASK_IRQ * imen_dump() */ .align 2 /* MUST be 32bit aligned */ .globl _apic_imen _apic_imen: .long HWI_MASK /* * */ .text SUPERALIGN_TEXT /* * Interrupt priority mechanism * -- soft splXX masks with group mechanism (cpl) * -- h/w masks for currently active or unused interrupts (imen) * -- ipending = active interrupts currently masked by cpl */ ENTRY(splz) /* * The caller has restored cpl and checked that (ipending & ~cpl) * is nonzero. We have to repeat the check since if there is an * interrupt while we're looking, _doreti processing for the * interrupt will handle all the unmasked pending interrupts * because we restored early. We're repeating the calculation * of (ipending & ~cpl) anyway so that the caller doesn't have * to pass it, so this only costs one "jne". "bsfl %ecx,%ecx" * is undefined when %ecx is 0 so we can't rely on the secondary * btrl tests. */ AICPL_LOCK movl _cpl,%eax #ifdef CPL_AND_CML orl _cml, %eax /* add cml to cpl */ #endif splz_next: /* * We don't need any locking here. (ipending & ~cpl) cannot grow * while we're looking at it - any interrupt will shrink it to 0. */ movl %eax,%ecx notl %ecx /* set bit = unmasked level */ andl _ipending,%ecx /* set bit = unmasked pending INT */ jne splz_unpend AICPL_UNLOCK ret ALIGN_TEXT splz_unpend: bsfl %ecx,%ecx - btrl %ecx, _ipending + btrl %ecx,_ipending jnc splz_next - /* - * HWIs: will JUMP thru *_vec[], see comments below. - * SWIs: setup CALL of swi_tty, swi_net, _softclock, swi_ast. - */ - movl ihandlers(,%ecx,4),%edx - testl %edx,%edx - je splz_next /* "can't happen" */ cmpl $NHWI,%ecx jae splz_swi - pushl %ecx - AICPL_UNLOCK - popl %ecx - /* * We would prefer to call the intr handler directly here but that * doesn't work for badly behaved handlers that want the interrupt * frame. Also, there's a problem determining the unit number. * We should change the interface so that the unit number is not * determined at config time. * * The vec[] routines build the proper frame on the stack, * then call one of _Xintr0 thru _XintrNN. */ + pushl %ecx + AICPL_UNLOCK + popl %ecx jmp *_vec(,%ecx,4) ALIGN_TEXT splz_swi: cmpl $SWI_AST,%ecx je splz_next /* "can't happen" */ pushl %eax orl imasks(,%ecx,4),%eax movl %eax,_cpl - pushl %edx + pushl %ecx AICPL_UNLOCK - popl %edx - call %edx + popl %ecx + call *_ihandlers(,%ecx,4) AICPL_LOCK popl %eax movl %eax,_cpl jmp splz_next /* * Fake clock interrupt(s) so that they appear to come from our caller instead * of from here, so that system profiling works. * XXX do this more generally (for all vectors; look up the C entry point). * XXX frame bogusness stops us from just jumping to the C entry point. * We have to clear iactive since this is an unpend call, and it will be * set from the time of the original INT. */ /* * The 'generic' vector stubs. */ #define BUILD_VEC(irq_num) \ ALIGN_TEXT ; \ __CONCAT(vec,irq_num): ; \ popl %eax ; \ pushfl ; \ pushl $KCSEL ; \ pushl %eax ; \ cli ; \ lock ; /* MP-safe */ \ andl $~IRQ_BIT(irq_num), iactive ; /* lazy masking */ \ MEXITCOUNT ; \ APIC_ITRACE(apic_itrace_splz, irq_num, APIC_ITRACE_SPLZ) ; \ jmp __CONCAT(_Xintr,irq_num) BUILD_VEC(0) BUILD_VEC(1) BUILD_VEC(2) BUILD_VEC(3) BUILD_VEC(4) BUILD_VEC(5) BUILD_VEC(6) BUILD_VEC(7) BUILD_VEC(8) BUILD_VEC(9) BUILD_VEC(10) BUILD_VEC(11) BUILD_VEC(12) BUILD_VEC(13) BUILD_VEC(14) BUILD_VEC(15) BUILD_VEC(16) /* 8 additional INTs in IO APIC */ BUILD_VEC(17) BUILD_VEC(18) BUILD_VEC(19) BUILD_VEC(20) BUILD_VEC(21) BUILD_VEC(22) BUILD_VEC(23) /****************************************************************************** * XXX FIXME: figure out where these belong. */ /* this nonsense is to verify that masks ALWAYS have 1 and only 1 bit set */ #define QUALIFY_MASKS_NOT #ifdef QUALIFY_MASKS #define QUALIFY_MASK \ btrl %ecx, %eax ; \ andl %eax, %eax ; \ jz 1f ; \ pushl $bad_mask ; \ call _panic ; \ 1: bad_mask: .asciz "bad mask" #else #define QUALIFY_MASK #endif /* * MULTIPLE_IOAPICSXXX: cannot assume apic #0 in the following function. * (soon to be) MP-safe function to clear ONE INT mask bit. * The passed arg is a 32bit u_int MASK. * It sets the associated bit in _apic_imen. * It sets the mask bit of the associated IO APIC register. */ ENTRY(INTREN) pushfl /* save state of EI flag */ cli /* prevent recursion */ IMASK_LOCK /* enter critical reg */ movl 8(%esp), %eax /* mask into %eax */ bsfl %eax, %ecx /* get pin index */ btrl %ecx, _apic_imen /* update _apic_imen */ QUALIFY_MASK leal 16(,%ecx,2), %ecx /* calculate register index */ movl $0, %edx /* XXX FIXME: APIC # */ movl _ioapic(,%edx,4), %edx /* %edx holds APIC base address */ movl %ecx, (%edx) /* write the target register index */ movl 16(%edx), %eax /* read the target register data */ andl $~IOART_INTMASK, %eax /* clear mask bit */ movl %eax, 16(%edx) /* write the APIC register data */ IMASK_UNLOCK /* exit critical reg */ popfl /* restore old state of EI flag */ ret /* * MULTIPLE_IOAPICSXXX: cannot assume apic #0 in the following function. * (soon to be) MP-safe function to set ONE INT mask bit. * The passed arg is a 32bit u_int MASK. * It clears the associated bit in _apic_imen. * It clears the mask bit of the associated IO APIC register. */ ENTRY(INTRDIS) pushfl /* save state of EI flag */ cli /* prevent recursion */ IMASK_LOCK /* enter critical reg */ movl 8(%esp), %eax /* mask into %eax */ bsfl %eax, %ecx /* get pin index */ btsl %ecx, _apic_imen /* update _apic_imen */ QUALIFY_MASK leal 16(,%ecx,2), %ecx /* calculate register index */ movl $0, %edx /* XXX FIXME: APIC # */ movl _ioapic(,%edx,4), %edx /* %edx holds APIC base address */ movl %ecx, (%edx) /* write the target register index */ movl 16(%edx), %eax /* read the target register data */ orl $IOART_INTMASK, %eax /* set mask bit */ movl %eax, 16(%edx) /* write the APIC register data */ IMASK_UNLOCK /* exit critical reg */ popfl /* restore old state of EI flag */ ret /****************************************************************************** * */ /* * void write_ioapic_mask(int apic, u_int mask); */ #define _INT_MASK 0x00010000 #define _PIN_MASK 0x00ffffff #define _OLD_ESI 0(%esp) #define _OLD_EBX 4(%esp) #define _RETADDR 8(%esp) #define _APIC 12(%esp) #define _MASK 16(%esp) .align 2 write_ioapic_mask: pushl %ebx /* scratch */ pushl %esi /* scratch */ movl _apic_imen, %ebx xorl _MASK, %ebx /* %ebx = _apic_imen ^ mask */ andl $_PIN_MASK, %ebx /* %ebx = _apic_imen & 0x00ffffff */ jz all_done /* no change, return */ movl _APIC, %esi /* APIC # */ movl _ioapic(,%esi,4), %esi /* %esi holds APIC base address */ next_loop: /* %ebx = diffs, %esi = APIC base */ bsfl %ebx, %ecx /* %ecx = index if 1st/next set bit */ jz all_done btrl %ecx, %ebx /* clear this bit in diffs */ leal 16(,%ecx,2), %edx /* calculate register index */ movl %edx, (%esi) /* write the target register index */ movl 16(%esi), %eax /* read the target register data */ btl %ecx, _MASK /* test for mask or unmask */ jnc clear /* bit is clear */ orl $_INT_MASK, %eax /* set mask bit */ jmp write clear: andl $~_INT_MASK, %eax /* clear mask bit */ write: movl %eax, 16(%esi) /* write the APIC register data */ jmp next_loop /* try another pass */ all_done: popl %esi popl %ebx ret #undef _OLD_ESI #undef _OLD_EBX #undef _RETADDR #undef _APIC #undef _MASK #undef _PIN_MASK #undef _INT_MASK #ifdef oldcode _INTREN: movl _apic_imen, %eax notl %eax /* mask = ~mask */ andl _apic_imen, %eax /* %eax = _apic_imen & ~mask */ pushl %eax /* new (future) _apic_imen value */ pushl $0 /* APIC# arg */ call write_ioapic_mask /* modify the APIC registers */ addl $4, %esp /* remove APIC# arg from stack */ popl _apic_imen /* _apic_imen |= mask */ ret _INTRDIS: movl _apic_imen, %eax orl 4(%esp), %eax /* %eax = _apic_imen | mask */ pushl %eax /* new (future) _apic_imen value */ pushl $0 /* APIC# arg */ call write_ioapic_mask /* modify the APIC registers */ addl $4, %esp /* remove APIC# arg from stack */ popl _apic_imen /* _apic_imen |= mask */ ret #endif /* oldcode */ #ifdef ready /* * u_int read_io_apic_mask(int apic); */ ALIGN_TEXT read_io_apic_mask: ret /* * Set INT mask bit for each bit set in 'mask'. * Ignore INT mask bit for all others. * * void set_io_apic_mask(apic, u_int32_t bits); */ ALIGN_TEXT set_io_apic_mask: ret /* * void set_ioapic_maskbit(int apic, int bit); */ ALIGN_TEXT set_ioapic_maskbit: ret /* * Clear INT mask bit for each bit set in 'mask'. * Ignore INT mask bit for all others. * * void clr_io_apic_mask(int apic, u_int32_t bits); */ ALIGN_TEXT clr_io_apic_mask: ret /* * void clr_ioapic_maskbit(int apic, int bit); */ ALIGN_TEXT clr_ioapic_maskbit: ret #endif /** ready */ /****************************************************************************** * */ /* * u_int io_apic_write(int apic, int select); */ ENTRY(io_apic_read) movl 4(%esp), %ecx /* APIC # */ movl _ioapic(,%ecx,4), %edx /* APIC base register address */ movl 8(%esp), %eax /* target register index */ movl %eax, (%edx) /* write the target register index */ movl 16(%edx), %eax /* read the APIC register data */ ret /* %eax = register value */ /* * void io_apic_write(int apic, int select, int value); */ ENTRY(io_apic_write) movl 4(%esp), %ecx /* APIC # */ movl _ioapic(,%ecx,4), %edx /* APIC base register address */ movl 8(%esp), %eax /* target register index */ movl %eax, (%edx) /* write the target register index */ movl 12(%esp), %eax /* target register value */ movl %eax, 16(%edx) /* write the APIC register data */ ret /* %eax = void */ /* * Send an EOI to the local APIC. */ ENTRY(apic_eoi) movl $0, _lapic+0xb0 ret Index: head/sys/i386/isa/apic_vector.s =================================================================== --- head/sys/i386/isa/apic_vector.s (revision 38243) +++ head/sys/i386/isa/apic_vector.s (revision 38244) @@ -1,1052 +1,1047 @@ /* * from: vector.s, 386BSD 0.1 unknown origin - * $Id: apic_vector.s,v 1.29 1998/04/22 22:49:27 tegge Exp $ + * $Id: apic_vector.s,v 1.30 1998/05/17 22:12:04 tegge Exp $ */ #include #include #include "i386/isa/intr_machdep.h" #ifdef FAST_SIMPLELOCK #define GET_FAST_INTR_LOCK \ pushl $_fast_intr_lock ; /* address of lock */ \ call _s_lock ; /* MP-safe */ \ addl $4,%esp #define REL_FAST_INTR_LOCK \ pushl $_fast_intr_lock ; /* address of lock */ \ call _s_unlock ; /* MP-safe */ \ addl $4,%esp #else /* FAST_SIMPLELOCK */ #define GET_FAST_INTR_LOCK \ call _get_isrlock #define REL_FAST_INTR_LOCK \ pushl $_mp_lock ; /* GIANT_LOCK */ \ call _MPrellock ; \ add $4, %esp #endif /* FAST_SIMPLELOCK */ /* convert an absolute IRQ# into a bitmask */ #define IRQ_BIT(irq_num) (1 << (irq_num)) /* make an index into the IO APIC from the IRQ# */ #define REDTBL_IDX(irq_num) (0x10 + ((irq_num) * 2)) /* * Macros for interrupt interrupt entry, call to handler, and exit. */ #ifdef FAST_WITHOUTCPL /* */ #define FAST_INTR(irq_num, vec_name) \ .text ; \ SUPERALIGN_TEXT ; \ IDTVEC(vec_name) ; \ pushl %eax ; /* save only call-used registers */ \ pushl %ecx ; \ pushl %edx ; \ pushl %ds ; \ MAYBE_PUSHL_ES ; \ movl $KDSEL,%eax ; \ movl %ax,%ds ; \ MAYBE_MOVW_AX_ES ; \ FAKE_MCOUNT((4+ACTUALLY_PUSHED)*4(%esp)) ; \ pushl _intr_unit + (irq_num) * 4 ; \ GET_FAST_INTR_LOCK ; \ call *_intr_handler + (irq_num) * 4 ; /* do the work ASAP */ \ REL_FAST_INTR_LOCK ; \ addl $4, %esp ; \ movl $0, lapic_eoi ; \ lock ; \ incl _cnt+V_INTR ; /* book-keeping can wait */ \ movl _intr_countp + (irq_num) * 4, %eax ; \ lock ; \ incl (%eax) ; \ MEXITCOUNT ; \ MAYBE_POPL_ES ; \ popl %ds ; \ popl %edx ; \ popl %ecx ; \ popl %eax ; \ iret #else /* FAST_WITHOUTCPL */ #define FAST_INTR(irq_num, vec_name) \ .text ; \ SUPERALIGN_TEXT ; \ IDTVEC(vec_name) ; \ pushl %eax ; /* save only call-used registers */ \ pushl %ecx ; \ pushl %edx ; \ pushl %ds ; \ MAYBE_PUSHL_ES ; \ movl $KDSEL, %eax ; \ movl %ax, %ds ; \ MAYBE_MOVW_AX_ES ; \ FAKE_MCOUNT((4+ACTUALLY_PUSHED)*4(%esp)) ; \ GET_FAST_INTR_LOCK ; \ pushl _intr_unit + (irq_num) * 4 ; \ call *_intr_handler + (irq_num) * 4 ; /* do the work ASAP */ \ addl $4, %esp ; \ movl $0, lapic_eoi ; \ lock ; \ incl _cnt+V_INTR ; /* book-keeping can wait */ \ movl _intr_countp + (irq_num) * 4,%eax ; \ lock ; \ incl (%eax) ; \ movl _cpl, %eax ; /* unmasking pending HWIs or SWIs? */ \ notl %eax ; \ andl _ipending, %eax ; \ jne 2f ; /* yes, maybe handle them */ \ 1: ; \ MEXITCOUNT ; \ REL_FAST_INTR_LOCK ; \ MAYBE_POPL_ES ; \ popl %ds ; \ popl %edx ; \ popl %ecx ; \ popl %eax ; \ iret ; \ ; \ ALIGN_TEXT ; \ 2: ; \ cmpb $3, _intr_nesting_level ; /* enough stack? */ \ jae 1b ; /* no, return */ \ movl _cpl, %eax ; \ /* XXX next line is probably unnecessary now. */ \ movl $HWI_MASK|SWI_MASK, _cpl ; /* limit nesting ... */ \ lock ; \ incb _intr_nesting_level ; /* ... really limit it ... */ \ sti ; /* to do this as early as possible */ \ MAYBE_POPL_ES ; /* discard most of thin frame ... */ \ popl %ecx ; /* ... original %ds ... */ \ popl %edx ; \ xchgl %eax, 4(%esp) ; /* orig %eax; save cpl */ \ pushal ; /* build fat frame (grrr) ... */ \ pushl %ecx ; /* ... actually %ds ... */ \ pushl %es ; \ movl $KDSEL, %eax ; \ movl %ax, %es ; \ movl (2+8+0)*4(%esp), %ecx ; /* %ecx from thin frame ... */ \ movl %ecx, (2+6)*4(%esp) ; /* ... to fat frame ... */ \ movl (2+8+1)*4(%esp), %eax ; /* ... cpl from thin frame */ \ pushl %eax ; \ subl $4, %esp ; /* junk for unit number */ \ MEXITCOUNT ; \ jmp _doreti #endif /** FAST_WITHOUTCPL */ /* * */ #define PUSH_FRAME \ pushl $0 ; /* dummy error code */ \ pushl $0 ; /* dummy trap type */ \ pushal ; \ pushl %ds ; /* save data and extra segments ... */ \ pushl %es #define POP_FRAME \ popl %es ; \ popl %ds ; \ popal ; \ addl $4+4,%esp #define MASK_IRQ(irq_num) \ IMASK_LOCK ; /* into critical reg */ \ testl $IRQ_BIT(irq_num), _apic_imen ; \ jne 7f ; /* masked, don't mask */ \ orl $IRQ_BIT(irq_num), _apic_imen ; /* set the mask bit */ \ movl _ioapic, %ecx ; /* ioapic[0] addr */ \ movl $REDTBL_IDX(irq_num), (%ecx) ; /* write the index */ \ movl IOAPIC_WINDOW(%ecx), %eax ; /* current value */ \ orl $IOART_INTMASK, %eax ; /* set the mask */ \ movl %eax, IOAPIC_WINDOW(%ecx) ; /* new value */ \ 7: ; /* already masked */ \ IMASK_UNLOCK /* * Test to see whether we are handling an edge or level triggered INT. * Level-triggered INTs must still be masked as we don't clear the source, * and the EOI cycle would cause redundant INTs to occur. */ #define MASK_LEVEL_IRQ(irq_num) \ testl $IRQ_BIT(irq_num), _apic_pin_trigger ; \ jz 9f ; /* edge, don't mask */ \ MASK_IRQ(irq_num) ; \ 9: #ifdef APIC_INTR_REORDER #define EOI_IRQ(irq_num) \ movl _apic_isrbit_location + 8 * (irq_num), %eax ; \ movl (%eax), %eax ; \ testl _apic_isrbit_location + 4 + 8 * (irq_num), %eax ; \ jz 9f ; /* not active */ \ movl $0, lapic_eoi ; \ APIC_ITRACE(apic_itrace_eoi, irq_num, APIC_ITRACE_EOI) ; \ 9: #else #define EOI_IRQ(irq_num) \ testl $IRQ_BIT(irq_num), lapic_isr1; \ jz 9f ; /* not active */ \ movl $0, lapic_eoi; \ APIC_ITRACE(apic_itrace_eoi, irq_num, APIC_ITRACE_EOI) ; \ 9: #endif /* * Test to see if the source is currntly masked, clear if so. */ #define UNMASK_IRQ(irq_num) \ IMASK_LOCK ; /* into critical reg */ \ testl $IRQ_BIT(irq_num), _apic_imen ; \ je 7f ; /* bit clear, not masked */ \ andl $~IRQ_BIT(irq_num), _apic_imen ;/* clear mask bit */ \ movl _ioapic,%ecx ; /* ioapic[0]addr */ \ movl $REDTBL_IDX(irq_num),(%ecx) ; /* write the index */ \ movl IOAPIC_WINDOW(%ecx),%eax ; /* current value */ \ andl $~IOART_INTMASK,%eax ; /* clear the mask */ \ movl %eax,IOAPIC_WINDOW(%ecx) ; /* new value */ \ 7: ; \ IMASK_UNLOCK #ifdef INTR_SIMPLELOCK #define ENLOCK #define DELOCK #define LATELOCK call _get_isrlock #else #define ENLOCK \ ISR_TRYLOCK ; /* XXX this is going away... */ \ testl %eax, %eax ; /* did we get it? */ \ jz 3f #define DELOCK ISR_RELLOCK #define LATELOCK #endif #ifdef APIC_INTR_DIAGNOSTIC #ifdef APIC_INTR_DIAGNOSTIC_IRQ log_intr_event: pushf cli pushl $CNAME(apic_itrace_debuglock) call _s_lock_np addl $4, %esp movl CNAME(apic_itrace_debugbuffer_idx), %ecx andl $32767, %ecx movl _cpuid, %eax shll $8, %eax orl 8(%esp), %eax movw %ax, CNAME(apic_itrace_debugbuffer)(,%ecx,2) incl %ecx andl $32767, %ecx movl %ecx, CNAME(apic_itrace_debugbuffer_idx) pushl $CNAME(apic_itrace_debuglock) call _s_unlock_np addl $4, %esp popf ret #define APIC_ITRACE(name, irq_num, id) \ lock ; /* MP-safe */ \ incl CNAME(name) + (irq_num) * 4 ; \ pushl %eax ; \ pushl %ecx ; \ pushl %edx ; \ movl $(irq_num), %eax ; \ cmpl $APIC_INTR_DIAGNOSTIC_IRQ, %eax ; \ jne 7f ; \ pushl $id ; \ call log_intr_event ; \ addl $4, %esp ; \ 7: ; \ popl %edx ; \ popl %ecx ; \ popl %eax #else #define APIC_ITRACE(name, irq_num, id) \ lock ; /* MP-safe */ \ incl CNAME(name) + (irq_num) * 4 #endif #define APIC_ITRACE_ENTER 1 #define APIC_ITRACE_EOI 2 #define APIC_ITRACE_TRYISRLOCK 3 #define APIC_ITRACE_GOTISRLOCK 4 #define APIC_ITRACE_ENTER2 5 #define APIC_ITRACE_LEAVE 6 #define APIC_ITRACE_UNMASK 7 #define APIC_ITRACE_ACTIVE 8 #define APIC_ITRACE_MASKED 9 #define APIC_ITRACE_NOISRLOCK 10 #define APIC_ITRACE_MASKED2 11 #define APIC_ITRACE_SPLZ 12 #define APIC_ITRACE_DORETI 13 #else #define APIC_ITRACE(name, irq_num, id) #endif #ifdef CPL_AND_CML #define INTR(irq_num, vec_name) \ .text ; \ SUPERALIGN_TEXT ; \ /* _XintrNN: entry point used by IDT/HWIs & splz_unpend via _vec[]. */ \ IDTVEC(vec_name) ; \ PUSH_FRAME ; \ movl $KDSEL, %eax ; /* reload with kernel's data segment */ \ movl %ax, %ds ; \ movl %ax, %es ; \ ; \ APIC_ITRACE(apic_itrace_enter, irq_num, APIC_ITRACE_ENTER) ; \ lock ; /* MP-safe */ \ btsl $(irq_num), iactive ; /* lazy masking */ \ jc 1f ; /* already active */ \ ; \ MASK_LEVEL_IRQ(irq_num) ; \ EOI_IRQ(irq_num) ; \ 0: ; \ APIC_ITRACE(apic_itrace_tryisrlock, irq_num, APIC_ITRACE_TRYISRLOCK) ;\ ENLOCK ; \ ; \ APIC_ITRACE(apic_itrace_gotisrlock, irq_num, APIC_ITRACE_GOTISRLOCK) ;\ AVCPL_LOCK ; /* MP-safe */ \ testl $IRQ_BIT(irq_num), _cpl ; \ jne 2f ; /* this INT masked */ \ testl $IRQ_BIT(irq_num), _cml ; \ jne 2f ; /* this INT masked */ \ orl $IRQ_BIT(irq_num), _cil ; \ AVCPL_UNLOCK ; \ ; \ incb _intr_nesting_level ; \ ; \ /* entry point used by doreti_unpend for HWIs. */ \ __CONCAT(Xresume,irq_num): ; \ FAKE_MCOUNT(12*4(%esp)) ; /* XXX avoid dbl cnt */ \ lock ; incl _cnt+V_INTR ; /* tally interrupts */ \ movl _intr_countp + (irq_num) * 4, %eax ; \ lock ; incl (%eax) ; \ ; \ AVCPL_LOCK ; /* MP-safe */ \ movl _cml, %eax ; \ pushl %eax ; \ orl _intr_mask + (irq_num) * 4, %eax ; \ movl %eax, _cml ; \ AVCPL_UNLOCK ; \ ; \ pushl _intr_unit + (irq_num) * 4 ; \ incl _inside_intr ; \ APIC_ITRACE(apic_itrace_enter2, irq_num, APIC_ITRACE_ENTER2) ; \ sti ; \ call *_intr_handler + (irq_num) * 4 ; \ cli ; \ APIC_ITRACE(apic_itrace_leave, irq_num, APIC_ITRACE_LEAVE) ; \ decl _inside_intr ; \ ; \ lock ; andl $~IRQ_BIT(irq_num), iactive ; \ lock ; andl $~IRQ_BIT(irq_num), _cil ; \ UNMASK_IRQ(irq_num) ; \ APIC_ITRACE(apic_itrace_unmask, irq_num, APIC_ITRACE_UNMASK) ; \ sti ; /* doreti repeats cli/sti */ \ MEXITCOUNT ; \ LATELOCK ; \ jmp _doreti ; \ ; \ ALIGN_TEXT ; \ 1: ; /* active */ \ APIC_ITRACE(apic_itrace_active, irq_num, APIC_ITRACE_ACTIVE) ; \ MASK_IRQ(irq_num) ; \ EOI_IRQ(irq_num) ; \ AVCPL_LOCK ; /* MP-safe */ \ orl $IRQ_BIT(irq_num), _ipending ; \ AVCPL_UNLOCK ; \ lock ; \ btsl $(irq_num), iactive ; /* still active */ \ jnc 0b ; /* retry */ \ POP_FRAME ; \ iret ; \ ; \ ALIGN_TEXT ; \ 2: ; /* masked by cpl|cml */ \ APIC_ITRACE(apic_itrace_masked, irq_num, APIC_ITRACE_MASKED) ; \ orl $IRQ_BIT(irq_num), _ipending ; \ AVCPL_UNLOCK ; \ DELOCK ; /* XXX this is going away... */ \ POP_FRAME ; \ iret ; \ ALIGN_TEXT ; \ 3: ; /* other cpu has isr lock */ \ APIC_ITRACE(apic_itrace_noisrlock, irq_num, APIC_ITRACE_NOISRLOCK) ;\ AVCPL_LOCK ; /* MP-safe */ \ orl $IRQ_BIT(irq_num), _ipending ; \ testl $IRQ_BIT(irq_num), _cpl ; \ jne 4f ; /* this INT masked */ \ testl $IRQ_BIT(irq_num), _cml ; \ jne 4f ; /* this INT masked */ \ orl $IRQ_BIT(irq_num), _cil ; \ AVCPL_UNLOCK ; \ call forward_irq ; /* forward irq to lock holder */ \ POP_FRAME ; /* and return */ \ iret ; \ ALIGN_TEXT ; \ 4: ; /* blocked */ \ APIC_ITRACE(apic_itrace_masked2, irq_num, APIC_ITRACE_MASKED2) ;\ AVCPL_UNLOCK ; \ POP_FRAME ; /* and return */ \ iret #else /* CPL_AND_CML */ #define INTR(irq_num, vec_name) \ .text ; \ SUPERALIGN_TEXT ; \ /* _XintrNN: entry point used by IDT/HWIs & splz_unpend via _vec[]. */ \ IDTVEC(vec_name) ; \ PUSH_FRAME ; \ movl $KDSEL, %eax ; /* reload with kernel's data segment */ \ movl %ax, %ds ; \ movl %ax, %es ; \ ; \ APIC_ITRACE(apic_itrace_enter, irq_num, APIC_ITRACE_ENTER) ; \ lock ; /* MP-safe */ \ btsl $(irq_num), iactive ; /* lazy masking */ \ jc 1f ; /* already active */ \ ; \ MASK_LEVEL_IRQ(irq_num) ; \ EOI_IRQ(irq_num) ; \ 0: ; \ APIC_ITRACE(apic_itrace_tryisrlock, irq_num, APIC_ITRACE_TRYISRLOCK) ;\ ISR_TRYLOCK ; /* XXX this is going away... */ \ testl %eax, %eax ; /* did we get it? */ \ jz 3f ; /* no */ \ ; \ APIC_ITRACE(apic_itrace_gotisrlock, irq_num, APIC_ITRACE_GOTISRLOCK) ;\ AVCPL_LOCK ; /* MP-safe */ \ testl $IRQ_BIT(irq_num), _cpl ; \ jne 2f ; /* this INT masked */ \ AVCPL_UNLOCK ; \ ; \ incb _intr_nesting_level ; \ ; \ /* entry point used by doreti_unpend for HWIs. */ \ __CONCAT(Xresume,irq_num): ; \ FAKE_MCOUNT(12*4(%esp)) ; /* XXX avoid dbl cnt */ \ lock ; incl _cnt+V_INTR ; /* tally interrupts */ \ movl _intr_countp + (irq_num) * 4, %eax ; \ lock ; incl (%eax) ; \ ; \ AVCPL_LOCK ; /* MP-safe */ \ movl _cpl, %eax ; \ pushl %eax ; \ orl _intr_mask + (irq_num) * 4, %eax ; \ movl %eax, _cpl ; \ andl $~IRQ_BIT(irq_num), _ipending ; \ AVCPL_UNLOCK ; \ ; \ pushl _intr_unit + (irq_num) * 4 ; \ APIC_ITRACE(apic_itrace_enter2, irq_num, APIC_ITRACE_ENTER2) ; \ sti ; \ call *_intr_handler + (irq_num) * 4 ; \ cli ; \ APIC_ITRACE(apic_itrace_leave, irq_num, APIC_ITRACE_LEAVE) ; \ ; \ lock ; andl $~IRQ_BIT(irq_num), iactive ; \ UNMASK_IRQ(irq_num) ; \ APIC_ITRACE(apic_itrace_unmask, irq_num, APIC_ITRACE_UNMASK) ; \ sti ; /* doreti repeats cli/sti */ \ MEXITCOUNT ; \ jmp _doreti ; \ ; \ ALIGN_TEXT ; \ 1: ; /* active */ \ APIC_ITRACE(apic_itrace_active, irq_num, APIC_ITRACE_ACTIVE) ; \ MASK_IRQ(irq_num) ; \ EOI_IRQ(irq_num) ; \ AVCPL_LOCK ; /* MP-safe */ \ orl $IRQ_BIT(irq_num), _ipending ; \ AVCPL_UNLOCK ; \ lock ; \ btsl $(irq_num), iactive ; /* still active */ \ jnc 0b ; /* retry */ \ POP_FRAME ; \ iret ; /* XXX: iactive bit might be 0 now */ \ ALIGN_TEXT ; \ 2: ; /* masked by cpl, leave iactive set */ \ APIC_ITRACE(apic_itrace_masked, irq_num, APIC_ITRACE_MASKED) ; \ orl $IRQ_BIT(irq_num), _ipending ; \ AVCPL_UNLOCK ; \ ISR_RELLOCK ; /* XXX this is going away... */ \ POP_FRAME ; \ iret ; \ ALIGN_TEXT ; \ 3: ; /* other cpu has isr lock */ \ APIC_ITRACE(apic_itrace_noisrlock, irq_num, APIC_ITRACE_NOISRLOCK) ;\ AVCPL_LOCK ; /* MP-safe */ \ orl $IRQ_BIT(irq_num), _ipending ; \ testl $IRQ_BIT(irq_num), _cpl ; \ jne 4f ; /* this INT masked */ \ AVCPL_UNLOCK ; \ call forward_irq ; /* forward irq to lock holder */ \ POP_FRAME ; /* and return */ \ iret ; \ ALIGN_TEXT ; \ 4: ; /* blocked */ \ APIC_ITRACE(apic_itrace_masked2, irq_num, APIC_ITRACE_MASKED2) ;\ AVCPL_UNLOCK ; \ POP_FRAME ; /* and return */ \ iret #endif /* CPL_AND_CML */ /* * Handle "spurious INTerrupts". * Notes: * This is different than the "spurious INTerrupt" generated by an * 8259 PIC for missing INTs. See the APIC documentation for details. * This routine should NOT do an 'EOI' cycle. */ .text SUPERALIGN_TEXT .globl _Xspuriousint _Xspuriousint: /* No EOI cycle used here */ iret /* * Handle TLB shootdowns. */ .text SUPERALIGN_TEXT .globl _Xinvltlb _Xinvltlb: pushl %eax #ifdef COUNT_XINVLTLB_HITS ss movl _cpuid, %eax ss incl _xhits(,%eax,4) #endif /* COUNT_XINVLTLB_HITS */ movl %cr3, %eax /* invalidate the TLB */ movl %eax, %cr3 ss /* stack segment, avoid %ds load */ movl $0, lapic_eoi /* End Of Interrupt to APIC */ popl %eax iret #ifdef BETTER_CLOCK /* * Executed by a CPU when it receives an Xcpucheckstate IPI from another CPU, * * - Stores current cpu state in checkstate_cpustate[cpuid] * 0 == user, 1 == sys, 2 == intr * - Stores current process in checkstate_curproc[cpuid] * * - Signals its receipt by setting bit cpuid in checkstate_probed_cpus. * * stack: 0 -> ds, 4 -> ebx, 8 -> eax, 12 -> eip, 16 -> cs, 20 -> eflags */ .text SUPERALIGN_TEXT .globl _Xcpucheckstate .globl _checkstate_cpustate .globl _checkstate_curproc .globl _checkstate_pc _Xcpucheckstate: pushl %eax pushl %ebx pushl %ds /* save current data segment */ movl $KDSEL, %eax movl %ax, %ds /* use KERNEL data segment */ movl $0, lapic_eoi /* End Of Interrupt to APIC */ movl $0, %ebx movl 16(%esp), %eax andl $3, %eax cmpl $3, %eax je 1f #ifdef VM86 testl $PSL_VM, 20(%esp) jne 1f #endif incl %ebx /* system or interrupt */ #ifdef CPL_AND_CML cmpl $0, _inside_intr je 1f incl %ebx /* interrupt */ #endif 1: movl _cpuid, %eax movl %ebx, _checkstate_cpustate(,%eax,4) movl _curproc, %ebx movl %ebx, _checkstate_curproc(,%eax,4) movl 12(%esp), %ebx movl %ebx, _checkstate_pc(,%eax,4) lock /* checkstate_probed_cpus |= (1<> 3) #ifdef AUTO_EOI_1 #define ENABLE_ICU1 /* use auto-EOI to reduce i/o */ #define OUTB_ICU1 #else #define ENABLE_ICU1 \ movb $ICU_EOI,%al ; /* as soon as possible send EOI ... */ \ OUTB_ICU1 /* ... to clear in service bit */ #define OUTB_ICU1 \ outb %al,$IO_ICU1 #endif #ifdef AUTO_EOI_2 /* * The data sheet says no auto-EOI on slave, but it sometimes works. */ #define ENABLE_ICU1_AND_2 ENABLE_ICU1 #else #define ENABLE_ICU1_AND_2 \ movb $ICU_EOI,%al ; /* as above */ \ outb %al,$IO_ICU2 ; /* but do second icu first ... */ \ OUTB_ICU1 /* ... then first icu (if !AUTO_EOI_1) */ #endif /* * Macros for interrupt interrupt entry, call to handler, and exit. */ #define FAST_INTR(irq_num, vec_name, enable_icus) \ .text ; \ SUPERALIGN_TEXT ; \ IDTVEC(vec_name) ; \ pushl %eax ; /* save only call-used registers */ \ pushl %ecx ; \ pushl %edx ; \ pushl %ds ; \ MAYBE_PUSHL_ES ; \ movl $KDSEL,%eax ; \ movl %ax,%ds ; \ MAYBE_MOVW_AX_ES ; \ FAKE_MCOUNT((4+ACTUALLY_PUSHED)*4(%esp)) ; \ pushl _intr_unit + (irq_num) * 4 ; \ call *_intr_handler + (irq_num) * 4 ; /* do the work ASAP */ \ enable_icus ; /* (re)enable ASAP (helps edge trigger?) */ \ addl $4,%esp ; \ incl _cnt+V_INTR ; /* book-keeping can wait */ \ movl _intr_countp + (irq_num) * 4,%eax ; \ incl (%eax) ; \ movl _cpl,%eax ; /* are we unmasking pending HWIs or SWIs? */ \ notl %eax ; \ andl _ipending,%eax ; \ jne 2f ; /* yes, maybe handle them */ \ 1: ; \ MEXITCOUNT ; \ MAYBE_POPL_ES ; \ popl %ds ; \ popl %edx ; \ popl %ecx ; \ popl %eax ; \ iret ; \ ; \ ALIGN_TEXT ; \ 2: ; \ cmpb $3,_intr_nesting_level ; /* is there enough stack? */ \ jae 1b ; /* no, return */ \ movl _cpl,%eax ; \ /* XXX next line is probably unnecessary now. */ \ movl $HWI_MASK|SWI_MASK,_cpl ; /* limit nesting ... */ \ incb _intr_nesting_level ; /* ... really limit it ... */ \ sti ; /* ... to do this as early as possible */ \ MAYBE_POPL_ES ; /* discard most of thin frame ... */ \ popl %ecx ; /* ... original %ds ... */ \ popl %edx ; \ xchgl %eax,4(%esp) ; /* orig %eax; save cpl */ \ pushal ; /* build fat frame (grrr) ... */ \ pushl %ecx ; /* ... actually %ds ... */ \ pushl %es ; \ movl $KDSEL,%eax ; \ movl %ax,%es ; \ movl (2+8+0)*4(%esp),%ecx ; /* ... %ecx from thin frame ... */ \ movl %ecx,(2+6)*4(%esp) ; /* ... to fat frame ... */ \ movl (2+8+1)*4(%esp),%eax ; /* ... cpl from thin frame */ \ pushl %eax ; \ subl $4,%esp ; /* junk for unit number */ \ MEXITCOUNT ; \ jmp _doreti #define INTR(irq_num, vec_name, icu, enable_icus, reg) \ .text ; \ SUPERALIGN_TEXT ; \ IDTVEC(vec_name) ; \ pushl $0 ; /* dummy error code */ \ pushl $0 ; /* dummy trap type */ \ pushal ; \ pushl %ds ; /* save our data and extra segments ... */ \ pushl %es ; \ movl $KDSEL,%eax ; /* ... and reload with kernel's own ... */ \ movl %ax,%ds ; /* ... early for obsolete reasons */ \ movl %ax,%es ; \ movb _imen + IRQ_BYTE(irq_num),%al ; \ orb $IRQ_BIT(irq_num),%al ; \ movb %al,_imen + IRQ_BYTE(irq_num) ; \ outb %al,$icu+ICU_IMR_OFFSET ; \ enable_icus ; \ movl _cpl,%eax ; \ testb $IRQ_BIT(irq_num),%reg ; \ jne 2f ; \ incb _intr_nesting_level ; \ __CONCAT(Xresume,irq_num): ; \ FAKE_MCOUNT(12*4(%esp)) ; /* XXX late to avoid double count */ \ incl _cnt+V_INTR ; /* tally interrupts */ \ movl _intr_countp + (irq_num) * 4,%eax ; \ incl (%eax) ; \ movl _cpl,%eax ; \ pushl %eax ; \ pushl _intr_unit + (irq_num) * 4 ; \ orl _intr_mask + (irq_num) * 4,%eax ; \ movl %eax,_cpl ; \ sti ; \ call *_intr_handler + (irq_num) * 4 ; \ cli ; /* must unmask _imen and icu atomically */ \ movb _imen + IRQ_BYTE(irq_num),%al ; \ andb $~IRQ_BIT(irq_num),%al ; \ movb %al,_imen + IRQ_BYTE(irq_num) ; \ outb %al,$icu+ICU_IMR_OFFSET ; \ sti ; /* XXX _doreti repeats the cli/sti */ \ MEXITCOUNT ; \ /* We could usually avoid the following jmp by inlining some of */ \ /* _doreti, but it's probably better to use less cache. */ \ jmp _doreti ; \ ; \ ALIGN_TEXT ; \ 2: ; \ /* XXX skip mcounting here to avoid double count */ \ orb $IRQ_BIT(irq_num),_ipending + IRQ_BYTE(irq_num) ; \ popl %es ; \ popl %ds ; \ popal ; \ addl $4+4,%esp ; \ iret MCOUNT_LABEL(bintr) FAST_INTR(0,fastintr0, ENABLE_ICU1) FAST_INTR(1,fastintr1, ENABLE_ICU1) FAST_INTR(2,fastintr2, ENABLE_ICU1) FAST_INTR(3,fastintr3, ENABLE_ICU1) FAST_INTR(4,fastintr4, ENABLE_ICU1) FAST_INTR(5,fastintr5, ENABLE_ICU1) FAST_INTR(6,fastintr6, ENABLE_ICU1) FAST_INTR(7,fastintr7, ENABLE_ICU1) FAST_INTR(8,fastintr8, ENABLE_ICU1_AND_2) FAST_INTR(9,fastintr9, ENABLE_ICU1_AND_2) FAST_INTR(10,fastintr10, ENABLE_ICU1_AND_2) FAST_INTR(11,fastintr11, ENABLE_ICU1_AND_2) FAST_INTR(12,fastintr12, ENABLE_ICU1_AND_2) FAST_INTR(13,fastintr13, ENABLE_ICU1_AND_2) FAST_INTR(14,fastintr14, ENABLE_ICU1_AND_2) FAST_INTR(15,fastintr15, ENABLE_ICU1_AND_2) INTR(0,intr0, IO_ICU1, ENABLE_ICU1, al) INTR(1,intr1, IO_ICU1, ENABLE_ICU1, al) INTR(2,intr2, IO_ICU1, ENABLE_ICU1, al) INTR(3,intr3, IO_ICU1, ENABLE_ICU1, al) INTR(4,intr4, IO_ICU1, ENABLE_ICU1, al) INTR(5,intr5, IO_ICU1, ENABLE_ICU1, al) INTR(6,intr6, IO_ICU1, ENABLE_ICU1, al) INTR(7,intr7, IO_ICU1, ENABLE_ICU1, al) INTR(8,intr8, IO_ICU2, ENABLE_ICU1_AND_2, ah) INTR(9,intr9, IO_ICU2, ENABLE_ICU1_AND_2, ah) INTR(10,intr10, IO_ICU2, ENABLE_ICU1_AND_2, ah) INTR(11,intr11, IO_ICU2, ENABLE_ICU1_AND_2, ah) INTR(12,intr12, IO_ICU2, ENABLE_ICU1_AND_2, ah) INTR(13,intr13, IO_ICU2, ENABLE_ICU1_AND_2, ah) INTR(14,intr14, IO_ICU2, ENABLE_ICU1_AND_2, ah) INTR(15,intr15, IO_ICU2, ENABLE_ICU1_AND_2, ah) MCOUNT_LABEL(eintr) .data .globl _ihandlers -_ihandlers: -ihandlers: /* addresses of interrupt handlers */ +_ihandlers: /* addresses of interrupt handlers */ /* actually resumption addresses for HWI's */ .long Xresume0, Xresume1, Xresume2, Xresume3 .long Xresume4, Xresume5, Xresume6, Xresume7 .long Xresume8, Xresume9, Xresume10, Xresume11 .long Xresume12, Xresume13, Xresume14, Xresume15 .long swi_tty, swi_net, dummycamisr, dummycamisr - .long _swi_vm, 0, 0, 0 - .long 0, 0, 0, 0 - .long 0, 0, _softclock, swi_ast + .long _swi_vm, _swi_null, _swi_null, _swi_null + .long _swi_null, _swi_null, _swi_null, _swi_null + .long _swi_null, _swi_null, _softclock, swi_ast imasks: /* masks for interrupt handlers */ .space NHWI*4 /* padding; HWI masks are elsewhere */ .long SWI_TTY_MASK, SWI_NET_MASK, SWI_CAMNET_MASK, SWI_CAMBIO_MASK .long SWI_VM_MASK, 0, 0, 0 .long 0, 0, 0, 0 .long 0, 0, SWI_CLOCK_MASK, SWI_AST_MASK /* * Interrupt counters and names. The format of these and the label names * must agree with what vmstat expects. The tables are indexed by device * ids so that we don't have to move the names around as devices are * attached. */ #include "vector.h" .globl _intrcnt, _eintrcnt _intrcnt: .space (NR_DEVICES + ICU_LEN) * 4 _eintrcnt: .globl _intrnames, _eintrnames _intrnames: .ascii DEVICE_NAMES .asciz "stray irq0" .asciz "stray irq1" .asciz "stray irq2" .asciz "stray irq3" .asciz "stray irq4" .asciz "stray irq5" .asciz "stray irq6" .asciz "stray irq7" .asciz "stray irq8" .asciz "stray irq9" .asciz "stray irq10" .asciz "stray irq11" .asciz "stray irq12" .asciz "stray irq13" .asciz "stray irq14" .asciz "stray irq15" _eintrnames: .text Index: head/sys/i386/isa/icu_ipl.s =================================================================== --- head/sys/i386/isa/icu_ipl.s (revision 38243) +++ head/sys/i386/isa/icu_ipl.s (revision 38244) @@ -1,173 +1,170 @@ /*- * Copyright (c) 1989, 1990 William F. Jolitz. * Copyright (c) 1990 The Regents of the University of California. * All rights reserved. * * This code is derived from software contributed to Berkeley by * William Jolitz. * * 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 by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. * - * $Id: icu_ipl.s,v 1.2 1997/08/24 00:05:13 fsmp Exp $ + * $Id: icu_ipl.s,v 1.3 1997/09/02 19:40:13 fsmp Exp $ */ .data ALIGN_DATA vec: .long vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7 .long vec8, vec9, vec10, vec11, vec12, vec13, vec14, vec15 /* interrupt mask enable (all h/w off) */ .globl _imen _imen: .long HWI_MASK /* * */ .text SUPERALIGN_TEXT /* * Interrupt priority mechanism * -- soft splXX masks with group mechanism (cpl) * -- h/w masks for currently active or unused interrupts (imen) * -- ipending = active interrupts currently masked by cpl */ ENTRY(splz) /* * The caller has restored cpl and checked that (ipending & ~cpl) * is nonzero. We have to repeat the check since if there is an * interrupt while we're looking, _doreti processing for the * interrupt will handle all the unmasked pending interrupts * because we restored early. We're repeating the calculation * of (ipending & ~cpl) anyway so that the caller doesn't have * to pass it, so this only costs one "jne". "bsfl %ecx,%ecx" * is undefined when %ecx is 0 so we can't rely on the secondary * btrl tests. */ movl _cpl,%eax splz_next: /* * We don't need any locking here. (ipending & ~cpl) cannot grow * while we're looking at it - any interrupt will shrink it to 0. */ movl %eax,%ecx notl %ecx andl _ipending,%ecx jne splz_unpend ret ALIGN_TEXT splz_unpend: bsfl %ecx,%ecx btrl %ecx,_ipending jnc splz_next - movl ihandlers(,%ecx,4),%edx - testl %edx,%edx - je splz_next /* "can't happen" */ cmpl $NHWI,%ecx jae splz_swi /* * We would prefer to call the intr handler directly here but that * doesn't work for badly behaved handlers that want the interrupt * frame. Also, there's a problem determining the unit number. * We should change the interface so that the unit number is not * determined at config time. */ jmp *vec(,%ecx,4) ALIGN_TEXT splz_swi: cmpl $SWI_AST,%ecx je splz_next /* "can't happen" */ pushl %eax orl imasks(,%ecx,4),%eax movl %eax,_cpl - call %edx + call *_ihandlers(,%ecx,4) popl %eax movl %eax,_cpl jmp splz_next /* * Fake clock interrupt(s) so that they appear to come from our caller instead * of from here, so that system profiling works. * XXX do this more generally (for all vectors; look up the C entry point). * XXX frame bogusness stops us from just jumping to the C entry point. */ ALIGN_TEXT vec0: popl %eax /* return address */ pushfl pushl $KCSEL pushl %eax cli MEXITCOUNT jmp _Xintr0 /* XXX might need _Xfastintr0 */ #ifndef PC98 ALIGN_TEXT vec8: popl %eax pushfl pushl $KCSEL pushl %eax cli MEXITCOUNT jmp _Xintr8 /* XXX might need _Xfastintr8 */ #endif /* PC98 */ /* * The 'generic' vector stubs. */ #define BUILD_VEC(irq_num) \ ALIGN_TEXT ; \ __CONCAT(vec,irq_num): ; \ int $ICU_OFFSET + (irq_num) ; \ ret BUILD_VEC(1) BUILD_VEC(2) BUILD_VEC(3) BUILD_VEC(4) BUILD_VEC(5) BUILD_VEC(6) BUILD_VEC(7) #ifdef PC98 BUILD_VEC(8) #endif BUILD_VEC(9) BUILD_VEC(10) BUILD_VEC(11) BUILD_VEC(12) BUILD_VEC(13) BUILD_VEC(14) BUILD_VEC(15) Index: head/sys/i386/isa/icu_vector.s =================================================================== --- head/sys/i386/isa/icu_vector.s (revision 38243) +++ head/sys/i386/isa/icu_vector.s (revision 38244) @@ -1,251 +1,250 @@ /* * from: vector.s, 386BSD 0.1 unknown origin - * $Id: icu_vector.s,v 1.6 1997/09/28 19:30:01 gibbs Exp $ + * $Id: icu_vector.s,v 1.7 1998/01/15 07:33:59 gibbs Exp $ */ /* * modified for PC98 by Kakefuda */ #ifdef PC98 #define ICU_IMR_OFFSET 2 /* IO_ICU{1,2} + 2 */ #else #define ICU_IMR_OFFSET 1 /* IO_ICU{1,2} + 1 */ #endif #define ICU_EOI 0x20 /* XXX - define elsewhere */ #define IRQ_BIT(irq_num) (1 << ((irq_num) % 8)) #define IRQ_BYTE(irq_num) ((irq_num) >> 3) #ifdef AUTO_EOI_1 #define ENABLE_ICU1 /* use auto-EOI to reduce i/o */ #define OUTB_ICU1 #else #define ENABLE_ICU1 \ movb $ICU_EOI,%al ; /* as soon as possible send EOI ... */ \ OUTB_ICU1 /* ... to clear in service bit */ #define OUTB_ICU1 \ outb %al,$IO_ICU1 #endif #ifdef AUTO_EOI_2 /* * The data sheet says no auto-EOI on slave, but it sometimes works. */ #define ENABLE_ICU1_AND_2 ENABLE_ICU1 #else #define ENABLE_ICU1_AND_2 \ movb $ICU_EOI,%al ; /* as above */ \ outb %al,$IO_ICU2 ; /* but do second icu first ... */ \ OUTB_ICU1 /* ... then first icu (if !AUTO_EOI_1) */ #endif /* * Macros for interrupt interrupt entry, call to handler, and exit. */ #define FAST_INTR(irq_num, vec_name, enable_icus) \ .text ; \ SUPERALIGN_TEXT ; \ IDTVEC(vec_name) ; \ pushl %eax ; /* save only call-used registers */ \ pushl %ecx ; \ pushl %edx ; \ pushl %ds ; \ MAYBE_PUSHL_ES ; \ movl $KDSEL,%eax ; \ movl %ax,%ds ; \ MAYBE_MOVW_AX_ES ; \ FAKE_MCOUNT((4+ACTUALLY_PUSHED)*4(%esp)) ; \ pushl _intr_unit + (irq_num) * 4 ; \ call *_intr_handler + (irq_num) * 4 ; /* do the work ASAP */ \ enable_icus ; /* (re)enable ASAP (helps edge trigger?) */ \ addl $4,%esp ; \ incl _cnt+V_INTR ; /* book-keeping can wait */ \ movl _intr_countp + (irq_num) * 4,%eax ; \ incl (%eax) ; \ movl _cpl,%eax ; /* are we unmasking pending HWIs or SWIs? */ \ notl %eax ; \ andl _ipending,%eax ; \ jne 2f ; /* yes, maybe handle them */ \ 1: ; \ MEXITCOUNT ; \ MAYBE_POPL_ES ; \ popl %ds ; \ popl %edx ; \ popl %ecx ; \ popl %eax ; \ iret ; \ ; \ ALIGN_TEXT ; \ 2: ; \ cmpb $3,_intr_nesting_level ; /* is there enough stack? */ \ jae 1b ; /* no, return */ \ movl _cpl,%eax ; \ /* XXX next line is probably unnecessary now. */ \ movl $HWI_MASK|SWI_MASK,_cpl ; /* limit nesting ... */ \ incb _intr_nesting_level ; /* ... really limit it ... */ \ sti ; /* ... to do this as early as possible */ \ MAYBE_POPL_ES ; /* discard most of thin frame ... */ \ popl %ecx ; /* ... original %ds ... */ \ popl %edx ; \ xchgl %eax,4(%esp) ; /* orig %eax; save cpl */ \ pushal ; /* build fat frame (grrr) ... */ \ pushl %ecx ; /* ... actually %ds ... */ \ pushl %es ; \ movl $KDSEL,%eax ; \ movl %ax,%es ; \ movl (2+8+0)*4(%esp),%ecx ; /* ... %ecx from thin frame ... */ \ movl %ecx,(2+6)*4(%esp) ; /* ... to fat frame ... */ \ movl (2+8+1)*4(%esp),%eax ; /* ... cpl from thin frame */ \ pushl %eax ; \ subl $4,%esp ; /* junk for unit number */ \ MEXITCOUNT ; \ jmp _doreti #define INTR(irq_num, vec_name, icu, enable_icus, reg) \ .text ; \ SUPERALIGN_TEXT ; \ IDTVEC(vec_name) ; \ pushl $0 ; /* dummy error code */ \ pushl $0 ; /* dummy trap type */ \ pushal ; \ pushl %ds ; /* save our data and extra segments ... */ \ pushl %es ; \ movl $KDSEL,%eax ; /* ... and reload with kernel's own ... */ \ movl %ax,%ds ; /* ... early for obsolete reasons */ \ movl %ax,%es ; \ movb _imen + IRQ_BYTE(irq_num),%al ; \ orb $IRQ_BIT(irq_num),%al ; \ movb %al,_imen + IRQ_BYTE(irq_num) ; \ outb %al,$icu+ICU_IMR_OFFSET ; \ enable_icus ; \ movl _cpl,%eax ; \ testb $IRQ_BIT(irq_num),%reg ; \ jne 2f ; \ incb _intr_nesting_level ; \ __CONCAT(Xresume,irq_num): ; \ FAKE_MCOUNT(12*4(%esp)) ; /* XXX late to avoid double count */ \ incl _cnt+V_INTR ; /* tally interrupts */ \ movl _intr_countp + (irq_num) * 4,%eax ; \ incl (%eax) ; \ movl _cpl,%eax ; \ pushl %eax ; \ pushl _intr_unit + (irq_num) * 4 ; \ orl _intr_mask + (irq_num) * 4,%eax ; \ movl %eax,_cpl ; \ sti ; \ call *_intr_handler + (irq_num) * 4 ; \ cli ; /* must unmask _imen and icu atomically */ \ movb _imen + IRQ_BYTE(irq_num),%al ; \ andb $~IRQ_BIT(irq_num),%al ; \ movb %al,_imen + IRQ_BYTE(irq_num) ; \ outb %al,$icu+ICU_IMR_OFFSET ; \ sti ; /* XXX _doreti repeats the cli/sti */ \ MEXITCOUNT ; \ /* We could usually avoid the following jmp by inlining some of */ \ /* _doreti, but it's probably better to use less cache. */ \ jmp _doreti ; \ ; \ ALIGN_TEXT ; \ 2: ; \ /* XXX skip mcounting here to avoid double count */ \ orb $IRQ_BIT(irq_num),_ipending + IRQ_BYTE(irq_num) ; \ popl %es ; \ popl %ds ; \ popal ; \ addl $4+4,%esp ; \ iret MCOUNT_LABEL(bintr) FAST_INTR(0,fastintr0, ENABLE_ICU1) FAST_INTR(1,fastintr1, ENABLE_ICU1) FAST_INTR(2,fastintr2, ENABLE_ICU1) FAST_INTR(3,fastintr3, ENABLE_ICU1) FAST_INTR(4,fastintr4, ENABLE_ICU1) FAST_INTR(5,fastintr5, ENABLE_ICU1) FAST_INTR(6,fastintr6, ENABLE_ICU1) FAST_INTR(7,fastintr7, ENABLE_ICU1) FAST_INTR(8,fastintr8, ENABLE_ICU1_AND_2) FAST_INTR(9,fastintr9, ENABLE_ICU1_AND_2) FAST_INTR(10,fastintr10, ENABLE_ICU1_AND_2) FAST_INTR(11,fastintr11, ENABLE_ICU1_AND_2) FAST_INTR(12,fastintr12, ENABLE_ICU1_AND_2) FAST_INTR(13,fastintr13, ENABLE_ICU1_AND_2) FAST_INTR(14,fastintr14, ENABLE_ICU1_AND_2) FAST_INTR(15,fastintr15, ENABLE_ICU1_AND_2) INTR(0,intr0, IO_ICU1, ENABLE_ICU1, al) INTR(1,intr1, IO_ICU1, ENABLE_ICU1, al) INTR(2,intr2, IO_ICU1, ENABLE_ICU1, al) INTR(3,intr3, IO_ICU1, ENABLE_ICU1, al) INTR(4,intr4, IO_ICU1, ENABLE_ICU1, al) INTR(5,intr5, IO_ICU1, ENABLE_ICU1, al) INTR(6,intr6, IO_ICU1, ENABLE_ICU1, al) INTR(7,intr7, IO_ICU1, ENABLE_ICU1, al) INTR(8,intr8, IO_ICU2, ENABLE_ICU1_AND_2, ah) INTR(9,intr9, IO_ICU2, ENABLE_ICU1_AND_2, ah) INTR(10,intr10, IO_ICU2, ENABLE_ICU1_AND_2, ah) INTR(11,intr11, IO_ICU2, ENABLE_ICU1_AND_2, ah) INTR(12,intr12, IO_ICU2, ENABLE_ICU1_AND_2, ah) INTR(13,intr13, IO_ICU2, ENABLE_ICU1_AND_2, ah) INTR(14,intr14, IO_ICU2, ENABLE_ICU1_AND_2, ah) INTR(15,intr15, IO_ICU2, ENABLE_ICU1_AND_2, ah) MCOUNT_LABEL(eintr) .data .globl _ihandlers -_ihandlers: -ihandlers: /* addresses of interrupt handlers */ +_ihandlers: /* addresses of interrupt handlers */ /* actually resumption addresses for HWI's */ .long Xresume0, Xresume1, Xresume2, Xresume3 .long Xresume4, Xresume5, Xresume6, Xresume7 .long Xresume8, Xresume9, Xresume10, Xresume11 .long Xresume12, Xresume13, Xresume14, Xresume15 .long swi_tty, swi_net, dummycamisr, dummycamisr - .long _swi_vm, 0, 0, 0 - .long 0, 0, 0, 0 - .long 0, 0, _softclock, swi_ast + .long _swi_vm, _swi_null, _swi_null, _swi_null + .long _swi_null, _swi_null, _swi_null, _swi_null + .long _swi_null, _swi_null, _softclock, swi_ast imasks: /* masks for interrupt handlers */ .space NHWI*4 /* padding; HWI masks are elsewhere */ .long SWI_TTY_MASK, SWI_NET_MASK, SWI_CAMNET_MASK, SWI_CAMBIO_MASK .long SWI_VM_MASK, 0, 0, 0 .long 0, 0, 0, 0 .long 0, 0, SWI_CLOCK_MASK, SWI_AST_MASK /* * Interrupt counters and names. The format of these and the label names * must agree with what vmstat expects. The tables are indexed by device * ids so that we don't have to move the names around as devices are * attached. */ #include "vector.h" .globl _intrcnt, _eintrcnt _intrcnt: .space (NR_DEVICES + ICU_LEN) * 4 _eintrcnt: .globl _intrnames, _eintrnames _intrnames: .ascii DEVICE_NAMES .asciz "stray irq0" .asciz "stray irq1" .asciz "stray irq2" .asciz "stray irq3" .asciz "stray irq4" .asciz "stray irq5" .asciz "stray irq6" .asciz "stray irq7" .asciz "stray irq8" .asciz "stray irq9" .asciz "stray irq10" .asciz "stray irq11" .asciz "stray irq12" .asciz "stray irq13" .asciz "stray irq14" .asciz "stray irq15" _eintrnames: .text Index: head/sys/i386/isa/ipl.s =================================================================== --- head/sys/i386/isa/ipl.s (revision 38243) +++ head/sys/i386/isa/ipl.s (revision 38244) @@ -1,446 +1,455 @@ /*- * Copyright (c) 1989, 1990 William F. Jolitz. * Copyright (c) 1990 The Regents of the University of California. * All rights reserved. * * This code is derived from software contributed to Berkeley by * William Jolitz. * * 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 by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. * * @(#)ipl.s * - * $Id: ipl.s,v 1.21 1998/03/23 19:52:59 jlemon Exp $ + * $Id: ipl.s,v 1.22 1998/07/27 16:51:33 jlemon Exp $ */ /* * AT/386 * Vector interrupt control section */ .data ALIGN_DATA /* current priority (all off) */ .globl _cpl _cpl: .long HWI_MASK | SWI_MASK .globl _tty_imask _tty_imask: .long 0 .globl _bio_imask _bio_imask: .long SWI_CAMBIO_MASK .globl _cam_imask _cam_imask: .long SWI_CAMBIO_MASK | SWI_CAMNET_MASK .globl _net_imask _net_imask: .long SWI_CAMNET_MASK .globl _soft_imask _soft_imask: .long SWI_MASK .globl _softnet_imask _softnet_imask: .long SWI_NET_MASK .globl _softtty_imask _softtty_imask: .long SWI_TTY_MASK /* pending interrupts blocked by splxxx() */ .globl _ipending _ipending: .long 0 /* set with bits for which queue to service */ .globl _netisr _netisr: .long 0 .globl _netisrs _netisrs: .long dummynetisr, dummynetisr, dummynetisr, dummynetisr .long dummynetisr, dummynetisr, dummynetisr, dummynetisr .long dummynetisr, dummynetisr, dummynetisr, dummynetisr .long dummynetisr, dummynetisr, dummynetisr, dummynetisr .long dummynetisr, dummynetisr, dummynetisr, dummynetisr .long dummynetisr, dummynetisr, dummynetisr, dummynetisr .long dummynetisr, dummynetisr, dummynetisr, dummynetisr .long dummynetisr, dummynetisr, dummynetisr, dummynetisr .text #ifdef SMP #ifdef notnow #define TEST_CIL \ cmpl $0x0100, _cil ; \ jne 1f ; \ cmpl $0, _inside_intr ; \ jne 1f ; \ int $3 ; \ 1: #else #define TEST_CIL #endif #endif /* * Handle return from interrupts, traps and syscalls. */ SUPERALIGN_TEXT _doreti: #ifdef SMP TEST_CIL #endif FAKE_MCOUNT(_bintr) /* init "from" _bintr -> _doreti */ addl $4,%esp /* discard unit number */ popl %eax /* cpl or cml to restore */ doreti_next: /* * Check for pending HWIs and SWIs atomically with restoring cpl * and exiting. The check has to be atomic with exiting to stop * (ipending & ~cpl) changing from zero to nonzero while we're * looking at it (this wouldn't be fatal but it would increase * interrupt latency). Restoring cpl has to be atomic with exiting * so that the stack cannot pile up (the nesting level of interrupt * handlers is limited by the number of bits in cpl). */ #ifdef SMP TEST_CIL cli /* early to prevent INT deadlock */ pushl %eax /* preserve cpl while getting lock */ ICPL_LOCK popl %eax doreti_next2: #endif movl %eax,%ecx #ifdef CPL_AND_CML orl _cpl, %ecx /* add cpl to cml */ #endif notl %ecx /* set bit = unmasked level */ #ifndef SMP cli #endif andl _ipending,%ecx /* set bit = unmasked pending INT */ jne doreti_unpend doreti_exit: #ifdef SMP TEST_CIL #endif #ifdef CPL_AND_CML movl %eax, _cml #else movl %eax,_cpl #endif FAST_ICPL_UNLOCK /* preserves %eax */ MPLOCKED decb _intr_nesting_level MEXITCOUNT #ifdef VM86 #ifdef CPL_AND_CML /* XXX CPL_AND_CML needs work */ #error not ready for vm86 #endif cmpl $1,_in_vm86call je 1f /* want cpl == SWI_AST_PENDING */ /* * XXX * Sometimes when attempting to return to vm86 mode, cpl is not * being reset to 0, so here we force it to 0 before returning to * vm86 mode. doreti_stop is a convenient place to set a breakpoint. * When the cpl problem is solved, this code can disappear. */ ICPL_LOCK cmpl $0,_cpl /* cpl == 0, skip it */ je 1f testl $PSL_VM,TF_EFLAGS(%esp) /* going to VM86 mode? */ jne doreti_stop testb $SEL_RPL_MASK,TRAPF_CS_OFF(%esp) /* to user mode? */ je 1f doreti_stop: movl $0,_cpl nop 1: FAST_ICPL_UNLOCK /* preserves %eax */ #endif /* VM86 */ #ifdef SMP #ifdef INTR_SIMPLELOCK #error code needed here to decide which lock to release, INTR or giant #endif /* release the kernel lock */ pushl $_mp_lock /* GIANT_LOCK */ call _MPrellock add $4, %esp #endif /* SMP */ .globl doreti_popl_es doreti_popl_es: popl %es .globl doreti_popl_ds doreti_popl_ds: popl %ds popal addl $8,%esp .globl doreti_iret doreti_iret: iret ALIGN_TEXT .globl doreti_iret_fault doreti_iret_fault: subl $8,%esp pushal pushl %ds .globl doreti_popl_ds_fault doreti_popl_ds_fault: pushl %es .globl doreti_popl_es_fault doreti_popl_es_fault: movl $0,4+4+32+4(%esp) /* XXX should be the error code */ movl $T_PROTFLT,4+4+32+0(%esp) jmp alltraps_with_regs_pushed ALIGN_TEXT doreti_unpend: /* * Enabling interrupts is safe because we haven't restored cpl yet. * The locking from the "btrl" test is probably no longer necessary. * We won't miss any new pending interrupts because we will check * for them again. */ #ifdef SMP TEST_CIL /* we enter with cpl locked */ bsfl %ecx, %ecx /* slow, but not worth optimizing */ btrl %ecx, _ipending jnc doreti_next2 /* some intr cleared memory copy */ cmpl $NHWI, %ecx jae 1f btsl %ecx, _cil 1: FAST_ICPL_UNLOCK /* preserves %eax */ sti /* late to prevent INT deadlock */ #else sti bsfl %ecx,%ecx /* slow, but not worth optimizing */ btrl %ecx,_ipending jnc doreti_next /* some intr cleared memory copy */ #endif /* SMP */ /* - * Setup JUMP to _Xresume0 thru _Xresume23 for HWIs, - * or - * Setup CALL of swi_tty, swi_net, _softclock, swi_ast for SWIs. + * Set up JUMP to _ihandlers[%ecx] for HWIs. + * Set up CALL of _ihandlers[%ecx] for SWIs. + * This is a bit early for the SMP case - we have to push %ecx and + * %edx, but could push only %ecx and load %edx later. */ - movl ihandlers(,%ecx,4),%edx - testl %edx,%edx -#if 0 - /* XXX SMP this would leave cil set: */ - je doreti_next /* "can't happen" */ -#else - jne 1f - int $3 /* _breakpoint */ - jmp doreti_next /* "can't happen" */ -1: -#endif + movl _ihandlers(,%ecx,4),%edx cmpl $NHWI,%ecx jae doreti_swi cli #ifdef SMP pushl %edx /* preserve %edx */ #ifdef APIC_INTR_DIAGNOSTIC pushl %ecx #endif pushl %eax /* preserve %eax */ ICPL_LOCK #ifdef CPL_AND_CML popl _cml #else popl _cpl #endif FAST_ICPL_UNLOCK #ifdef APIC_INTR_DIAGNOSTIC popl %ecx #endif popl %edx #else movl %eax,_cpl #endif MEXITCOUNT #ifdef APIC_INTR_DIAGNOSTIC lock incl CNAME(apic_itrace_doreti)(,%ecx,4) #ifdef APIC_INTR_DIAGNOSTIC_IRQ cmpl $APIC_INTR_DIAGNOSTIC_IRQ,%ecx jne 9f pushl %eax pushl %ecx pushl %edx pushl $APIC_ITRACE_DORETI call log_intr_event addl $4,%esp popl %edx popl %ecx popl %eax 9: #endif #endif jmp %edx ALIGN_TEXT doreti_swi: #ifdef SMP TEST_CIL #endif pushl %eax /* * The SWI_AST handler has to run at cpl = SWI_AST_MASK and the * SWI_CLOCK handler at cpl = SWI_CLOCK_MASK, so we have to restore * all the h/w bits in cpl now and have to worry about stack growth. * The worst case is currently (30 Jan 1994) 2 SWI handlers nested * in dying interrupt frames and about 12 HWIs nested in active * interrupt frames. There are only 4 different SWIs and the HWI * and SWI masks limit the nesting further. */ #ifdef SMP orl imasks(,%ecx,4), %eax + pushl %ecx /* preserve for use by _swi_generic */ pushl %edx /* save handler entry point */ cli /* prevent INT deadlock */ pushl %eax /* save cpl|cml */ ICPL_LOCK #ifdef CPL_AND_CML popl _cml /* restore cml */ #else popl _cpl /* restore cpl */ #endif FAST_ICPL_UNLOCK sti popl %edx /* restore handler entry point */ + popl %ecx #else orl imasks(,%ecx,4),%eax movl %eax,_cpl #endif call %edx popl %eax jmp doreti_next ALIGN_TEXT swi_ast: addl $8,%esp /* discard raddr & cpl to get trap frame */ #ifdef VM86 cmpl $1,_in_vm86call je 1f /* stay in kernel mode */ #endif testb $SEL_RPL_MASK,TRAPF_CS_OFF(%esp) je swi_ast_phantom swi_ast_user: movl $T_ASTFLT,(2+8+0)*4(%esp) movb $0,_intr_nesting_level /* finish becoming a trap handler */ call _trap subl %eax,%eax /* recover cpl|cml */ #ifdef CPL_AND_CML movl %eax, _cpl #endif movb $1,_intr_nesting_level /* for doreti_next to decrement */ jmp doreti_next ALIGN_TEXT swi_ast_phantom: #ifdef VM86 /* * check for ast from vm86 mode. Placed down here so the jumps do * not get taken for mainline code. */ testl $PSL_VM,TF_EFLAGS(%esp) jne swi_ast_user 1: #endif /* VM86 */ /* * These happen when there is an interrupt in a trap handler before * ASTs can be masked or in an lcall handler before they can be * masked or after they are unmasked. They could be avoided for * trap entries by using interrupt gates, and for lcall exits by * using by using cli, but they are unavoidable for lcall entries. */ cli ICPL_LOCK orl $SWI_AST_PENDING, _ipending /* cpl is unlocked in doreti_exit */ subl %eax,%eax #ifdef CPL_AND_CML movl %eax, _cpl #endif jmp doreti_exit /* SWI_AST is highest so we must be done */ ALIGN_TEXT swi_net: MCOUNT bsfl _netisr,%eax je swi_net_done swi_net_more: btrl %eax,_netisr jnc swi_net_next call *_netisrs(,%eax,4) swi_net_next: bsfl _netisr,%eax jne swi_net_more swi_net_done: ret ALIGN_TEXT dummynetisr: MCOUNT ret ALIGN_TEXT dummycamisr: MCOUNT ret /* - * XXX there should be a registration function to put the handler for the - * attached driver directly in ihandlers. Then this function will go away. + * This function will go away soon when register_swi() is used to register + * the poll functions. */ ALIGN_TEXT swi_tty: MCOUNT #include "cy.h" #if NCY > 0 call _cypoll #endif #include "rc.h" #if NRC > 0 call _rcpoll #endif #include "sio.h" #if NSIO > 0 jmp _siopoll #else ret #endif + +/* + * The arg is in a nonstandard place, so swi_dispatcher() can't be called + * directly and swi_generic() can't use ENTRY() or MCOUNT. + */ + ALIGN_TEXT + .globl _swi_generic +_swi_generic: + pushl %ecx + FAKE_MCOUNT(4(%esp)) + call _swi_dispatcher + popl %ecx + ret + +ENTRY(swi_null) + ret #ifdef APIC_IO #include "i386/isa/apic_ipl.s" #else #include "i386/isa/icu_ipl.s" #endif /* APIC_IO */ Index: head/sys/kern/kern_intr.c =================================================================== --- head/sys/kern/kern_intr.c (revision 38243) +++ head/sys/kern/kern_intr.c (revision 38244) @@ -1,440 +1,531 @@ /* * Copyright (c) 1997, Stefan Esser * All rights reserved. * * 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 unmodified, 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 AUTHOR ``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 AUTHOR 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. * - * $Id: kern_intr.c,v 1.17 1998/06/18 15:32:08 bde Exp $ + * $Id: kern_intr.c,v 1.18 1998/07/15 02:32:08 bde Exp $ * */ #ifdef __i386__ /* * This file is pretty i386 specific. I might be able to make it more * portable in the future but for now turn it off for non-i386 ports. */ #include #include #include #include #ifdef RESOURCE_CHECK #include #endif /* RESOURCE_CHECK */ +#include + #include #include + #include #include typedef struct intrec { intrmask_t mask; inthand2_t *handler; void *argument; struct intrec *next; void *devdata; int intr; intrmask_t *maskptr; int flags; } intrec; +struct swilist { + swihand_t *sl_handler; + struct swilist *sl_next; +}; + +static intrec *intreclist_head[NHWI]; +static struct swilist swilists[NSWI]; + /* * The interrupt multiplexer calls each of the handlers in turn, * and applies the associated interrupt mask to "cpl", which is * defined as a ".long" in /sys/i386/isa/ipl.s */ #ifndef SMP -#include - static __inline intrmask_t splq(intrmask_t mask) { intrmask_t tmp = cpl; cpl |= mask; return (tmp); } #endif /* SMP */ static void intr_mux(void *arg) { intrec *p = arg; while (p != NULL) { int oldspl = splq(p->mask); p->handler(p->argument); splx(oldspl); p = p->next; } } -/* XXX better use NHWI from for array size ??? */ -static intrec *intreclist_head[ICU_LEN]; - static intrec* find_idesc(unsigned *maskptr, int irq) { intrec *p = intreclist_head[irq]; while (p && p->maskptr != maskptr) p = p->next; return (p); } static intrec** find_pred(intrec *idesc, int irq) { intrec **pp = &intreclist_head[irq]; intrec *p = *pp; while (p != idesc) { if (p == NULL) return (NULL); pp = &p->next; p = *pp; } return (pp); } /* * Both the low level handler and the shared interrupt multiplexer * block out further interrupts as set in the handlers "mask", while * the handler is running. In fact *maskptr should be used for this * purpose, but since this requires one more pointer dereference on * each interrupt, we rather bother update "mask" whenever *maskptr * changes. The function "update_masks" should be called **after** * all manipulation of the linked list of interrupt handlers hung * off of intrdec_head[irq] is complete, since the chain of handlers * will both determine the *maskptr values and the instances of mask * that are fixed. This function should be called with the irq for * which a new handler has been add blocked, since the masks may not * yet know about the use of this irq for a device of a certain class. */ static void update_mux_masks(void) { int irq; for (irq = 0; irq < ICU_LEN; irq++) { intrec *idesc = intreclist_head[irq]; while (idesc != NULL) { if (idesc->maskptr != NULL) { /* our copy of *maskptr may be stale, refresh */ idesc->mask = *idesc->maskptr; } idesc = idesc->next; } } } static void update_masks(intrmask_t *maskptr, int irq) { intrmask_t mask = 1 << irq; if (maskptr == NULL) return; if (find_idesc(maskptr, irq) == NULL) { /* no reference to this maskptr was found in this irq's chain */ if ((*maskptr & mask) == 0) return; /* the irq was included in the classes mask, remove it */ INTRUNMASK(*maskptr, mask); } else { /* a reference to this maskptr was found in this irq's chain */ if ((*maskptr & mask) != 0) return; /* put the irq into the classes mask */ INTRMASK(*maskptr, mask); } /* we need to update all values in the intr_mask[irq] array */ update_intr_masks(); /* update mask in chains of the interrupt multiplex handler as well */ update_mux_masks(); } /* * Add interrupt handler to linked list hung off of intreclist_head[irq] * and install shared interrupt multiplex handler, if necessary */ static int add_intrdesc(intrec *idesc) { int irq = idesc->intr; intrec *head = intreclist_head[irq]; if (head == NULL) { /* first handler for this irq, just install it */ if (icu_setup(irq, idesc->handler, idesc->argument, idesc->maskptr, idesc->flags) != 0) return (-1); update_intrname(irq, (intptr_t)idesc->devdata); /* keep reference */ intreclist_head[irq] = idesc; } else { if ((idesc->flags & INTR_EXCL) != 0 || (head->flags & INTR_EXCL) != 0) { /* * can't append new handler, if either list head or * new handler do not allow interrupts to be shared */ if (bootverbose) printf("\tdevice combination doesn't support " "shared irq%d\n", irq); return (-1); } if (head->next == NULL) { /* * second handler for this irq, replace device driver's * handler by shared interrupt multiplexer function */ icu_unset(irq, head->handler); if (icu_setup(irq, (inthand2_t*)intr_mux, head, 0, 0) != 0) return (-1); if (bootverbose) printf("\tusing shared irq%d.\n", irq); update_intrname(irq, -1); } /* just append to the end of the chain */ while (head->next != NULL) head = head->next; head->next = idesc; } update_masks(idesc->maskptr, irq); return (0); } /* * Add the interrupt handler descriptor data structure created by an * earlier call of create_intr() to the linked list for its irq and * adjust the interrupt masks if necessary. * * This function effectively activates the handler. */ int intr_connect(intrec *idesc) { int errcode = -1; int irq; #ifdef RESOURCE_CHECK int resflag; #endif /* RESOURCE_CHECK */ if (idesc == NULL) return (-1); irq = idesc->intr; #ifdef RESOURCE_CHECK resflag = (idesc->flags & INTR_EXCL) ? RESF_NONE : RESF_SHARED; if (resource_claim(idesc->devdata, REST_INT, resflag, irq, irq) == 0) #endif /* RESOURCE_CHECK */ { /* block this irq */ intrmask_t oldspl = splq(1 << irq); /* add irq to class selected by maskptr */ errcode = add_intrdesc(idesc); splx(oldspl); } if (errcode != 0 && bootverbose) printf("\tintr_connect(irq%d) failed, result=%d\n", irq, errcode); return (errcode); } /* * Remove the interrupt handler descriptor data connected created by an * earlier call of intr_connect() from the linked list and adjust the * interrupt masks if necessary. * * This function deactivates the handler. */ int intr_disconnect(intrec *idesc) { intrec **hook, *head; int irq; int errcode = 0; if (idesc == NULL) return (-1); irq = idesc->intr; /* find pointer that keeps the reference to this interrupt descriptor */ hook = find_pred(idesc, irq); if (hook == NULL) return (-1); /* make copy of original list head, the line after may overwrite it */ head = intreclist_head[irq]; /* unlink: make predecessor point to idesc->next instead of to idesc */ *hook = idesc->next; /* now check whether the element we removed was the list head */ if (idesc == head) { intrmask_t oldspl = splq(1 << irq); /* we want to remove the list head, which was known to intr_mux */ icu_unset(irq, (inthand2_t*)intr_mux); /* check whether the new list head is the only element on list */ head = intreclist_head[irq]; if (head != NULL) { if (head->next != NULL) { /* install the multiplex handler with new list head as argument */ errcode = icu_setup(irq, (inthand2_t*)intr_mux, head, 0, 0); if (errcode == 0) update_intrname(irq, -1); } else { /* install the one remaining handler for this irq */ errcode = icu_setup(irq, head->handler, head->argument, head->maskptr, head->flags); if (errcode == 0) update_intrname(irq, (intptr_t)head->devdata); } } splx(oldspl); } update_masks(idesc->maskptr, irq); #ifdef RESOURCE_CHECK resource_free(idesc->devdata); #endif /* RESOURCE_CHECK */ return (0); } /* * Create an interrupt handler descriptor data structure, which later can * be activated or deactivated at will by calls of [dis]connect(intrec*). * * The dev_instance pointer is required for resource management, and will * only be passed through to resource_claim(). * * The interrupt handler takes an argument of type (void*), which is not * what is currently used for ISA devices. But since the unit number passed * to an ISA interrupt handler can be stored in a (void*) variable, this * causes no problems. Eventually all the ISA interrupt handlers should be * modified to accept the pointer to their private data, too, instead of * an integer index. * * There will be functions that derive a driver and unit name from a * dev_instance variable, and those functions will be used to maintain the * interrupt counter label array referenced by systat and vmstat to report * device interrupt rates (->update_intrlabels). */ intrec * intr_create(void *dev_instance, int irq, inthand2_t handler, void *arg, intrmask_t *maskptr, int flags) { intrec *idesc; if (ICU_LEN > 8 * sizeof *maskptr) { printf("create_intr: ICU_LEN of %d too high for %d bit intrmask\n", ICU_LEN, 8 * sizeof *maskptr); return (NULL); } if ((unsigned)irq >= ICU_LEN) { printf("create_intr: requested irq%d too high, limit is %d\n", irq, ICU_LEN -1); return (NULL); } idesc = malloc(sizeof *idesc, M_DEVBUF, M_WAITOK); if (idesc) { idesc->next = NULL; bzero(idesc, sizeof *idesc); idesc->devdata = dev_instance; idesc->handler = handler; idesc->argument = arg; idesc->maskptr = maskptr; idesc->intr = irq; idesc->flags = flags; } return (idesc); } /* * Return the memory held by the interrupt handler descriptor data structure * to the system. Make sure, the handler is not actively used anymore, before. */ int intr_destroy(intrec *rec) { if (intr_disconnect(rec) != 0) return (-1); free(rec, M_DEVBUF); return (0); } /* * Emulate the register_intr() call previously defined as low level function. * That function (now icu_setup()) may no longer be directly called, since * a conflict between an ISA and PCI interrupt might go by unnocticed, else. */ int register_intr(int intr, int device_id, u_int flags, inthand2_t handler, u_int *maskptr, int unit) { /* XXX modify to include isa_device instead of device_id */ intrec *idesc; flags |= INTR_EXCL; idesc = intr_create((void *)(intptr_t)device_id, intr, handler, (void*)(intptr_t)unit, maskptr, flags); return (intr_connect(idesc)); } /* * Emulate the old unregister_intr() low level function. * Make sure there is just one interrupt, that it was * registered as non-shared, and that the handlers match. */ int unregister_intr(int intr, inthand2_t handler) { intrec *p = intreclist_head[intr]; if (p != NULL && (p->flags & INTR_EXCL) != 0 && p->handler == handler) return (intr_destroy(p)); return (EINVAL); +} + +void +register_swi(intr, handler) + int intr; + swihand_t *handler; +{ + struct swilist *slp, *slq; + int s; + + if (intr < NHWI || intr >= NHWI + NSWI) + panic("register_swi: bad intr %d", intr); + if (handler == swi_generic || handler == swi_null) + panic("register_swi: bad handler %p", (void *)handler); + slp = &swilists[intr - NHWI]; + s = splhigh(); + if (ihandlers[intr] == swi_null) + ihandlers[intr] = handler; + else { + if (slp->sl_next == NULL) { + slp->sl_handler = ihandlers[intr]; + ihandlers[intr] = swi_generic; + } + slq = malloc(sizeof(*slq), M_DEVBUF, M_NOWAIT); + if (slq == NULL) + panic("register_swi: malloc failed"); + slq->sl_handler = handler; + slq->sl_next = NULL; + while (slp->sl_next != NULL) + slp = slp->sl_next; + slp->sl_next = slq; + } + splx(s); +} + +void +swi_dispatcher(intr) + int intr; +{ + struct swilist *slp; + + slp = &swilists[intr - NHWI]; + do { + (*slp->sl_handler)(); + slp = slp->sl_next; + } while (slp != NULL); +} + +void +unregister_swi(intr, handler) + int intr; + swihand_t *handler; +{ + struct swilist *slfoundpred, *slp, *slq; + int s; + + if (intr < NHWI || intr >= NHWI + NSWI) + panic("unregister_swi: bad intr %d", intr); + if (handler == swi_generic || handler == swi_null) + panic("unregister_swi: bad handler %p", (void *)handler); + slp = &swilists[intr - NHWI]; + s = splhigh(); + if (ihandlers[intr] == handler) + ihandlers[intr] = swi_null; + else if (slp->sl_next != NULL) { + slfoundpred = NULL; + for (slq = slp->sl_next; slq != NULL; + slp = slq, slq = slp->sl_next) + if (slq->sl_handler == handler) + slfoundpred = slp; + slp = &swilists[intr - NHWI]; + if (slfoundpred != NULL) { + slq = slfoundpred->sl_next; + slfoundpred->sl_next = slq->sl_next; + free(slq, M_DEVBUF); + } else if (slp->sl_handler == handler) { + slq = slp->sl_next; + slp->sl_next = slq->sl_next; + slp->sl_handler = slq->sl_handler; + free(slq, M_DEVBUF); + } + if (slp->sl_next == NULL) + ihandlers[intr] = slp->sl_handler; + } + splx(s); } #endif /* __i386__ */ Index: head/sys/sys/interrupt.h =================================================================== --- head/sys/sys/interrupt.h (revision 38243) +++ head/sys/sys/interrupt.h (revision 38244) @@ -1,44 +1,57 @@ /* * Copyright (c) 1997, Stefan Esser * All rights reserved. * * 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 unmodified, 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 AUTHOR ``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 AUTHOR 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. * - * $Id: interrupt.h,v 1.5 1997/06/08 17:15:31 ache Exp $ + * $Id: interrupt.h,v 1.6 1997/07/09 18:08:15 ache Exp $ */ /* XXX currently dev_instance must be set to the ISA device_id or -1 for PCI */ #define INTR_FAST 0x00000001 /* fast interrupt handler */ #define INTR_EXCL 0x00010000 /* excl. intr, default is shared */ +typedef void swihand_t __P((void)); + struct intrec *intr_create(void *dev_instance, int irq, inthand2_t handler, void *arg, intrmask_t *maskptr, int flags); int intr_destroy(struct intrec *idesc); int intr_connect(struct intrec *idesc); int intr_disconnect(struct intrec *idesc); +void register_swi __P((int intr, swihand_t *handler)); +void swi_dispatcher __P((int intr)); +swihand_t swi_generic; +swihand_t swi_null; +void unregister_swi __P((int intr, swihand_t *handler)); + /* XXX emulate old interface for now ... */ int register_intr __P((int intr, int device_id, u_int flags, inthand2_t *handler, u_int *maskptr, int unit)); int unregister_intr(int intr, inthand2_t handler); + +#ifdef NHWI +/* XXX type change in middle; MI code uses only the top NSWI entries. */ +extern swihand_t *ihandlers[NHWI + NSWI]; +#endif