1/* $OpenBSD: vector.s,v 1.16 2003/04/17 03:42:14 drahn Exp $ */ 2/* $NetBSD: vector.s,v 1.32 1996/01/07 21:29:47 mycroft Exp $ */ 3 4/* 5 * Copyright (c) 1993, 1994, 1995 Charles M. Hannum. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by Charles M. Hannum. 18 * 4. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33#include <i386/isa/icu.h> 34#include <dev/isa/isareg.h> 35 36#define ICU_HARDWARE_MASK 37 38#define MY_COUNT _C_LABEL(uvmexp) 39 40/* 41 * These macros are fairly self explanatory. If ICU_SPECIAL_MASK_MODE is 42 * defined, we try to take advantage of the ICU's `special mask mode' by only 43 * EOIing the interrupts on return. This avoids the requirement of masking and 44 * unmasking. We can't do this without special mask mode, because the ICU 45 * would also hold interrupts that it thinks are of lower priority. 46 * 47 * Many machines do not support special mask mode, so by default we don't try 48 * to use it. 49 */ 50 51#define IRQ_BIT(irq_num) (1 << ((irq_num) % 8)) 52#define IRQ_BYTE(irq_num) ((irq_num) / 8) 53 54#ifdef ICU_SPECIAL_MASK_MODE 55 56#define ACK1(irq_num) 57#define ACK2(irq_num) \ 58 movb $(0x60|IRQ_SLAVE),%al /* specific EOI for IRQ2 */ ;\ 59 outb %al,$IO_ICU1 60#define MASK(irq_num, icu) 61#define UNMASK(irq_num, icu) \ 62 movb $(0x60|(irq_num%8)),%al /* specific EOI */ ;\ 63 outb %al,$icu 64 65#else /* ICU_SPECIAL_MASK_MODE */ 66 67#ifndef AUTO_EOI_1 68#define ACK1(irq_num) \ 69 movb $(0x60|(irq_num%8)),%al /* specific EOI */ ;\ 70 outb %al,$IO_ICU1 71#else 72#define ACK1(irq_num) 73#endif 74 75#ifndef AUTO_EOI_2 76#define ACK2(irq_num) \ 77 movb $(0x60|(irq_num%8)),%al /* specific EOI */ ;\ 78 outb %al,$IO_ICU2 /* do the second ICU first */ ;\ 79 movb $(0x60|IRQ_SLAVE),%al /* specific EOI for IRQ2 */ ;\ 80 outb %al,$IO_ICU1 81#else 82#define ACK2(irq_num) 83#endif 84 85#ifdef ICU_HARDWARE_MASK 86 87#define MASK(irq_num, icu) \ 88 movb _C_LABEL(imen) + IRQ_BYTE(irq_num),%al ;\ 89 orb $IRQ_BIT(irq_num),%al ;\ 90 movb %al,_C_LABEL(imen) + IRQ_BYTE(irq_num) ;\ 91 FASTER_NOP ;\ 92 outb %al,$(icu+1) 93#define UNMASK(irq_num, icu) \ 94 cli ;\ 95 movb _C_LABEL(imen) + IRQ_BYTE(irq_num),%al ;\ 96 andb $~IRQ_BIT(irq_num),%al ;\ 97 movb %al,_C_LABEL(imen) + IRQ_BYTE(irq_num) ;\ 98 FASTER_NOP ;\ 99 outb %al,$(icu+1) ;\ 100 sti 101 102#else /* ICU_HARDWARE_MASK */ 103 104#define MASK(irq_num, icu) 105#define UNMASK(irq_num, icu) 106 107#endif /* ICU_HARDWARE_MASK */ 108 109#endif /* ICU_SPECIAL_MASK_MODE */ 110 111/* 112 * Macros for interrupt entry, call to handler, and exit. 113 * 114 * XXX 115 * The interrupt frame is set up to look like a trap frame. This may be a 116 * waste. The only handler which needs a frame is the clock handler, and it 117 * only needs a few bits. Xdoreti() needs a trap frame for handling ASTs, but 118 * it could easily convert the frame on demand. 119 * 120 * The direct costs of setting up a trap frame are two pushl's (error code and 121 * trap number), an addl to get rid of these, and pushing and popping the 122 * callee-saved registers %esi, %edi, %ebx, and %ebp twice. 123 * 124 * If the interrupt frame is made more flexible, INTR can push %eax first and 125 * decide the ipending case with less overhead, e.g., by avoiding loading the 126 * segment registers. 127 * 128 * XXX 129 * Should we do a cld on every system entry to avoid the requirement for 130 * scattered cld's? 131 */ 132 133 .globl _C_LABEL(isa_strayintr) 134 135/* 136 * Normal vectors. 137 * 138 * We cdr down the intrhand chain, calling each handler with its appropriate 139 * argument (0 meaning a pointer to the frame, for clock interrupts). 140 * 141 * The handler returns one of three values: 142 * 0 - This interrupt wasn't for me. 143 * 1 - This interrupt was for me. 144 * -1 - This interrupt might have been for me, but I don't know. 145 * If there are no handlers, or they all return 0, we flags it as a `stray' 146 * interrupt. On a system with level-triggered interrupts, we could terminate 147 * immediately when one of them returns 1; but this is a PC. 148 * 149 * On exit, we jump to Xdoreti(), to process soft interrupts and ASTs. 150 */ 151#define INTR(irq_num, icu, ack) \ 152IDTVEC(recurse/**/irq_num) ;\ 153 pushfl ;\ 154 pushl %cs ;\ 155 pushl %esi ;\ 156 cli ;\ 157_C_LABEL(Xintr)/**/irq_num/**/: ;\ 158 pushl $0 /* dummy error code */ ;\ 159 pushl $T_ASTFLT /* trap # for doing ASTs */ ;\ 160 INTRENTRY ;\ 161 MAKE_FRAME ;\ 162 MASK(irq_num, icu) /* mask it in hardware */ ;\ 163 ack(irq_num) /* and allow other intrs */ ;\ 164 incl MY_COUNT+V_INTR /* statistical info */ ;\ 165 movl _C_LABEL(iminlevel) + (irq_num) * 4, %eax ;\ 166 movzbl _C_LABEL(cpl),%ebx ;\ 167 cmpl %eax,%ebx ;\ 168 jae _C_LABEL(Xhold/**/irq_num)/* currently masked; hold it */;\ 169_C_LABEL(Xresume)/**/irq_num/**/: ;\ 170 movzbl _C_LABEL(cpl),%eax /* cpl to restore on exit */ ;\ 171 pushl %eax ;\ 172 movl _C_LABEL(imaxlevel) + (irq_num) * 4,%eax ;\ 173 movl %eax,_C_LABEL(cpl) /* block enough for this irq */ ;\ 174 sti /* safe to take intrs now */ ;\ 175 movl _C_LABEL(intrhand) + (irq_num) * 4,%ebx /* head of chain */ ;\ 176 testl %ebx,%ebx ;\ 177 jz _C_LABEL(Xstray)/**/irq_num /* no handlears; we're stray */ ;\ 178 STRAY_INITIALIZE /* nobody claimed it yet */ ;\ 1797: movl IH_ARG(%ebx),%eax /* get handler arg */ ;\ 180 testl %eax,%eax ;\ 181 jnz 4f ;\ 182 movl %esp,%eax /* 0 means frame pointer */ ;\ 1834: pushl %eax ;\ 184 call *IH_FUN(%ebx) /* call it */ ;\ 185 addl $4,%esp /* toss the arg */ ;\ 186 STRAY_INTEGRATE /* maybe he claimed it */ ;\ 187 orl %eax,%eax /* should it be counted? */ ;\ 188 jz 5f /* no, skip it */ ;\ 189 incl IH_COUNT(%ebx) /* count the intrs */ ;\ 1905: movl IH_NEXT(%ebx),%ebx /* next handler in chain */ ;\ 191 testl %ebx,%ebx ;\ 192 jnz 7b ;\ 193 STRAY_TEST /* see if it's a stray */ ;\ 1946: UNMASK(irq_num, icu) /* unmask it in hardware */ ;\ 195 jmp _C_LABEL(Xdoreti) /* lower spl and do ASTs */ ;\ 196IDTVEC(stray/**/irq_num) ;\ 197 pushl $irq_num ;\ 198 call _C_LABEL(isa_strayintr) ;\ 199 addl $4,%esp ;\ 200 jmp 6b ;\ 201IDTVEC(hold/**/irq_num) ;\ 202 orb $IRQ_BIT(irq_num),_C_LABEL(ipending) + IRQ_BYTE(irq_num) ;\ 203 INTRFASTEXIT 204 205#if defined(DEBUG) && defined(notdef) 206#define STRAY_INITIALIZE \ 207 xorl %esi,%esi 208#define STRAY_INTEGRATE \ 209 orl %eax,%esi 210#define STRAY_TEST \ 211 testl %esi,%esi ;\ 212 jz _C_LABEL(Xstray)/**/irq_num 213#else /* !DEBUG */ 214#define STRAY_INITIALIZE 215#define STRAY_INTEGRATE 216#define STRAY_TEST 217#endif /* DEBUG */ 218 219#ifdef DDB 220#define MAKE_FRAME \ 221 leal -8(%esp),%ebp 222#else /* !DDB */ 223#define MAKE_FRAME 224#endif /* DDB */ 225 226INTR(0, IO_ICU1, ACK1) 227INTR(1, IO_ICU1, ACK1) 228INTR(2, IO_ICU1, ACK1) 229INTR(3, IO_ICU1, ACK1) 230INTR(4, IO_ICU1, ACK1) 231INTR(5, IO_ICU1, ACK1) 232INTR(6, IO_ICU1, ACK1) 233INTR(7, IO_ICU1, ACK1) 234INTR(8, IO_ICU2, ACK2) 235INTR(9, IO_ICU2, ACK2) 236INTR(10, IO_ICU2, ACK2) 237INTR(11, IO_ICU2, ACK2) 238INTR(12, IO_ICU2, ACK2) 239INTR(13, IO_ICU2, ACK2) 240INTR(14, IO_ICU2, ACK2) 241INTR(15, IO_ICU2, ACK2) 242 243/* 244 * These tables are used by the ISA configuration code. 245 */ 246/* interrupt service routine entry points */ 247IDTVEC(intr) 248 .long _C_LABEL(Xintr0), _C_LABEL(Xintr1), _C_LABEL(Xintr2) 249 .long _C_LABEL(Xintr3), _C_LABEL(Xintr4), _C_LABEL(Xintr5) 250 .long _C_LABEL(Xintr6), _C_LABEL(Xintr7), _C_LABEL(Xintr8) 251 .long _C_LABEL(Xintr9), _C_LABEL(Xintr10), _C_LABEL(Xintr11) 252 .long _C_LABEL(Xintr12), _C_LABEL(Xintr13) 253 .long _C_LABEL(Xintr14), _C_LABEL(Xintr15) 254 255/* 256 * These tables are used by Xdoreti() and Xspllower(). 257 */ 258/* resume points for suspended interrupts */ 259IDTVEC(resume) 260 .long _C_LABEL(Xresume0), _C_LABEL(Xresume1) 261 .long _C_LABEL(Xresume2), _C_LABEL(Xresume3) 262 .long _C_LABEL(Xresume4), _C_LABEL(Xresume5) 263 .long _C_LABEL(Xresume6), _C_LABEL(Xresume7) 264 .long _C_LABEL(Xresume8), _C_LABEL(Xresume9) 265 .long _C_LABEL(Xresume10), _C_LABEL(Xresume11) 266 .long _C_LABEL(Xresume12), _C_LABEL(Xresume13) 267 .long _C_LABEL(Xresume14), _C_LABEL(Xresume15) 268 /* for soft interrupts */ 269 .long 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 270 .long _C_LABEL(Xsofttty), _C_LABEL(Xsoftnet) 271 .long _C_LABEL(Xsoftclock) 272/* fake interrupts to resume from splx() */ 273IDTVEC(recurse) 274 .long _C_LABEL(Xrecurse0), _C_LABEL(Xrecurse1) 275 .long _C_LABEL(Xrecurse2), _C_LABEL(Xrecurse3) 276 .long _C_LABEL(Xrecurse4), _C_LABEL(Xrecurse5) 277 .long _C_LABEL(Xrecurse6), _C_LABEL(Xrecurse7) 278 .long _C_LABEL(Xrecurse8), _C_LABEL(Xrecurse9) 279 .long _C_LABEL(Xrecurse10), _C_LABEL(Xrecurse11) 280 .long _C_LABEL(Xrecurse12), _C_LABEL(Xrecurse13) 281 .long _C_LABEL(Xrecurse14), _C_LABEL(Xrecurse15) 282 /* for soft interrupts */ 283 .long 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 284 .long _C_LABEL(Xsofttty), _C_LABEL(Xsoftnet) 285 .long _C_LABEL(Xsoftclock) 286 287/* Some bogus data, to keep vmstat happy, for now. */ 288 .globl _C_LABEL(intrnames), _C_LABEL(eintrnames) 289 .globl _C_LABEL(intrcnt), _C_LABEL(eintrcnt) 290_C_LABEL(intrnames): 291 .long 0 292_C_LABEL(eintrnames): 293_C_LABEL(intrcnt): 294 .long 0 295_C_LABEL(eintrcnt): 296