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.


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