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.


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