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.


Cleanup and sanity-checking of OOB accesses and pointer-to-local issues (Coverity...
[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[16];
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        // interrupt pending in the master's irr
322         & (~(state->master_imr))    // and is not masked in the master 
323         & (~(state->master_icw3));  // and the pin is not hooked to slave
324 }
325
326 static int pic_intr_pending_from_slave(struct guest_info * info, void * private_data) {
327     struct pic_internal * state = (struct pic_internal*)private_data;
328
329     return (!(state->master_imr & 0x4)) &&                // master has slave unmasked and
330               (state->slave_irr & (~(state->slave_imr))); // slave is pending
331 }
332
333 static int pic_intr_pending(struct guest_info * info, void * private_data) {
334
335     return pic_intr_pending_from_master(info,private_data) || 
336            pic_intr_pending_from_slave(info,private_data);
337 }
338
339 /*
340   8259 prioritization is oddball since there are two chips.  The 
341   slave chip signals an interrupt through pin 2 of the master chip.  
342   This means that all the slave chip's pins are actually at a higher priority
343   than pins 3..7 of the master.   The scheme is as follows, from highest
344   to lowest priority, including legacy mappings:
345  
346   Master  Slave    Typical Legacy Use
347   --------------------------------------------------------------
348   IRQ0             Timer (8254)
349   IRQ1             Keyboard (8042)
350   IRQ2              ****NOT USED - Slave chip inputs here
351           IRQ8     RTC
352           IRQ9     VGA / previous IRQ2 (or PCI via PIRQ LINK B)
353           IRQ10    unused (or PCI via PIRQ LINK C)
354           IRQ11    unused (or PCI via PIRQ LINK D)
355           IRQ12    PS/2 Mouse (8042)
356           IRQ13    Coprocessor error
357           IRQ14    First IDE controller
358           IRQ15    Second IDE controller
359   IRQ3             Second and Fourth Serial Port (COM2/4)
360   IRQ4             First and Third serial port (COM1/3)
361   IRQ5             Second Parallel Port (or PCI via PIRQ LINK A)
362   IRQ6             Floppy controller
363   IRQ7             First Parallel Port
364
365 */
366
367 static int pic_get_intr_number(struct guest_info * info, void * private_data) {
368     struct pic_internal * state = (struct pic_internal *)private_data;
369     int i = 0;
370     int vec = -1;
371
372     PrintDebug(info->vm_info, info, "8259 PIC: getnum: master_irr: 0x%x master_imr: 0x%x\n", state->master_irr, state->master_imr);
373     PrintDebug(info->vm_info, info, "8259 PIC: getnum: slave_irr: 0x%x slave_imr: 0x%x\n", state->slave_irr, state->slave_imr);
374
375     // First, see if we have something upstream of the slave
376     for (i=0;i<2;i++) {
377       // Interrupt requested and not masked
378       if (((state->master_irr & ~(state->master_imr)) >> i) & 0x01) {
379         PrintDebug(info->vm_info, info, "8259 PIC: IRQ: %d, master_icw2: %x\n", i, state->master_icw2);
380         vec = pic_irq_to_vec(info, state, i);
381         if (vec<0) { 
382           PrintError(info->vm_info, info, "8259 PIC: Master Interrupt Ready, but vector=%d\n",vec); 
383         }
384         break;
385       }
386     }
387     
388     // Next, the slave
389     if (vec<0 &&                      // Nothing upstream and
390         !(state->master_imr & 0x4)) { // Master is not masking the slave 
391       for (i = 8; i < 16; i++) {
392         if (((state->slave_irr & ~(state->slave_imr)) >> (i - 8)) & 0x01) {
393           PrintDebug(info->vm_info, info, "8259 PIC: IRQ: %d, slave_icw2: %x\n", i, state->slave_icw2);
394           vec = pic_irq_to_vec(info, state, i);
395           if (vec<0) { 
396             PrintError(info->vm_info, info, "8259 PIC: Slave Interrupt Readby, but vector=%d\n",vec); 
397           }
398           break;
399         }
400       }
401     }
402
403     // And finally the master downstream of the slave
404     if (vec<0) {
405       for (i = 3; i < 8; i++) {
406         if (((state->master_irr & ~(state->master_imr)) >> i) & 0x01) {
407           PrintDebug(info->vm_info, info, "8259 PIC: IRQ: %d, master_icw2: %x\n", i, state->master_icw2);
408           vec = pic_irq_to_vec(info, state, i);
409           if (vec<0) { 
410             PrintError(info->vm_info, info, "8259 PIC: Master Interrupt Ready in 2nd pass, but vector=%d\n",vec);
411           }
412           break;
413         }
414       }
415     }
416   
417     if (vec>=0) {
418       PrintDebug(info->vm_info, info, "8259 PIC: get num is returning vector %d\n",vec);
419     } else {
420       PrintDebug(info->vm_info, info, "8259 PIC: no vector available\n");
421     }
422     
423     return vec;
424 }
425
426
427
428
429 /* The vec number is the number returned by pic_get_irq_number(), not the pin number. */
430 /* In other words, it's the INT vector the PIC is feeding the processor                */
431 static int pic_begin_irq(struct guest_info * info, void * private_data, int vec) {
432   struct pic_internal * state = (struct pic_internal*)private_data;
433   int irq;
434   
435   irq = pic_vec_to_irq(info,state,vec);
436   
437   if (irq<0) { 
438     // Not an error - could be for other interrupt controller
439     PrintDebug(info->vm_info,info,"8259 PIC: Ignoring begin_irq on vector %d since it's not ours\n", vec);
440     return 0;
441   }
442   
443   if (irq <= 7) {
444     // Master
445     PrintDebug(info->vm_info, info, "8259 PIC: Master: Beginning IRQ %d\n",irq);
446     // This should always be true: See pic_get_irq_number
447     if (((state->master_irr & (~(state->master_imr))) >> irq) & 0x01) {
448       // unmasked - let's start it
449       state->master_isr |= (0x1 << irq);
450       // auto reset the request if the elcr has this as edge-triggered
451       if (!(state->master_elcr & (0x1 << irq))) {
452         state->master_irr &= ~(0x1 << irq);
453       }
454     } else {
455       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);
456     }
457   } else if (irq>=8 && irq<=15)  {
458     // Slave
459     PrintDebug(info->vm_info, info, "8259 PIC: Master + Slave: Beginning IRQ %d\n",irq);
460     // This should always be true: See pic_get_irq_number
461     if (((state->slave_irr & (~(state->slave_imr))) >> (irq - 8)) & 0x01) {
462       // unmasked - so let's start it in the slave
463       state->slave_isr |= (0x1 << (irq - 8));
464       // We must have previously pushed it to the master's irr,
465       // so all we need to do here is put it in service there too
466       state->master_isr |= 0x4; // pin 2 is where the slave attaches
467       
468       // auto-reset the request in the slave if it's marked as edge-triggered
469       if (!(state->slave_elcr & (0x1 << (irq - 8)))) {
470         state->slave_irr &= ~(0x1 << (irq - 8));
471       }
472       
473       // auto-reset the request in pin 2 of the master if it's marked as edge-trigged
474       if (!(state->master_elcr & 0x04)) {
475         state->master_irr &= ~0x04;
476       }
477     } else {
478       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);
479     }
480   } else {
481     PrintDebug(info->vm_info, info, "8259 PIC: Ignoring begin_irq for %d since I don't own it\n", irq);
482   }
483
484   return 0;
485 }
486
487
488 /*
489   static int pic_end_irq(void * private_data, int irq) {
490   return 0;
491   }
492 */
493
494
495
496 static struct intr_ctrl_ops intr_ops = {
497     .intr_pending = pic_intr_pending,
498     .get_intr_number = pic_get_intr_number,
499     .begin_irq = pic_begin_irq
500 };
501
502 static struct intr_router_ops router_ops = {
503     .raise_intr = pic_raise_intr,
504     .lower_intr = pic_lower_intr
505 };
506
507
508 static int read_master_port1(struct guest_info * core, ushort_t port, void * dst, uint_t length, void * priv_data) {
509     struct pic_internal * state = (struct pic_internal *)priv_data;
510
511     if (length != 1) {
512         PrintError(core->vm_info, core, "8259 PIC: Master: Invalid Read length (rd_Master1)\n");
513         return -1;
514     }
515   
516     if ((state->master_ocw3 & 0x03) == 0x02) {
517         *(uint8_t *)dst = state->master_irr;
518     } else if ((state->master_ocw3 & 0x03) == 0x03) {
519         *(uint8_t *)dst = state->master_isr;
520     } else {
521         *(uint8_t *)dst = 0;
522     }
523   
524     return 1;
525 }
526
527 static int read_master_port2(struct guest_info * core, ushort_t port, void * dst, uint_t length, void * priv_data) {
528     struct pic_internal * state = (struct pic_internal *)priv_data;
529
530     if (length != 1) {
531         PrintError(core->vm_info, core, "8259 PIC: Master: Invalid Read length (rd_Master2)\n");
532         return -1;
533     }
534
535     *(uint8_t *)dst = state->master_imr;
536
537     return 1;
538   
539 }
540
541 static int read_slave_port1(struct guest_info * core, ushort_t port, void * dst, uint_t length, void * priv_data) {
542     struct pic_internal * state = (struct pic_internal *)priv_data;
543
544     if (length != 1) {
545         PrintError(core->vm_info, core, "8259 PIC: Slave: Invalid Read length (rd_Slave1)\n");
546         return -1;
547     }
548   
549     if ((state->slave_ocw3 & 0x03) == 0x02) {
550         *(uint8_t*)dst = state->slave_irr;
551     } else if ((state->slave_ocw3 & 0x03) == 0x03) {
552         *(uint8_t *)dst = state->slave_isr;
553     } else {
554         *(uint8_t *)dst = 0;
555     }
556
557     return 1;
558 }
559
560 static int read_slave_port2(struct guest_info * core, ushort_t port, void * dst, uint_t length, void * priv_data) {
561     struct pic_internal * state = (struct pic_internal *)priv_data;
562
563     if (length != 1) {
564         PrintError(core->vm_info, core, "8259 PIC: Slave: Invalid Read length  (rd_Slave2)\n");
565         return -1;
566     }
567
568     *(uint8_t *)dst = state->slave_imr;
569
570     return 1;
571 }
572
573
574 static int write_master_port1(struct guest_info * core, ushort_t port, void * src, uint_t length, void * priv_data) {
575     struct pic_internal * state = (struct pic_internal *)priv_data;
576     uint8_t cw = *(uint8_t *)src;
577
578     PrintDebug(core->vm_info, core, "8259 PIC: Master: Write port 1 with 0x%x\n",cw);
579
580     if (length != 1) {
581         PrintError(core->vm_info, core, "8259 PIC: Master: Invalid Write length (wr_Master1)\n");
582         return -1;
583     }
584
585     v3_clear_pending_intr(core);
586
587     if (IS_ICW1(cw)) {
588
589         PrintDebug(core->vm_info, core, "8259 PIC: Master: Setting ICW1 = %x (wr_Master1)\n", cw);
590
591         state->master_icw1 = cw;
592         state->master_state = ICW2;
593
594     } else if (state->master_state == READY) {
595         if (IS_OCW2(cw)) {
596             // handle the EOI here
597             struct ocw2 * cw2 =  (struct ocw2*)&cw;
598             int eoi_irq=-1;
599
600             PrintDebug(core->vm_info, core, "8259 PIC: Master: Handling OCW2 = %x (wr_Master1)\n", cw);
601
602             if ((cw2->EOI) && (!cw2->R) && (cw2->SL)) {
603                 // specific EOI;
604                 state->master_isr &= ~(0x01 << cw2->level);
605                 eoi_irq = cw2->level;
606
607                 /*
608                 // ack the irq if requested
609                 if (state->irq_ack_cbs[irq].ack) {
610                     state->irq_ack_cbs[irq].ack(info, irq, state->irq_ack_cbs[irq].private_data);
611                 }
612                 */
613
614             } else if ((cw2->EOI) & (!cw2->R) && (!cw2->SL)) {
615                 int i;
616                 // Non-specific EOI
617                 PrintDebug(core->vm_info, core, "8259 PIC: Master: Pre ISR = %x (wr_Master1)\n", state->master_isr);
618                 for (i = 0; i < 8; i++) {
619                     if (state->master_isr & (0x01 << i)) {
620                         state->master_isr &= ~(0x01 << i);
621                         eoi_irq=i;
622                         break;
623                     }
624                 }
625                 if (i==8) { 
626                   PrintDebug(core->vm_info, core, "8259 PIC: Master: Strange... non-specific EOI but no in-service interrupts\n");
627                 }
628                 
629                 PrintDebug(core->vm_info, core, "8259 PIC: Master: Post ISR = %x (wr_Master1)\n", state->master_isr);
630             } else if (!(cw2->EOI) && (cw2->R) && (cw2->SL)) {
631                 PrintDebug(core->vm_info, core, "8259 PIC: Master: Ignoring set-priority, priorities not implemented (level=%d, wr_Master1)\n", cw2->level);
632             } else if (!(cw2->EOI) && !(cw2->R) && (cw2->SL)) {
633                 PrintDebug(core->vm_info, core, "8259 PIC: Master: Ignoring no-op (level=%d, wr_Master1)\n", cw2->level);
634             } else {
635                 PrintError(core->vm_info, core, "8259 PIC: Master: Command not handled, or in error (wr_Master1)\n");
636                 return -1;
637             }
638
639             if (cw2->EOI) {
640               if (pic_intr_pending_from_master(core,state)) {
641                 // this is perfectly fine as there may be other latched interrupts
642                 // but it would be strange if the one we just cleared is suddenly
643                 // alive again - well, depending on concurrent behavior external to 
644                 int irq = pic_vec_to_irq(core,state,pic_get_intr_number(core,state));
645
646                 if (irq == eoi_irq) { 
647           // Not necessarily an error, since it could have been raised again in another thread...
648                   PrintError(core->vm_info, core, "8259 PIC: Master: IRQ %d pending after EOI of IRQ %d\n", irq,eoi_irq);
649                   DumpPICState(state);
650                 }
651               }
652             }
653             
654             state->master_ocw2 = cw;
655         } else if (IS_OCW3(cw)) {
656           PrintDebug(core->vm_info, core, "8259 PIC: Master: Handling OCW3 = %x (wr_Master1)\n", cw);
657           state->master_ocw3 = cw;
658         } else {
659           PrintError(core->vm_info, core, "8259 PIC: Master: Invalid OCW to PIC (wr_Master1)\n");
660           PrintError(core->vm_info, core, "8259 PIC: Master: CW=%x\n", cw);
661           return -1;
662         }
663     } else {
664       PrintError(core->vm_info, core, "8259 PIC: Master: Invalid PIC State (wr_Master1)\n");
665       PrintError(core->vm_info, core, "8259 PIC: Master: CW=%x\n", cw);
666       return -1;
667     }
668     
669     return 1;
670 }
671
672 static int write_master_port2(struct guest_info * core, ushort_t port, void * src, uint_t length, void * priv_data) {
673   struct pic_internal * state = (struct pic_internal *)priv_data;
674   uint8_t cw = *(uint8_t *)src;    
675   
676   PrintDebug(core->vm_info, core, "8259 PIC: Master: Write master port 2 with 0x%x\n",cw);
677
678   if (length != 1) {
679     PrintError(core->vm_info, core, "8259 PIC: Master: Invalid Write length (wr_Master2)\n");
680         return -1;
681     }
682
683     v3_clear_pending_intr(core);
684
685     if (state->master_state == ICW2) {
686         struct icw1 * cw1 = (struct icw1 *)&(state->master_icw1);
687
688         PrintDebug(core->vm_info, core, "8259 PIC: Master: Setting ICW2 = %x (wr_Master2)\n", cw);
689         state->master_icw2 = cw;
690
691
692
693         if (cw1->sngl == 0) {
694             state->master_state = ICW3;
695         } else if (cw1->ic4 == 1) {
696             state->master_state = ICW4;
697         } else {
698             state->master_state = READY;
699         }
700
701
702
703     } else if (state->master_state == ICW3) {
704         struct icw1 * cw1 = (struct icw1 *)&(state->master_icw1);
705
706         PrintDebug(core->vm_info, core, "8259 PIC: Master: Setting ICW3 = %x (wr_Master2)\n", cw);
707
708         state->master_icw3 = cw;
709
710         if (cw1->ic4 == 1) {
711             state->master_state = ICW4;
712         } else {
713             state->master_state = READY;
714         }
715
716     } else if (state->master_state == ICW4) {
717         PrintDebug(core->vm_info, core, "8259 PIC: Master: Setting ICW4 = %x (wr_Master2)\n", cw);
718         state->master_icw4 = cw;
719         state->master_state = READY;
720     } else if ((state->master_state == ICW1) || (state->master_state == READY)) {
721         PrintDebug(core->vm_info, core, "8259 PIC: Master: Setting IMR = %x (wr_Master2)\n", cw);
722         state->master_imr = cw;
723     } else {
724         // error
725         PrintError(core->vm_info, core, "8259 PIC: Master: Invalid master PIC State (wr_Master2) (state=%d)\n", 
726                 state->master_state);
727         return -1;
728     }
729
730     return 1;
731 }
732
733 static int write_slave_port1(struct guest_info * core, ushort_t port, void * src, uint_t length, void * priv_data) {
734     struct pic_internal * state = (struct pic_internal *)priv_data;
735     uint8_t cw = *(uint8_t *)src;
736
737     PrintDebug(core->vm_info, core, "8259 PIC: Slave: Write slave port 1 with 0x%x\n",cw);
738
739     if (length != 1) {
740         // error
741         PrintError(core->vm_info, core, "8259 PIC: Slave: Invalid Write length (wr_Slave1)\n");
742         return -1;
743     }
744
745     v3_clear_pending_intr(core);
746
747     if (IS_ICW1(cw)) {
748         PrintDebug(core->vm_info, core, "8259 PIC: Slave: Setting ICW1 = %x (wr_Slave1)\n", cw);
749         state->slave_icw1 = cw;
750         state->slave_state = ICW2;
751     } else if (state->slave_state == READY) {
752         if (IS_OCW2(cw)) {
753             int eoi_irq = -1;
754             // handle the EOI here
755             struct ocw2 * cw2 =  (struct ocw2 *)&cw;
756
757             PrintDebug(core->vm_info, core, "8259 PIC: Slave: Setting OCW2 = %x (wr_Slave1)\n", cw);
758
759             if ((cw2->EOI) && (!cw2->R) && (cw2->SL)) {
760                 // specific EOI;
761                 state->slave_isr &= ~(0x01 << cw2->level);
762                 eoi_irq = 8+cw2->level;
763             } else if ((cw2->EOI) & (!cw2->R) && (!cw2->SL)) {
764                 int i;
765                 // Non-specific EOI
766                 PrintDebug(core->vm_info, core, "8259 PIC: Slave: Pre ISR = %x (wr_Slave1)\n", state->slave_isr);
767                 for (i = 0; i < 8; i++) {
768                     if (state->slave_isr & (0x01 << i)) {
769                         state->slave_isr &= ~(0x01 << i);
770                         eoi_irq=8+i;
771                         break;
772                     }
773                 }
774                 if (i==8) { 
775                   PrintDebug(core->vm_info, core, "8259 PIC: Slave: Strange... non-specific EOI but no in-service interrupts\n");
776                 }
777                 PrintDebug(core->vm_info, core, "8259 PIC: Slave: Post ISR = %x (wr_Slave1)\n", state->slave_isr);
778             } else {
779                 PrintError(core->vm_info, core, "8259 PIC: Slave: Command not handled or invalid  (wr_Slave1)\n");
780                 return -1;
781             }
782
783             // If we now have no further requested interrupts, 
784             // we are not requesting from the master either
785             if (!(state->slave_irr)) { 
786               state->master_irr &= ~0x04;
787             }
788
789             if (cw2->EOI) {
790                 if (pic_intr_pending_from_slave(core,state)) {
791                   // this is perfectly fine as there may be other latched interrupts
792                   // but it would be strange if the one we just cleared is suddenly
793                   // alive again - well, depending on concurrent behavior external to 
794                   int irq = pic_vec_to_irq(core,state,pic_get_intr_number(core,state));
795                   
796                   if (irq == eoi_irq) { 
797                     // Not necessarily an error, since it could have been raised again in another thread.
798             PrintError(core->vm_info, core, "8259 PIC: Slave: IRQ %d pending after EOI of IRQ %d\n", irq,eoi_irq);
799                     DumpPICState(state);
800                   }
801                 }
802             }
803
804             state->slave_ocw2 = cw;
805         } else if (IS_OCW3(cw)) {
806             // Basically sets the IRR/ISR read flag
807             PrintDebug(core->vm_info, core, "8259 PIC: Slave: Setting OCW3 = %x (wr_Slave1)\n", cw);
808             state->slave_ocw3 = cw;
809         } else {
810             PrintError(core->vm_info, core, "8259 PIC: Slave: Invalid command work (wr_Slave1)\n");
811             return -1;
812         }
813     } else {
814         PrintError(core->vm_info, core, "8259 PIC: Slave: Invalid State writing (wr_Slave1)\n");
815         return -1;
816     }
817
818     return 1;
819 }
820
821 static int write_slave_port2(struct guest_info * core, ushort_t port, void * src, uint_t length, void * priv_data) {
822     struct pic_internal * state = (struct pic_internal *)priv_data;
823     uint8_t cw = *(uint8_t *)src;    
824
825     PrintDebug(core->vm_info, core, "8259 PIC: Slave: Write slave port 2 with 0x%x\n",cw);
826
827     if (length != 1) {
828         PrintError(core->vm_info, core, "8259 PIC: Slave: Invalid write length (wr_Slave2)\n");
829         return -1;
830     }
831
832     v3_clear_pending_intr(core);
833
834
835     if (state->slave_state == ICW2) {
836         struct icw1 * cw1 =  (struct icw1 *)&(state->master_icw1);
837
838         PrintDebug(core->vm_info, core, "8259 PIC: Slave: Setting ICW2 = %x (wr_Slave2)\n", cw);
839
840         state->slave_icw2 = cw;
841
842         if (cw1->sngl == 0) {
843             state->slave_state = ICW3;
844         } else if (cw1->ic4 == 1) {
845             state->slave_state = ICW4;
846         } else {
847             state->slave_state = READY;
848         }
849
850     } else if (state->slave_state == ICW3) {
851         struct icw1 * cw1 =  (struct icw1 *)&(state->master_icw1);
852
853         PrintDebug(core->vm_info, core, "8259 PIC: Slave: Setting ICW3 = %x (wr_Slave2)\n", cw);
854
855         state->slave_icw3 = cw;
856
857         if (cw1->ic4 == 1) {
858             state->slave_state = ICW4;
859         } else {
860             state->slave_state = READY;
861         }
862
863     } else if (state->slave_state == ICW4) {
864         PrintDebug(core->vm_info, core, "8259 PIC: Slave: Setting ICW4 = %x (wr_Slave2)\n", cw);
865         state->slave_icw4 = cw;
866         state->slave_state = READY;
867     } else if ((state->slave_state == ICW1) || (state->slave_state == READY)) {
868         PrintDebug(core->vm_info, core, "8259 PIC: Slave: Setting IMR = %x (wr_Slave2)\n", cw);
869         state->slave_imr = cw;
870     } else {
871         PrintError(core->vm_info, core, "8259 PIC: Slave: Invalid State at write (wr_Slave2)\n");
872         return -1;
873     }
874
875     return 1;
876 }
877
878
879
880
881 static int read_elcr_port(struct guest_info * core, ushort_t port, void * dst, uint_t length, void * priv_data) {
882     struct pic_internal * state = (struct pic_internal *)priv_data;
883     
884     if (length != 1) {
885         PrintError(core->vm_info, core, "8259 PIC: ELCR read of invalid length %d\n", length);
886         return -1;
887     }
888
889     if (port == ELCR1_PORT) {
890         // master
891         *(uint8_t *)dst = state->master_elcr;
892     } else if (port == ELCR2_PORT) {
893         *(uint8_t *)dst = state->slave_elcr;
894     } else {
895         PrintError(core->vm_info, core, "8259 PIC: Invalid port %x\n", port);
896         return -1;
897     }
898
899     return length;
900 }
901
902
903 static int write_elcr_port(struct guest_info * core, ushort_t port, void * src, uint_t length, void * priv_data) {
904     struct pic_internal * state = (struct pic_internal *)priv_data;
905     
906     if (length != 1) {
907         PrintError(core->vm_info, core, "8259 PIC: ELCR read of invalid length %d\n", length);
908         return -1;
909     }
910
911     if (port == ELCR1_PORT) {
912         // master
913         state->master_elcr  = (*(uint8_t *)src) & state->master_elcr_mask;
914     } else if (port == ELCR2_PORT) {
915         state->slave_elcr  = (*(uint8_t *)src) & state->slave_elcr_mask;
916     } else {
917         PrintError(core->vm_info, core, "8259 PIC: Invalid port %x\n", port);
918         return -1;
919     }
920
921     return length;
922 }
923
924
925
926 static int pic_free(struct pic_internal * state) {
927     struct guest_info * core = state->core;
928
929     v3_remove_intr_controller(core, state->controller_handle);
930     v3_remove_intr_router(core->vm_info, state->router_handle);
931
932     V3_Free(state);
933     return 0;
934 }
935
936 #ifdef V3_CONFIG_CHECKPOINT
937 static int pic_save(struct v3_chkpt_ctx * ctx, void * private_data) {
938     struct pic_internal * pic = (struct pic_internal *)private_data;
939
940     V3_CHKPT_SAVE(ctx, "MASTER_IRR", pic->master_irr, savefailout);
941     V3_CHKPT_SAVE(ctx, "SLAVE_IRR", pic->slave_irr, savefailout);
942   
943     V3_CHKPT_SAVE(ctx, "MASTER_ISR", pic->master_isr, savefailout);
944     V3_CHKPT_SAVE(ctx, "SLAVE_ISR", pic->slave_isr, savefailout);
945
946     V3_CHKPT_SAVE(ctx, "MASTER_ELCR", pic->master_elcr, savefailout);
947     V3_CHKPT_SAVE(ctx, "SLAVE_ELCR", pic->slave_elcr, savefailout);
948     V3_CHKPT_SAVE(ctx, "MASTER_ELCR_MASK", pic->master_elcr_mask, savefailout);
949     V3_CHKPT_SAVE(ctx, "SLAVE_ELCR_MASK", pic->slave_elcr_mask, savefailout);
950
951     V3_CHKPT_SAVE(ctx, "MASTER_ICW1", pic->master_icw1, savefailout);
952     V3_CHKPT_SAVE(ctx, "MASTER_ICW2", pic->master_icw2, savefailout);
953     V3_CHKPT_SAVE(ctx, "MASTER_ICW3", pic->master_icw3, savefailout);
954     V3_CHKPT_SAVE(ctx, "MASTER_ICW4", pic->master_icw4, savefailout);
955
956
957     V3_CHKPT_SAVE(ctx, "SLAVE_ICW1", pic->slave_icw1, savefailout);
958     V3_CHKPT_SAVE(ctx, "SLAVE_ICW2", pic->slave_icw2, savefailout);
959     V3_CHKPT_SAVE(ctx, "SLAVE_ICW3", pic->slave_icw3, savefailout);
960     V3_CHKPT_SAVE(ctx, "SLAVE_ICW4", pic->slave_icw4, savefailout);
961
962
963     V3_CHKPT_SAVE(ctx, "MASTER_IMR", pic->master_imr, savefailout);
964     V3_CHKPT_SAVE(ctx, "SLAVE_IMR", pic->slave_imr, savefailout);
965     V3_CHKPT_SAVE(ctx, "MASTER_OCW2", pic->master_ocw2, savefailout);
966     V3_CHKPT_SAVE(ctx, "MASTER_OCW3", pic->master_ocw3, savefailout);
967     V3_CHKPT_SAVE(ctx, "SLAVE_OCW2", pic->slave_ocw2, savefailout);
968     V3_CHKPT_SAVE(ctx, "SLAVE_OCW3", pic->slave_ocw3, savefailout);
969
970     V3_CHKPT_SAVE(ctx, "MASTER_STATE", pic->master_state, savefailout);
971     V3_CHKPT_SAVE(ctx, "SLAVE_STATE", pic->slave_state, savefailout);
972
973     
974     return 0;
975
976  savefailout:
977     PrintError(VM_NONE, VCORE_NONE, "Failed to save PIC\n");
978     return -1;
979
980 }
981
982 static int pic_load(struct v3_chkpt_ctx * ctx, void * private_data) {
983     struct pic_internal * pic = (struct pic_internal *)private_data;
984
985    
986     V3_CHKPT_LOAD(ctx, "MASTER_IRR", pic->master_irr, loadfailout);
987     V3_CHKPT_LOAD(ctx, "SLAVE_IRR", pic->slave_irr, loadfailout);
988   
989     V3_CHKPT_LOAD(ctx, "MASTER_ISR", pic->master_isr, loadfailout);
990     V3_CHKPT_LOAD(ctx, "SLAVE_ISR", pic->slave_isr, loadfailout);
991
992     V3_CHKPT_LOAD(ctx, "MASTER_ELCR", pic->master_elcr, loadfailout);
993     V3_CHKPT_LOAD(ctx, "SLAVE_ELCR", pic->slave_elcr, loadfailout);
994     V3_CHKPT_LOAD(ctx, "MASTER_ELCR_MASK", pic->master_elcr_mask, loadfailout);
995     V3_CHKPT_LOAD(ctx, "SLAVE_ELCR_MASK", pic->slave_elcr_mask, loadfailout);
996
997     V3_CHKPT_LOAD(ctx, "MASTER_ICW1", pic->master_icw1, loadfailout);
998     V3_CHKPT_LOAD(ctx, "MASTER_ICW2", pic->master_icw2, loadfailout);
999     V3_CHKPT_LOAD(ctx, "MASTER_ICW3", pic->master_icw3, loadfailout);
1000     V3_CHKPT_LOAD(ctx, "MASTER_ICW4", pic->master_icw4, loadfailout);
1001
1002
1003     V3_CHKPT_LOAD(ctx, "SLAVE_ICW1", pic->slave_icw1, loadfailout);
1004     V3_CHKPT_LOAD(ctx, "SLAVE_ICW2", pic->slave_icw2, loadfailout);
1005     V3_CHKPT_LOAD(ctx, "SLAVE_ICW3", pic->slave_icw3, loadfailout);
1006     V3_CHKPT_LOAD(ctx, "SLAVE_ICW4", pic->slave_icw4, loadfailout);
1007
1008
1009     V3_CHKPT_LOAD(ctx, "MASTER_IMR", pic->master_imr, loadfailout);
1010     V3_CHKPT_LOAD(ctx, "SLAVE_IMR", pic->slave_imr, loadfailout);
1011     V3_CHKPT_LOAD(ctx, "MASTER_OCW2", pic->master_ocw2, loadfailout);
1012     V3_CHKPT_LOAD(ctx, "MASTER_OCW3", pic->master_ocw3, loadfailout);
1013     V3_CHKPT_LOAD(ctx, "SLAVE_OCW2", pic->slave_ocw2, loadfailout);
1014     V3_CHKPT_LOAD(ctx, "SLAVE_OCW3", pic->slave_ocw3, loadfailout);
1015
1016     V3_CHKPT_LOAD(ctx, "MASTER_STATE", pic->master_state, loadfailout);
1017     V3_CHKPT_LOAD(ctx, "SLAVE_STATE", pic->slave_state, loadfailout);
1018
1019     return 0;
1020
1021  loadfailout:
1022     PrintError(VM_NONE, VCORE_NONE, "Failed to load PIC\n");
1023     return -1;
1024 }
1025
1026 #endif
1027
1028
1029 static struct v3_device_ops dev_ops = {
1030     .free = (int (*)(void *))pic_free,
1031 #ifdef V3_CONFIG_CHECKPOINT
1032     .save = pic_save,
1033     .load = pic_load
1034 #endif
1035 };
1036
1037
1038
1039
1040
1041 static int pic_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
1042     struct pic_internal * state = NULL;
1043     char * dev_id = v3_cfg_val(cfg, "ID");
1044     int ret = 0;
1045
1046     // PIC is only usable in non-multicore environments
1047     // just hardcode the core context
1048     struct guest_info * core = &(vm->cores[0]);
1049         
1050     state = (struct pic_internal *)V3_Malloc(sizeof(struct pic_internal));
1051
1052     if (!state) {
1053         PrintError(vm, VCORE_NONE, "8259 PIC: Cannot allocate in init\n");
1054         return -1;
1055     }
1056
1057     struct vm_device * dev = v3_add_device(vm, dev_id, &dev_ops, state);
1058
1059     if (dev == NULL) {
1060         PrintError(vm, VCORE_NONE, "8259 PIC: Could not add device %s\n", dev_id);
1061         V3_Free(state);
1062         return -1;
1063     }
1064
1065     state->core = core;
1066
1067     state->controller_handle = v3_register_intr_controller(core, &intr_ops, state);
1068     state->router_handle = v3_register_intr_router(vm, &router_ops, state);
1069
1070     state->master_irr = 0;
1071     state->master_isr = 0;
1072     state->master_elcr = 0;
1073     state->master_elcr_mask = 0xf8;
1074     state->master_icw1 = 0;
1075     state->master_icw2 = 0;
1076     state->master_icw3 = 0;
1077     state->master_icw4 = 0;
1078     state->master_imr = 0;
1079     state->master_ocw2 = 0;
1080     state->master_ocw3 = 0x02;
1081     state->master_state = ICW1;
1082
1083
1084     state->slave_irr = 0;
1085     state->slave_isr = 0;
1086     state->slave_elcr = 0;
1087     state->slave_elcr_mask = 0xde;
1088     state->slave_icw1 = 0;
1089     state->slave_icw2 = 0;
1090     state->slave_icw3 = 0;
1091     state->slave_icw4 = 0;
1092     state->slave_imr = 0;
1093     state->slave_ocw2 = 0;
1094     state->slave_ocw3 = 0x02;
1095     state->slave_state = ICW1;
1096
1097
1098     ret |= v3_dev_hook_io(dev, MASTER_PORT1, &read_master_port1, &write_master_port1);
1099     ret |= v3_dev_hook_io(dev, MASTER_PORT2, &read_master_port2, &write_master_port2);
1100     ret |= v3_dev_hook_io(dev, SLAVE_PORT1, &read_slave_port1, &write_slave_port1);
1101     ret |= v3_dev_hook_io(dev, SLAVE_PORT2, &read_slave_port2, &write_slave_port2);
1102
1103
1104     ret |= v3_dev_hook_io(dev, ELCR1_PORT, &read_elcr_port, &write_elcr_port);
1105     ret |= v3_dev_hook_io(dev, ELCR2_PORT, &read_elcr_port, &write_elcr_port);
1106
1107     if (ret != 0) {
1108         PrintError(vm, VCORE_NONE, "8259 PIC: Error hooking io ports\n");
1109         v3_remove_device(dev);
1110         return -1;
1111     }
1112
1113     return 0;
1114 }
1115
1116
1117
1118 device_register("8259A", pic_init);