1 /*
2 * from: vector.s, 386BSD 0.1 unknown origin
3 * $FreeBSD: releng/5.0/sys/i386/isa/icu_vector.s 93945 2002-04-06 08:25:05Z nyan $
4 */
5
6 #define IRQ_BIT(irq_num) (1 << ((irq_num) % 8))
7 #define IRQ_LBIT(irq_num) (1 << (irq_num))
8 #define IRQ_BYTE(irq_num) ((irq_num) >> 3)
9
10 #ifdef AUTO_EOI_1
11
12 #define ENABLE_ICU1 /* use auto-EOI to reduce i/o */
13 #define OUTB_ICU1
14
15 #else
16
17 #define ENABLE_ICU1 \
18 movb $ICU_EOI,%al ; /* as soon as possible send EOI ... */ \
19 OUTB_ICU1 /* ... to clear in service bit */
20
21 #define OUTB_ICU1 \
22 outb %al,$IO_ICU1
23
24 #endif
25
26 #ifdef AUTO_EOI_2
27 /*
28 * The data sheet says no auto-EOI on slave, but it sometimes works.
29 */
30 #define ENABLE_ICU1_AND_2 ENABLE_ICU1
31
32 #else
33
34 #define ENABLE_ICU1_AND_2 \
35 movb $ICU_EOI,%al ; /* as above */ \
36 outb %al,$IO_ICU2 ; /* but do second icu first ... */ \
37 OUTB_ICU1 /* ... then first icu (if !AUTO_EOI_1) */
38
39 #endif
40
41 #define PUSH_FRAME \
42 pushl $0 ; /* dummy error code */ \
43 pushl $0 ; /* dummy trap type */ \
44 pushal ; /* 8 ints */ \
45 pushl %ds ; /* save data and extra segments ... */ \
46 pushl %es ; \
47 pushl %fs
48
49 #define PUSH_DUMMY \
50 pushfl ; /* eflags */ \
51 pushl %cs ; /* cs */ \
52 pushl 12(%esp) ; /* original caller eip */ \
53 pushl $0 ; /* dummy error code */ \
54 pushl $0 ; /* dummy trap type */ \
55 subl $11*4,%esp
56
57 #define POP_FRAME \
58 popl %fs ; \
59 popl %es ; \
60 popl %ds ; \
61 popal ; \
62 addl $4+4,%esp
63
64 #define POP_DUMMY \
65 addl $16*4,%esp
66
67 #define MASK_IRQ(icu, irq_num) \
68 movb imen + IRQ_BYTE(irq_num),%al ; \
69 orb $IRQ_BIT(irq_num),%al ; \
70 movb %al,imen + IRQ_BYTE(irq_num) ; \
71 outb %al,$icu+ICU_IMR_OFFSET
72
73 #define UNMASK_IRQ(icu, irq_num) \
74 movb imen + IRQ_BYTE(irq_num),%al ; \
75 andb $~IRQ_BIT(irq_num),%al ; \
76 movb %al,imen + IRQ_BYTE(irq_num) ; \
77 outb %al,$icu+ICU_IMR_OFFSET
78 /*
79 * Macros for interrupt interrupt entry, call to handler, and exit.
80 */
81
82 #define FAST_INTR(irq_num, vec_name, icu, enable_icus) \
83 .text ; \
84 SUPERALIGN_TEXT ; \
85 IDTVEC(vec_name) ; \
86 PUSH_FRAME ; \
87 mov $KDSEL,%ax ; \
88 mov %ax,%ds ; \
89 mov %ax,%es ; \
90 mov $KPSEL,%ax ; \
91 mov %ax,%fs ; \
92 FAKE_MCOUNT((12+ACTUALLY_PUSHED)*4(%esp)) ; \
93 movl PCPU(CURTHREAD),%ebx ; \
94 cmpl $0,TD_CRITNEST(%ebx) ; \
95 je 1f ; \
96 ; \
97 movl $1,PCPU(INT_PENDING) ; \
98 orl $IRQ_LBIT(irq_num),PCPU(FPENDING) ; \
99 MASK_IRQ(icu, irq_num) ; \
100 enable_icus ; \
101 jmp 10f ; \
102 1: ; \
103 incl TD_CRITNEST(%ebx) ; \
104 incl TD_INTR_NESTING_LEVEL(%ebx) ; \
105 pushl intr_unit + (irq_num) * 4 ; \
106 call *intr_handler + (irq_num) * 4 ; \
107 addl $4,%esp ; \
108 enable_icus ; \
109 incl cnt+V_INTR ; /* book-keeping can wait */ \
110 movl intr_countp + (irq_num) * 4,%eax ; \
111 incl (%eax) ; \
112 decl TD_CRITNEST(%ebx) ; \
113 cmpl $0,PCPU(INT_PENDING) ; \
114 je 2f ; \
115 ; \
116 call i386_unpend ; \
117 2: ; \
118 decl TD_INTR_NESTING_LEVEL(%ebx) ; \
119 10: ; \
120 MEXITCOUNT ; \
121 jmp doreti
122
123 /*
124 * Restart a fast interrupt that was held up by a critical section.
125 * This routine is called from unpend(). unpend() ensures we are
126 * in a critical section and deals with the interrupt nesting level
127 * for us. If we previously masked the irq, we have to unmask it.
128 *
129 * We have a choice. We can regenerate the irq using the 'int'
130 * instruction or we can create a dummy frame and call the interrupt
131 * handler directly. I've chosen to use the dummy-frame method.
132 */
133 #define FAST_UNPEND(irq_num, vec_name, icu) \
134 .text ; \
135 SUPERALIGN_TEXT ; \
136 IDTVEC(vec_name) ; \
137 ; \
138 pushl %ebp ; \
139 movl %esp, %ebp ; \
140 PUSH_DUMMY ; \
141 pushl intr_unit + (irq_num) * 4 ; \
142 call *intr_handler + (irq_num) * 4 ; /* do the work ASAP */ \
143 addl $4, %esp ; \
144 incl cnt+V_INTR ; /* book-keeping can wait */ \
145 movl intr_countp + (irq_num) * 4,%eax ; \
146 incl (%eax) ; \
147 UNMASK_IRQ(icu, irq_num) ; \
148 POP_DUMMY ; \
149 popl %ebp ; \
150 ret
151
152 /*
153 * Slow, threaded interrupts.
154 *
155 * XXX Most of the parameters here are obsolete. Fix this when we're
156 * done.
157 * XXX we really shouldn't return via doreti if we just schedule the
158 * interrupt handler and don't run anything. We could just do an
159 * iret. FIXME.
160 */
161 #define INTR(irq_num, vec_name, icu, enable_icus, maybe_extra_ipending) \
162 .text ; \
163 SUPERALIGN_TEXT ; \
164 IDTVEC(vec_name) ; \
165 PUSH_FRAME ; \
166 mov $KDSEL,%ax ; /* load kernel ds, es and fs */ \
167 mov %ax,%ds ; \
168 mov %ax,%es ; \
169 mov $KPSEL,%ax ; \
170 mov %ax,%fs ; \
171 ; \
172 maybe_extra_ipending ; \
173 MASK_IRQ(icu, irq_num) ; \
174 enable_icus ; \
175 ; \
176 movl PCPU(CURTHREAD),%ebx ; \
177 cmpl $0,TD_CRITNEST(%ebx) ; \
178 je 1f ; \
179 movl $1,PCPU(INT_PENDING); \
180 orl $IRQ_LBIT(irq_num),PCPU(IPENDING) ; \
181 jmp 10f ; \
182 1: ; \
183 incl TD_INTR_NESTING_LEVEL(%ebx) ; \
184 ; \
185 FAKE_MCOUNT(13*4(%esp)) ; /* XXX late to avoid double count */ \
186 cmpl $0,PCPU(INT_PENDING) ; \
187 je 9f ; \
188 call i386_unpend ; \
189 9: ; \
190 pushl $irq_num; /* pass the IRQ */ \
191 call sched_ithd ; \
192 addl $4, %esp ; /* discard the parameter */ \
193 ; \
194 decl TD_INTR_NESTING_LEVEL(%ebx) ; \
195 10: ; \
196 MEXITCOUNT ; \
197 jmp doreti
198
199 MCOUNT_LABEL(bintr)
200 FAST_INTR(0,fastintr0, IO_ICU1, ENABLE_ICU1)
201 FAST_INTR(1,fastintr1, IO_ICU1, ENABLE_ICU1)
202 FAST_INTR(2,fastintr2, IO_ICU1, ENABLE_ICU1)
203 FAST_INTR(3,fastintr3, IO_ICU1, ENABLE_ICU1)
204 FAST_INTR(4,fastintr4, IO_ICU1, ENABLE_ICU1)
205 FAST_INTR(5,fastintr5, IO_ICU1, ENABLE_ICU1)
206 FAST_INTR(6,fastintr6, IO_ICU1, ENABLE_ICU1)
207 FAST_INTR(7,fastintr7, IO_ICU1, ENABLE_ICU1)
208 FAST_INTR(8,fastintr8, IO_ICU2, ENABLE_ICU1_AND_2)
209 FAST_INTR(9,fastintr9, IO_ICU2, ENABLE_ICU1_AND_2)
210 FAST_INTR(10,fastintr10, IO_ICU2, ENABLE_ICU1_AND_2)
211 FAST_INTR(11,fastintr11, IO_ICU2, ENABLE_ICU1_AND_2)
212 FAST_INTR(12,fastintr12, IO_ICU2, ENABLE_ICU1_AND_2)
213 FAST_INTR(13,fastintr13, IO_ICU2, ENABLE_ICU1_AND_2)
214 FAST_INTR(14,fastintr14, IO_ICU2, ENABLE_ICU1_AND_2)
215 FAST_INTR(15,fastintr15, IO_ICU2, ENABLE_ICU1_AND_2)
216
217 #define CLKINTR_PENDING movl $1,CNAME(clkintr_pending)
218 /* Threaded interrupts */
219 INTR(0,intr0, IO_ICU1, ENABLE_ICU1, CLKINTR_PENDING)
220 INTR(1,intr1, IO_ICU1, ENABLE_ICU1,)
221 INTR(2,intr2, IO_ICU1, ENABLE_ICU1,)
222 INTR(3,intr3, IO_ICU1, ENABLE_ICU1,)
223 INTR(4,intr4, IO_ICU1, ENABLE_ICU1,)
224 INTR(5,intr5, IO_ICU1, ENABLE_ICU1,)
225 INTR(6,intr6, IO_ICU1, ENABLE_ICU1,)
226 INTR(7,intr7, IO_ICU1, ENABLE_ICU1,)
227 INTR(8,intr8, IO_ICU2, ENABLE_ICU1_AND_2,)
228 INTR(9,intr9, IO_ICU2, ENABLE_ICU1_AND_2,)
229 INTR(10,intr10, IO_ICU2, ENABLE_ICU1_AND_2,)
230 INTR(11,intr11, IO_ICU2, ENABLE_ICU1_AND_2,)
231 INTR(12,intr12, IO_ICU2, ENABLE_ICU1_AND_2,)
232 INTR(13,intr13, IO_ICU2, ENABLE_ICU1_AND_2,)
233 INTR(14,intr14, IO_ICU2, ENABLE_ICU1_AND_2,)
234 INTR(15,intr15, IO_ICU2, ENABLE_ICU1_AND_2,)
235
236 FAST_UNPEND(0,fastunpend0, IO_ICU1)
237 FAST_UNPEND(1,fastunpend1, IO_ICU1)
238 FAST_UNPEND(2,fastunpend2, IO_ICU1)
239 FAST_UNPEND(3,fastunpend3, IO_ICU1)
240 FAST_UNPEND(4,fastunpend4, IO_ICU1)
241 FAST_UNPEND(5,fastunpend5, IO_ICU1)
242 FAST_UNPEND(6,fastunpend6, IO_ICU1)
243 FAST_UNPEND(7,fastunpend7, IO_ICU1)
244 FAST_UNPEND(8,fastunpend8, IO_ICU2)
245 FAST_UNPEND(9,fastunpend9, IO_ICU2)
246 FAST_UNPEND(10,fastunpend10, IO_ICU2)
247 FAST_UNPEND(11,fastunpend11, IO_ICU2)
248 FAST_UNPEND(12,fastunpend12, IO_ICU2)
249 FAST_UNPEND(13,fastunpend13, IO_ICU2)
250 FAST_UNPEND(14,fastunpend14, IO_ICU2)
251 FAST_UNPEND(15,fastunpend15, IO_ICU2)
252 MCOUNT_LABEL(eintr)
253
Cache object: f249b1e0f72507b5d3e00adf3054154f
|