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