Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


*** empty log message ***
[palacios.releases.git] / palacios / src / devices / 8259a.c
1 #include <devices/8259a.h>
2 #include <palacios/vmm_intr.h>
3 #include <palacios/vmm_types.h>
4 #include <palacios/vmm.h>
5
6
7 typedef enum {RESET, ICW1, ICW2, ICW3, ICW4,  READY} pic_state_t;
8
9 static const uint_t MASTER_PORT1 = 0x20;
10 static const uint_t MASTER_PORT2 = 0x21;
11 static const uint_t SLAVE_PORT1 = 0xA0;
12 static const uint_t SLAVE_PORT2 = 0xA1;
13
14 #define IS_ICW1(x) (((x & 0x10) >> 4) == 0x1)
15 #define IS_OCW2(x) (((x & 0x18) >> 3) == 0x0)
16 #define IS_OCW3(x) (((x & 0x18) >> 3) == 0x1)
17
18
19 struct icw1 {
20   uint_t ic4    : 1;  // ICW4 has to be read
21   uint_t sngl   : 1;  // single (only one PIC)
22   uint_t adi    : 1;  // call address interval
23   uint_t ltim   : 1;  // level interrupt mode
24   uint_t one    : 1;
25   uint_t rsvd   : 3;
26 };
27
28
29 struct icw2 {
30   uint_t rsvd   : 3;
31   uint_t vector : 5;
32 };
33
34
35 // Each bit that is set indicates that the IR input has a slave
36 struct icw3_master {
37   uint_t S0   : 1;
38   uint_t S1   : 1;
39   uint_t S2   : 1;
40   uint_t S3   : 1;
41   uint_t S4   : 1;
42   uint_t S5   : 1;
43   uint_t S6   : 1;
44   uint_t S7   : 1;
45 };
46
47 // The ID is the Slave device ID
48 struct icw3_slave {
49   uint_t id     : 3;
50   uint_t zeroes : 5;
51 };
52
53 struct icw4 {
54   uint_t uPM    : 1;  // 1=x86
55   uint_t AEOI   : 1;  // Automatic End of Interrupt
56   uint_t M_S    : 1;  // only if buffered 1=master,0=slave 
57   uint_t BUF    : 1;  // buffered mode
58   uint_t SFNM   : 1;  // special fully nexted mode
59   uint_t zeroes : 3;
60 };
61
62
63 struct ocw1 {
64   uint_t m0     : 1;
65   uint_t m1     : 1;
66   uint_t m2     : 1;
67   uint_t m3     : 1;
68   uint_t m4     : 1;
69   uint_t m5     : 1;
70   uint_t m6     : 1;
71   uint_t m7     : 1;
72 };
73
74 struct ocw2 {
75   uint_t level  : 3;
76   uint_t cw_code : 2; // should be 00
77   uint_t EOI    : 1;
78   uint_t SL     : 1;
79   uint_t R      : 1;
80 };
81
82 struct ocw3 {
83   uint_t RIS    : 1;
84   uint_t RR     : 1;
85   uint_t P      : 1;
86   uint_t cw_code : 2; // should be 01
87   uint_t smm    : 1;
88   uint_t esmm   : 1;
89   uint_t zero2  : 1;
90 };
91
92
93 struct pic_internal {
94
95
96   char master_irr;
97   char slave_irr;
98   
99   char master_isr;
100   char slave_isr;
101
102   char master_icw1;
103   char master_icw2;
104   char master_icw3;
105   char master_icw4;
106
107
108   char slave_icw1;
109   char slave_icw2;
110   char slave_icw3;
111   char slave_icw4;
112
113
114   char master_imr;
115   char slave_imr;
116   char master_ocw2;
117   char master_ocw3;
118   char slave_ocw2;
119   char slave_ocw3;
120
121   pic_state_t master_state;
122   pic_state_t slave_state;
123 };
124
125
126
127 static int pic_raise_intr(void * private_data, int irq) {
128   struct pic_internal * state = (struct pic_internal*)private_data;
129
130   if (irq == 2) {
131     irq = 9;
132   }
133
134   PrintDebug("8259 PIC: Raising irq %d in the PIC\n", irq);
135
136   if (irq <= 7) {
137     state->master_irr |= 0x01 << irq;
138   } else if ((irq > 7) && (irq < 16)) {
139     state->slave_irr |= 0x01 << (irq - 7);
140   } else {
141     PrintDebug("8259 PIC: Invalid IRQ raised (%d)\n", irq);
142     return -1;
143   }
144
145   return 0;
146 }
147
148 static int pic_intr_pending(void * private_data) {
149   struct pic_internal * state = (struct pic_internal*)private_data;
150
151   if ((state->master_irr & ~(state->master_imr)) || 
152       (state->slave_irr & ~(state->slave_imr))) {
153     return 1;
154   }
155
156   return 0;
157 }
158
159 static int pic_get_intr_number(void * private_data) {
160   struct pic_internal * state = (struct pic_internal*)private_data;
161   int i;
162
163   for (i = 0; i < 16; i++) {
164     if (i <= 7) {
165       if (((state->master_irr & ~(state->master_imr)) >> i) == 0x01) {
166         //state->master_isr |= (0x1 << i);
167         // reset the irr
168         //state->master_irr &= ~(0x1 << i);
169         PrintDebug("8259 PIC: IRQ: %d, icw2: %x\n", i, state->master_icw2);
170         return i + state->master_icw2;
171       }
172     } else {
173       if (((state->slave_irr & ~(state->slave_imr)) >> (i - 8)) == 0x01) {
174         //state->slave_isr |= (0x1 << (i - 8));
175         //state->slave_irr &= ~(0x1 << (i - 8));
176         return (i - 8) + state->slave_icw2;
177       }
178     }
179   }
180
181   return 0;
182 }
183
184
185
186 /* The IRQ number is the number returned by pic_get_intr_number(), not the pin number */
187 static int pic_begin_irq(void * private_data, int irq) {
188   struct pic_internal * state = (struct pic_internal*)private_data;
189
190   if ((irq >= state->master_icw2) && (irq <= state->master_icw2 + 7)) {
191     irq &= 0x7;
192   } else if ((irq >= state->slave_icw2) && (irq <= state->slave_icw2 + 7)) {
193     irq &= 0x7;
194     irq += 8;
195   } else {
196     PrintDebug("8259 PIC: Could not find IRQ to Begin\n");
197     return -1;
198   }
199
200   if (irq <= 7) {
201     if (((state->master_irr & ~(state->master_imr)) >> irq) == 0x01) {
202       state->master_isr |= (0x1 << irq);
203       state->master_irr &= ~(0x1 << irq);
204     }
205   } else {
206     state->slave_isr |= (0x1 << (irq - 8));
207     state->slave_irr &= ~(0x1 << (irq - 8));
208   }
209
210   return 0;
211 }
212
213
214 /*
215 static int pic_end_irq(void * private_data, int irq) {
216   return 0;
217 }
218 */
219
220 static struct intr_ctrl_ops intr_ops = {
221   .intr_pending = pic_intr_pending,
222   .get_intr_number = pic_get_intr_number,
223   .raise_intr = pic_raise_intr,
224   .begin_irq = pic_begin_irq,
225 };
226
227
228
229
230 int read_master_port1(ushort_t port, void * dst, uint_t length, struct vm_device * dev) {
231   struct pic_internal * state = (struct pic_internal*)dev->private_data;
232
233   if (length != 1) {
234     PrintDebug("8259 PIC: Invalid Read length (rd_Master1)\n");
235     return -1;
236   }
237   
238   if ((state->master_ocw3 & 0x03) == 0x02) {
239     *(char *)dst = state->master_irr;
240   } else if ((state->master_ocw3 & 0x03) == 0x03) {
241     *(char *)dst = state->master_isr;
242   } else {
243     *(char *)dst = 0;
244   }
245   
246   return 1;
247 }
248
249 int read_master_port2(ushort_t port, void * dst, uint_t length, struct vm_device * dev) {
250   struct pic_internal * state = (struct pic_internal*)dev->private_data;
251
252   if (length != 1) {
253     PrintDebug("8259 PIC: Invalid Read length (rd_Master2)\n");
254     return -1;
255   }
256
257   *(char *)dst = state->master_imr;
258
259   return 1;
260   
261 }
262
263 int read_slave_port1(ushort_t port, void * dst, uint_t length, struct vm_device * dev) {
264   struct pic_internal * state = (struct pic_internal*)dev->private_data;
265
266   if (length != 1) {
267     PrintDebug("8259 PIC: Invalid Read length (rd_Slave1)\n");
268     return -1;
269   }
270   
271   if ((state->slave_ocw3 & 0x03) == 0x02) {
272     *(char*)dst = state->slave_irr;
273   } else if ((state->slave_ocw3 & 0x03) == 0x03) {
274     *(char *)dst = state->slave_isr;
275   } else {
276     *(char *)dst = 0;
277   }
278
279   return 1;
280 }
281
282 int read_slave_port2(ushort_t port, void * dst, uint_t length, struct vm_device * dev) {
283   struct pic_internal * state = (struct pic_internal*)dev->private_data;
284
285   if (length != 1) {
286     PrintDebug("8259 PIC: Invalid Read length  (rd_Slave2)\n");
287     return -1;
288   }
289
290   *(char *)dst = state->slave_imr;
291
292   return 1;
293 }
294
295
296 int write_master_port1(ushort_t port, void * src, uint_t length, struct vm_device * dev) {
297   struct pic_internal * state = (struct pic_internal*)dev->private_data;
298   char cw = *(char *)src;
299
300   if (length != 1) {
301     PrintDebug("8259 PIC: Invalid Write length (wr_Master1)\n");
302     return -1;
303   }
304   
305   if (IS_ICW1(cw)) {
306     state->master_icw1 = cw;
307     state->master_state = ICW2;
308
309   } else if (state->master_state == READY) {
310     if (IS_OCW2(cw)) {
311       // handle the EOI here
312       struct ocw2 * cw2 =  (struct ocw2*)&cw;
313
314       
315       if ((cw2->EOI) && (!cw2->R) && (cw2->SL)) {
316         // specific EOI;
317         state->master_isr &= ~(0x01 << cw2->level);
318       } else if ((cw2->EOI) & (!cw2->R) && (!cw2->SL)) {
319         int i;
320         // Non-specific EOI
321         PrintDebug("8259 PIC: Pre ISR = %x (wr_Master1)\n", state->master_isr);
322         for (i = 0; i < 8; i++) {
323           if (state->master_isr & (0x01 << i)) {
324             state->master_isr &= ~(0x01 << i);
325             break;
326           }
327         }       
328         PrintDebug("8259 PIC: Post ISR = %x (wr_Master1)\n", state->master_isr);
329       } else {
330         PrintDebug("8259 PIC: Command not handled, or in error (wr_Master1)\n");
331         return -1;
332       }
333
334       state->master_ocw2 = cw;
335     } else if (IS_OCW3(cw)) {
336       state->master_ocw3 = cw;
337     } else {
338       PrintDebug("8259 PIC: Invalid OCW to PIC (wr_Master1)\n");
339       PrintDebug("8259 PIC: CW=%x\n", cw);
340       return -1;
341     }
342   } else {
343     PrintDebug("8259 PIC: Invalid PIC State (wr_Master1)\n");
344     PrintDebug("8259 PIC: CW=%x\n", cw);
345     return -1;
346   }
347
348   return 1;
349 }
350
351 int write_master_port2(ushort_t port, void * src, uint_t length, struct vm_device * dev) {
352     struct pic_internal * state = (struct pic_internal*)dev->private_data;
353     char cw = *(char *)src;    
354
355     if (length != 1) {
356       PrintDebug("8259 PIC: Invalid Write length (wr_Master2)\n");
357       return -1;
358     }
359     
360     if (state->master_state == ICW2) {
361       struct icw1 * cw1 = (struct icw1 *)&(state->master_icw1);
362
363       PrintDebug("8259 PIC: Setting ICW2 = %x (wr_Master2)\n", cw);
364       state->master_icw2 = cw;
365
366       if (cw1->sngl == 0) {
367         state->master_state = ICW3;
368       } else if (cw1->ic4 == 1) {
369         state->master_state = ICW4;
370       } else {
371         state->master_state = READY;
372       }
373
374     } else if (state->master_state == ICW3) {
375       struct icw1 * cw1 = (struct icw1 *)&(state->master_icw1);
376
377       state->master_icw3 = cw;
378
379       if (cw1->ic4 == 1) {
380         state->master_state = ICW4;
381       } else {
382         state->master_state = READY;
383       }
384
385     } else if (state->master_state == ICW4) {
386       state->master_icw4 = cw;
387       state->master_state = READY;
388     } else if (state->master_state == READY) {
389       state->master_imr = cw;
390     } else {
391       // error
392       PrintDebug("8259 PIC: Invalid master PIC State (wr_Master2)\n");
393       return -1;
394     }
395
396     return 1;
397 }
398
399 int write_slave_port1(ushort_t port, void * src, uint_t length, struct vm_device * dev) {
400   struct pic_internal * state = (struct pic_internal*)dev->private_data;
401   char cw = *(char *)src;
402
403   if (length != 1) {
404     // error
405     PrintDebug("8259 PIC: Invalid Write length (wr_Slave1)\n");
406     return -1;
407   }
408
409   if (IS_ICW1(cw)) {
410     state->slave_icw1 = cw;
411     state->slave_state = ICW2;
412   } else if (state->slave_state == READY) {
413     if (IS_OCW2(cw)) {
414       // handle the EOI here
415       struct ocw2 * cw2 =  (struct ocw2 *)&cw;
416       
417       if ((cw2->EOI) && (!cw2->R) && (cw2->SL)) {
418         // specific EOI;
419         state->slave_isr &= ~(0x01 << cw2->level);
420       } else if ((cw2->EOI) & (!cw2->R) && (!cw2->SL)) {
421         int i;
422         // Non-specific EOI
423         PrintDebug("8259 PIC: Pre ISR = %x (wr_Slave1)\n", state->slave_isr);
424         for (i = 0; i < 8; i++) {
425           if (state->slave_isr & (0x01 << i)) {
426             state->slave_isr &= ~(0x01 << i);
427             break;
428           }
429         }       
430         PrintDebug("8259 PIC: Post ISR = %x (wr_Slave1)\n", state->slave_isr);
431       } else {
432         PrintDebug("8259 PIC: Command not handled or invalid  (wr_Slave1)\n");
433         return -1;
434       }
435
436       state->slave_ocw2 = cw;
437     } else if (IS_OCW3(cw)) {
438       // Basically sets the IRR/ISR read flag
439       state->slave_ocw3 = cw;
440     } else {
441       PrintDebug("8259 PIC: Invalid command work (wr_Slave1)\n");
442       return -1;
443     }
444   } else {
445     PrintDebug("8259 PIC: Invalid State writing (wr_Slave1)\n");
446     return -1;
447   }
448
449   return 1;
450 }
451
452 int write_slave_port2(ushort_t port, void * src, uint_t length, struct vm_device * dev) {
453     struct pic_internal * state = (struct pic_internal*)dev->private_data;
454     char cw = *(char *)src;    
455
456     if (length != 1) {
457       PrintDebug("8259 PIC: Invalid write length (wr_Slave2)\n");
458       return -1;
459     }
460
461     if (state->slave_state == ICW2) {
462       struct icw1 * cw1 =  (struct icw1 *)&(state->master_icw1);
463
464       state->slave_icw2 = cw;
465
466       if (cw1->sngl == 0) {
467         state->slave_state = ICW3;
468       } else if (cw1->ic4 == 1) {
469         state->slave_state = ICW4;
470       } else {
471         state->slave_state = READY;
472       }
473
474     } else if (state->slave_state == ICW3) {
475       struct icw1 * cw1 =  (struct icw1 *)&(state->master_icw1);
476
477       state->slave_icw3 = cw;
478
479       if (cw1->ic4 == 1) {
480         state->slave_state = ICW4;
481       } else {
482         state->slave_state = READY;
483       }
484
485     } else if (state->slave_state == ICW4) {
486       state->slave_icw4 = cw;
487       state->slave_state = READY;
488     } else if (state->slave_state == READY) {
489       state->slave_imr = cw;
490     } else {
491       PrintDebug("8259 PIC: Invalid State at write (wr_Slave2)\n");
492       return -1;
493     }
494
495     return 1;
496 }
497
498
499
500
501
502
503
504
505 int pic_init(struct vm_device * dev) {
506   struct pic_internal * state = (struct pic_internal*)dev->private_data;
507
508   set_intr_controller(dev->vm, &intr_ops, state);
509
510   state->master_irr = 0;
511   state->master_isr = 0;
512   state->master_icw1 = 0;
513   state->master_icw2 = 0;
514   state->master_icw3 = 0;
515   state->master_icw4 = 0;
516   state->master_imr = 0;
517   state->master_ocw2 = 0;
518   state->master_ocw3 = 0x02;
519   state->master_state = ICW1;
520
521
522   state->slave_irr = 0;
523   state->slave_isr = 0;
524   state->slave_icw1 = 0;
525   state->slave_icw2 = 0;
526   state->slave_icw3 = 0;
527   state->slave_icw4 = 0;
528   state->slave_imr = 0;
529   state->slave_ocw2 = 0;
530   state->slave_ocw3 = 0x02;
531   state->slave_state = ICW1;
532
533
534   dev_hook_io(dev, MASTER_PORT1, &read_master_port1, &write_master_port1);
535   dev_hook_io(dev, MASTER_PORT2, &read_master_port2, &write_master_port2);
536   dev_hook_io(dev, SLAVE_PORT1, &read_slave_port1, &write_slave_port1);
537   dev_hook_io(dev, SLAVE_PORT2, &read_slave_port2, &write_slave_port2);
538
539   return 0;
540 }
541
542
543 int pic_deinit(struct vm_device * dev) {
544   dev_unhook_io(dev, MASTER_PORT1);
545   dev_unhook_io(dev, MASTER_PORT2);
546   dev_unhook_io(dev, SLAVE_PORT1);
547   dev_unhook_io(dev, SLAVE_PORT2);
548
549   return 0;
550 }
551
552
553
554
555
556
557
558 static struct vm_device_ops dev_ops = {
559   .init = pic_init,
560   .deinit = pic_deinit,
561   .reset = NULL,
562   .start = NULL,
563   .stop = NULL,
564 };
565
566
567 struct vm_device * create_pic() {
568   struct pic_internal * state = NULL;
569   state = (struct pic_internal *)V3_Malloc(sizeof(struct pic_internal));
570   V3_ASSERT(state != NULL);
571
572   struct vm_device *device = create_device("8259A", &dev_ops, state);
573
574   return device;
575 }
576
577
578
579