/*- * 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. * * from: @(#)icu.s 7.2 (Berkeley) 5/21/91 * $Id: icu.s,v 1.19 1993/07/11 14:12:40 mycroft Exp $ */ /* * AT/386 * Vector interrupt control section */ /* * XXX - this file is now misnamed. All spls are now soft and the only thing * related to the hardware icu is that the bit numbering is the same in the * soft priority masks as in the hard ones. */ #ifdef notyet #include "sio.h" #else #define NSIO 0 #endif #define HIGHMASK 0xffff #define SOFTCLOCKMASK 0x8000 .data .globl _cpl _cpl: .long 0xffff # current priority (all off) .globl _imen _imen: .long 0xffff # interrupt mask enable (all off) .globl _highmask _highmask: .long HIGHMASK .globl _ttymask _ttymask: .long 0 .globl _biomask _biomask: .long 0 .globl _netmask _netmask: .long 0 .globl _impmask _impmask: .long 0 .globl _ipending _ipending: .long 0 vec: .long INTRLOCAL(vec0), INTRLOCAL(vec1), INTRLOCAL(vec2) .long INTRLOCAL(vec3), INTRLOCAL(vec4), INTRLOCAL(vec5) .long INTRLOCAL(vec6), INTRLOCAL(vec7), INTRLOCAL(vec8) .long INTRLOCAL(vec9), INTRLOCAL(vec10), INTRLOCAL(vec11) .long INTRLOCAL(vec12), INTRLOCAL(vec13), INTRLOCAL(vec14) .long INTRLOCAL(vec15) #define GENSPL(name, mask, event) \ .globl _spl/**/name ; \ ALIGN_TEXT ; \ _spl/**/name: ; \ COUNT_EVENT(_intrcnt_spl, event) ; \ movl _cpl,%eax ; \ movl %eax,%edx ; \ orl mask,%edx ; \ movl %edx,_cpl ; \ SHOW_CPL ; \ ret #define FASTSPL(mask) \ movl mask,_cpl ; \ SHOW_CPL #define FASTSPL_VARMASK(varmask) \ movl varmask,%eax ; \ movl %eax,_cpl ; \ SHOW_CPL .text ALIGN_TEXT INTRLOCAL(unpend_v): COUNT_EVENT(_intrcnt_spl, 0) bsfl %eax,%eax # slow, but not worth optimizing btrl %eax,_ipending jnc INTRLOCAL(unpend_v_next) # some intr cleared the in-memory bit SHOW_IPENDING movl Vresume(,%eax,4),%eax testl %eax,%eax je INTRLOCAL(noresume) jmp %eax ALIGN_TEXT /* * XXX - must be some fastintr, need to register those too. */ INTRLOCAL(noresume): #if NSIO > 0 call _softsio1 #endif INTRLOCAL(unpend_v_next): movl _cpl,%eax movl %eax,%edx notl %eax andl _ipending,%eax je INTRLOCAL(none_to_unpend) jmp INTRLOCAL(unpend_v) /* * Handle return from interrupt after device handler finishes */ ALIGN_TEXT doreti: COUNT_EVENT(_intrcnt_spl, 1) addl $4,%esp # discard unit arg popl %eax # get previous priority /* * Now interrupt frame is a trap frame! * * XXX - setting up the interrupt frame to be almost a stack frame is mostly * a waste of time. */ movl %eax,_cpl SHOW_CPL movl %eax,%edx notl %eax andl _ipending,%eax jne INTRLOCAL(unpend_v) INTRLOCAL(none_to_unpend): testl %edx,%edx # returning to zero priority? jne 1f # nope, going to non-zero priority movl _netisr,%eax testl %eax,%eax # check for softint s/traps jne 2f # there are some jmp test_resched # XXX - schedule jumps better COUNT_EVENT(_intrcnt_spl, 2) # XXX ALIGN_TEXT # XXX 1: # XXX COUNT_EVENT(_intrcnt_spl, 3) popl %es popl %ds popal addl $8,%esp iret #include "../net/netisr.h" #define DONET(s, c, event) ; \ .globl c ; \ btrl $s,_netisr ; \ jnc 1f ; \ COUNT_EVENT(_intrcnt_spl, event) ; \ call c ; \ 1: ALIGN_TEXT 2: COUNT_EVENT(_intrcnt_spl, 4) /* * XXX - might need extra locking while testing reg copy of netisr, but * interrupt routines setting it would not cause any new problems (since we * don't loop, fresh bits will not be processed until the next doreti or spl0) */ testl $~((1 << NETISR_SCLK) | (1 << NETISR_AST)),%eax je test_ASTs # no net stuff, just temporary AST's FASTSPL_VARMASK(_netmask) DONET(NETISR_RAW, _rawintr, 5) #ifdef INET DONET(NETISR_IP, _ipintr, 6) #endif #ifdef IMP DONET(NETISR_IMP, _impintr, 7) #endif #ifdef NS DONET(NETISR_NS, _nsintr, 8) #endif #ifdef ISO DONET(NETISR_ISO, _clnlintr, 25) #endif FASTSPL($0) test_ASTs: btrl $NETISR_SCLK,_netisr jnc test_resched COUNT_EVENT(_intrcnt_spl, 9) FASTSPL($SOFTCLOCKMASK) /* * Back to an interrupt frame for a moment. */ pushl $0 # previous cpl (probably not used) pushl $0x7f # dummy unit number call _softclock addl $8,%esp # discard dummies FASTSPL($0) test_resched: #ifdef notused1 btrl $NETISR_AST,_netisr jnc 2f #endif #ifdef notused2 cmpl $0,_want_resched je 2f #endif cmpl $0,_astpending # XXX - put it back in netisr to je 2f # reduce the number of tests testb $SEL_RPL_MASK,TRAPF_CS_OFF(%esp) # to non-kernel (i.e., user)? je 2f # nope, leave COUNT_EVENT(_intrcnt_spl, 10) movl $0,_astpending call _trap 2: COUNT_EVENT(_intrcnt_spl, 11) popl %es popl %ds popal addl $8,%esp iret /* * 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 */ GENSPL(bio, _biomask, 12) GENSPL(clock, $HIGHMASK, 13) /* splclock == splhigh ex for count */ GENSPL(high, $HIGHMASK, 14) GENSPL(imp, _impmask, 15) GENSPL(net, _netmask, 16) GENSPL(softclock, $SOFTCLOCKMASK, 17) GENSPL(tty, _ttymask, 18) .globl _splnone .globl _spl0 ALIGN_TEXT _splnone: _spl0: COUNT_EVENT(_intrcnt_spl, 19) in_spl0: movl _cpl,%eax pushl %eax # save old priority testl $~((1 << NETISR_SCLK) | (1 << NETISR_AST)),_netisr jz INTRLOCAL(over_net_stuff_for_spl0) movl _netmask,%eax # mask off those network devices movl %eax,_cpl # set new priority SHOW_CPL DONET(NETISR_RAW, _rawintr, 20) #ifdef INET DONET(NETISR_IP, _ipintr, 21) #endif #ifdef IMP DONET(NETISR_IMP, _impintr, 26) #endif #ifdef NS DONET(NETISR_NS, _nsintr, 27) #endif #ifdef ISO DONET(NETISR_ISO, _clnlintr, 28) #endif INTRLOCAL(over_net_stuff_for_spl0): movl $0,_cpl # set new priority SHOW_CPL movl _ipending,%eax testl %eax,%eax jne INTRLOCAL(unpend_V) popl %eax # return old priority ret .globl _splx ALIGN_TEXT _splx: COUNT_EVENT(_intrcnt_spl, 22) movl 4(%esp),%eax # new priority testl %eax,%eax je in_spl0 # going to "zero level" is special COUNT_EVENT(_intrcnt_spl, 23) movl _cpl,%edx # save old priority movl %eax,_cpl # set new priority SHOW_CPL notl %eax andl _ipending,%eax jne INTRLOCAL(unpend_V_result_edx) movl %edx,%eax # return old priority ret ALIGN_TEXT INTRLOCAL(unpend_V_result_edx): pushl %edx INTRLOCAL(unpend_V): COUNT_EVENT(_intrcnt_spl, 24) bsfl %eax,%eax btrl %eax,_ipending jnc INTRLOCAL(unpend_V_next) SHOW_IPENDING movl Vresume(,%eax,4),%edx testl %edx,%edx je INTRLOCAL(noresumeV) /* * 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(,%eax,4) ALIGN_TEXT /* * XXX - must be some fastintr, need to register those too. */ INTRLOCAL(noresumeV): #if NSIO > 0 call _softsio1 #endif INTRLOCAL(unpend_V_next): movl _cpl,%eax notl %eax andl _ipending,%eax jne INTRLOCAL(unpend_V) popl %eax ret #define BUILD_VEC(irq_num) \ ALIGN_TEXT ; \ INTRLOCAL(vec/**/irq_num): ; \ int $ICU_OFFSET + (irq_num) ; \ popl %eax ; \ ret 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)