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.


8259 PIC corrections and cleanup
[palacios.git] / palacios / src / devices / 8259a.c
1 /*
2  * This file is part of the Palacios Virtual Machine Monitor developed
3  * by the V3VEE Project with funding from the United States National 
4  * Science Foundation and the Department of Energy.  
5  *
6  * The V3VEE Project is a joint project between Northwestern University
7  * and the University of New Mexico.  You can find out more at 
8  * http://www.v3vee.org
9  *
10  * Copyright (c) 2008, Jack Lange <jarusl@cs.northwestern.edu> 
11  * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org> 
12  * All rights reserved.
13  *
14  * Author: Jack Lange <jarusl@cs.northwestern.edu>
15  *
16  * This is free software.  You are permitted to use,
17  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
18  */
19
20
21
22 #include <palacios/vmm_intr.h>
23 #include <palacios/vmm_types.h>
24 #include <palacios/vmm.h>
25 #include <palacios/vmm_dev_mgr.h>
26 #include <palacios/vm_guest.h>
27
28 #ifndef V3_CONFIG_DEBUG_PIC
29 #undef PrintDebug
30 #define PrintDebug(fmt, args...)
31 #endif
32
33
34 typedef enum {RESET, ICW1, ICW2, ICW3, ICW4,  READY} pic_state_t;
35
36 static const uint_t MASTER_PORT1 = 0x20;
37 static const uint_t MASTER_PORT2 = 0x21;
38 static const uint_t SLAVE_PORT1 = 0xA0;
39 static const uint_t SLAVE_PORT2 = 0xA1;
40
41 static const uint_t ELCR1_PORT = 0x4d0;
42 static const uint_t ELCR2_PORT = 0x4d1;
43
44
45 #define IS_ICW1(x) (((x & 0x10) >> 4) == 0x1)
46 #define IS_OCW2(x) (((x & 0x18) >> 3) == 0x0)
47 #define IS_OCW3(x) (((x & 0x18) >> 3) == 0x1)
48
49
50 struct icw1 {
51     uint_t ic4    : 1;  // ICW4 has to be read
52     uint_t sngl   : 1;  // single (only one PIC)
53     uint_t adi    : 1;  // call address interval
54     uint_t ltim   : 1;  // level interrupt mode
55     uint_t one    : 1;
56     uint_t rsvd   : 3;
57 };
58
59
60 struct icw2 {
61     uint_t rsvd   : 3;
62     uint_t vector : 5;
63 };
64
65
66 // Each bit that is set indicates that the IR input has a slave
67 struct icw3_master {
68     uint_t S0   : 1;
69     uint_t S1   : 1;
70     uint_t S2   : 1;
71     uint_t S3   : 1;
72     uint_t S4   : 1;
73     uint_t S5   : 1;
74     uint_t S6   : 1;
75     uint_t S7   : 1;
76 };
77
78 // The ID is the Slave device ID
79 struct icw3_slave {
80     uint_t id     : 3;
81     uint_t zeroes : 5;
82 };
83
84 struct icw4 {
85     uint_t uPM    : 1;  // 1=x86
86     uint_t AEOI   : 1;  // Automatic End of Interrupt
87     uint_t M_S    : 1;  // only if buffered 1=master,0=slave 
88     uint_t BUF    : 1;  // buffered mode
89     uint_t SFNM   : 1;  // special fully nexted mode
90     uint_t zeroes : 3;
91 };
92
93
94 struct ocw1 {
95     uint_t m0     : 1;
96     uint_t m1     : 1;
97     uint_t m2     : 1;
98     uint_t m3     : 1;
99     uint_t m4     : 1;
100     uint_t m5     : 1;
101     uint_t m6     : 1;
102     uint_t m7     : 1;
103 };
104
105 struct ocw2 {
106     uint_t level  : 3;
107     uint_t cw_code : 2; // should be 00
108     uint_t EOI    : 1;
109     uint_t SL     : 1;
110     uint_t R      : 1;
111 };
112
113 struct ocw3 {
114     uint_t RIS    : 1;
115     uint_t RR     : 1;
116     uint_t P      : 1;
117     uint_t cw_code : 2; // should be 01
118     uint_t smm    : 1;
119     uint_t esmm   : 1;
120     uint_t zero2  : 1;
121 };
122
123
124 struct pic_internal {
125
126
127     uint8_t master_irr;
128     uint8_t slave_irr;
129   
130     uint8_t master_isr;
131     uint8_t slave_isr;
132
133     uint8_t master_elcr;
134     uint8_t slave_elcr;
135     uint8_t master_elcr_mask;
136     uint8_t slave_elcr_mask;
137
138     uint8_t master_icw1;
139     uint8_t master_icw2;
140     uint8_t master_icw3;
141     uint8_t master_icw4;
142
143
144     uint8_t slave_icw1;
145     uint8_t slave_icw2;
146     uint8_t slave_icw3;
147     uint8_t slave_icw4;
148
149
150     uint8_t master_imr;
151     uint8_t slave_imr;
152     uint8_t master_ocw2;
153     uint8_t master_ocw3;
154     uint8_t slave_ocw2;
155     uint8_t slave_ocw3;
156
157     pic_state_t master_state;
158     pic_state_t slave_state;
159
160     struct guest_info * core;
161
162     struct {
163         int (*ack)(struct guest_info * core, uint32_t irq, void * private_data);
164         void * private_data;
165     } irq_ack_cbs[15];
166
167
168     void * router_handle;
169     void * controller_handle;
170 };
171
172
173 static void DumpPICState(struct pic_internal *p)
174 {
175
176     V3_Print(VM_NONE, VCORE_NONE, "8259 PIC: master_state=0x%x\n",p->master_state);
177     V3_Print(VM_NONE, VCORE_NONE, "8259 PIC: master_irr=0x%x\n",p->master_irr);
178     V3_Print(VM_NONE, VCORE_NONE, "8259 PIC: master_isr=0x%x\n",p->master_isr);
179     V3_Print(VM_NONE, VCORE_NONE, "8259 PIC: master_imr=0x%x\n",p->master_imr);
180
181     V3_Print(VM_NONE, VCORE_NONE, "8259 PIC: master_ocw2=0x%x\n",p->master_ocw2);
182     V3_Print(VM_NONE, VCORE_NONE, "8259 PIC: master_ocw3=0x%x\n",p->master_ocw3);
183
184     V3_Print(VM_NONE, VCORE_NONE, "8259 PIC: master_icw1=0x%x\n",p->master_icw1);
185     V3_Print(VM_NONE, VCORE_NONE, "8259 PIC: master_icw2=0x%x\n",p->master_icw2);
186     V3_Print(VM_NONE, VCORE_NONE, "8259 PIC: master_icw3=0x%x\n",p->master_icw3);
187     V3_Print(VM_NONE, VCORE_NONE, "8259 PIC: master_icw4=0x%x\n",p->master_icw4);
188
189     V3_Print(VM_NONE, VCORE_NONE, "8259 PIC: slave_state=0x%x\n",p->slave_state);
190     V3_Print(VM_NONE, VCORE_NONE, "8259 PIC: slave_irr=0x%x\n",p->slave_irr);
191     V3_Print(VM_NONE, VCORE_NONE, "8259 PIC: slave_isr=0x%x\n",p->slave_isr);
192     V3_Print(VM_NONE, VCORE_NONE, "8259 PIC: slave_imr=0x%x\n",p->slave_imr);
193
194     V3_Print(VM_NONE, VCORE_NONE, "8259 PIC: slave_ocw2=0x%x\n",p->slave_ocw2);
195     V3_Print(VM_NONE, VCORE_NONE, "8259 PIC: slave_ocw3=0x%x\n",p->slave_ocw3);
196
197     V3_Print(VM_NONE, VCORE_NONE, "8259 PIC: slave_icw1=0x%x\n",p->slave_icw1);
198     V3_Print(VM_NONE, VCORE_NONE, "8259 PIC: slave_icw2=0x%x\n",p->slave_icw2);
199     V3_Print(VM_NONE, VCORE_NONE, "8259 PIC: slave_icw3=0x%x\n",p->slave_icw3);
200     V3_Print(VM_NONE, VCORE_NONE, "8259 PIC: slave_icw4=0x%x\n",p->slave_icw4);
201
202 }
203
204
205 static int pic_vec_to_irq(struct guest_info *info, struct pic_internal *state, int vec)
206 {
207   if ((vec >= state->master_icw2) && (vec <= state->master_icw2 + 7)) {
208     return vec & 0x7;
209   } else if ((vec >= state->slave_icw2) && (vec <= state->slave_icw2 + 7)) {
210     return (vec & 0x7) + 8;
211   } else {
212     // Note that this is not an error since there may also be IOAPICs 
213     PrintDebug(info->vm_info, info, "8259 PIC: Cannot translate vector %d back to an IRQ I support\n",vec);
214     return -1;
215   }
216 }
217
218 static int pic_irq_to_vec(struct guest_info *info, struct pic_internal *state, int irq)
219 {
220   if (irq<0) { 
221     return -1;
222   }
223
224   // This will treat IRQ2 as occuring on the master, 
225   // not on slave IRQ9 as expected for legacy behavior
226   // We shouldn't see anything attempting to raise IRQ2...
227   if (irq==2) { 
228     PrintError(info->vm_info, info, "8259 PIC: Warning - IRQ 2 is being translated...\n");
229   }
230
231   if (irq<=7) { 
232     return irq + state->master_icw2;
233   } else if (irq<=15) { 
234     return (irq-8) + state->slave_icw2;
235   } else {
236     PrintDebug(info->vm_info, info, "8259 PIC: Warning: IRQ %d is being translated, but only IRQs 0..15 are supported\n",irq);
237     return -1;
238   }
239     
240 }
241
242
243 static int pic_raise_intr(struct v3_vm_info * vm, void * private_data, struct v3_irq * irq) {
244     struct pic_internal * state = (struct pic_internal*)private_data;
245     uint8_t irq_num = irq->irq;
246
247     if (irq_num == 2) {
248         PrintError(vm, VCORE_NONE, "8259 PIC: Warning - IRQ 2 is being raised...\n");
249         // This is the legacy reroute of IRQ2 to IRQ9
250         irq_num = 9;
251     }
252
253     PrintDebug(vm, VCORE_NONE, "8259 PIC: Raising irq %d in the PIC\n", irq_num);
254
255     if (irq_num <= 7) {
256       state->master_irr |= 0x01 << irq_num;
257       PrintDebug(vm, VCORE_NONE, "8259 PIC: Master: Raising IRQ %d\n",irq_num);
258     } else if ((irq_num > 7) && (irq_num < 16)) {
259       state->slave_irr |= 0x01 << (irq_num - 8);
260       state->master_irr |= 0x04;   // immediately signal to the master pin we're attached to
261       PrintDebug(vm, VCORE_NONE, "8259 PIC: Master + Slave: Raising IRQ %d\n",irq_num);
262     } else {
263       // This is not an error as the system could have other interrupt controllers
264       PrintDebug(vm, VCORE_NONE, "8259 PIC: Ignoring raise of IRQ %d as it is not supported by the PIC\n", irq_num);
265       return 0;
266     }
267
268     state->irq_ack_cbs[irq_num].ack = irq->ack;
269     state->irq_ack_cbs[irq_num].private_data = irq->private_data;
270
271     if (V3_Get_CPU() != vm->cores[0].pcpu_id) {
272         // guest is running on another core, interrupt it to deliver irq
273         v3_interrupt_cpu(vm, 0, 0);
274     }
275
276     return 0;
277 }
278
279
280 static int pic_lower_intr(struct v3_vm_info * vm, void * private_data, struct v3_irq * irq) {
281     struct pic_internal * state = (struct pic_internal*)private_data;
282     uint8_t irq_num = irq->irq;
283
284     if (irq_num == 2) {
285       PrintError(vm, VCORE_NONE, "8259 PIC: Warning - IRQ 2 is being lowered...\n");
286       // Legacy reroute of IRQ2 to IRQ9
287       irq_num = 9;
288     }
289     
290     PrintDebug(vm, VCORE_NONE, "8259 PIC: [pic_lower_intr] IRQ line %d now low\n", irq_num);
291
292     if (irq_num <= 7) {
293         // master
294         PrintDebug(vm, VCORE_NONE, "8259 PIC: Master: IRQ line %d lowered\n", irq_num);
295         state->master_irr &= ~(1 << irq_num);
296         // Note that another interrupt may still be in the IRR, but that's OK
297         // We'll recognize it on the next entry
298     } else if ((irq_num > 7) && (irq_num < 16)) {
299         // slave
300         PrintDebug(vm, VCORE_NONE, "8259 PIC: Slave: IRQ line %d lowered\n", irq_num);
301         state->slave_irr &= ~(1 << (irq_num - 8));
302         if ((state->slave_irr & (~(state->slave_imr))) == 0) {
303           // If there is no other slave interrupt available, we can
304           // turn off IRQ2 on the master
305           PrintDebug(vm, VCORE_NONE, "8259 PIC: Master: IRQ line 2 also lowered due to no other interrupts pending in slave\n");
306           state->master_irr &= ~(0x04);
307         }
308     } else {
309       // This is not an error as the system could have other interrupt controllers
310       PrintDebug(vm, VCORE_NONE, "8259 PIC: Ignoring lower of IRQ %d as it is not supported by the PIC\n",irq_num);
311     }
312
313     return 0;
314 }
315
316
317
318 static int pic_intr_pending_from_master(struct guest_info * info, void * private_data) {
319     struct pic_internal * state = (struct pic_internal*)private_data;
320
321     return state->master_irr & (~(state->master_imr));
322 }
323
324 static int pic_intr_pending_from_slave(struct guest_info * info, void * private_data) {
325     struct pic_internal * state = (struct pic_internal*)private_data;
326
327     return (!(state->master_imr & 0x4)) &&                // master has slave unmasked and
328               (state->slave_irr & (~(state->slave_imr))); // slave is pending
329 }
330
331 static int pic_intr_pending(struct guest_info * info, void * private_data) {
332
333     return pic_intr_pending_from_master(info,private_data) || 
334            pic_intr_pending_from_slave(info,private_data);
335 }
336
337 /*
338   8259 prioritization is oddball since there are two chips.  The 
339   slave chip signals an interrupt through pin 2 of the master chip.  
340   This means that all the slave chip's pins are actually at a higher priority
341   than pins 3..7 of the master.   The scheme is as follows, from highest
342   to lowest priority, including legacy mappings:
343  
344   Master  Slave    Typical Legacy Use
345   --------------------------------------------------------------
346   IRQ0             Timer (8254)
347   IRQ1             Keyboard (8042)
348   IRQ2              ****NOT USED - Slave chip inputs here
349           IRQ8     RTC
350           IRQ9     VGA / previous IRQ2 (or PCI via PIRQ LINK B)
351           IRQ10    unused (or PCI via PIRQ LINK C)
352           IRQ11    unused (or PCI via PIRQ LINK D)
353           IRQ12    PS/2 Mouse (8042)
354           IRQ13    Coprocessor error
355           IRQ14    First IDE controller
356           IRQ15    Second IDE controller
357   IRQ3             Second and Fourth Serial Port (COM2/4)
358   IRQ4             First and Third serial port (COM1/3)
359   IRQ5             Second Parallel Port (or PCI via PIRQ LINK A)
360   IRQ6             Floppy controller
361   IRQ7             First Parallel Port
362
363 */
364
365 static int pic_get_intr_number(struct guest_info * info, void * private_data) {
366     struct pic_internal * state = (struct pic_internal *)private_data;
367     int i = 0;
368     int vec = -1;
369
370     PrintDebug(info->vm_info, info, "8259 PIC: getnum: master_irr: 0x%x master_imr: 0x%x\n", state->master_irr, state->master_imr);
371     PrintDebug(info->vm_info, info, "8259 PIC: getnum: slave_irr: 0x%x slave_imr: 0x%x\n", state->slave_irr, state->slave_imr);
372
373     // First, see if we have something upstream of the slave
374     for (i=0;i<2;i++) {
375       // Interrupt requested and not masked
376       if (((state->master_irr & ~(state->master_imr)) >> i) & 0x01) {
377         PrintDebug(info->vm_info, info, "8259 PIC: IRQ: %d, master_icw2: %x\n", i, state->master_icw2);
378         vec = pic_irq_to_vec(info, state, i);
379         if (vec<0) { 
380           PrintError(info->vm_info, info, "8259 PIC: Master Interrupt Ready, but vector=%d\n",vec); 
381         }
382         break;
383       }
384     }
385     
386     // Next, the slave
387     if (vec<0 &&                      // Nothing upstream and
388         !(state->master_imr & 0x4)) { // Master is not masking the slave 
389       for (i = 8; i < 16; i++) {
390         if (((state->slave_irr & ~(state->slave_imr)) >> (i - 8)) & 0x01) {
391           PrintDebug(info->vm_info, info, "8259 PIC: IRQ: %d, slave_icw2: %x\n", i, state->slave_icw2);
392           vec = pic_irq_to_vec(info, state, i);
393           if (vec<0) { 
394             PrintError(info->vm_info, info, "8259 PIC: Slave Interrupt Readby, but vector=%d\n",vec); 
395           }
396           break;
397         }
398       }
399     }
400
401     // And finally the master downstream of the slave
402     if (vec<0) {
403       for (i = 3; i < 8; i++) {
404         if (((state->master_irr & ~(state->master_imr)) >> i) & 0x01) {
405           PrintDebug(info->vm_info, info, "8259 PIC: IRQ: %d, master_icw2: %x\n", i, state->master_icw2);
406           vec = pic_irq_to_vec(info, state, i);
407           if (vec<0) { 
408             PrintError(info->vm_info, info, "8259 PIC: Master Interrupt Ready in 2nd pass, but vector=%d\n",vec);
409           }
410           break;
411         }
412       }
413     }
414   
415     if (vec>=0) {
416       PrintDebug(info->vm_info, info, "8259 PIC: get num is returning vector %d\n",vec);
417     } else {
418       PrintDebug(info->vm_info, info, "8259 PIC: no vector available\n");
419     }
420     
421     return vec;
422 }
423
424
425
426
427 /* The vec number is the number returned by pic_get_irq_number(), not the pin number. */
428 /* In other words, it's the INT vector the PIC is feeding the processor                */
429 static int pic_begin_irq(struct guest_info * info, void * private_data, int vec) {
430   struct pic_internal * state = (struct pic_internal*)private_data;
431   int irq;
432   
433   irq = pic_vec_to_irq(info,state,vec);
434   
435   if (irq<0) { 
436     // Not an error - could be for other interrupt controller
437     PrintDebug(info->vm_info,info,"8259 PIC: Ignoring begin_irq on vector %d since it's not ours\n", vec);
438     return 0;
439   }
440   
441   if (irq <= 7) {
442     // Master
443     PrintDebug(info->vm_info, info, "8259 PIC: Master: Beginning IRQ %d\n",irq);
444     // This should always be true: See pic_get_irq_number
445     if (((state->master_irr & (~(state->master_imr))) >> irq) & 0x01) {
446       // unmasked - let's start it
447       state->master_isr |= (0x1 << irq);
448       // auto reset the request if the elcr has this as edge-triggered
449       if (!(state->master_elcr & (0x1 << irq))) {
450         state->master_irr &= ~(0x1 << irq);
451       }
452     } else {
453       PrintDebug(info->vm_info, info, "8259 PIC: Master: Ignoring begin_irq vector %d since I either do not see it set or have it masked (mnaster_irr=0x%x, master_imr=0x%x\n", irq, state->master_irr, state->master_imr);
454     }
455   } else if (irq>=8 && irq<=15)  {
456     // Slave
457     PrintDebug(info->vm_info, info, "8259 PIC: Master + Slave: Beginning IRQ %d\n",irq);
458     // This should always be true: See pic_get_irq_number
459     if (((state->slave_irr & (~(state->slave_imr))) >> (irq - 8)) & 0x01) {
460       // unmasked - so let's start it in the slave
461       state->slave_isr |= (0x1 << (irq - 8));
462       // We must have previously pushed it to the master's irr,
463       // so all we need to do here is put it in service there too
464       state->master_isr |= 0x4; // pin 2 is where the slave attaches
465       
466       // auto-reset the request in the slave if it's marked as edge-triggered
467       if (!(state->slave_elcr & (0x1 << (irq - 8)))) {
468         state->slave_irr &= ~(0x1 << (irq - 8));
469       }
470       
471       // auto-reset the request in pin 2 of the master if it's marked as edge-trigged
472       if (!(state->master_elcr & 0x04)) {
473         state->master_irr &= ~0x04;
474       }
475     } else {
476       PrintDebug(info->vm_info, info, "8259 PIC: Maser + Slave: Ignoring begin_irq for %d since I either don't see it set or I don't own it (master_irr=0x%x, master_imr=0x%x, slave_irr=0x%x, slave_imr=0x%x\n", irq,state->master_irr, state->master_imr, state->slave_irr, state->slave_imr);
477     }
478   } else {
479     PrintDebug(info->vm_info, info, "8259 PIC: Ignoring begin_irq for %d since I don't own it\n", irq);
480   }
481
482   return 0;
483 }
484
485
486 /*
487   static int pic_end_irq(void * private_data, int irq) {
488   return 0;
489   }
490 */
491
492
493
494 static struct intr_ctrl_ops intr_ops = {
495     .intr_pending = pic_intr_pending,
496     .get_intr_number = pic_get_intr_number,
497     .begin_irq = pic_begin_irq
498 };
499
500 static struct intr_router_ops router_ops = {
501     .raise_intr = pic_raise_intr,
502     .lower_intr = pic_lower_intr
503 };
504
505
506 static int read_master_port1(struct guest_info * core, ushort_t port, void * dst, uint_t length, void * priv_data) {
507     struct pic_internal * state = (struct pic_internal *)priv_data;
508
509     if (length != 1) {
510         PrintError(core->vm_info, core, "8259 PIC: Master: Invalid Read length (rd_Master1)\n");
511         return -1;
512     }
513   
514     if ((state->master_ocw3 & 0x03) == 0x02) {
515         *(uint8_t *)dst = state->master_irr;
516     } else if ((state->master_ocw3 & 0x03) == 0x03) {
517         *(uint8_t *)dst = state->master_isr;
518     } else {
519         *(uint8_t *)dst = 0;
520     }
521   
522     return 1;
523 }
524
525 static int read_master_port2(struct guest_info * core, ushort_t port, void * dst, uint_t length, void * priv_data) {
526     struct pic_internal * state = (struct pic_internal *)priv_data;
527
528     if (length != 1) {
529         PrintError(core->vm_info, core, "8259 PIC: Master: Invalid Read length (rd_Master2)\n");
530         return -1;
531     }
532
533     *(uint8_t *)dst = state->master_imr;
534
535     return 1;
536   
537 }
538
539 static int read_slave_port1(struct guest_info * core, ushort_t port, void * dst, uint_t length, void * priv_data) {
540     struct pic_internal * state = (struct pic_internal *)priv_data;
541
542     if (length != 1) {
543         PrintError(core->vm_info, core, "8259 PIC: Slave: Invalid Read length (rd_Slave1)\n");
544         return -1;
545     }
546   
547     if ((state->slave_ocw3 & 0x03) == 0x02) {
548         *(uint8_t*)dst = state->slave_irr;
549     } else if ((state->slave_ocw3 & 0x03) == 0x03) {
550         *(uint8_t *)dst = state->slave_isr;
551     } else {
552         *(uint8_t *)dst = 0;
553     }
554
555     return 1;
556 }
557
558 static int read_slave_port2(struct guest_info * core, ushort_t port, void * dst, uint_t length, void * priv_data) {
559     struct pic_internal * state = (struct pic_internal *)priv_data;
560
561     if (length != 1) {
562         PrintError(core->vm_info, core, "8259 PIC: Slave: Invalid Read length  (rd_Slave2)\n");
563         return -1;
564     }
565
566     *(uint8_t *)dst = state->slave_imr;
567
568     return 1;
569 }
570
571
572 static int write_master_port1(struct guest_info * core, ushort_t port, void * src, uint_t length, void * priv_data) {
573     struct pic_internal * state = (struct pic_internal *)priv_data;
574     uint8_t cw = *(uint8_t *)src;
575
576     PrintDebug(core->vm_info, core, "8259 PIC: Master: Write port 1 with 0x%x\n",cw);
577
578     if (length != 1) {
579         PrintError(core->vm_info, core, "8259 PIC: Master: Invalid Write length (wr_Master1)\n");
580         return -1;
581     }
582
583     v3_clear_pending_intr(core);
584
585     if (IS_ICW1(cw)) {
586
587         PrintDebug(core->vm_info, core, "8259 PIC: Master: Setting ICW1 = %x (wr_Master1)\n", cw);
588
589         state->master_icw1 = cw;
590         state->master_state = ICW2;
591
592     } else if (state->master_state == READY) {
593         if (IS_OCW2(cw)) {
594             // handle the EOI here
595             struct ocw2 * cw2 =  (struct ocw2*)&cw;
596             int eoi_irq;
597
598             PrintDebug(core->vm_info, core, "8259 PIC: Master: Handling OCW2 = %x (wr_Master1)\n", cw);
599
600             if ((cw2->EOI) && (!cw2->R) && (cw2->SL)) {
601                 // specific EOI;
602                 state->master_isr &= ~(0x01 << cw2->level);
603                 eoi_irq = cw2->level;
604
605                 /*
606                 // ack the irq if requested
607                 if (state->irq_ack_cbs[irq].ack) {
608                     state->irq_ack_cbs[irq].ack(info, irq, state->irq_ack_cbs[irq].private_data);
609                 }
610                 */
611
612             } else if ((cw2->EOI) & (!cw2->R) && (!cw2->SL)) {
613                 int i;
614                 // Non-specific EOI
615                 PrintDebug(core->vm_info, core, "8259 PIC: Master: Pre ISR = %x (wr_Master1)\n", state->master_isr);
616                 for (i = 0; i < 8; i++) {
617                     if (state->master_isr & (0x01 << i)) {
618                         state->master_isr &= ~(0x01 << i);
619                         eoi_irq=i;
620                         break;
621                     }
622                 }
623                 if (i==8) { 
624                   PrintDebug(core->vm_info, core, "8259 PIC: Master: Strange... non-specific EOI but no in-service interrupts\n");
625                 }
626                 
627                 PrintDebug(core->vm_info, core, "8259 PIC: Master: Post ISR = %x (wr_Master1)\n", state->master_isr);
628             } else if (!(cw2->EOI) && (cw2->R) && (cw2->SL)) {
629                 PrintDebug(core->vm_info, core, "8259 PIC: Master: Ignoring set-priority, priorities not implemented (level=%d, wr_Master1)\n", cw2->level);
630             } else if (!(cw2->EOI) && !(cw2->R) && (cw2->SL)) {
631                 PrintDebug(core->vm_info, core, "8259 PIC: Master: Ignoring no-op (level=%d, wr_Master1)\n", cw2->level);
632             } else {
633                 PrintError(core->vm_info, core, "8259 PIC: Master: Command not handled, or in error (wr_Master1)\n");
634                 return -1;
635             }
636
637             if (cw2->EOI) {
638               if (pic_intr_pending_from_master(core,state)) {
639                 // this is perfectly fine as there may be other latched interrupts
640                 // but it would be strange if the one we just cleared is suddenly
641                 // alive again - well, depending on concurrent behavior external to 
642                 int irq = pic_vec_to_irq(core,state,pic_get_intr_number(core,state));
643
644                 if (irq == eoi_irq) { 
645           // Not necessarily an error, since it could have been raised again in another thread...
646                   PrintError(core->vm_info, core, "8259 PIC: Master: IRQ %d pending after EOI of IRQ %d\n", irq,eoi_irq);
647                   DumpPICState(state);
648                 }
649               }
650             }
651             
652             state->master_ocw2 = cw;
653         } else if (IS_OCW3(cw)) {
654           PrintDebug(core->vm_info, core, "8259 PIC: Master: Handling OCW3 = %x (wr_Master1)\n", cw);
655           state->master_ocw3 = cw;
656         } else {
657           PrintError(core->vm_info, core, "8259 PIC: Master: Invalid OCW to PIC (wr_Master1)\n");
658           PrintError(core->vm_info, core, "8259 PIC: Master: CW=%x\n", cw);
659           return -1;
660         }
661     } else {
662       PrintError(core->vm_info, core, "8259 PIC: Master: Invalid PIC State (wr_Master1)\n");
663       PrintError(core->vm_info, core, "8259 PIC: Master: CW=%x\n", cw);
664       return -1;
665     }
666     
667     return 1;
668 }
669
670 static int write_master_port2(struct guest_info * core, ushort_t port, void * src, uint_t length, void * priv_data) {
671   struct pic_internal * state = (struct pic_internal *)priv_data;
672   uint8_t cw = *(uint8_t *)src;    
673   
674   PrintDebug(core->vm_info, core, "8259 PIC: Master: Write master port 2 with 0x%x\n",cw);
675
676   if (length != 1) {
677     PrintError(core->vm_info, core, "8259 PIC: Master: Invalid Write length (wr_Master2)\n");
678         return -1;
679     }
680
681     v3_clear_pending_intr(core);
682
683     if (state->master_state == ICW2) {
684         struct icw1 * cw1 = (struct icw1 *)&(state->master_icw1);
685
686         PrintDebug(core->vm_info, core, "8259 PIC: Master: Setting ICW2 = %x (wr_Master2)\n", cw);
687         state->master_icw2 = cw;
688
689
690
691         if (cw1->sngl == 0) {
692             state->master_state = ICW3;
693         } else if (cw1->ic4 == 1) {
694             state->master_state = ICW4;
695         } else {
696             state->master_state = READY;
697         }
698
699
700
701     } else if (state->master_state == ICW3) {
702         struct icw1 * cw1 = (struct icw1 *)&(state->master_icw1);
703
704         PrintDebug(core->vm_info, core, "8259 PIC: Master: Setting ICW3 = %x (wr_Master2)\n", cw);
705
706         state->master_icw3 = cw;
707
708         if (cw1->ic4 == 1) {
709             state->master_state = ICW4;
710         } else {
711             state->master_state = READY;
712         }
713
714     } else if (state->master_state == ICW4) {
715         PrintDebug(core->vm_info, core, "8259 PIC: Master: Setting ICW4 = %x (wr_Master2)\n", cw);
716         state->master_icw4 = cw;
717         state->master_state = READY;
718     } else if ((state->master_state == ICW1) || (state->master_state == READY)) {
719         PrintDebug(core->vm_info, core, "8259 PIC: Master: Setting IMR = %x (wr_Master2)\n", cw);
720         state->master_imr = cw;
721     } else {
722         // error
723         PrintError(core->vm_info, core, "8259 PIC: Master: Invalid master PIC State (wr_Master2) (state=%d)\n", 
724                 state->master_state);
725         return -1;
726     }
727
728     return 1;
729 }
730
731 static int write_slave_port1(struct guest_info * core, ushort_t port, void * src, uint_t length, void * priv_data) {
732     struct pic_internal * state = (struct pic_internal *)priv_data;
733     uint8_t cw = *(uint8_t *)src;
734
735     PrintDebug(core->vm_info, core, "8259 PIC: Slave: Write slave port 1 with 0x%x\n",cw);
736
737     if (length != 1) {
738         // error
739         PrintError(core->vm_info, core, "8259 PIC: Slave: Invalid Write length (wr_Slave1)\n");
740         return -1;
741     }
742
743     v3_clear_pending_intr(core);
744
745     if (IS_ICW1(cw)) {
746         PrintDebug(core->vm_info, core, "8259 PIC: Slave: Setting ICW1 = %x (wr_Slave1)\n", cw);
747         state->slave_icw1 = cw;
748         state->slave_state = ICW2;
749     } else if (state->slave_state == READY) {
750         if (IS_OCW2(cw)) {
751             int eoi_irq;
752             // handle the EOI here
753             struct ocw2 * cw2 =  (struct ocw2 *)&cw;
754
755             PrintDebug(core->vm_info, core, "8259 PIC: Slave: Setting OCW2 = %x (wr_Slave1)\n", cw);
756
757             if ((cw2->EOI) && (!cw2->R) && (cw2->SL)) {
758                 // specific EOI;
759                 state->slave_isr &= ~(0x01 << cw2->level);
760                 eoi_irq = 8+cw2->level;
761             } else if ((cw2->EOI) & (!cw2->R) && (!cw2->SL)) {
762                 int i;
763                 // Non-specific EOI
764                 PrintDebug(core->vm_info, core, "8259 PIC: Slave: Pre ISR = %x (wr_Slave1)\n", state->slave_isr);
765                 for (i = 0; i < 8; i++) {
766                     if (state->slave_isr & (0x01 << i)) {
767                         state->slave_isr &= ~(0x01 << i);
768                         eoi_irq=8+i;
769                         break;
770                     }
771                 }
772                 if (i==8) { 
773                   PrintDebug(core->vm_info, core, "8259 PIC: Slave: Strange... non-specific EOI but no in-service interrupts\n");
774                 }
775                 PrintDebug(core->vm_info, core, "8259 PIC: Slave: Post ISR = %x (wr_Slave1)\n", state->slave_isr);
776             } else {
777                 PrintError(core->vm_info, core, "8259 PIC: Slave: Command not handled or invalid  (wr_Slave1)\n");
778                 return -1;
779             }
780
781             // If we now have no further requested interrupts, 
782             // we are not requesting from the master either
783             if (!(state->slave_irr)) { 
784               state->master_irr &= ~0x04;
785             }
786
787             if (cw2->EOI) {
788                 if (pic_intr_pending_from_slave(core,state)) {
789                   // this is perfectly fine as there may be other latched interrupts
790                   // but it would be strange if the one we just cleared is suddenly
791                   // alive again - well, depending on concurrent behavior external to 
792                   int irq = pic_vec_to_irq(core,state,pic_get_intr_number(core,state));
793                   
794                   if (irq == eoi_irq) { 
795                     // Not necessarily an error, since it could have been raised again in another thread.
796             PrintError(core->vm_info, core, "8259 PIC: Slave: IRQ %d pending after EOI of IRQ %d\n", irq,eoi_irq);
797                     DumpPICState(state);
798                   }
799                 }
800             }
801
802             state->slave_ocw2 = cw;
803         } else if (IS_OCW3(cw)) {
804             // Basically sets the IRR/ISR read flag
805             PrintDebug(core->vm_info, core, "8259 PIC: Slave: Setting OCW3 = %x (wr_Slave1)\n", cw);
806             state->slave_ocw3 = cw;
807         } else {
808             PrintError(core->vm_info, core, "8259 PIC: Slave: Invalid command work (wr_Slave1)\n");
809             return -1;
810         }
811     } else {
812         PrintError(core->vm_info, core, "8259 PIC: Slave: Invalid State writing (wr_Slave1)\n");
813         return -1;
814     }
815
816     return 1;
817 }
818
819 static int write_slave_port2(struct guest_info * core, ushort_t port, void * src, uint_t length, void * priv_data) {
820     struct pic_internal * state = (struct pic_internal *)priv_data;
821     uint8_t cw = *(uint8_t *)src;    
822
823     PrintDebug(core->vm_info, core, "8259 PIC: Slave: Write slave port 2 with 0x%x\n",cw);
824
825     if (length != 1) {
826         PrintError(core->vm_info, core, "8259 PIC: Slave: Invalid write length (wr_Slave2)\n");
827         return -1;
828     }
829
830     v3_clear_pending_intr(core);
831
832
833     if (state->slave_state == ICW2) {
834         struct icw1 * cw1 =  (struct icw1 *)&(state->master_icw1);
835
836         PrintDebug(core->vm_info, core, "8259 PIC: Slave: Setting ICW2 = %x (wr_Slave2)\n", cw);
837
838         state->slave_icw2 = cw;
839
840         if (cw1->sngl == 0) {
841             state->slave_state = ICW3;
842         } else if (cw1->ic4 == 1) {
843             state->slave_state = ICW4;
844         } else {
845             state->slave_state = READY;
846         }
847
848     } else if (state->slave_state == ICW3) {
849         struct icw1 * cw1 =  (struct icw1 *)&(state->master_icw1);
850
851         PrintDebug(core->vm_info, core, "8259 PIC: Slave: Setting ICW3 = %x (wr_Slave2)\n", cw);
852
853         state->slave_icw3 = cw;
854
855         if (cw1->ic4 == 1) {
856             state->slave_state = ICW4;
857         } else {
858             state->slave_state = READY;
859         }
860
861     } else if (state->slave_state == ICW4) {
862         PrintDebug(core->vm_info, core, "8259 PIC: Slave: Setting ICW4 = %x (wr_Slave2)\n", cw);
863         state->slave_icw4 = cw;
864         state->slave_state = READY;
865     } else if ((state->slave_state == ICW1) || (state->slave_state == READY)) {
866         PrintDebug(core->vm_info, core, "8259 PIC: Slave: Setting IMR = %x (wr_Slave2)\n", cw);
867         state->slave_imr = cw;
868     } else {
869         PrintError(core->vm_info, core, "8259 PIC: Slave: Invalid State at write (wr_Slave2)\n");
870         return -1;
871     }
872
873     return 1;
874 }
875
876
877
878
879 static int read_elcr_port(struct guest_info * core, ushort_t port, void * dst, uint_t length, void * priv_data) {
880     struct pic_internal * state = (struct pic_internal *)priv_data;
881     
882     if (length != 1) {
883         PrintError(core->vm_info, core, "8259 PIC: ELCR read of invalid length %d\n", length);
884         return -1;
885     }
886
887     if (port == ELCR1_PORT) {
888         // master
889         *(uint8_t *)dst = state->master_elcr;
890     } else if (port == ELCR2_PORT) {
891         *(uint8_t *)dst = state->slave_elcr;
892     } else {
893         PrintError(core->vm_info, core, "8259 PIC: Invalid port %x\n", port);
894         return -1;
895     }
896
897     return length;
898 }
899
900
901 static int write_elcr_port(struct guest_info * core, ushort_t port, void * src, uint_t length, void * priv_data) {
902     struct pic_internal * state = (struct pic_internal *)priv_data;
903     
904     if (length != 1) {
905         PrintError(core->vm_info, core, "8259 PIC: ELCR read of invalid length %d\n", length);
906         return -1;
907     }
908
909     if (port == ELCR1_PORT) {
910         // master
911         state->master_elcr  = (*(uint8_t *)src) & state->master_elcr_mask;
912     } else if (port == ELCR2_PORT) {
913         state->slave_elcr  = (*(uint8_t *)src) & state->slave_elcr_mask;
914     } else {
915         PrintError(core->vm_info, core, "8259 PIC: Invalid port %x\n", port);
916         return -1;
917     }
918
919     return length;
920 }
921
922
923
924 static int pic_free(struct pic_internal * state) {
925     struct guest_info * core = state->core;
926
927     v3_remove_intr_controller(core, state->controller_handle);
928     v3_remove_intr_router(core->vm_info, state->router_handle);
929
930     V3_Free(state);
931     return 0;
932 }
933
934 #ifdef V3_CONFIG_CHECKPOINT
935 static int pic_save(struct v3_chkpt_ctx * ctx, void * private_data) {
936     struct pic_internal * pic = (struct pic_internal *)private_data;
937
938     V3_CHKPT_SAVE(ctx, "MASTER_IRR", pic->master_irr, savefailout);
939     V3_CHKPT_SAVE(ctx, "SLAVE_IRR", pic->slave_irr, savefailout);
940   
941     V3_CHKPT_SAVE(ctx, "MASTER_ISR", pic->master_isr, savefailout);
942     V3_CHKPT_SAVE(ctx, "SLAVE_ISR", pic->slave_isr, savefailout);
943
944     V3_CHKPT_SAVE(ctx, "MASTER_ELCR", pic->master_elcr, savefailout);
945     V3_CHKPT_SAVE(ctx, "SLAVE_ELCR", pic->slave_elcr, savefailout);
946     V3_CHKPT_SAVE(ctx, "MASTER_ELCR_MASK", pic->master_elcr_mask, savefailout);
947     V3_CHKPT_SAVE(ctx, "SLAVE_ELCR_MASK", pic->slave_elcr_mask, savefailout);
948
949     V3_CHKPT_SAVE(ctx, "MASTER_ICW1", pic->master_icw1, savefailout);
950     V3_CHKPT_SAVE(ctx, "MASTER_ICW2", pic->master_icw2, savefailout);
951     V3_CHKPT_SAVE(ctx, "MASTER_ICW3", pic->master_icw3, savefailout);
952     V3_CHKPT_SAVE(ctx, "MASTER_ICW4", pic->master_icw4, savefailout);
953
954
955     V3_CHKPT_SAVE(ctx, "SLAVE_ICW1", pic->slave_icw1, savefailout);
956     V3_CHKPT_SAVE(ctx, "SLAVE_ICW2", pic->slave_icw2, savefailout);
957     V3_CHKPT_SAVE(ctx, "SLAVE_ICW3", pic->slave_icw3, savefailout);
958     V3_CHKPT_SAVE(ctx, "SLAVE_ICW4", pic->slave_icw4, savefailout);
959
960
961     V3_CHKPT_SAVE(ctx, "MASTER_IMR", pic->master_imr, savefailout);
962     V3_CHKPT_SAVE(ctx, "SLAVE_IMR", pic->slave_imr, savefailout);
963     V3_CHKPT_SAVE(ctx, "MASTER_OCW2", pic->master_ocw2, savefailout);
964     V3_CHKPT_SAVE(ctx, "MASTER_OCW3", pic->master_ocw3, savefailout);
965     V3_CHKPT_SAVE(ctx, "SLAVE_OCW2", pic->slave_ocw2, savefailout);
966     V3_CHKPT_SAVE(ctx, "SLAVE_OCW3", pic->slave_ocw3, savefailout);
967
968     V3_CHKPT_SAVE(ctx, "MASTER_STATE", pic->master_state, savefailout);
969     V3_CHKPT_SAVE(ctx, "SLAVE_STATE", pic->slave_state, savefailout);
970
971     
972     return 0;
973
974  savefailout:
975     PrintError(VM_NONE, VCORE_NONE, "Failed to save PIC\n");
976     return -1;
977
978 }
979
980 static int pic_load(struct v3_chkpt_ctx * ctx, void * private_data) {
981     struct pic_internal * pic = (struct pic_internal *)private_data;
982
983    
984     V3_CHKPT_LOAD(ctx, "MASTER_IRR", pic->master_irr, loadfailout);
985     V3_CHKPT_LOAD(ctx, "SLAVE_IRR", pic->slave_irr, loadfailout);
986   
987     V3_CHKPT_LOAD(ctx, "MASTER_ISR", pic->master_isr, loadfailout);
988     V3_CHKPT_LOAD(ctx, "SLAVE_ISR", pic->slave_isr, loadfailout);
989
990     V3_CHKPT_LOAD(ctx, "MASTER_ELCR", pic->master_elcr, loadfailout);
991     V3_CHKPT_LOAD(ctx, "SLAVE_ELCR", pic->slave_elcr, loadfailout);
992     V3_CHKPT_LOAD(ctx, "MASTER_ELCR_MASK", pic->master_elcr_mask, loadfailout);
993     V3_CHKPT_LOAD(ctx, "SLAVE_ELCR_MASK", pic->slave_elcr_mask, loadfailout);
994
995     V3_CHKPT_LOAD(ctx, "MASTER_ICW1", pic->master_icw1, loadfailout);
996     V3_CHKPT_LOAD(ctx, "MASTER_ICW2", pic->master_icw2, loadfailout);
997     V3_CHKPT_LOAD(ctx, "MASTER_ICW3", pic->master_icw3, loadfailout);
998     V3_CHKPT_LOAD(ctx, "MASTER_ICW4", pic->master_icw4, loadfailout);
999
1000
1001     V3_CHKPT_LOAD(ctx, "SLAVE_ICW1", pic->slave_icw1, loadfailout);
1002     V3_CHKPT_LOAD(ctx, "SLAVE_ICW2", pic->slave_icw2, loadfailout);
1003     V3_CHKPT_LOAD(ctx, "SLAVE_ICW3", pic->slave_icw3, loadfailout);
1004     V3_CHKPT_LOAD(ctx, "SLAVE_ICW4", pic->slave_icw4, loadfailout);
1005
1006
1007     V3_CHKPT_LOAD(ctx, "MASTER_IMR", pic->master_imr, loadfailout);
1008     V3_CHKPT_LOAD(ctx, "SLAVE_IMR", pic->slave_imr, loadfailout);
1009     V3_CHKPT_LOAD(ctx, "MASTER_OCW2", pic->master_ocw2, loadfailout);
1010     V3_CHKPT_LOAD(ctx, "MASTER_OCW3", pic->master_ocw3, loadfailout);
1011     V3_CHKPT_LOAD(ctx, "SLAVE_OCW2", pic->slave_ocw2, loadfailout);
1012     V3_CHKPT_LOAD(ctx, "SLAVE_OCW3", pic->slave_ocw3, loadfailout);
1013
1014     V3_CHKPT_LOAD(ctx, "MASTER_STATE", pic->master_state, loadfailout);
1015     V3_CHKPT_LOAD(ctx, "SLAVE_STATE", pic->slave_state, loadfailout);
1016
1017     return 0;
1018
1019  loadfailout:
1020     PrintError(VM_NONE, VCORE_NONE, "Failed to load PIC\n");
1021     return -1;
1022 }
1023
1024 #endif
1025
1026
1027 static struct v3_device_ops dev_ops = {
1028     .free = (int (*)(void *))pic_free,
1029 #ifdef V3_CONFIG_CHECKPOINT
1030     .save = pic_save,
1031     .load = pic_load
1032 #endif
1033 };
1034
1035
1036
1037
1038
1039 static int pic_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
1040     struct pic_internal * state = NULL;
1041     char * dev_id = v3_cfg_val(cfg, "ID");
1042     int ret = 0;
1043
1044     // PIC is only usable in non-multicore environments
1045     // just hardcode the core context
1046     struct guest_info * core = &(vm->cores[0]);
1047         
1048     state = (struct pic_internal *)V3_Malloc(sizeof(struct pic_internal));
1049
1050     if (!state) {
1051         PrintError(vm, VCORE_NONE, "8259 PIC: Cannot allocate in init\n");
1052         return -1;
1053     }
1054
1055     struct vm_device * dev = v3_add_device(vm, dev_id, &dev_ops, state);
1056
1057     if (dev == NULL) {
1058         PrintError(vm, VCORE_NONE, "8259 PIC: Could not add device %s\n", dev_id);
1059         V3_Free(state);
1060         return -1;
1061     }
1062
1063     state->core = core;
1064
1065     state->controller_handle = v3_register_intr_controller(core, &intr_ops, state);
1066     state->router_handle = v3_register_intr_router(vm, &router_ops, state);
1067
1068     state->master_irr = 0;
1069     state->master_isr = 0;
1070     state->master_elcr = 0;
1071     state->master_elcr_mask = 0xf8;
1072     state->master_icw1 = 0;
1073     state->master_icw2 = 0;
1074     state->master_icw3 = 0;
1075     state->master_icw4 = 0;
1076     state->master_imr = 0;
1077     state->master_ocw2 = 0;
1078     state->master_ocw3 = 0x02;
1079     state->master_state = ICW1;
1080
1081
1082     state->slave_irr = 0;
1083     state->slave_isr = 0;
1084     state->slave_elcr = 0;
1085     state->slave_elcr_mask = 0xde;
1086     state->slave_icw1 = 0;
1087     state->slave_icw2 = 0;
1088     state->slave_icw3 = 0;
1089     state->slave_icw4 = 0;
1090     state->slave_imr = 0;
1091     state->slave_ocw2 = 0;
1092     state->slave_ocw3 = 0x02;
1093     state->slave_state = ICW1;
1094
1095
1096     ret |= v3_dev_hook_io(dev, MASTER_PORT1, &read_master_port1, &write_master_port1);
1097     ret |= v3_dev_hook_io(dev, MASTER_PORT2, &read_master_port2, &write_master_port2);
1098     ret |= v3_dev_hook_io(dev, SLAVE_PORT1, &read_slave_port1, &write_slave_port1);
1099     ret |= v3_dev_hook_io(dev, SLAVE_PORT2, &read_slave_port2, &write_slave_port2);
1100
1101
1102     ret |= v3_dev_hook_io(dev, ELCR1_PORT, &read_elcr_port, &write_elcr_port);
1103     ret |= v3_dev_hook_io(dev, ELCR2_PORT, &read_elcr_port, &write_elcr_port);
1104
1105     if (ret != 0) {
1106         PrintError(vm, VCORE_NONE, "8259 PIC: Error hooking io ports\n");
1107         v3_remove_device(dev);
1108         return -1;
1109     }
1110
1111     return 0;
1112 }
1113
1114
1115
1116 device_register("8259A", pic_init);