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