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.


add interrupt deinitialization to devices
[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 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     uchar_t master_irr;
128     uchar_t slave_irr;
129   
130     uchar_t master_isr;
131     uchar_t slave_isr;
132
133     uchar_t master_elcr;
134     uchar_t slave_elcr;
135     uchar_t master_elcr_mask;
136     uchar_t slave_elcr_mask;
137
138     uchar_t master_icw1;
139     uchar_t master_icw2;
140     uchar_t master_icw3;
141     uchar_t master_icw4;
142
143
144     uchar_t slave_icw1;
145     uchar_t slave_icw2;
146     uchar_t slave_icw3;
147     uchar_t slave_icw4;
148
149
150     uchar_t master_imr;
151     uchar_t slave_imr;
152     uchar_t master_ocw2;
153     uchar_t master_ocw3;
154     uchar_t slave_ocw2;
155     uchar_t slave_ocw3;
156
157     pic_state_t master_state;
158     pic_state_t slave_state;
159
160     struct guest_info * core;
161
162
163     void * router_handle;
164     void * controller_handle;
165 };
166
167
168 static void DumpPICState(struct pic_internal *p)
169 {
170
171     PrintDebug("8259 PIC: master_state=0x%x\n",p->master_state);
172     PrintDebug("8259 PIC: master_irr=0x%x\n",p->master_irr);
173     PrintDebug("8259 PIC: master_isr=0x%x\n",p->master_isr);
174     PrintDebug("8259 PIC: master_imr=0x%x\n",p->master_imr);
175
176     PrintDebug("8259 PIC: master_ocw2=0x%x\n",p->master_ocw2);
177     PrintDebug("8259 PIC: master_ocw3=0x%x\n",p->master_ocw3);
178
179     PrintDebug("8259 PIC: master_icw1=0x%x\n",p->master_icw1);
180     PrintDebug("8259 PIC: master_icw2=0x%x\n",p->master_icw2);
181     PrintDebug("8259 PIC: master_icw3=0x%x\n",p->master_icw3);
182     PrintDebug("8259 PIC: master_icw4=0x%x\n",p->master_icw4);
183
184     PrintDebug("8259 PIC: slave_state=0x%x\n",p->slave_state);
185     PrintDebug("8259 PIC: slave_irr=0x%x\n",p->slave_irr);
186     PrintDebug("8259 PIC: slave_isr=0x%x\n",p->slave_isr);
187     PrintDebug("8259 PIC: slave_imr=0x%x\n",p->slave_imr);
188
189     PrintDebug("8259 PIC: slave_ocw2=0x%x\n",p->slave_ocw2);
190     PrintDebug("8259 PIC: slave_ocw3=0x%x\n",p->slave_ocw3);
191
192     PrintDebug("8259 PIC: slave_icw1=0x%x\n",p->slave_icw1);
193     PrintDebug("8259 PIC: slave_icw2=0x%x\n",p->slave_icw2);
194     PrintDebug("8259 PIC: slave_icw3=0x%x\n",p->slave_icw3);
195     PrintDebug("8259 PIC: slave_icw4=0x%x\n",p->slave_icw4);
196
197 }
198
199
200 static int pic_raise_intr(struct v3_vm_info * vm, void * private_data, int irq) {
201     struct pic_internal * state = (struct pic_internal*)private_data;
202
203     if (irq == 2) {
204         irq = 9;
205         state->master_irr |= 0x04;  // PAD
206     }
207
208     PrintDebug("8259 PIC: Raising irq %d in the PIC\n", irq);
209
210     if (irq <= 7) {
211         state->master_irr |= 0x01 << irq;
212     } else if ((irq > 7) && (irq < 16)) {
213         state->slave_irr |= 0x01 << (irq - 8);  // PAD if -7 then irq 15=no irq
214     } else {
215         PrintDebug("8259 PIC: Invalid IRQ raised (%d)\n", irq);
216         return -1;
217     }
218
219     v3_interrupt_cpu(vm, 0, 0);
220
221     return 0;
222 }
223
224
225 static int pic_lower_intr(struct v3_vm_info * vm, void * private_data, int irq) {
226     struct pic_internal * state = (struct pic_internal*)private_data;
227
228     PrintDebug("[pic_lower_intr] IRQ line %d now low\n", irq);
229     if (irq <= 7) {
230
231         state->master_irr &= ~(1 << irq);
232         if ((state->master_irr & ~(state->master_imr)) == 0) {
233             PrintDebug("\t\tFIXME: Master maybe should do sth\n");
234         }
235     } else if ((irq > 7) && (irq < 16)) {
236
237         state->slave_irr &= ~(1 << (irq - 8));
238         if ((state->slave_irr & (~(state->slave_imr))) == 0) {
239             PrintDebug("\t\tFIXME: Slave maybe should do sth\n");
240         }
241     }
242     return 0;
243 }
244
245
246
247 static int pic_intr_pending(struct guest_info * info, void * private_data) {
248     struct pic_internal * state = (struct pic_internal*)private_data;
249
250     if ((state->master_irr & ~(state->master_imr)) || 
251         (state->slave_irr & ~(state->slave_imr))) {
252         return 1;
253     }
254
255     return 0;
256 }
257
258 static int pic_get_intr_number(struct guest_info * info, void * private_data) {
259     struct pic_internal * state = (struct pic_internal *)private_data;
260     int i = 0;
261     int irq = -1;
262
263     PrintDebug("8259 PIC: getnum: master_irr: 0x%x master_imr: 0x%x\n", state->master_irr, state->master_imr);
264     PrintDebug("8259 PIC: getnum: slave_irr: 0x%x slave_imr: 0x%x\n", state->slave_irr, state->slave_imr);
265
266     for (i = 0; i < 16; i++) {
267         if (i <= 7) {
268             if (((state->master_irr & ~(state->master_imr)) >> i) & 0x01) {
269                 //state->master_isr |= (0x1 << i);
270                 // reset the irr
271                 //state->master_irr &= ~(0x1 << i);
272                 PrintDebug("8259 PIC: IRQ: %d, master_icw2: %x\n", i, state->master_icw2);
273                 irq = i + state->master_icw2;
274                 break;
275             }
276         } else {
277             if (((state->slave_irr & ~(state->slave_imr)) >> (i - 8)) & 0x01) {
278                 //state->slave_isr |= (0x1 << (i - 8));
279                 //state->slave_irr &= ~(0x1 << (i - 8));
280                 PrintDebug("8259 PIC: IRQ: %d, slave_icw2: %x\n", i, state->slave_icw2);
281                 irq = (i - 8) + state->slave_icw2;
282                 break;
283             }
284         }
285     }
286
287 #if 1
288     if ((i == 15) || (i == 6)) { 
289         DumpPICState(state);
290     }
291 #endif
292   
293     if (i == 16) { 
294         return -1;
295     } else {
296         PrintDebug("8259 PIC: get num is returning %d\n",irq);
297         return irq;
298     }
299 }
300
301
302
303 /* The IRQ number is the number returned by pic_get_intr_number(), not the pin number */
304 static int pic_begin_irq(struct guest_info * info, void * private_data, int irq) {
305     struct pic_internal * state = (struct pic_internal*)private_data;
306     
307     if ((irq >= state->master_icw2) && (irq <= state->master_icw2 + 7)) {
308        irq &= 0x7;
309     } else if ((irq >= state->slave_icw2) && (irq <= state->slave_icw2 + 7)) {
310        irq &= 0x7;
311        irq += 8;
312     } else {
313        //    PrintError("8259 PIC: Could not find IRQ (0x%x) to Begin\n",irq);
314        return -1;
315     }
316     
317     if (irq <= 7) {
318         // This should always be true: See pic_get_intr_number
319        if (((state->master_irr & ~(state->master_imr)) >> irq) & 0x01) {
320            state->master_isr |= (0x1 << irq);
321
322            if (!(state->master_elcr & (0x1 << irq))) {
323                state->master_irr &= ~(0x1 << irq);
324            }
325        } else {
326            PrintDebug("8259 PIC: (master) Ignoring begin_irq for %d since I don't own it\n",irq);
327        }
328
329     } else {
330         // This should always be true: See pic_get_intr_number
331         if (((state->slave_irr & ~(state->slave_imr)) >> (irq - 8)) & 0x01) {
332            state->slave_isr |= (0x1 << (irq - 8));
333            
334            if (!(state->slave_elcr & (0x1 << (irq - 8)))) {
335                state->slave_irr &= ~(0x1 << (irq - 8));
336            }
337         } else {
338            PrintDebug("8259 PIC: (slave) Ignoring begin_irq for %d since I don't own it\n",irq);
339         }
340
341     }
342
343     return 0;
344 }
345
346
347 /*
348   static int pic_end_irq(void * private_data, int irq) {
349   return 0;
350   }
351 */
352
353
354
355 static struct intr_ctrl_ops intr_ops = {
356     .intr_pending = pic_intr_pending,
357     .get_intr_number = pic_get_intr_number,
358     .begin_irq = pic_begin_irq
359 };
360
361 static struct intr_router_ops router_ops = {
362     .raise_intr = pic_raise_intr,
363     .lower_intr = pic_lower_intr
364 };
365
366
367 static int read_master_port1(struct guest_info * core, ushort_t port, void * dst, uint_t length, void * priv_data) {
368     struct pic_internal * state = (struct pic_internal *)priv_data;
369
370     if (length != 1) {
371         PrintError("8259 PIC: Invalid Read length (rd_Master1)\n");
372         return -1;
373     }
374   
375     if ((state->master_ocw3 & 0x03) == 0x02) {
376         *(uchar_t *)dst = state->master_irr;
377     } else if ((state->master_ocw3 & 0x03) == 0x03) {
378         *(uchar_t *)dst = state->master_isr;
379     } else {
380         *(uchar_t *)dst = 0;
381     }
382   
383     return 1;
384 }
385
386 static int read_master_port2(struct guest_info * core, ushort_t port, void * dst, uint_t length, void * priv_data) {
387     struct pic_internal * state = (struct pic_internal *)priv_data;
388
389     if (length != 1) {
390         PrintError("8259 PIC: Invalid Read length (rd_Master2)\n");
391         return -1;
392     }
393
394     *(uchar_t *)dst = state->master_imr;
395
396     return 1;
397   
398 }
399
400 static int read_slave_port1(struct guest_info * core, ushort_t port, void * dst, uint_t length, void * priv_data) {
401     struct pic_internal * state = (struct pic_internal *)priv_data;
402
403     if (length != 1) {
404         PrintError("8259 PIC: Invalid Read length (rd_Slave1)\n");
405         return -1;
406     }
407   
408     if ((state->slave_ocw3 & 0x03) == 0x02) {
409         *(uchar_t*)dst = state->slave_irr;
410     } else if ((state->slave_ocw3 & 0x03) == 0x03) {
411         *(uchar_t *)dst = state->slave_isr;
412     } else {
413         *(uchar_t *)dst = 0;
414     }
415
416     return 1;
417 }
418
419 static int read_slave_port2(struct guest_info * core, ushort_t port, void * dst, uint_t length, void * priv_data) {
420     struct pic_internal * state = (struct pic_internal *)priv_data;
421
422     if (length != 1) {
423         PrintError("8259 PIC: Invalid Read length  (rd_Slave2)\n");
424         return -1;
425     }
426
427     *(uchar_t *)dst = state->slave_imr;
428
429     return 1;
430 }
431
432
433 static int write_master_port1(struct guest_info * core, ushort_t port, void * src, uint_t length, void * priv_data) {
434     struct pic_internal * state = (struct pic_internal *)priv_data;
435     uchar_t cw = *(uchar_t *)src;
436
437     PrintDebug("8259 PIC: Write master port 1 with 0x%x\n",cw);
438
439     if (length != 1) {
440         PrintError("8259 PIC: Invalid Write length (wr_Master1)\n");
441         return -1;
442     }
443
444     v3_clear_pending_intr(core);
445
446     if (IS_ICW1(cw)) {
447
448         PrintDebug("8259 PIC: Setting ICW1 = %x (wr_Master1)\n", cw);
449
450         state->master_icw1 = cw;
451         state->master_state = ICW2;
452
453     } else if (state->master_state == READY) {
454         if (IS_OCW2(cw)) {
455             // handle the EOI here
456             struct ocw2 * cw2 =  (struct ocw2*)&cw;
457
458             PrintDebug("8259 PIC: Handling OCW2 = %x (wr_Master1)\n", cw);
459
460             if ((cw2->EOI) && (!cw2->R) && (cw2->SL)) {
461                 // specific EOI;
462                 state->master_isr &= ~(0x01 << cw2->level);
463             } else if ((cw2->EOI) & (!cw2->R) && (!cw2->SL)) {
464                 int i;
465                 // Non-specific EOI
466                 PrintDebug("8259 PIC: Pre ISR = %x (wr_Master1)\n", state->master_isr);
467                 for (i = 0; i < 8; i++) {
468                     if (state->master_isr & (0x01 << i)) {
469                         state->master_isr &= ~(0x01 << i);
470                         break;
471                     }
472                 }       
473                 PrintDebug("8259 PIC: Post ISR = %x (wr_Master1)\n", state->master_isr);
474             } else if (!(cw2->EOI) && (cw2->R) && (cw2->SL)) {
475                 PrintDebug("8259 PIC: Ignoring set-priority, priorities not implemented (level=%d, wr_Master1)\n", cw2->level);
476             } else if (!(cw2->EOI) && !(cw2->R) && (cw2->SL)) {
477                 PrintDebug("8259 PIC: Ignoring no-op (level=%d, wr_Master1)\n", cw2->level);
478             } else {
479                 PrintError("8259 PIC: Command not handled, or in error (wr_Master1)\n");
480                 return -1;
481             }
482
483             state->master_ocw2 = cw;
484         } else if (IS_OCW3(cw)) {
485             PrintDebug("8259 PIC: Handling OCW3 = %x (wr_Master1)\n", cw);
486             state->master_ocw3 = cw;
487         } else {
488             PrintError("8259 PIC: Invalid OCW to PIC (wr_Master1)\n");
489             PrintError("8259 PIC: CW=%x\n", cw);
490             return -1;
491         }
492     } else {
493         PrintError("8259 PIC: Invalid PIC State (wr_Master1)\n");
494         PrintError("8259 PIC: CW=%x\n", cw);
495         return -1;
496     }
497
498     return 1;
499 }
500
501 static int write_master_port2(struct guest_info * core, ushort_t port, void * src, uint_t length, void * priv_data) {
502     struct pic_internal * state = (struct pic_internal *)priv_data;
503     uchar_t cw = *(uchar_t *)src;    
504
505     PrintDebug("8259 PIC: Write master port 2 with 0x%x\n",cw);
506
507     if (length != 1) {
508         PrintError("8259 PIC: Invalid Write length (wr_Master2)\n");
509         return -1;
510     }
511
512     v3_clear_pending_intr(core);
513
514     if (state->master_state == ICW2) {
515         struct icw1 * cw1 = (struct icw1 *)&(state->master_icw1);
516
517         PrintDebug("8259 PIC: Setting ICW2 = %x (wr_Master2)\n", cw);
518         state->master_icw2 = cw;
519
520
521
522         if (cw1->sngl == 0) {
523             state->master_state = ICW3;
524         } else if (cw1->ic4 == 1) {
525             state->master_state = ICW4;
526         } else {
527             state->master_state = READY;
528         }
529
530
531
532     } else if (state->master_state == ICW3) {
533         struct icw1 * cw1 = (struct icw1 *)&(state->master_icw1);
534
535         PrintDebug("8259 PIC: Setting ICW3 = %x (wr_Master2)\n", cw);
536
537         state->master_icw3 = cw;
538
539         if (cw1->ic4 == 1) {
540             state->master_state = ICW4;
541         } else {
542             state->master_state = READY;
543         }
544
545     } else if (state->master_state == ICW4) {
546         PrintDebug("8259 PIC: Setting ICW4 = %x (wr_Master2)\n", cw);
547         state->master_icw4 = cw;
548         state->master_state = READY;
549     } else if ((state->master_state == ICW1) || (state->master_state == READY)) {
550         PrintDebug("8259 PIC: Setting IMR = %x (wr_Master2)\n", cw);
551         state->master_imr = cw;
552     } else {
553         // error
554         PrintError("8259 PIC: Invalid master PIC State (wr_Master2) (state=%d)\n", 
555                 state->master_state);
556         return -1;
557     }
558
559     return 1;
560 }
561
562 static int write_slave_port1(struct guest_info * core, ushort_t port, void * src, uint_t length, void * priv_data) {
563     struct pic_internal * state = (struct pic_internal *)priv_data;
564     uchar_t cw = *(uchar_t *)src;
565
566     PrintDebug("8259 PIC: Write slave port 1 with 0x%x\n",cw);
567
568     if (length != 1) {
569         // error
570         PrintError("8259 PIC: Invalid Write length (wr_Slave1)\n");
571         return -1;
572     }
573
574     v3_clear_pending_intr(core);
575
576     if (IS_ICW1(cw)) {
577         PrintDebug("8259 PIC: Setting ICW1 = %x (wr_Slave1)\n", cw);
578         state->slave_icw1 = cw;
579         state->slave_state = ICW2;
580     } else if (state->slave_state == READY) {
581         if (IS_OCW2(cw)) {
582             // handle the EOI here
583             struct ocw2 * cw2 =  (struct ocw2 *)&cw;
584
585             PrintDebug("8259 PIC: Setting OCW2 = %x (wr_Slave1)\n", cw);
586
587             if ((cw2->EOI) && (!cw2->R) && (cw2->SL)) {
588                 // specific EOI;
589                 state->slave_isr &= ~(0x01 << cw2->level);
590             } else if ((cw2->EOI) & (!cw2->R) && (!cw2->SL)) {
591                 int i;
592                 // Non-specific EOI
593                 PrintDebug("8259 PIC: Pre ISR = %x (wr_Slave1)\n", state->slave_isr);
594                 for (i = 0; i < 8; i++) {
595                     if (state->slave_isr & (0x01 << i)) {
596                         state->slave_isr &= ~(0x01 << i);
597                         break;
598                     }
599                 }
600                 PrintDebug("8259 PIC: Post ISR = %x (wr_Slave1)\n", state->slave_isr);
601             } else {
602                 PrintError("8259 PIC: Command not handled or invalid  (wr_Slave1)\n");
603                 return -1;
604             }
605
606             state->slave_ocw2 = cw;
607         } else if (IS_OCW3(cw)) {
608             // Basically sets the IRR/ISR read flag
609             PrintDebug("8259 PIC: Setting OCW3 = %x (wr_Slave1)\n", cw);
610             state->slave_ocw3 = cw;
611         } else {
612             PrintError("8259 PIC: Invalid command work (wr_Slave1)\n");
613             return -1;
614         }
615     } else {
616         PrintError("8259 PIC: Invalid State writing (wr_Slave1)\n");
617         return -1;
618     }
619
620     return 1;
621 }
622
623 static int write_slave_port2(struct guest_info * core, ushort_t port, void * src, uint_t length, void * priv_data) {
624     struct pic_internal * state = (struct pic_internal *)priv_data;
625     uchar_t cw = *(uchar_t *)src;    
626
627     PrintDebug("8259 PIC: Write slave port 2 with 0x%x\n",cw);
628
629     if (length != 1) {
630         PrintError("8259 PIC: Invalid write length (wr_Slave2)\n");
631         return -1;
632     }
633
634     v3_clear_pending_intr(core);
635
636
637     if (state->slave_state == ICW2) {
638         struct icw1 * cw1 =  (struct icw1 *)&(state->master_icw1);
639
640         PrintDebug("8259 PIC: Setting ICW2 = %x (wr_Slave2)\n", cw);
641
642         state->slave_icw2 = cw;
643
644         if (cw1->sngl == 0) {
645             state->slave_state = ICW3;
646         } else if (cw1->ic4 == 1) {
647             state->slave_state = ICW4;
648         } else {
649             state->slave_state = READY;
650         }
651
652     } else if (state->slave_state == ICW3) {
653         struct icw1 * cw1 =  (struct icw1 *)&(state->master_icw1);
654
655         PrintDebug("8259 PIC: Setting ICW3 = %x (wr_Slave2)\n", cw);
656
657         state->slave_icw3 = cw;
658
659         if (cw1->ic4 == 1) {
660             state->slave_state = ICW4;
661         } else {
662             state->slave_state = READY;
663         }
664
665     } else if (state->slave_state == ICW4) {
666         PrintDebug("8259 PIC: Setting ICW4 = %x (wr_Slave2)\n", cw);
667         state->slave_icw4 = cw;
668         state->slave_state = READY;
669     } else if ((state->slave_state == ICW1) || (state->slave_state == READY)) {
670         PrintDebug("8259 PIC: Setting IMR = %x (wr_Slave2)\n", cw);
671         state->slave_imr = cw;
672     } else {
673         PrintError("8259 PIC: Invalid State at write (wr_Slave2)\n");
674         return -1;
675     }
676
677     return 1;
678 }
679
680
681
682
683 static int read_elcr_port(struct guest_info * core, ushort_t port, void * dst, uint_t length, void * priv_data) {
684     struct pic_internal * state = (struct pic_internal *)priv_data;
685     
686     if (length != 1) {
687         PrintError("ELCR read of invalid length %d\n", length);
688         return -1;
689     }
690
691     if (port == ELCR1_PORT) {
692         // master
693         *(uint8_t *)dst = state->master_elcr;
694     } else if (port == ELCR2_PORT) {
695         *(uint8_t *)dst = state->slave_elcr;
696     } else {
697         PrintError("Invalid port %x\n", port);
698         return -1;
699     }
700
701     return length;
702 }
703
704
705 static int write_elcr_port(struct guest_info * core, ushort_t port, void * src, uint_t length, void * priv_data) {
706     struct pic_internal * state = (struct pic_internal *)priv_data;
707     
708     if (length != 1) {
709         PrintError("ELCR read of invalid length %d\n", length);
710         return -1;
711     }
712
713     if (port == ELCR1_PORT) {
714         // master
715         state->master_elcr  = (*(uint8_t *)src) & state->master_elcr_mask;
716     } else if (port == ELCR2_PORT) {
717         state->slave_elcr  = (*(uint8_t *)src) & state->slave_elcr_mask;
718     } else {
719         PrintError("Invalid port %x\n", port);
720         return -1;
721     }
722
723     return length;
724 }
725
726
727
728 static int pic_free(struct pic_internal * state) {
729     struct guest_info * core = state->core;
730
731     v3_remove_intr_controller(core, state->controller_handle);
732     v3_remove_intr_router(core->vm_info, state->router_handle);
733
734     V3_Free(state);
735     return 0;
736 }
737
738
739 static struct v3_device_ops dev_ops = {
740     .free = (int (*)(void *))pic_free,
741
742 };
743
744
745
746
747
748 static int pic_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
749     struct pic_internal * state = NULL;
750     char * dev_id = v3_cfg_val(cfg, "ID");
751     int ret = 0;
752
753     // PIC is only usable in non-multicore environments
754     // just hardcode the core context
755     struct guest_info * core = &(vm->cores[0]);
756         
757     state = (struct pic_internal *)V3_Malloc(sizeof(struct pic_internal));
758
759     V3_ASSERT(state != NULL);
760
761     struct vm_device * dev = v3_add_device(vm, dev_id, &dev_ops, state);
762
763     if (dev == NULL) {
764         PrintError("Could not add device %s\n", dev_id);
765         V3_Free(state);
766         return -1;
767     }
768
769     state->core = core;
770
771     state->controller_handle = v3_register_intr_controller(core, &intr_ops, state);
772     state->router_handle = v3_register_intr_router(vm, &router_ops, state);
773
774     state->master_irr = 0;
775     state->master_isr = 0;
776     state->master_elcr = 0;
777     state->master_elcr_mask = 0xf8;
778     state->master_icw1 = 0;
779     state->master_icw2 = 0;
780     state->master_icw3 = 0;
781     state->master_icw4 = 0;
782     state->master_imr = 0;
783     state->master_ocw2 = 0;
784     state->master_ocw3 = 0x02;
785     state->master_state = ICW1;
786
787
788     state->slave_irr = 0;
789     state->slave_isr = 0;
790     state->slave_elcr = 0;
791     state->slave_elcr_mask = 0xde;
792     state->slave_icw1 = 0;
793     state->slave_icw2 = 0;
794     state->slave_icw3 = 0;
795     state->slave_icw4 = 0;
796     state->slave_imr = 0;
797     state->slave_ocw2 = 0;
798     state->slave_ocw3 = 0x02;
799     state->slave_state = ICW1;
800
801
802     ret |= v3_dev_hook_io(dev, MASTER_PORT1, &read_master_port1, &write_master_port1);
803     ret |= v3_dev_hook_io(dev, MASTER_PORT2, &read_master_port2, &write_master_port2);
804     ret |= v3_dev_hook_io(dev, SLAVE_PORT1, &read_slave_port1, &write_slave_port1);
805     ret |= v3_dev_hook_io(dev, SLAVE_PORT2, &read_slave_port2, &write_slave_port2);
806
807
808     ret |= v3_dev_hook_io(dev, ELCR1_PORT, &read_elcr_port, &write_elcr_port);
809     ret |= v3_dev_hook_io(dev, ELCR2_PORT, &read_elcr_port, &write_elcr_port);
810
811     if (ret != 0) {
812         PrintError("Error hooking io ports\n");
813         v3_remove_device(dev);
814         return -1;
815     }
816
817     return 0;
818 }
819
820
821
822 device_register("8259A", pic_init);