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.


Context-based output infrastructure (V3_Print, etc) and modifications to use it
[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     PrintDebug(VM_NONE, VCORE_NONE, "8259 PIC: master_state=0x%x\n",p->master_state);
177     PrintDebug(VM_NONE, VCORE_NONE, "8259 PIC: master_irr=0x%x\n",p->master_irr);
178     PrintDebug(VM_NONE, VCORE_NONE, "8259 PIC: master_isr=0x%x\n",p->master_isr);
179     PrintDebug(VM_NONE, VCORE_NONE, "8259 PIC: master_imr=0x%x\n",p->master_imr);
180
181     PrintDebug(VM_NONE, VCORE_NONE, "8259 PIC: master_ocw2=0x%x\n",p->master_ocw2);
182     PrintDebug(VM_NONE, VCORE_NONE, "8259 PIC: master_ocw3=0x%x\n",p->master_ocw3);
183
184     PrintDebug(VM_NONE, VCORE_NONE, "8259 PIC: master_icw1=0x%x\n",p->master_icw1);
185     PrintDebug(VM_NONE, VCORE_NONE, "8259 PIC: master_icw2=0x%x\n",p->master_icw2);
186     PrintDebug(VM_NONE, VCORE_NONE, "8259 PIC: master_icw3=0x%x\n",p->master_icw3);
187     PrintDebug(VM_NONE, VCORE_NONE, "8259 PIC: master_icw4=0x%x\n",p->master_icw4);
188
189     PrintDebug(VM_NONE, VCORE_NONE, "8259 PIC: slave_state=0x%x\n",p->slave_state);
190     PrintDebug(VM_NONE, VCORE_NONE, "8259 PIC: slave_irr=0x%x\n",p->slave_irr);
191     PrintDebug(VM_NONE, VCORE_NONE, "8259 PIC: slave_isr=0x%x\n",p->slave_isr);
192     PrintDebug(VM_NONE, VCORE_NONE, "8259 PIC: slave_imr=0x%x\n",p->slave_imr);
193
194     PrintDebug(VM_NONE, VCORE_NONE, "8259 PIC: slave_ocw2=0x%x\n",p->slave_ocw2);
195     PrintDebug(VM_NONE, VCORE_NONE, "8259 PIC: slave_ocw3=0x%x\n",p->slave_ocw3);
196
197     PrintDebug(VM_NONE, VCORE_NONE, "8259 PIC: slave_icw1=0x%x\n",p->slave_icw1);
198     PrintDebug(VM_NONE, VCORE_NONE, "8259 PIC: slave_icw2=0x%x\n",p->slave_icw2);
199     PrintDebug(VM_NONE, VCORE_NONE, "8259 PIC: slave_icw3=0x%x\n",p->slave_icw3);
200     PrintDebug(VM_NONE, VCORE_NONE, "8259 PIC: slave_icw4=0x%x\n",p->slave_icw4);
201
202 }
203
204
205 static int pic_raise_intr(struct v3_vm_info * vm, void * private_data, struct v3_irq * irq) {
206     struct pic_internal * state = (struct pic_internal*)private_data;
207     uint8_t irq_num = irq->irq;
208
209     if (irq_num == 2) {
210         irq_num = 9;
211         state->master_irr |= 0x04;
212     }
213
214     PrintDebug(vm, VCORE_NONE, "8259 PIC: Raising irq %d in the PIC\n", irq_num);
215
216     if (irq_num <= 7) {
217         state->master_irr |= 0x01 << irq_num;
218     } else if ((irq_num > 7) && (irq_num < 16)) {
219         state->slave_irr |= 0x01 << (irq_num - 8);
220     } else {
221         PrintDebug(vm, VCORE_NONE, "8259 PIC: Invalid IRQ raised (%d)\n", irq_num);
222         return -1;
223     }
224
225     state->irq_ack_cbs[irq_num].ack = irq->ack;
226     state->irq_ack_cbs[irq_num].private_data = irq->private_data;
227
228     if (V3_Get_CPU() != vm->cores[0].pcpu_id) {
229         // guest is running on another core, interrupt it to deliver irq
230         v3_interrupt_cpu(vm, 0, 0);
231     }
232
233     return 0;
234 }
235
236
237 static int pic_lower_intr(struct v3_vm_info * vm, void * private_data, struct v3_irq * irq) {
238     struct pic_internal * state = (struct pic_internal*)private_data;
239     uint8_t irq_num = irq->irq;
240
241
242     PrintDebug(vm, VCORE_NONE, "[pic_lower_intr] IRQ line %d now low\n", irq_num);
243     if (irq_num <= 7) {
244
245         state->master_irr &= ~(1 << irq_num);
246         if ((state->master_irr & ~(state->master_imr)) == 0) {
247             PrintDebug(vm, VCORE_NONE, "\t\tFIXME: Master maybe should do sth\n");
248         }
249     } else if ((irq_num > 7) && (irq_num < 16)) {
250
251         state->slave_irr &= ~(1 << (irq_num - 8));
252         if ((state->slave_irr & (~(state->slave_imr))) == 0) {
253             PrintDebug(vm, VCORE_NONE, "\t\tFIXME: Slave maybe should do sth\n");
254         }
255     }
256     return 0;
257 }
258
259
260
261 static int pic_intr_pending(struct guest_info * info, void * private_data) {
262     struct pic_internal * state = (struct pic_internal*)private_data;
263
264     if ((state->master_irr & ~(state->master_imr)) || 
265         (state->slave_irr & ~(state->slave_imr))) {
266         return 1;
267     }
268
269     return 0;
270 }
271
272 static int pic_get_intr_number(struct guest_info * info, void * private_data) {
273     struct pic_internal * state = (struct pic_internal *)private_data;
274     int i = 0;
275     int irq = -1;
276
277     PrintDebug(info->vm_info, info, "8259 PIC: getnum: master_irr: 0x%x master_imr: 0x%x\n", state->master_irr, state->master_imr);
278     PrintDebug(info->vm_info, info, "8259 PIC: getnum: slave_irr: 0x%x slave_imr: 0x%x\n", state->slave_irr, state->slave_imr);
279
280     for (i = 0; i < 16; i++) {
281         if (i <= 7) {
282             if (((state->master_irr & ~(state->master_imr)) >> i) & 0x01) {
283                 //state->master_isr |= (0x1 << i);
284                 // reset the irr
285                 //state->master_irr &= ~(0x1 << i);
286                 PrintDebug(info->vm_info, info, "8259 PIC: IRQ: %d, master_icw2: %x\n", i, state->master_icw2);
287                 irq = i + state->master_icw2;
288                 break;
289             }
290         } else {
291             if (((state->slave_irr & ~(state->slave_imr)) >> (i - 8)) & 0x01) {
292                 //state->slave_isr |= (0x1 << (i - 8));
293                 //state->slave_irr &= ~(0x1 << (i - 8));
294                 PrintDebug(info->vm_info, info, "8259 PIC: IRQ: %d, slave_icw2: %x\n", i, state->slave_icw2);
295                 irq = (i - 8) + state->slave_icw2;
296                 break;
297             }
298         }
299     }
300
301 #if 1
302     if ((i == 15) || (i == 6)) { 
303         DumpPICState(state);
304     }
305 #endif
306   
307     if (i == 16) { 
308         return -1;
309     } else {
310         PrintDebug(info->vm_info, info, "8259 PIC: get num is returning %d\n",irq);
311         return irq;
312     }
313 }
314
315
316
317 /* The IRQ number is the number returned by pic_get_intr_number(), not the pin number */
318 static int pic_begin_irq(struct guest_info * info, void * private_data, int irq) {
319     struct pic_internal * state = (struct pic_internal*)private_data;
320     
321     if ((irq >= state->master_icw2) && (irq <= state->master_icw2 + 7)) {
322        irq &= 0x7;
323     } else if ((irq >= state->slave_icw2) && (irq <= state->slave_icw2 + 7)) {
324        irq &= 0x7;
325        irq += 8;
326     } else {
327        //    PrintError(info->vm_info, info, "8259 PIC: Could not find IRQ (0x%x) to Begin\n",irq);
328        return -1;
329     }
330     
331     if (irq <= 7) {
332         // This should always be true: See pic_get_intr_number
333        if (((state->master_irr & ~(state->master_imr)) >> irq) & 0x01) {
334            state->master_isr |= (0x1 << irq);
335
336            if (!(state->master_elcr & (0x1 << irq))) {
337                state->master_irr &= ~(0x1 << irq);
338            }
339        } else {
340            PrintDebug(info->vm_info, info, "8259 PIC: (master) Ignoring begin_irq for %d since I don't own it\n", irq);
341        }
342
343     } else {
344         // This should always be true: See pic_get_intr_number
345         if (((state->slave_irr & ~(state->slave_imr)) >> (irq - 8)) & 0x01) {
346            state->slave_isr |= (0x1 << (irq - 8));
347            
348            if (!(state->slave_elcr & (0x1 << (irq - 8)))) {
349                state->slave_irr &= ~(0x1 << (irq - 8));
350            }
351         } else {
352            PrintDebug(info->vm_info, info, "8259 PIC: (slave) Ignoring begin_irq for %d since I don't own it\n", irq);
353         }
354     }
355
356
357
358     return 0;
359 }
360
361
362 /*
363   static int pic_end_irq(void * private_data, int irq) {
364   return 0;
365   }
366 */
367
368
369
370 static struct intr_ctrl_ops intr_ops = {
371     .intr_pending = pic_intr_pending,
372     .get_intr_number = pic_get_intr_number,
373     .begin_irq = pic_begin_irq
374 };
375
376 static struct intr_router_ops router_ops = {
377     .raise_intr = pic_raise_intr,
378     .lower_intr = pic_lower_intr
379 };
380
381
382 static int read_master_port1(struct guest_info * core, ushort_t port, void * dst, uint_t length, void * priv_data) {
383     struct pic_internal * state = (struct pic_internal *)priv_data;
384
385     if (length != 1) {
386         PrintError(core->vm_info, core, "8259 PIC: Invalid Read length (rd_Master1)\n");
387         return -1;
388     }
389   
390     if ((state->master_ocw3 & 0x03) == 0x02) {
391         *(uint8_t *)dst = state->master_irr;
392     } else if ((state->master_ocw3 & 0x03) == 0x03) {
393         *(uint8_t *)dst = state->master_isr;
394     } else {
395         *(uint8_t *)dst = 0;
396     }
397   
398     return 1;
399 }
400
401 static int read_master_port2(struct guest_info * core, ushort_t port, void * dst, uint_t length, void * priv_data) {
402     struct pic_internal * state = (struct pic_internal *)priv_data;
403
404     if (length != 1) {
405         PrintError(core->vm_info, core, "8259 PIC: Invalid Read length (rd_Master2)\n");
406         return -1;
407     }
408
409     *(uint8_t *)dst = state->master_imr;
410
411     return 1;
412   
413 }
414
415 static int read_slave_port1(struct guest_info * core, ushort_t port, void * dst, uint_t length, void * priv_data) {
416     struct pic_internal * state = (struct pic_internal *)priv_data;
417
418     if (length != 1) {
419         PrintError(core->vm_info, core, "8259 PIC: Invalid Read length (rd_Slave1)\n");
420         return -1;
421     }
422   
423     if ((state->slave_ocw3 & 0x03) == 0x02) {
424         *(uint8_t*)dst = state->slave_irr;
425     } else if ((state->slave_ocw3 & 0x03) == 0x03) {
426         *(uint8_t *)dst = state->slave_isr;
427     } else {
428         *(uint8_t *)dst = 0;
429     }
430
431     return 1;
432 }
433
434 static int read_slave_port2(struct guest_info * core, ushort_t port, void * dst, uint_t length, void * priv_data) {
435     struct pic_internal * state = (struct pic_internal *)priv_data;
436
437     if (length != 1) {
438         PrintError(core->vm_info, core, "8259 PIC: Invalid Read length  (rd_Slave2)\n");
439         return -1;
440     }
441
442     *(uint8_t *)dst = state->slave_imr;
443
444     return 1;
445 }
446
447
448 static int write_master_port1(struct guest_info * core, ushort_t port, void * src, uint_t length, void * priv_data) {
449     struct pic_internal * state = (struct pic_internal *)priv_data;
450     uint8_t cw = *(uint8_t *)src;
451
452     PrintDebug(core->vm_info, core, "8259 PIC: Write master port 1 with 0x%x\n",cw);
453
454     if (length != 1) {
455         PrintError(core->vm_info, core, "8259 PIC: Invalid Write length (wr_Master1)\n");
456         return -1;
457     }
458
459     v3_clear_pending_intr(core);
460
461     if (IS_ICW1(cw)) {
462
463         PrintDebug(core->vm_info, core, "8259 PIC: Setting ICW1 = %x (wr_Master1)\n", cw);
464
465         state->master_icw1 = cw;
466         state->master_state = ICW2;
467
468     } else if (state->master_state == READY) {
469         if (IS_OCW2(cw)) {
470             // handle the EOI here
471             struct ocw2 * cw2 =  (struct ocw2*)&cw;
472
473             PrintDebug(core->vm_info, core, "8259 PIC: Handling OCW2 = %x (wr_Master1)\n", cw);
474
475             if ((cw2->EOI) && (!cw2->R) && (cw2->SL)) {
476                 // specific EOI;
477                 state->master_isr &= ~(0x01 << cw2->level);
478
479
480                 /*
481                 // ack the irq if requested
482                 if (state->irq_ack_cbs[irq].ack) {
483                     state->irq_ack_cbs[irq].ack(info, irq, state->irq_ack_cbs[irq].private_data);
484                 }
485                 */
486
487             } else if ((cw2->EOI) & (!cw2->R) && (!cw2->SL)) {
488                 int i;
489                 // Non-specific EOI
490                 PrintDebug(core->vm_info, core, "8259 PIC: Pre ISR = %x (wr_Master1)\n", state->master_isr);
491                 for (i = 0; i < 8; i++) {
492                     if (state->master_isr & (0x01 << i)) {
493                         state->master_isr &= ~(0x01 << i);
494                         break;
495                     }
496                 }
497                 PrintDebug(core->vm_info, core, "8259 PIC: Post ISR = %x (wr_Master1)\n", state->master_isr);
498             } else if (!(cw2->EOI) && (cw2->R) && (cw2->SL)) {
499                 PrintDebug(core->vm_info, core, "8259 PIC: Ignoring set-priority, priorities not implemented (level=%d, wr_Master1)\n", cw2->level);
500             } else if (!(cw2->EOI) && !(cw2->R) && (cw2->SL)) {
501                 PrintDebug(core->vm_info, core, "8259 PIC: Ignoring no-op (level=%d, wr_Master1)\n", cw2->level);
502             } else {
503                 PrintError(core->vm_info, core, "8259 PIC: Command not handled, or in error (wr_Master1)\n");
504                 return -1;
505             }
506
507             if (cw2->EOI) {
508                 if (pic_get_intr_number(core,  state) != -1) {
509                     PrintError(core->vm_info, core, "Interrupt pending after EOI\n");
510                 }
511             }
512
513
514             state->master_ocw2 = cw;
515         } else if (IS_OCW3(cw)) {
516             PrintDebug(core->vm_info, core, "8259 PIC: Handling OCW3 = %x (wr_Master1)\n", cw);
517             state->master_ocw3 = cw;
518         } else {
519             PrintError(core->vm_info, core, "8259 PIC: Invalid OCW to PIC (wr_Master1)\n");
520             PrintError(core->vm_info, core, "8259 PIC: CW=%x\n", cw);
521             return -1;
522         }
523     } else {
524         PrintError(core->vm_info, core, "8259 PIC: Invalid PIC State (wr_Master1)\n");
525         PrintError(core->vm_info, core, "8259 PIC: CW=%x\n", cw);
526         return -1;
527     }
528
529     return 1;
530 }
531
532 static int write_master_port2(struct guest_info * core, ushort_t port, void * src, uint_t length, void * priv_data) {
533     struct pic_internal * state = (struct pic_internal *)priv_data;
534     uint8_t cw = *(uint8_t *)src;    
535
536     PrintDebug(core->vm_info, core, "8259 PIC: Write master port 2 with 0x%x\n",cw);
537
538     if (length != 1) {
539         PrintError(core->vm_info, core, "8259 PIC: Invalid Write length (wr_Master2)\n");
540         return -1;
541     }
542
543     v3_clear_pending_intr(core);
544
545     if (state->master_state == ICW2) {
546         struct icw1 * cw1 = (struct icw1 *)&(state->master_icw1);
547
548         PrintDebug(core->vm_info, core, "8259 PIC: Setting ICW2 = %x (wr_Master2)\n", cw);
549         state->master_icw2 = cw;
550
551
552
553         if (cw1->sngl == 0) {
554             state->master_state = ICW3;
555         } else if (cw1->ic4 == 1) {
556             state->master_state = ICW4;
557         } else {
558             state->master_state = READY;
559         }
560
561
562
563     } else if (state->master_state == ICW3) {
564         struct icw1 * cw1 = (struct icw1 *)&(state->master_icw1);
565
566         PrintDebug(core->vm_info, core, "8259 PIC: Setting ICW3 = %x (wr_Master2)\n", cw);
567
568         state->master_icw3 = cw;
569
570         if (cw1->ic4 == 1) {
571             state->master_state = ICW4;
572         } else {
573             state->master_state = READY;
574         }
575
576     } else if (state->master_state == ICW4) {
577         PrintDebug(core->vm_info, core, "8259 PIC: Setting ICW4 = %x (wr_Master2)\n", cw);
578         state->master_icw4 = cw;
579         state->master_state = READY;
580     } else if ((state->master_state == ICW1) || (state->master_state == READY)) {
581         PrintDebug(core->vm_info, core, "8259 PIC: Setting IMR = %x (wr_Master2)\n", cw);
582         state->master_imr = cw;
583     } else {
584         // error
585         PrintError(core->vm_info, core, "8259 PIC: Invalid master PIC State (wr_Master2) (state=%d)\n", 
586                 state->master_state);
587         return -1;
588     }
589
590     return 1;
591 }
592
593 static int write_slave_port1(struct guest_info * core, ushort_t port, void * src, uint_t length, void * priv_data) {
594     struct pic_internal * state = (struct pic_internal *)priv_data;
595     uint8_t cw = *(uint8_t *)src;
596
597     PrintDebug(core->vm_info, core, "8259 PIC: Write slave port 1 with 0x%x\n",cw);
598
599     if (length != 1) {
600         // error
601         PrintError(core->vm_info, core, "8259 PIC: Invalid Write length (wr_Slave1)\n");
602         return -1;
603     }
604
605     v3_clear_pending_intr(core);
606
607     if (IS_ICW1(cw)) {
608         PrintDebug(core->vm_info, core, "8259 PIC: Setting ICW1 = %x (wr_Slave1)\n", cw);
609         state->slave_icw1 = cw;
610         state->slave_state = ICW2;
611     } else if (state->slave_state == READY) {
612         if (IS_OCW2(cw)) {
613             // handle the EOI here
614             struct ocw2 * cw2 =  (struct ocw2 *)&cw;
615
616             PrintDebug(core->vm_info, core, "8259 PIC: Setting OCW2 = %x (wr_Slave1)\n", cw);
617
618             if ((cw2->EOI) && (!cw2->R) && (cw2->SL)) {
619                 // specific EOI;
620                 state->slave_isr &= ~(0x01 << cw2->level);
621             } else if ((cw2->EOI) & (!cw2->R) && (!cw2->SL)) {
622                 int i;
623                 // Non-specific EOI
624                 PrintDebug(core->vm_info, core, "8259 PIC: Pre ISR = %x (wr_Slave1)\n", state->slave_isr);
625                 for (i = 0; i < 8; i++) {
626                     if (state->slave_isr & (0x01 << i)) {
627                         state->slave_isr &= ~(0x01 << i);
628                         break;
629                     }
630                 }
631                 PrintDebug(core->vm_info, core, "8259 PIC: Post ISR = %x (wr_Slave1)\n", state->slave_isr);
632             } else {
633                 PrintError(core->vm_info, core, "8259 PIC: Command not handled or invalid  (wr_Slave1)\n");
634                 return -1;
635             }
636
637             if (cw2->EOI) {
638                 if (pic_get_intr_number(core,  state) != -1) {
639                     PrintError(core->vm_info, core, "Interrupt pending after EOI\n");
640                 }
641             }
642
643
644
645             state->slave_ocw2 = cw;
646         } else if (IS_OCW3(cw)) {
647             // Basically sets the IRR/ISR read flag
648             PrintDebug(core->vm_info, core, "8259 PIC: Setting OCW3 = %x (wr_Slave1)\n", cw);
649             state->slave_ocw3 = cw;
650         } else {
651             PrintError(core->vm_info, core, "8259 PIC: Invalid command work (wr_Slave1)\n");
652             return -1;
653         }
654     } else {
655         PrintError(core->vm_info, core, "8259 PIC: Invalid State writing (wr_Slave1)\n");
656         return -1;
657     }
658
659     return 1;
660 }
661
662 static int write_slave_port2(struct guest_info * core, ushort_t port, void * src, uint_t length, void * priv_data) {
663     struct pic_internal * state = (struct pic_internal *)priv_data;
664     uint8_t cw = *(uint8_t *)src;    
665
666     PrintDebug(core->vm_info, core, "8259 PIC: Write slave port 2 with 0x%x\n",cw);
667
668     if (length != 1) {
669         PrintError(core->vm_info, core, "8259 PIC: Invalid write length (wr_Slave2)\n");
670         return -1;
671     }
672
673     v3_clear_pending_intr(core);
674
675
676     if (state->slave_state == ICW2) {
677         struct icw1 * cw1 =  (struct icw1 *)&(state->master_icw1);
678
679         PrintDebug(core->vm_info, core, "8259 PIC: Setting ICW2 = %x (wr_Slave2)\n", cw);
680
681         state->slave_icw2 = cw;
682
683         if (cw1->sngl == 0) {
684             state->slave_state = ICW3;
685         } else if (cw1->ic4 == 1) {
686             state->slave_state = ICW4;
687         } else {
688             state->slave_state = READY;
689         }
690
691     } else if (state->slave_state == ICW3) {
692         struct icw1 * cw1 =  (struct icw1 *)&(state->master_icw1);
693
694         PrintDebug(core->vm_info, core, "8259 PIC: Setting ICW3 = %x (wr_Slave2)\n", cw);
695
696         state->slave_icw3 = cw;
697
698         if (cw1->ic4 == 1) {
699             state->slave_state = ICW4;
700         } else {
701             state->slave_state = READY;
702         }
703
704     } else if (state->slave_state == ICW4) {
705         PrintDebug(core->vm_info, core, "8259 PIC: Setting ICW4 = %x (wr_Slave2)\n", cw);
706         state->slave_icw4 = cw;
707         state->slave_state = READY;
708     } else if ((state->slave_state == ICW1) || (state->slave_state == READY)) {
709         PrintDebug(core->vm_info, core, "8259 PIC: Setting IMR = %x (wr_Slave2)\n", cw);
710         state->slave_imr = cw;
711     } else {
712         PrintError(core->vm_info, core, "8259 PIC: Invalid State at write (wr_Slave2)\n");
713         return -1;
714     }
715
716     return 1;
717 }
718
719
720
721
722 static int read_elcr_port(struct guest_info * core, ushort_t port, void * dst, uint_t length, void * priv_data) {
723     struct pic_internal * state = (struct pic_internal *)priv_data;
724     
725     if (length != 1) {
726         PrintError(core->vm_info, core, "ELCR read of invalid length %d\n", length);
727         return -1;
728     }
729
730     if (port == ELCR1_PORT) {
731         // master
732         *(uint8_t *)dst = state->master_elcr;
733     } else if (port == ELCR2_PORT) {
734         *(uint8_t *)dst = state->slave_elcr;
735     } else {
736         PrintError(core->vm_info, core, "Invalid port %x\n", port);
737         return -1;
738     }
739
740     return length;
741 }
742
743
744 static int write_elcr_port(struct guest_info * core, ushort_t port, void * src, uint_t length, void * priv_data) {
745     struct pic_internal * state = (struct pic_internal *)priv_data;
746     
747     if (length != 1) {
748         PrintError(core->vm_info, core, "ELCR read of invalid length %d\n", length);
749         return -1;
750     }
751
752     if (port == ELCR1_PORT) {
753         // master
754         state->master_elcr  = (*(uint8_t *)src) & state->master_elcr_mask;
755     } else if (port == ELCR2_PORT) {
756         state->slave_elcr  = (*(uint8_t *)src) & state->slave_elcr_mask;
757     } else {
758         PrintError(core->vm_info, core, "Invalid port %x\n", port);
759         return -1;
760     }
761
762     return length;
763 }
764
765
766
767 static int pic_free(struct pic_internal * state) {
768     struct guest_info * core = state->core;
769
770     v3_remove_intr_controller(core, state->controller_handle);
771     v3_remove_intr_router(core->vm_info, state->router_handle);
772
773     V3_Free(state);
774     return 0;
775 }
776
777 #ifdef V3_CONFIG_CHECKPOINT
778 static int pic_save(struct v3_chkpt_ctx * ctx, void * private_data) {
779     struct pic_internal * pic = (struct pic_internal *)private_data;
780
781     V3_CHKPT_SAVE(ctx, "MASTER_IRR", pic->master_irr, savefailout);
782     V3_CHKPT_SAVE(ctx, "SLAVE_IRR", pic->slave_irr, savefailout);
783   
784     V3_CHKPT_SAVE(ctx, "MASTER_ISR", pic->master_isr, savefailout);
785     V3_CHKPT_SAVE(ctx, "SLAVE_ISR", pic->slave_isr, savefailout);
786
787     V3_CHKPT_SAVE(ctx, "MASTER_ELCR", pic->master_elcr, savefailout);
788     V3_CHKPT_SAVE(ctx, "SLAVE_ELCR", pic->slave_elcr, savefailout);
789     V3_CHKPT_SAVE(ctx, "MASTER_ELCR_MASK", pic->master_elcr_mask, savefailout);
790     V3_CHKPT_SAVE(ctx, "SLAVE_ELCR_MASK", pic->slave_elcr_mask, savefailout);
791
792     V3_CHKPT_SAVE(ctx, "MASTER_ICW1", pic->master_icw1, savefailout);
793     V3_CHKPT_SAVE(ctx, "MASTER_ICW2", pic->master_icw2, savefailout);
794     V3_CHKPT_SAVE(ctx, "MASTER_ICW3", pic->master_icw3, savefailout);
795     V3_CHKPT_SAVE(ctx, "MASTER_ICW4", pic->master_icw4, savefailout);
796
797
798     V3_CHKPT_SAVE(ctx, "SLAVE_ICW1", pic->slave_icw1, savefailout);
799     V3_CHKPT_SAVE(ctx, "SLAVE_ICW2", pic->slave_icw2, savefailout);
800     V3_CHKPT_SAVE(ctx, "SLAVE_ICW3", pic->slave_icw3, savefailout);
801     V3_CHKPT_SAVE(ctx, "SLAVE_ICW4", pic->slave_icw4, savefailout);
802
803
804     V3_CHKPT_SAVE(ctx, "MASTER_IMR", pic->master_imr, savefailout);
805     V3_CHKPT_SAVE(ctx, "SLAVE_IMR", pic->slave_imr, savefailout);
806     V3_CHKPT_SAVE(ctx, "MASTER_OCW2", pic->master_ocw2, savefailout);
807     V3_CHKPT_SAVE(ctx, "MASTER_OCW3", pic->master_ocw3, savefailout);
808     V3_CHKPT_SAVE(ctx, "SLAVE_OCW2", pic->slave_ocw2, savefailout);
809     V3_CHKPT_SAVE(ctx, "SLAVE_OCW3", pic->slave_ocw3, savefailout);
810
811     V3_CHKPT_SAVE(ctx, "MASTER_STATE", pic->master_state, savefailout);
812     V3_CHKPT_SAVE(ctx, "SLAVE_STATE", pic->slave_state, savefailout);
813
814     
815     return 0;
816
817  savefailout:
818     PrintError(VM_NONE, VCORE_NONE, "Failed to save PIC\n");
819     return -1;
820
821 }
822
823 static int pic_load(struct v3_chkpt_ctx * ctx, void * private_data) {
824     struct pic_internal * pic = (struct pic_internal *)private_data;
825
826    
827     V3_CHKPT_LOAD(ctx, "MASTER_IRR", pic->master_irr, loadfailout);
828     V3_CHKPT_LOAD(ctx, "SLAVE_IRR", pic->slave_irr, loadfailout);
829   
830     V3_CHKPT_LOAD(ctx, "MASTER_ISR", pic->master_isr, loadfailout);
831     V3_CHKPT_LOAD(ctx, "SLAVE_ISR", pic->slave_isr, loadfailout);
832
833     V3_CHKPT_LOAD(ctx, "MASTER_ELCR", pic->master_elcr, loadfailout);
834     V3_CHKPT_LOAD(ctx, "SLAVE_ELCR", pic->slave_elcr, loadfailout);
835     V3_CHKPT_LOAD(ctx, "MASTER_ELCR_MASK", pic->master_elcr_mask, loadfailout);
836     V3_CHKPT_LOAD(ctx, "SLAVE_ELCR_MASK", pic->slave_elcr_mask, loadfailout);
837
838     V3_CHKPT_LOAD(ctx, "MASTER_ICW1", pic->master_icw1, loadfailout);
839     V3_CHKPT_LOAD(ctx, "MASTER_ICW2", pic->master_icw2, loadfailout);
840     V3_CHKPT_LOAD(ctx, "MASTER_ICW3", pic->master_icw3, loadfailout);
841     V3_CHKPT_LOAD(ctx, "MASTER_ICW4", pic->master_icw4, loadfailout);
842
843
844     V3_CHKPT_LOAD(ctx, "SLAVE_ICW1", pic->slave_icw1, loadfailout);
845     V3_CHKPT_LOAD(ctx, "SLAVE_ICW2", pic->slave_icw2, loadfailout);
846     V3_CHKPT_LOAD(ctx, "SLAVE_ICW3", pic->slave_icw3, loadfailout);
847     V3_CHKPT_LOAD(ctx, "SLAVE_ICW4", pic->slave_icw4, loadfailout);
848
849
850     V3_CHKPT_LOAD(ctx, "MASTER_IMR", pic->master_imr, loadfailout);
851     V3_CHKPT_LOAD(ctx, "SLAVE_IMR", pic->slave_imr, loadfailout);
852     V3_CHKPT_LOAD(ctx, "MASTER_OCW2", pic->master_ocw2, loadfailout);
853     V3_CHKPT_LOAD(ctx, "MASTER_OCW3", pic->master_ocw3, loadfailout);
854     V3_CHKPT_LOAD(ctx, "SLAVE_OCW2", pic->slave_ocw2, loadfailout);
855     V3_CHKPT_LOAD(ctx, "SLAVE_OCW3", pic->slave_ocw3, loadfailout);
856
857     V3_CHKPT_LOAD(ctx, "MASTER_STATE", pic->master_state, loadfailout);
858     V3_CHKPT_LOAD(ctx, "SLAVE_STATE", pic->slave_state, loadfailout);
859
860     return 0;
861
862  loadfailout:
863     PrintError(VM_NONE, VCORE_NONE, "Failed to load PIC\n");
864     return -1;
865 }
866
867 #endif
868
869
870 static struct v3_device_ops dev_ops = {
871     .free = (int (*)(void *))pic_free,
872 #ifdef V3_CONFIG_CHECKPOINT
873     .save = pic_save,
874     .load = pic_load
875 #endif
876 };
877
878
879
880
881
882 static int pic_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
883     struct pic_internal * state = NULL;
884     char * dev_id = v3_cfg_val(cfg, "ID");
885     int ret = 0;
886
887     // PIC is only usable in non-multicore environments
888     // just hardcode the core context
889     struct guest_info * core = &(vm->cores[0]);
890         
891     state = (struct pic_internal *)V3_Malloc(sizeof(struct pic_internal));
892
893     if (!state) {
894         PrintError(vm, VCORE_NONE, "Cannot allocate in init\n");
895         return -1;
896     }
897
898     struct vm_device * dev = v3_add_device(vm, dev_id, &dev_ops, state);
899
900     if (dev == NULL) {
901         PrintError(vm, VCORE_NONE, "Could not add device %s\n", dev_id);
902         V3_Free(state);
903         return -1;
904     }
905
906     state->core = core;
907
908     state->controller_handle = v3_register_intr_controller(core, &intr_ops, state);
909     state->router_handle = v3_register_intr_router(vm, &router_ops, state);
910
911     state->master_irr = 0;
912     state->master_isr = 0;
913     state->master_elcr = 0;
914     state->master_elcr_mask = 0xf8;
915     state->master_icw1 = 0;
916     state->master_icw2 = 0;
917     state->master_icw3 = 0;
918     state->master_icw4 = 0;
919     state->master_imr = 0;
920     state->master_ocw2 = 0;
921     state->master_ocw3 = 0x02;
922     state->master_state = ICW1;
923
924
925     state->slave_irr = 0;
926     state->slave_isr = 0;
927     state->slave_elcr = 0;
928     state->slave_elcr_mask = 0xde;
929     state->slave_icw1 = 0;
930     state->slave_icw2 = 0;
931     state->slave_icw3 = 0;
932     state->slave_icw4 = 0;
933     state->slave_imr = 0;
934     state->slave_ocw2 = 0;
935     state->slave_ocw3 = 0x02;
936     state->slave_state = ICW1;
937
938
939     ret |= v3_dev_hook_io(dev, MASTER_PORT1, &read_master_port1, &write_master_port1);
940     ret |= v3_dev_hook_io(dev, MASTER_PORT2, &read_master_port2, &write_master_port2);
941     ret |= v3_dev_hook_io(dev, SLAVE_PORT1, &read_slave_port1, &write_slave_port1);
942     ret |= v3_dev_hook_io(dev, SLAVE_PORT2, &read_slave_port2, &write_slave_port2);
943
944
945     ret |= v3_dev_hook_io(dev, ELCR1_PORT, &read_elcr_port, &write_elcr_port);
946     ret |= v3_dev_hook_io(dev, ELCR2_PORT, &read_elcr_port, &write_elcr_port);
947
948     if (ret != 0) {
949         PrintError(vm, VCORE_NONE, "Error hooking io ports\n");
950         v3_remove_device(dev);
951         return -1;
952     }
953
954     return 0;
955 }
956
957
958
959 device_register("8259A", pic_init);