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.


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