7e37c8594d4d982bb97fd64edfc1d50930899e62
[dragonfly.git] / usr.bin / doscmd / int.c
1 /*
2 ** No copyright?!
3 */
4 /*
5  * Notes:
6  *   1) Second PIC is not implemented.
7  *   2) Interrupt priority management is not implemented.
8  *   3) What should be read from port 0x20?
9  *
10  * "within interrupt processing" means the following is true:
11  *   1) Hardware interrupt <irql> is delivered by hardint().
12  *   2) Next interrupt <irql> is not possible yet by either:
13  *      a) V_IF;
14  *      b) Interrupt mask;
15  *      c) Current irql.
16  *
17  * Related functions:
18  *   int isinhardint(int irql)
19  *   void set_eoir(int irql, void (*eoir)(void *), void *arg);
20  *
21  * $FreeBSD: src/usr.bin/doscmd/int.c,v 1.3.2.2 2002/04/25 11:04:51 tg Exp $
22  * $DragonFly: src/usr.bin/doscmd/int.c,v 1.2 2003/06/17 04:29:26 dillon Exp $
23  */
24
25 #include "doscmd.h"
26
27 struct IRQ {
28     int pending;
29     int busy;
30     int within;
31     void (*eoir)(void *arg);
32     void *arg;
33 };
34
35 static unsigned char IM;
36 static int Irql;
37 static struct IRQ Irqs[8];
38
39 #define int_allowed(n) ((IM & 1 << (n)) == 0 && Irql > (n))
40
41 void
42 set_eoir(int irql, void (*eoir)(void *), void *arg)
43 {
44     Irqs [irql].eoir = eoir;
45     Irqs [irql].arg = arg;
46 }
47
48 int
49 isinhardint(int irql)
50 {
51     return Irqs[irql].within;
52 }
53
54 static void
55 set_vip(void)
56 {
57     regcontext_t *REGS = saved_regcontext;
58     int irql;
59     
60     if (R_EFLAGS & PSL_VIF) {
61         R_EFLAGS &= ~PSL_VIP;
62         return;
63     }
64     
65     for (irql = 0; irql < 8; irql++)
66         if (int_allowed(irql) && (Irqs[irql].within || Irqs[irql].pending)) {
67             R_EFLAGS |= PSL_VIP;
68             return;
69         }
70     
71     R_EFLAGS &= ~PSL_VIP;
72 }
73
74 void
75 resume_interrupt(void)
76 {
77     regcontext_t      *REGS = saved_regcontext;
78     int irql;
79     
80     if (R_EFLAGS & PSL_VIF) {
81         for (irql = 0; irql < 8; irql++)
82             if (Irqs[irql].within && int_allowed(irql)) {
83                 Irqs[irql].within = 0;
84                 if (Irqs[irql].eoir)
85                     Irqs[irql].eoir(Irqs[irql].arg);
86             }
87         
88         for (irql = 0; irql < 8; irql++)
89             if (Irqs[irql].pending && int_allowed(irql)) {
90                 Irqs[irql].pending = 0;
91                 hardint(irql);
92                 break;
93             }
94     }
95     set_vip();
96 }
97
98 void
99 send_eoi(void)
100 {
101     if (Irql >= 8)
102         return;
103     
104     Irqs[Irql].busy = 0;
105     
106     while (++Irql < 8)
107         if (Irqs [Irql].busy)
108             break;
109     
110     resume_interrupt();
111 }
112
113 /*
114 ** Cause a hardware interrupt to happen immediately after
115 ** we return to vm86 mode
116 */
117 void
118 hardint(int irql)
119 {
120     regcontext_t        *REGS = saved_regcontext;
121     u_long vec = ivec[8 + irql];
122
123     /* 
124     ** if we're dead, or there's no vector, or the saved registers
125     ** are invalid
126     */
127     if (dead || !saved_valid || vec == 0)
128         return;
129     
130     /* 
131     ** if the vector points into the BIOS, or the handler at the
132     ** other end is just an IRET, don't bother 
133     */
134     if ((vec >> 16) == 0xf000 || *(u_char *)VECPTR(vec) == 0xcf)
135         return;
136     
137     if (!int_allowed(irql)) {
138         Irqs[irql].pending = 1;
139         return;
140     }
141     
142     if ((R_EFLAGS & PSL_VIF) == 0) {
143         Irqs[irql].pending = 1;
144         R_EFLAGS |= PSL_VIP;
145         return;
146     }
147     
148     debug(D_TRAPS | (8 + irql), "Int%02x [%04lx:%04lx]\n",
149           8 + irql, vec >> 16, vec & 0xffff);
150     
151     Irql = irql;
152     Irqs[Irql].busy = 1;
153     if (Irqs[Irql].eoir)
154         Irqs[Irql].within = 1;
155     
156     PUSH((R_FLAGS & ~PSL_I) | (R_EFLAGS & PSL_VIF ? PSL_I : 0), REGS);
157     PUSH(R_CS, REGS);
158     PUSH(R_IP, REGS);
159     R_EFLAGS &= ~PSL_VIF;               /* XXX disable interrupts */
160     PUTVEC(R_CS, R_IP, vec);
161 }
162
163 void
164 unpend(int irql)
165 {
166     if (!Irqs[irql].pending)
167         return;
168     Irqs[irql].pending = 0;
169     set_vip();
170 }
171
172 static unsigned char
173 irqc_in(int port)
174 {
175     return 0x60; /* What should be here? */
176 }
177  
178 static void
179 irqc_out(int port, unsigned char val)
180 {
181     if (val == 0x20)
182         send_eoi();
183 }
184
185 static unsigned char
186 imr_in(int port)
187 {
188     return IM;
189 }
190  
191 static void
192 imr_out(int port, unsigned char val)
193 {
194     IM = val;
195     resume_interrupt();
196 }
197  
198 /*
199 ** Cause a software interrupt to happen immediately after we
200 ** return to vm86 mode
201 */
202 void
203 softint(int intnum)
204 {
205     regcontext_t        *REGS = saved_regcontext;
206     u_long vec = ivec[intnum];
207
208     /*
209     ** if we're dead, or there's no vector or the saved registers are
210     ** invalid
211     */
212     if (dead || !saved_valid || vec == 0)
213         return;
214
215     /* 
216     ** if the vector points into the BIOS, or the handler at the other
217     ** end is just an IRET, don't bother.
218     */
219     if ((vec >> 16) == 0xf000 || *(u_char *)VECPTR(vec) == 0xcf)
220         return;
221
222     debug(D_TRAPS | intnum, "INT %02x [%04lx:%04lx]\n", 
223           intnum, vec >> 16, vec & 0xffff);
224
225     PUSH((R_FLAGS & ~PSL_I) | (R_EFLAGS & PSL_VIF ? PSL_I : 0), REGS);
226     PUSH(R_CS, REGS);
227     PUSH(R_IP, REGS);
228     R_EFLAGS &= ~PSL_VIF;               /* XXX disable interrupts? */
229     PUTVEC(R_CS, R_IP, vec);
230 }
231
232 void
233 init_ints(void)
234 {
235     int i;
236     
237     for (i = 0; i < 8; i++) {
238         Irqs[i].busy = 0;
239         Irqs[i].pending = 0;
240         Irqs[i].within = 0;
241     }
242     
243     IM = 0x00;
244     Irql = 8;
245     
246     define_input_port_handler(0x20, irqc_in);
247     define_output_port_handler(0x20, irqc_out);
248     define_input_port_handler(0x21, imr_in);
249     define_output_port_handler(0x21, imr_out);
250 }