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.


Fix interrupt injection bug due to caching irq vectors after vector mappings have...
[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
27 #ifndef CONFIG_DEBUG_PIC
28 #undef PrintDebug
29 #define PrintDebug(fmt, args...)
30 #endif
31
32
33 typedef enum {RESET, ICW1, ICW2, ICW3, ICW4,  READY} pic_state_t;
34
35 static const uint_t MASTER_PORT1 = 0x20;
36 static const uint_t MASTER_PORT2 = 0x21;
37 static const uint_t SLAVE_PORT1 = 0xA0;
38 static const uint_t SLAVE_PORT2 = 0xA1;
39
40 static const uint_t ELCR1_PORT = 0x4d0;
41 static const uint_t ELCR2_PORT = 0x4d1;
42
43
44 #define IS_ICW1(x) (((x & 0x10) >> 4) == 0x1)
45 #define IS_OCW2(x) (((x & 0x18) >> 3) == 0x0)
46 #define IS_OCW3(x) (((x & 0x18) >> 3) == 0x1)
47
48
49 struct icw1 {
50     uint_t ic4    : 1;  // ICW4 has to be read
51     uint_t sngl   : 1;  // single (only one PIC)
52     uint_t adi    : 1;  // call address interval
53     uint_t ltim   : 1;  // level interrupt mode
54     uint_t one    : 1;
55     uint_t rsvd   : 3;
56 };
57
58
59 struct icw2 {
60     uint_t rsvd   : 3;
61     uint_t vector : 5;
62 };
63
64
65 // Each bit that is set indicates that the IR input has a slave
66 struct icw3_master {
67     uint_t S0   : 1;
68     uint_t S1   : 1;
69     uint_t S2   : 1;
70     uint_t S3   : 1;
71     uint_t S4   : 1;
72     uint_t S5   : 1;
73     uint_t S6   : 1;
74     uint_t S7   : 1;
75 };
76
77 // The ID is the Slave device ID
78 struct icw3_slave {
79     uint_t id     : 3;
80     uint_t zeroes : 5;
81 };
82
83 struct icw4 {
84     uint_t uPM    : 1;  // 1=x86
85     uint_t AEOI   : 1;  // Automatic End of Interrupt
86     uint_t M_S    : 1;  // only if buffered 1=master,0=slave 
87     uint_t BUF    : 1;  // buffered mode
88     uint_t SFNM   : 1;  // special fully nexted mode
89     uint_t zeroes : 3;
90 };
91
92
93 struct ocw1 {
94     uint_t m0     : 1;
95     uint_t m1     : 1;
96     uint_t m2     : 1;
97     uint_t m3     : 1;
98     uint_t m4     : 1;
99     uint_t m5     : 1;
100     uint_t m6     : 1;
101     uint_t m7     : 1;
102 };
103
104 struct ocw2 {
105     uint_t level  : 3;
106     uint_t cw_code : 2; // should be 00
107     uint_t EOI    : 1;
108     uint_t SL     : 1;
109     uint_t R      : 1;
110 };
111
112 struct ocw3 {
113     uint_t RIS    : 1;
114     uint_t RR     : 1;
115     uint_t P      : 1;
116     uint_t cw_code : 2; // should be 01
117     uint_t smm    : 1;
118     uint_t esmm   : 1;
119     uint_t zero2  : 1;
120 };
121
122
123 struct pic_internal {
124
125
126     uchar_t master_irr;
127     uchar_t slave_irr;
128   
129     uchar_t master_isr;
130     uchar_t slave_isr;
131
132     uchar_t master_elcr;
133     uchar_t slave_elcr;
134     uchar_t master_elcr_mask;
135     uchar_t slave_elcr_mask;
136
137     uchar_t master_icw1;
138     uchar_t master_icw2;
139     uchar_t master_icw3;
140     uchar_t master_icw4;
141
142
143     uchar_t slave_icw1;
144     uchar_t slave_icw2;
145     uchar_t slave_icw3;
146     uchar_t slave_icw4;
147
148
149     uchar_t master_imr;
150     uchar_t slave_imr;
151     uchar_t master_ocw2;
152     uchar_t master_ocw3;
153     uchar_t slave_ocw2;
154     uchar_t slave_ocw3;
155
156     pic_state_t master_state;
157     pic_state_t slave_state;
158 };
159
160
161 static void DumpPICState(struct pic_internal *p)
162 {
163
164     PrintDebug("8259 PIC: master_state=0x%x\n",p->master_state);
165     PrintDebug("8259 PIC: master_irr=0x%x\n",p->master_irr);
166     PrintDebug("8259 PIC: master_isr=0x%x\n",p->master_isr);
167     PrintDebug("8259 PIC: master_imr=0x%x\n",p->master_imr);
168
169     PrintDebug("8259 PIC: master_ocw2=0x%x\n",p->master_ocw2);
170     PrintDebug("8259 PIC: master_ocw3=0x%x\n",p->master_ocw3);
171
172     PrintDebug("8259 PIC: master_icw1=0x%x\n",p->master_icw1);
173     PrintDebug("8259 PIC: master_icw2=0x%x\n",p->master_icw2);
174     PrintDebug("8259 PIC: master_icw3=0x%x\n",p->master_icw3);
175     PrintDebug("8259 PIC: master_icw4=0x%x\n",p->master_icw4);
176
177     PrintDebug("8259 PIC: slave_state=0x%x\n",p->slave_state);
178     PrintDebug("8259 PIC: slave_irr=0x%x\n",p->slave_irr);
179     PrintDebug("8259 PIC: slave_isr=0x%x\n",p->slave_isr);
180     PrintDebug("8259 PIC: slave_imr=0x%x\n",p->slave_imr);
181
182     PrintDebug("8259 PIC: slave_ocw2=0x%x\n",p->slave_ocw2);
183     PrintDebug("8259 PIC: slave_ocw3=0x%x\n",p->slave_ocw3);
184
185     PrintDebug("8259 PIC: slave_icw1=0x%x\n",p->slave_icw1);
186     PrintDebug("8259 PIC: slave_icw2=0x%x\n",p->slave_icw2);
187     PrintDebug("8259 PIC: slave_icw3=0x%x\n",p->slave_icw3);
188     PrintDebug("8259 PIC: slave_icw4=0x%x\n",p->slave_icw4);
189
190 }
191
192
193 static int pic_raise_intr(struct guest_info * info, void * private_data, int irq) {
194     struct pic_internal * state = (struct pic_internal*)private_data;
195
196     if (irq == 2) {
197         irq = 9;
198         state->master_irr |= 0x04;  // PAD
199     }
200
201     PrintDebug("8259 PIC: Raising irq %d in the PIC\n", irq);
202
203     if (irq <= 7) {
204         state->master_irr |= 0x01 << irq;
205     } else if ((irq > 7) && (irq < 16)) {
206         state->slave_irr |= 0x01 << (irq - 8);  // PAD if -7 then irq 15=no irq
207     } else {
208         PrintDebug("8259 PIC: Invalid IRQ raised (%d)\n", irq);
209         return -1;
210     }
211
212     v3_interrupt_cpu(info, 0);
213
214     return 0;
215 }
216
217
218 static int pic_lower_intr(struct guest_info * info, void * private_data, int irq) {
219     struct pic_internal * state = (struct pic_internal*)private_data;
220
221     PrintDebug("[pic_lower_intr] IRQ line %d now low\n", irq);
222     if (irq <= 7) {
223
224         state->master_irr &= ~(1 << irq);
225         if ((state->master_irr & ~(state->master_imr)) == 0) {
226             PrintDebug("\t\tFIXME: Master maybe should do sth\n");
227         }
228     } else if ((irq > 7) && (irq < 16)) {
229
230         state->slave_irr &= ~(1 << (irq - 8));
231         if ((state->slave_irr & (~(state->slave_imr))) == 0) {
232             PrintDebug("\t\tFIXME: Slave maybe should do sth\n");
233         }
234     }
235     return 0;
236 }
237
238
239
240 static int pic_intr_pending(struct guest_info * info, void * private_data) {
241     struct pic_internal * state = (struct pic_internal*)private_data;
242
243     if ((state->master_irr & ~(state->master_imr)) || 
244         (state->slave_irr & ~(state->slave_imr))) {
245         return 1;
246     }
247
248     return 0;
249 }
250
251 static int pic_get_intr_number(struct guest_info * info, void * private_data) {
252     struct pic_internal * state = (struct pic_internal *)private_data;
253     int i = 0;
254     int irq = -1;
255
256     PrintDebug("8259 PIC: getnum: master_irr: 0x%x master_imr: 0x%x\n", state->master_irr, state->master_imr);
257     PrintDebug("8259 PIC: getnum: slave_irr: 0x%x slave_imr: 0x%x\n", state->slave_irr, state->slave_imr);
258
259     for (i = 0; i < 16; i++) {
260         if (i <= 7) {
261             if (((state->master_irr & ~(state->master_imr)) >> i) == 0x01) {
262                 //state->master_isr |= (0x1 << i);
263                 // reset the irr
264                 //state->master_irr &= ~(0x1 << i);
265                 PrintDebug("8259 PIC: IRQ: %d, master_icw2: %x\n", i, state->master_icw2);
266                 irq = i + state->master_icw2;
267                 break;
268             }
269         } else {
270             if (((state->slave_irr & ~(state->slave_imr)) >> (i - 8)) == 0x01) {
271                 //state->slave_isr |= (0x1 << (i - 8));
272                 //state->slave_irr &= ~(0x1 << (i - 8));
273                 PrintDebug("8259 PIC: IRQ: %d, slave_icw2: %x\n", i, state->slave_icw2);
274                 irq=  (i - 8) + state->slave_icw2;
275                 break;
276             }
277         }
278     }
279
280     if ((i == 15) || (i == 6)) { 
281         DumpPICState(state);
282     }
283   
284     if (i == 16) { 
285         return -1;
286     } else {
287         return irq;
288     }
289 }
290
291
292
293 /* The IRQ number is the number returned by pic_get_intr_number(), not the pin number */
294 static int pic_begin_irq(struct guest_info * info, void * private_data, int irq) {
295     struct pic_internal * state = (struct pic_internal*)private_data;
296     
297     if ((irq >= state->master_icw2) && (irq <= state->master_icw2 + 7)) {
298        irq &= 0x7;
299     } else if ((irq >= state->slave_icw2) && (irq <= state->slave_icw2 + 7)) {
300        irq &= 0x7;
301        irq += 8;
302     } else {
303        //    PrintError("8259 PIC: Could not find IRQ (0x%x) to Begin\n",irq);
304        return -1;
305     }
306     
307     if (irq <= 7) {
308        if (((state->master_irr & ~(state->master_imr)) >> irq) == 0x01) {
309            state->master_isr |= (0x1 << irq);
310
311            if (!(state->master_elcr & (0x1 << irq))) {
312                state->master_irr &= ~(0x1 << irq);
313            }
314        }
315     } else {
316        state->slave_isr |= (0x1 << (irq - 8));
317
318        if (!(state->slave_elcr & (0x1 << irq))) {
319            state->slave_irr &= ~(0x1 << (irq - 8));
320        }
321     }
322
323     return 0;
324 }
325
326
327 /*
328   static int pic_end_irq(void * private_data, int irq) {
329   return 0;
330   }
331 */
332
333
334
335 static struct intr_ctrl_ops intr_ops = {
336     .intr_pending = pic_intr_pending,
337     .get_intr_number = pic_get_intr_number,
338     .raise_intr = pic_raise_intr,
339     .begin_irq = pic_begin_irq,
340     .lower_intr = pic_lower_intr, 
341
342 };
343
344
345
346
347 static int read_master_port1(ushort_t port, void * dst, uint_t length, struct vm_device * dev) {
348     struct pic_internal * state = (struct pic_internal*)dev->private_data;
349
350     if (length != 1) {
351         PrintError("8259 PIC: Invalid Read length (rd_Master1)\n");
352         return -1;
353     }
354   
355     if ((state->master_ocw3 & 0x03) == 0x02) {
356         *(uchar_t *)dst = state->master_irr;
357     } else if ((state->master_ocw3 & 0x03) == 0x03) {
358         *(uchar_t *)dst = state->master_isr;
359     } else {
360         *(uchar_t *)dst = 0;
361     }
362   
363     return 1;
364 }
365
366 static int read_master_port2(ushort_t port, void * dst, uint_t length, struct vm_device * dev) {
367     struct pic_internal * state = (struct pic_internal*)dev->private_data;
368
369     if (length != 1) {
370         PrintError("8259 PIC: Invalid Read length (rd_Master2)\n");
371         return -1;
372     }
373
374     *(uchar_t *)dst = state->master_imr;
375
376     return 1;
377   
378 }
379
380 static int read_slave_port1(ushort_t port, void * dst, uint_t length, struct vm_device * dev) {
381     struct pic_internal * state = (struct pic_internal*)dev->private_data;
382
383     if (length != 1) {
384         PrintError("8259 PIC: Invalid Read length (rd_Slave1)\n");
385         return -1;
386     }
387   
388     if ((state->slave_ocw3 & 0x03) == 0x02) {
389         *(uchar_t*)dst = state->slave_irr;
390     } else if ((state->slave_ocw3 & 0x03) == 0x03) {
391         *(uchar_t *)dst = state->slave_isr;
392     } else {
393         *(uchar_t *)dst = 0;
394     }
395
396     return 1;
397 }
398
399 static int read_slave_port2(ushort_t port, void * dst, uint_t length, struct vm_device * dev) {
400     struct pic_internal * state = (struct pic_internal*)dev->private_data;
401
402     if (length != 1) {
403         PrintError("8259 PIC: Invalid Read length  (rd_Slave2)\n");
404         return -1;
405     }
406
407     *(uchar_t *)dst = state->slave_imr;
408
409     return 1;
410 }
411
412
413 static int write_master_port1(ushort_t port, void * src, uint_t length, struct vm_device * dev) {
414     struct pic_internal * state = (struct pic_internal*)dev->private_data;
415     uchar_t cw = *(uchar_t *)src;
416
417     PrintDebug("8259 PIC: Write master port 1 with 0x%x\n",cw);
418
419     if (length != 1) {
420         PrintError("8259 PIC: Invalid Write length (wr_Master1)\n");
421         return -1;
422     }
423
424     v3_clear_pending_intr(dev->vm);
425
426     if (IS_ICW1(cw)) {
427
428         PrintDebug("8259 PIC: Setting ICW1 = %x (wr_Master1)\n", cw);
429
430         state->master_icw1 = cw;
431         state->master_state = ICW2;
432
433     } else if (state->master_state == READY) {
434         if (IS_OCW2(cw)) {
435             // handle the EOI here
436             struct ocw2 * cw2 =  (struct ocw2*)&cw;
437
438             PrintDebug("8259 PIC: Handling OCW2 = %x (wr_Master1)\n", cw);
439
440             if ((cw2->EOI) && (!cw2->R) && (cw2->SL)) {
441                 // specific EOI;
442                 state->master_isr &= ~(0x01 << cw2->level);
443             } else if ((cw2->EOI) & (!cw2->R) && (!cw2->SL)) {
444                 int i;
445                 // Non-specific EOI
446                 PrintDebug("8259 PIC: Pre ISR = %x (wr_Master1)\n", state->master_isr);
447                 for (i = 0; i < 8; i++) {
448                     if (state->master_isr & (0x01 << i)) {
449                         state->master_isr &= ~(0x01 << i);
450                         break;
451                     }
452                 }       
453                 PrintDebug("8259 PIC: Post ISR = %x (wr_Master1)\n", state->master_isr);
454             } else {
455                 PrintError("8259 PIC: Command not handled, or in error (wr_Master1)\n");
456                 return -1;
457             }
458
459             state->master_ocw2 = cw;
460         } else if (IS_OCW3(cw)) {
461             PrintDebug("8259 PIC: Handling OCW3 = %x (wr_Master1)\n", cw);
462             state->master_ocw3 = cw;
463         } else {
464             PrintError("8259 PIC: Invalid OCW to PIC (wr_Master1)\n");
465             PrintError("8259 PIC: CW=%x\n", cw);
466             return -1;
467         }
468     } else {
469         PrintError("8259 PIC: Invalid PIC State (wr_Master1)\n");
470         PrintError("8259 PIC: CW=%x\n", cw);
471         return -1;
472     }
473
474     return 1;
475 }
476
477 static int write_master_port2(ushort_t port, void * src, uint_t length, struct vm_device * dev) {
478     struct pic_internal * state = (struct pic_internal*)dev->private_data;
479     uchar_t cw = *(uchar_t *)src;    
480
481     PrintDebug("8259 PIC: Write master port 2 with 0x%x\n",cw);
482
483     if (length != 1) {
484         PrintError("8259 PIC: Invalid Write length (wr_Master2)\n");
485         return -1;
486     }
487
488     v3_clear_pending_intr(dev->vm);
489
490     if (state->master_state == ICW2) {
491         struct icw1 * cw1 = (struct icw1 *)&(state->master_icw1);
492
493         PrintDebug("8259 PIC: Setting ICW2 = %x (wr_Master2)\n", cw);
494         state->master_icw2 = cw;
495
496
497
498         if (cw1->sngl == 0) {
499             state->master_state = ICW3;
500         } else if (cw1->ic4 == 1) {
501             state->master_state = ICW4;
502         } else {
503             state->master_state = READY;
504         }
505
506
507
508     } else if (state->master_state == ICW3) {
509         struct icw1 * cw1 = (struct icw1 *)&(state->master_icw1);
510
511         PrintDebug("8259 PIC: Setting ICW3 = %x (wr_Master2)\n", cw);
512
513         state->master_icw3 = cw;
514
515         if (cw1->ic4 == 1) {
516             state->master_state = ICW4;
517         } else {
518             state->master_state = READY;
519         }
520
521     } else if (state->master_state == ICW4) {
522         PrintDebug("8259 PIC: Setting ICW4 = %x (wr_Master2)\n", cw);
523         state->master_icw4 = cw;
524         state->master_state = READY;
525     } else if ((state->master_state == ICW1) || (state->master_state == READY)) {
526         PrintDebug("8259 PIC: Setting IMR = %x (wr_Master2)\n", cw);
527         state->master_imr = cw;
528     } else {
529         // error
530         PrintError("8259 PIC: Invalid master PIC State (wr_Master2) (state=%d)\n", 
531                 state->master_state);
532         return -1;
533     }
534
535     return 1;
536 }
537
538 static int write_slave_port1(ushort_t port, void * src, uint_t length, struct vm_device * dev) {
539     struct pic_internal * state = (struct pic_internal*)dev->private_data;
540     uchar_t cw = *(uchar_t *)src;
541
542     PrintDebug("8259 PIC: Write slave port 1 with 0x%x\n",cw);
543
544     if (length != 1) {
545         // error
546         PrintError("8259 PIC: Invalid Write length (wr_Slave1)\n");
547         return -1;
548     }
549
550     v3_clear_pending_intr(dev->vm);
551
552     if (IS_ICW1(cw)) {
553         PrintDebug("8259 PIC: Setting ICW1 = %x (wr_Slave1)\n", cw);
554         state->slave_icw1 = cw;
555         state->slave_state = ICW2;
556     } else if (state->slave_state == READY) {
557         if (IS_OCW2(cw)) {
558             // handle the EOI here
559             struct ocw2 * cw2 =  (struct ocw2 *)&cw;
560
561             PrintDebug("8259 PIC: Setting OCW2 = %x (wr_Slave1)\n", cw);
562
563             if ((cw2->EOI) && (!cw2->R) && (cw2->SL)) {
564                 // specific EOI;
565                 state->slave_isr &= ~(0x01 << cw2->level);
566             } else if ((cw2->EOI) & (!cw2->R) && (!cw2->SL)) {
567                 int i;
568                 // Non-specific EOI
569                 PrintDebug("8259 PIC: Pre ISR = %x (wr_Slave1)\n", state->slave_isr);
570                 for (i = 0; i < 8; i++) {
571                     if (state->slave_isr & (0x01 << i)) {
572                         state->slave_isr &= ~(0x01 << i);
573                         break;
574                     }
575                 }
576                 PrintDebug("8259 PIC: Post ISR = %x (wr_Slave1)\n", state->slave_isr);
577             } else {
578                 PrintError("8259 PIC: Command not handled or invalid  (wr_Slave1)\n");
579                 return -1;
580             }
581
582             state->slave_ocw2 = cw;
583         } else if (IS_OCW3(cw)) {
584             // Basically sets the IRR/ISR read flag
585             PrintDebug("8259 PIC: Setting OCW3 = %x (wr_Slave1)\n", cw);
586             state->slave_ocw3 = cw;
587         } else {
588             PrintError("8259 PIC: Invalid command work (wr_Slave1)\n");
589             return -1;
590         }
591     } else {
592         PrintError("8259 PIC: Invalid State writing (wr_Slave1)\n");
593         return -1;
594     }
595
596     return 1;
597 }
598
599 static int write_slave_port2(ushort_t port, void * src, uint_t length, struct vm_device * dev) {
600     struct pic_internal * state = (struct pic_internal*)dev->private_data;
601     uchar_t cw = *(uchar_t *)src;    
602
603     PrintDebug("8259 PIC: Write slave port 2 with 0x%x\n",cw);
604
605     if (length != 1) {
606         PrintError("8259 PIC: Invalid write length (wr_Slave2)\n");
607         return -1;
608     }
609
610     v3_clear_pending_intr(dev->vm);
611
612
613     if (state->slave_state == ICW2) {
614         struct icw1 * cw1 =  (struct icw1 *)&(state->master_icw1);
615
616         PrintDebug("8259 PIC: Setting ICW2 = %x (wr_Slave2)\n", cw);
617
618         state->slave_icw2 = cw;
619
620         if (cw1->sngl == 0) {
621             state->slave_state = ICW3;
622         } else if (cw1->ic4 == 1) {
623             state->slave_state = ICW4;
624         } else {
625             state->slave_state = READY;
626         }
627
628     } else if (state->slave_state == ICW3) {
629         struct icw1 * cw1 =  (struct icw1 *)&(state->master_icw1);
630
631         PrintDebug("8259 PIC: Setting ICW3 = %x (wr_Slave2)\n", cw);
632
633         state->slave_icw3 = cw;
634
635         if (cw1->ic4 == 1) {
636             state->slave_state = ICW4;
637         } else {
638             state->slave_state = READY;
639         }
640
641     } else if (state->slave_state == ICW4) {
642         PrintDebug("8259 PIC: Setting ICW4 = %x (wr_Slave2)\n", cw);
643         state->slave_icw4 = cw;
644         state->slave_state = READY;
645     } else if ((state->slave_state == ICW1) || (state->slave_state == READY)) {
646         PrintDebug("8259 PIC: Setting IMR = %x (wr_Slave2)\n", cw);
647         state->slave_imr = cw;
648     } else {
649         PrintError("8259 PIC: Invalid State at write (wr_Slave2)\n");
650         return -1;
651     }
652
653     return 1;
654 }
655
656
657
658
659 static int read_elcr_port(ushort_t port, void * dst, uint_t length, struct vm_device * dev) {
660     struct pic_internal * state = (struct pic_internal*)dev->private_data;
661     
662     if (length != 1) {
663         PrintError("ELCR read of invalid length %d\n", length);
664         return -1;
665     }
666
667     if (port == ELCR1_PORT) {
668         // master
669         *(uint8_t *)dst = state->master_elcr;
670     } else if (port == ELCR2_PORT) {
671         *(uint8_t *)dst = state->slave_elcr;
672     } else {
673         PrintError("Invalid port %x\n", port);
674         return -1;
675     }
676
677     return length;
678 }
679
680
681 static int write_elcr_port(ushort_t port, void * src, uint_t length, struct vm_device * dev) {
682     struct pic_internal * state = (struct pic_internal*)dev->private_data;
683     
684     if (length != 1) {
685         PrintError("ELCR read of invalid length %d\n", length);
686         return -1;
687     }
688
689     if (port == ELCR1_PORT) {
690         // master
691         state->master_elcr  = (*(uint8_t *)src) & state->master_elcr_mask;
692     } else if (port == ELCR2_PORT) {
693         state->slave_elcr  = (*(uint8_t *)src) & state->slave_elcr_mask;
694     } else {
695         PrintError("Invalid port %x\n", port);
696         return -1;
697     }
698
699     return length;
700 }
701
702
703
704
705
706
707 static int pic_free(struct vm_device * dev) {
708     v3_dev_unhook_io(dev, MASTER_PORT1);
709     v3_dev_unhook_io(dev, MASTER_PORT2);
710     v3_dev_unhook_io(dev, SLAVE_PORT1);
711     v3_dev_unhook_io(dev, SLAVE_PORT2);
712
713     return 0;
714 }
715
716
717
718
719
720
721
722 static struct v3_device_ops dev_ops = {
723     .free = pic_free,
724     .reset = NULL,
725     .start = NULL,
726     .stop = NULL,
727 };
728
729
730
731 static int pic_init(struct guest_info * vm, v3_cfg_tree_t * cfg) {
732     struct pic_internal * state = NULL;
733     state = (struct pic_internal *)V3_Malloc(sizeof(struct pic_internal));
734     char * name = v3_cfg_val(cfg, "name");
735
736     V3_ASSERT(state != NULL);
737
738     struct vm_device * dev = v3_allocate_device(name, &dev_ops, state);
739
740     if (v3_attach_device(vm, dev) == -1) {
741         PrintError("Could not attach device %s\n", name);
742         return -1;
743     }
744
745
746     v3_register_intr_controller(vm, &intr_ops, state);
747
748     state->master_irr = 0;
749     state->master_isr = 0;
750     state->master_elcr = 0;
751     state->master_elcr_mask = 0xf8;
752     state->master_icw1 = 0;
753     state->master_icw2 = 0;
754     state->master_icw3 = 0;
755     state->master_icw4 = 0;
756     state->master_imr = 0;
757     state->master_ocw2 = 0;
758     state->master_ocw3 = 0x02;
759     state->master_state = ICW1;
760
761
762     state->slave_irr = 0;
763     state->slave_isr = 0;
764     state->slave_elcr = 0;
765     state->slave_elcr_mask = 0xde;
766     state->slave_icw1 = 0;
767     state->slave_icw2 = 0;
768     state->slave_icw3 = 0;
769     state->slave_icw4 = 0;
770     state->slave_imr = 0;
771     state->slave_ocw2 = 0;
772     state->slave_ocw3 = 0x02;
773     state->slave_state = ICW1;
774
775
776     v3_dev_hook_io(dev, MASTER_PORT1, &read_master_port1, &write_master_port1);
777     v3_dev_hook_io(dev, MASTER_PORT2, &read_master_port2, &write_master_port2);
778     v3_dev_hook_io(dev, SLAVE_PORT1, &read_slave_port1, &write_slave_port1);
779     v3_dev_hook_io(dev, SLAVE_PORT2, &read_slave_port2, &write_slave_port2);
780
781
782     v3_dev_hook_io(dev, ELCR1_PORT, &read_elcr_port, &write_elcr_port);
783     v3_dev_hook_io(dev, ELCR2_PORT, &read_elcr_port, &write_elcr_port);
784
785     return 0;
786 }
787
788
789
790 device_register("8259A", pic_init);