Statistics
| Branch: | Revision:

root / hw / i8259.c @ 80cabfad

History | View | Annotate | Download (10.2 kB)

1 80cabfad bellard
/*
2 80cabfad bellard
 * QEMU 8259 interrupt controller emulation
3 80cabfad bellard
 * 
4 80cabfad bellard
 * Copyright (c) 2003-2004 Fabrice Bellard
5 80cabfad bellard
 * 
6 80cabfad bellard
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 80cabfad bellard
 * of this software and associated documentation files (the "Software"), to deal
8 80cabfad bellard
 * in the Software without restriction, including without limitation the rights
9 80cabfad bellard
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 80cabfad bellard
 * copies of the Software, and to permit persons to whom the Software is
11 80cabfad bellard
 * furnished to do so, subject to the following conditions:
12 80cabfad bellard
 *
13 80cabfad bellard
 * The above copyright notice and this permission notice shall be included in
14 80cabfad bellard
 * all copies or substantial portions of the Software.
15 80cabfad bellard
 *
16 80cabfad bellard
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 80cabfad bellard
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 80cabfad bellard
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 80cabfad bellard
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 80cabfad bellard
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 80cabfad bellard
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 80cabfad bellard
 * THE SOFTWARE.
23 80cabfad bellard
 */
24 80cabfad bellard
#include <stdlib.h>
25 80cabfad bellard
#include <stdio.h>
26 80cabfad bellard
#include <stdarg.h>
27 80cabfad bellard
#include <string.h>
28 80cabfad bellard
#include <getopt.h>
29 80cabfad bellard
#include <inttypes.h>
30 80cabfad bellard
#include <unistd.h>
31 80cabfad bellard
#include <sys/mman.h>
32 80cabfad bellard
#include <fcntl.h>
33 80cabfad bellard
#include <signal.h>
34 80cabfad bellard
#include <time.h>
35 80cabfad bellard
#include <sys/time.h>
36 80cabfad bellard
#include <malloc.h>
37 80cabfad bellard
#include <termios.h>
38 80cabfad bellard
#include <sys/poll.h>
39 80cabfad bellard
#include <errno.h>
40 80cabfad bellard
#include <sys/wait.h>
41 80cabfad bellard
#include <netinet/in.h>
42 80cabfad bellard
43 80cabfad bellard
#include "cpu.h"
44 80cabfad bellard
#include "vl.h"
45 80cabfad bellard
46 80cabfad bellard
/* debug PIC */
47 80cabfad bellard
//#define DEBUG_PIC
48 80cabfad bellard
49 80cabfad bellard
typedef struct PicState {
50 80cabfad bellard
    uint8_t last_irr; /* edge detection */
51 80cabfad bellard
    uint8_t irr; /* interrupt request register */
52 80cabfad bellard
    uint8_t imr; /* interrupt mask register */
53 80cabfad bellard
    uint8_t isr; /* interrupt service register */
54 80cabfad bellard
    uint8_t priority_add; /* highest irq priority */
55 80cabfad bellard
    uint8_t irq_base;
56 80cabfad bellard
    uint8_t read_reg_select;
57 80cabfad bellard
    uint8_t poll;
58 80cabfad bellard
    uint8_t special_mask;
59 80cabfad bellard
    uint8_t init_state;
60 80cabfad bellard
    uint8_t auto_eoi;
61 80cabfad bellard
    uint8_t rotate_on_auto_eoi;
62 80cabfad bellard
    uint8_t special_fully_nested_mode;
63 80cabfad bellard
    uint8_t init4; /* true if 4 byte init */
64 80cabfad bellard
} PicState;
65 80cabfad bellard
66 80cabfad bellard
/* 0 is master pic, 1 is slave pic */
67 80cabfad bellard
PicState pics[2];
68 80cabfad bellard
int pic_irq_requested;
69 80cabfad bellard
70 80cabfad bellard
/* set irq level. If an edge is detected, then the IRR is set to 1 */
71 80cabfad bellard
static inline void pic_set_irq1(PicState *s, int irq, int level)
72 80cabfad bellard
{
73 80cabfad bellard
    int mask;
74 80cabfad bellard
    mask = 1 << irq;
75 80cabfad bellard
    if (level) {
76 80cabfad bellard
        if ((s->last_irr & mask) == 0)
77 80cabfad bellard
            s->irr |= mask;
78 80cabfad bellard
        s->last_irr |= mask;
79 80cabfad bellard
    } else {
80 80cabfad bellard
        s->last_irr &= ~mask;
81 80cabfad bellard
    }
82 80cabfad bellard
}
83 80cabfad bellard
84 80cabfad bellard
/* return the highest priority found in mask (highest = smallest
85 80cabfad bellard
   number). Return 8 if no irq */
86 80cabfad bellard
static inline int get_priority(PicState *s, int mask)
87 80cabfad bellard
{
88 80cabfad bellard
    int priority;
89 80cabfad bellard
    if (mask == 0)
90 80cabfad bellard
        return 8;
91 80cabfad bellard
    priority = 0;
92 80cabfad bellard
    while ((mask & (1 << ((priority + s->priority_add) & 7))) == 0)
93 80cabfad bellard
        priority++;
94 80cabfad bellard
    return priority;
95 80cabfad bellard
}
96 80cabfad bellard
97 80cabfad bellard
/* return the pic wanted interrupt. return -1 if none */
98 80cabfad bellard
static int pic_get_irq(PicState *s)
99 80cabfad bellard
{
100 80cabfad bellard
    int mask, cur_priority, priority;
101 80cabfad bellard
102 80cabfad bellard
    mask = s->irr & ~s->imr;
103 80cabfad bellard
    priority = get_priority(s, mask);
104 80cabfad bellard
    if (priority == 8)
105 80cabfad bellard
        return -1;
106 80cabfad bellard
    /* compute current priority. If special fully nested mode on the
107 80cabfad bellard
       master, the IRQ coming from the slave is not taken into account
108 80cabfad bellard
       for the priority computation. */
109 80cabfad bellard
    mask = s->isr;
110 80cabfad bellard
    if (s->special_fully_nested_mode && s == &pics[0])
111 80cabfad bellard
        mask &= ~(1 << 2);
112 80cabfad bellard
    cur_priority = get_priority(s, mask);
113 80cabfad bellard
    if (priority < cur_priority) {
114 80cabfad bellard
        /* higher priority found: an irq should be generated */
115 80cabfad bellard
        return (priority + s->priority_add) & 7;
116 80cabfad bellard
    } else {
117 80cabfad bellard
        return -1;
118 80cabfad bellard
    }
119 80cabfad bellard
}
120 80cabfad bellard
121 80cabfad bellard
/* raise irq to CPU if necessary. must be called every time the active
122 80cabfad bellard
   irq may change */
123 80cabfad bellard
void pic_update_irq(void)
124 80cabfad bellard
{
125 80cabfad bellard
    int irq2, irq;
126 80cabfad bellard
127 80cabfad bellard
    /* first look at slave pic */
128 80cabfad bellard
    irq2 = pic_get_irq(&pics[1]);
129 80cabfad bellard
    if (irq2 >= 0) {
130 80cabfad bellard
        /* if irq request by slave pic, signal master PIC */
131 80cabfad bellard
        pic_set_irq1(&pics[0], 2, 1);
132 80cabfad bellard
        pic_set_irq1(&pics[0], 2, 0);
133 80cabfad bellard
    }
134 80cabfad bellard
    /* look at requested irq */
135 80cabfad bellard
    irq = pic_get_irq(&pics[0]);
136 80cabfad bellard
    if (irq >= 0) {
137 80cabfad bellard
        if (irq == 2) {
138 80cabfad bellard
            /* from slave pic */
139 80cabfad bellard
            pic_irq_requested = 8 + irq2;
140 80cabfad bellard
        } else {
141 80cabfad bellard
            /* from master pic */
142 80cabfad bellard
            pic_irq_requested = irq;
143 80cabfad bellard
        }
144 80cabfad bellard
#if defined(DEBUG_PIC)
145 80cabfad bellard
        {
146 80cabfad bellard
            int i;
147 80cabfad bellard
            for(i = 0; i < 2; i++) {
148 80cabfad bellard
                printf("pic%d: imr=%x irr=%x padd=%d\n", 
149 80cabfad bellard
                       i, pics[i].imr, pics[i].irr, pics[i].priority_add);
150 80cabfad bellard
                
151 80cabfad bellard
            }
152 80cabfad bellard
        }
153 80cabfad bellard
        printf("pic: cpu_interrupt req=%d\n", pic_irq_requested);
154 80cabfad bellard
#endif
155 80cabfad bellard
        cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
156 80cabfad bellard
    }
157 80cabfad bellard
}
158 80cabfad bellard
159 80cabfad bellard
#ifdef DEBUG_IRQ_LATENCY
160 80cabfad bellard
int64_t irq_time[16];
161 80cabfad bellard
int64_t cpu_get_ticks(void);
162 80cabfad bellard
#endif
163 80cabfad bellard
#if defined(DEBUG_PIC)
164 80cabfad bellard
int irq_level[16];
165 80cabfad bellard
#endif
166 80cabfad bellard
167 80cabfad bellard
void pic_set_irq(int irq, int level)
168 80cabfad bellard
{
169 80cabfad bellard
#if defined(DEBUG_PIC)
170 80cabfad bellard
    if (level != irq_level[irq]) {
171 80cabfad bellard
        printf("pic_set_irq: irq=%d level=%d\n", irq, level);
172 80cabfad bellard
        irq_level[irq] = level;
173 80cabfad bellard
    }
174 80cabfad bellard
#endif
175 80cabfad bellard
#ifdef DEBUG_IRQ_LATENCY
176 80cabfad bellard
    if (level) {
177 80cabfad bellard
        irq_time[irq] = cpu_get_ticks();
178 80cabfad bellard
    }
179 80cabfad bellard
#endif
180 80cabfad bellard
    pic_set_irq1(&pics[irq >> 3], irq & 7, level);
181 80cabfad bellard
    pic_update_irq();
182 80cabfad bellard
}
183 80cabfad bellard
184 80cabfad bellard
/* acknowledge interrupt 'irq' */
185 80cabfad bellard
static inline void pic_intack(PicState *s, int irq)
186 80cabfad bellard
{
187 80cabfad bellard
    if (s->auto_eoi) {
188 80cabfad bellard
        if (s->rotate_on_auto_eoi)
189 80cabfad bellard
            s->priority_add = (irq + 1) & 7;
190 80cabfad bellard
    } else {
191 80cabfad bellard
        s->isr |= (1 << irq);
192 80cabfad bellard
    }
193 80cabfad bellard
    s->irr &= ~(1 << irq);
194 80cabfad bellard
}
195 80cabfad bellard
196 80cabfad bellard
int cpu_x86_get_pic_interrupt(CPUState *env)
197 80cabfad bellard
{
198 80cabfad bellard
    int irq, irq2, intno;
199 80cabfad bellard
200 80cabfad bellard
    /* signal the pic that the irq was acked by the CPU */
201 80cabfad bellard
    irq = pic_irq_requested;
202 80cabfad bellard
#ifdef DEBUG_IRQ_LATENCY
203 80cabfad bellard
    printf("IRQ%d latency=%0.3fus\n", 
204 80cabfad bellard
           irq, 
205 80cabfad bellard
           (double)(cpu_get_ticks() - irq_time[irq]) * 1000000.0 / ticks_per_sec);
206 80cabfad bellard
#endif
207 80cabfad bellard
#if defined(DEBUG_PIC)
208 80cabfad bellard
    printf("pic_interrupt: irq=%d\n", irq);
209 80cabfad bellard
#endif
210 80cabfad bellard
211 80cabfad bellard
    if (irq >= 8) {
212 80cabfad bellard
        irq2 = irq & 7;
213 80cabfad bellard
        pic_intack(&pics[1], irq2);
214 80cabfad bellard
        irq = 2;
215 80cabfad bellard
        intno = pics[1].irq_base + irq2;
216 80cabfad bellard
    } else {
217 80cabfad bellard
        intno = pics[0].irq_base + irq;
218 80cabfad bellard
    }
219 80cabfad bellard
    pic_intack(&pics[0], irq);
220 80cabfad bellard
    return intno;
221 80cabfad bellard
}
222 80cabfad bellard
223 80cabfad bellard
void pic_ioport_write(CPUState *env, uint32_t addr, uint32_t val)
224 80cabfad bellard
{
225 80cabfad bellard
    PicState *s;
226 80cabfad bellard
    int priority, cmd, irq;
227 80cabfad bellard
228 80cabfad bellard
#ifdef DEBUG_PIC
229 80cabfad bellard
    printf("pic_write: addr=0x%02x val=0x%02x\n", addr, val);
230 80cabfad bellard
#endif
231 80cabfad bellard
    s = &pics[addr >> 7];
232 80cabfad bellard
    addr &= 1;
233 80cabfad bellard
    if (addr == 0) {
234 80cabfad bellard
        if (val & 0x10) {
235 80cabfad bellard
            /* init */
236 80cabfad bellard
            memset(s, 0, sizeof(PicState));
237 80cabfad bellard
            s->init_state = 1;
238 80cabfad bellard
            s->init4 = val & 1;
239 80cabfad bellard
            if (val & 0x02)
240 80cabfad bellard
                hw_error("single mode not supported");
241 80cabfad bellard
            if (val & 0x08)
242 80cabfad bellard
                hw_error("level sensitive irq not supported");
243 80cabfad bellard
        } else if (val & 0x08) {
244 80cabfad bellard
            if (val & 0x04)
245 80cabfad bellard
                s->poll = 1;
246 80cabfad bellard
            if (val & 0x02)
247 80cabfad bellard
                s->read_reg_select = val & 1;
248 80cabfad bellard
            if (val & 0x40)
249 80cabfad bellard
                s->special_mask = (val >> 5) & 1;
250 80cabfad bellard
        } else {
251 80cabfad bellard
            cmd = val >> 5;
252 80cabfad bellard
            switch(cmd) {
253 80cabfad bellard
            case 0:
254 80cabfad bellard
            case 4:
255 80cabfad bellard
                s->rotate_on_auto_eoi = cmd >> 2;
256 80cabfad bellard
                break;
257 80cabfad bellard
            case 1: /* end of interrupt */
258 80cabfad bellard
            case 5:
259 80cabfad bellard
                priority = get_priority(s, s->isr);
260 80cabfad bellard
                if (priority != 8) {
261 80cabfad bellard
                    irq = (priority + s->priority_add) & 7;
262 80cabfad bellard
                    s->isr &= ~(1 << irq);
263 80cabfad bellard
                    if (cmd == 5)
264 80cabfad bellard
                        s->priority_add = (irq + 1) & 7;
265 80cabfad bellard
                    pic_update_irq();
266 80cabfad bellard
                }
267 80cabfad bellard
                break;
268 80cabfad bellard
            case 3:
269 80cabfad bellard
                irq = val & 7;
270 80cabfad bellard
                s->isr &= ~(1 << irq);
271 80cabfad bellard
                pic_update_irq();
272 80cabfad bellard
                break;
273 80cabfad bellard
            case 6:
274 80cabfad bellard
                s->priority_add = (val + 1) & 7;
275 80cabfad bellard
                pic_update_irq();
276 80cabfad bellard
                break;
277 80cabfad bellard
            case 7:
278 80cabfad bellard
                irq = val & 7;
279 80cabfad bellard
                s->isr &= ~(1 << irq);
280 80cabfad bellard
                s->priority_add = (irq + 1) & 7;
281 80cabfad bellard
                pic_update_irq();
282 80cabfad bellard
                break;
283 80cabfad bellard
            default:
284 80cabfad bellard
                /* no operation */
285 80cabfad bellard
                break;
286 80cabfad bellard
            }
287 80cabfad bellard
        }
288 80cabfad bellard
    } else {
289 80cabfad bellard
        switch(s->init_state) {
290 80cabfad bellard
        case 0:
291 80cabfad bellard
            /* normal mode */
292 80cabfad bellard
            s->imr = val;
293 80cabfad bellard
            pic_update_irq();
294 80cabfad bellard
            break;
295 80cabfad bellard
        case 1:
296 80cabfad bellard
            s->irq_base = val & 0xf8;
297 80cabfad bellard
            s->init_state = 2;
298 80cabfad bellard
            break;
299 80cabfad bellard
        case 2:
300 80cabfad bellard
            if (s->init4) {
301 80cabfad bellard
                s->init_state = 3;
302 80cabfad bellard
            } else {
303 80cabfad bellard
                s->init_state = 0;
304 80cabfad bellard
            }
305 80cabfad bellard
            break;
306 80cabfad bellard
        case 3:
307 80cabfad bellard
            s->special_fully_nested_mode = (val >> 4) & 1;
308 80cabfad bellard
            s->auto_eoi = (val >> 1) & 1;
309 80cabfad bellard
            s->init_state = 0;
310 80cabfad bellard
            break;
311 80cabfad bellard
        }
312 80cabfad bellard
    }
313 80cabfad bellard
}
314 80cabfad bellard
315 80cabfad bellard
static uint32_t pic_poll_read (PicState *s, uint32_t addr1)
316 80cabfad bellard
{
317 80cabfad bellard
    int ret;
318 80cabfad bellard
319 80cabfad bellard
    ret = pic_get_irq(s);
320 80cabfad bellard
    if (ret >= 0) {
321 80cabfad bellard
        if (addr1 >> 7) {
322 80cabfad bellard
            pics[0].isr &= ~(1 << 2);
323 80cabfad bellard
            pics[0].irr &= ~(1 << 2);
324 80cabfad bellard
        }
325 80cabfad bellard
        s->irr &= ~(1 << ret);
326 80cabfad bellard
        s->isr &= ~(1 << ret);
327 80cabfad bellard
        if (addr1 >> 7 || ret != 2)
328 80cabfad bellard
            pic_update_irq();
329 80cabfad bellard
    } else {
330 80cabfad bellard
        ret = 0x07;
331 80cabfad bellard
        pic_update_irq();
332 80cabfad bellard
    }
333 80cabfad bellard
334 80cabfad bellard
    return ret;
335 80cabfad bellard
}
336 80cabfad bellard
337 80cabfad bellard
uint32_t pic_ioport_read(CPUState *env, uint32_t addr1)
338 80cabfad bellard
{
339 80cabfad bellard
    PicState *s;
340 80cabfad bellard
    unsigned int addr;
341 80cabfad bellard
    int ret;
342 80cabfad bellard
343 80cabfad bellard
    addr = addr1;
344 80cabfad bellard
    s = &pics[addr >> 7];
345 80cabfad bellard
    addr &= 1;
346 80cabfad bellard
    if (s->poll) {
347 80cabfad bellard
        ret = pic_poll_read(s, addr1);
348 80cabfad bellard
        s->poll = 0;
349 80cabfad bellard
    } else {
350 80cabfad bellard
        if (addr == 0) {
351 80cabfad bellard
            if (s->read_reg_select)
352 80cabfad bellard
                ret = s->isr;
353 80cabfad bellard
            else
354 80cabfad bellard
                ret = s->irr;
355 80cabfad bellard
        } else {
356 80cabfad bellard
            ret = s->imr;
357 80cabfad bellard
        }
358 80cabfad bellard
    }
359 80cabfad bellard
#ifdef DEBUG_PIC
360 80cabfad bellard
    printf("pic_read: addr=0x%02x val=0x%02x\n", addr1, ret);
361 80cabfad bellard
#endif
362 80cabfad bellard
    return ret;
363 80cabfad bellard
}
364 80cabfad bellard
365 80cabfad bellard
/* memory mapped interrupt status */
366 80cabfad bellard
uint32_t pic_intack_read(CPUState *env)
367 80cabfad bellard
{
368 80cabfad bellard
    int ret;
369 80cabfad bellard
370 80cabfad bellard
    ret = pic_poll_read(&pics[0], 0x00);
371 80cabfad bellard
    if (ret == 2)
372 80cabfad bellard
        ret = pic_poll_read(&pics[1], 0x80) + 8;
373 80cabfad bellard
    /* Prepare for ISR read */
374 80cabfad bellard
    pics[0].read_reg_select = 1;
375 80cabfad bellard
    
376 80cabfad bellard
    return ret;
377 80cabfad bellard
}
378 80cabfad bellard
379 80cabfad bellard
void pic_init(void)
380 80cabfad bellard
{
381 80cabfad bellard
#if defined (TARGET_I386) || defined (TARGET_PPC)
382 80cabfad bellard
    register_ioport_write(0x20, 2, pic_ioport_write, 1);
383 80cabfad bellard
    register_ioport_read(0x20, 2, pic_ioport_read, 1);
384 80cabfad bellard
    register_ioport_write(0xa0, 2, pic_ioport_write, 1);
385 80cabfad bellard
    register_ioport_read(0xa0, 2, pic_ioport_read, 1);
386 80cabfad bellard
#endif
387 80cabfad bellard
}