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.


bug fix for interrupt check
[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 v3_vm_info * vm, 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(vm, 0, 0);
213
214     return 0;
215 }
216
217
218 static int pic_lower_intr(struct v3_vm_info * vm, 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         // This should always be true: See pic_get_intr_number
309        if (((state->master_irr & ~(state->master_imr)) >> irq) & 0x01) {
310            state->master_isr |= (0x1 << irq);
311
312            if (!(state->master_elcr & (0x1 << irq))) {
313                state->master_irr &= ~(0x1 << irq);
314            }
315        }
316     } else {
317         // This should always be true: See pic_get_intr_number
318         if (((state->slave_irr & ~(state->slave_imr)) >> (irq - 8)) & 0x01) {
319            state->slave_isr |= (0x1 << (irq - 8));
320            
321            if (!(state->slave_elcr & (0x1 << (irq - 8)))) {
322                state->slave_irr &= ~(0x1 << (irq - 8));
323            }
324        }
325     }
326
327     return 0;
328 }
329
330
331 /*
332   static int pic_end_irq(void * private_data, int irq) {
333   return 0;
334   }
335 */
336
337
338
339 static struct intr_ctrl_ops intr_ops = {
340     .intr_pending = pic_intr_pending,
341     .get_intr_number = pic_get_intr_number,
342     .begin_irq = pic_begin_irq
343 };
344
345 static struct intr_router_ops router_ops = {
346     .raise_intr = pic_raise_intr,
347     .lower_intr = pic_lower_intr
348 };
349
350
351 static int read_master_port1(struct guest_info * core, ushort_t port, void * dst, uint_t length, struct vm_device * dev) {
352     struct pic_internal * state = (struct pic_internal*)dev->private_data;
353
354     if (length != 1) {
355         PrintError("8259 PIC: Invalid Read length (rd_Master1)\n");
356         return -1;
357     }
358   
359     if ((state->master_ocw3 & 0x03) == 0x02) {
360         *(uchar_t *)dst = state->master_irr;
361     } else if ((state->master_ocw3 & 0x03) == 0x03) {
362         *(uchar_t *)dst = state->master_isr;
363     } else {
364         *(uchar_t *)dst = 0;
365     }
366   
367     return 1;
368 }
369
370 static int read_master_port2(struct guest_info * core, ushort_t port, void * dst, uint_t length, struct vm_device * dev) {
371     struct pic_internal * state = (struct pic_internal*)dev->private_data;
372
373     if (length != 1) {
374         PrintError("8259 PIC: Invalid Read length (rd_Master2)\n");
375         return -1;
376     }
377
378     *(uchar_t *)dst = state->master_imr;
379
380     return 1;
381   
382 }
383
384 static int read_slave_port1(struct guest_info * core, ushort_t port, void * dst, uint_t length, struct vm_device * dev) {
385     struct pic_internal * state = (struct pic_internal*)dev->private_data;
386
387     if (length != 1) {
388         PrintError("8259 PIC: Invalid Read length (rd_Slave1)\n");
389         return -1;
390     }
391   
392     if ((state->slave_ocw3 & 0x03) == 0x02) {
393         *(uchar_t*)dst = state->slave_irr;
394     } else if ((state->slave_ocw3 & 0x03) == 0x03) {
395         *(uchar_t *)dst = state->slave_isr;
396     } else {
397         *(uchar_t *)dst = 0;
398     }
399
400     return 1;
401 }
402
403 static int read_slave_port2(struct guest_info * core, ushort_t port, void * dst, uint_t length, struct vm_device * dev) {
404     struct pic_internal * state = (struct pic_internal*)dev->private_data;
405
406     if (length != 1) {
407         PrintError("8259 PIC: Invalid Read length  (rd_Slave2)\n");
408         return -1;
409     }
410
411     *(uchar_t *)dst = state->slave_imr;
412
413     return 1;
414 }
415
416
417 static int write_master_port1(struct guest_info * core, ushort_t port, void * src, uint_t length, struct vm_device * dev) {
418     struct pic_internal * state = (struct pic_internal*)dev->private_data;
419     uchar_t cw = *(uchar_t *)src;
420
421     PrintDebug("8259 PIC: Write master port 1 with 0x%x\n",cw);
422
423     if (length != 1) {
424         PrintError("8259 PIC: Invalid Write length (wr_Master1)\n");
425         return -1;
426     }
427
428     v3_clear_pending_intr(core);
429
430     if (IS_ICW1(cw)) {
431
432         PrintDebug("8259 PIC: Setting ICW1 = %x (wr_Master1)\n", cw);
433
434         state->master_icw1 = cw;
435         state->master_state = ICW2;
436
437     } else if (state->master_state == READY) {
438         if (IS_OCW2(cw)) {
439             // handle the EOI here
440             struct ocw2 * cw2 =  (struct ocw2*)&cw;
441
442             PrintDebug("8259 PIC: Handling OCW2 = %x (wr_Master1)\n", cw);
443
444             if ((cw2->EOI) && (!cw2->R) && (cw2->SL)) {
445                 // specific EOI;
446                 state->master_isr &= ~(0x01 << cw2->level);
447             } else if ((cw2->EOI) & (!cw2->R) && (!cw2->SL)) {
448                 int i;
449                 // Non-specific EOI
450                 PrintDebug("8259 PIC: Pre ISR = %x (wr_Master1)\n", state->master_isr);
451                 for (i = 0; i < 8; i++) {
452                     if (state->master_isr & (0x01 << i)) {
453                         state->master_isr &= ~(0x01 << i);
454                         break;
455                     }
456                 }       
457                 PrintDebug("8259 PIC: Post ISR = %x (wr_Master1)\n", state->master_isr);
458             } else {
459                 PrintError("8259 PIC: Command not handled, or in error (wr_Master1)\n");
460                 return -1;
461             }
462
463             state->master_ocw2 = cw;
464         } else if (IS_OCW3(cw)) {
465             PrintDebug("8259 PIC: Handling OCW3 = %x (wr_Master1)\n", cw);
466             state->master_ocw3 = cw;
467         } else {
468             PrintError("8259 PIC: Invalid OCW to PIC (wr_Master1)\n");
469             PrintError("8259 PIC: CW=%x\n", cw);
470             return -1;
471         }
472     } else {
473         PrintError("8259 PIC: Invalid PIC State (wr_Master1)\n");
474         PrintError("8259 PIC: CW=%x\n", cw);
475         return -1;
476     }
477
478     return 1;
479 }
480
481 static int write_master_port2(struct guest_info * core, ushort_t port, void * src, uint_t length, struct vm_device * dev) {
482     struct pic_internal * state = (struct pic_internal*)dev->private_data;
483     uchar_t cw = *(uchar_t *)src;    
484
485     PrintDebug("8259 PIC: Write master port 2 with 0x%x\n",cw);
486
487     if (length != 1) {
488         PrintError("8259 PIC: Invalid Write length (wr_Master2)\n");
489         return -1;
490     }
491
492     v3_clear_pending_intr(core);
493
494     if (state->master_state == ICW2) {
495         struct icw1 * cw1 = (struct icw1 *)&(state->master_icw1);
496
497         PrintDebug("8259 PIC: Setting ICW2 = %x (wr_Master2)\n", cw);
498         state->master_icw2 = cw;
499
500
501
502         if (cw1->sngl == 0) {
503             state->master_state = ICW3;
504         } else if (cw1->ic4 == 1) {
505             state->master_state = ICW4;
506         } else {
507             state->master_state = READY;
508         }
509
510
511
512     } else if (state->master_state == ICW3) {
513         struct icw1 * cw1 = (struct icw1 *)&(state->master_icw1);
514
515         PrintDebug("8259 PIC: Setting ICW3 = %x (wr_Master2)\n", cw);
516
517         state->master_icw3 = cw;
518
519         if (cw1->ic4 == 1) {
520             state->master_state = ICW4;
521         } else {
522             state->master_state = READY;
523         }
524
525     } else if (state->master_state == ICW4) {
526         PrintDebug("8259 PIC: Setting ICW4 = %x (wr_Master2)\n", cw);
527         state->master_icw4 = cw;
528         state->master_state = READY;
529     } else if ((state->master_state == ICW1) || (state->master_state == READY)) {
530         PrintDebug("8259 PIC: Setting IMR = %x (wr_Master2)\n", cw);
531         state->master_imr = cw;
532     } else {
533         // error
534         PrintError("8259 PIC: Invalid master PIC State (wr_Master2) (state=%d)\n", 
535                 state->master_state);
536         return -1;
537     }
538
539     return 1;
540 }
541
542 static int write_slave_port1(struct guest_info * core, ushort_t port, void * src, uint_t length, struct vm_device * dev) {
543     struct pic_internal * state = (struct pic_internal*)dev->private_data;
544     uchar_t cw = *(uchar_t *)src;
545
546     PrintDebug("8259 PIC: Write slave port 1 with 0x%x\n",cw);
547
548     if (length != 1) {
549         // error
550         PrintError("8259 PIC: Invalid Write length (wr_Slave1)\n");
551         return -1;
552     }
553
554     v3_clear_pending_intr(core);
555
556     if (IS_ICW1(cw)) {
557         PrintDebug("8259 PIC: Setting ICW1 = %x (wr_Slave1)\n", cw);
558         state->slave_icw1 = cw;
559         state->slave_state = ICW2;
560     } else if (state->slave_state == READY) {
561         if (IS_OCW2(cw)) {
562             // handle the EOI here
563             struct ocw2 * cw2 =  (struct ocw2 *)&cw;
564
565             PrintDebug("8259 PIC: Setting OCW2 = %x (wr_Slave1)\n", cw);
566
567             if ((cw2->EOI) && (!cw2->R) && (cw2->SL)) {
568                 // specific EOI;
569                 state->slave_isr &= ~(0x01 << cw2->level);
570             } else if ((cw2->EOI) & (!cw2->R) && (!cw2->SL)) {
571                 int i;
572                 // Non-specific EOI
573                 PrintDebug("8259 PIC: Pre ISR = %x (wr_Slave1)\n", state->slave_isr);
574                 for (i = 0; i < 8; i++) {
575                     if (state->slave_isr & (0x01 << i)) {
576                         state->slave_isr &= ~(0x01 << i);
577                         break;
578                     }
579                 }
580                 PrintDebug("8259 PIC: Post ISR = %x (wr_Slave1)\n", state->slave_isr);
581             } else {
582                 PrintError("8259 PIC: Command not handled or invalid  (wr_Slave1)\n");
583                 return -1;
584             }
585
586             state->slave_ocw2 = cw;
587         } else if (IS_OCW3(cw)) {
588             // Basically sets the IRR/ISR read flag
589             PrintDebug("8259 PIC: Setting OCW3 = %x (wr_Slave1)\n", cw);
590             state->slave_ocw3 = cw;
591         } else {
592             PrintError("8259 PIC: Invalid command work (wr_Slave1)\n");
593             return -1;
594         }
595     } else {
596         PrintError("8259 PIC: Invalid State writing (wr_Slave1)\n");
597         return -1;
598     }
599
600     return 1;
601 }
602
603 static int write_slave_port2(struct guest_info * core, ushort_t port, void * src, uint_t length, struct vm_device * dev) {
604     struct pic_internal * state = (struct pic_internal*)dev->private_data;
605     uchar_t cw = *(uchar_t *)src;    
606
607     PrintDebug("8259 PIC: Write slave port 2 with 0x%x\n",cw);
608
609     if (length != 1) {
610         PrintError("8259 PIC: Invalid write length (wr_Slave2)\n");
611         return -1;
612     }
613
614     v3_clear_pending_intr(core);
615
616
617     if (state->slave_state == ICW2) {
618         struct icw1 * cw1 =  (struct icw1 *)&(state->master_icw1);
619
620         PrintDebug("8259 PIC: Setting ICW2 = %x (wr_Slave2)\n", cw);
621
622         state->slave_icw2 = cw;
623
624         if (cw1->sngl == 0) {
625             state->slave_state = ICW3;
626         } else if (cw1->ic4 == 1) {
627             state->slave_state = ICW4;
628         } else {
629             state->slave_state = READY;
630         }
631
632     } else if (state->slave_state == ICW3) {
633         struct icw1 * cw1 =  (struct icw1 *)&(state->master_icw1);
634
635         PrintDebug("8259 PIC: Setting ICW3 = %x (wr_Slave2)\n", cw);
636
637         state->slave_icw3 = cw;
638
639         if (cw1->ic4 == 1) {
640             state->slave_state = ICW4;
641         } else {
642             state->slave_state = READY;
643         }
644
645     } else if (state->slave_state == ICW4) {
646         PrintDebug("8259 PIC: Setting ICW4 = %x (wr_Slave2)\n", cw);
647         state->slave_icw4 = cw;
648         state->slave_state = READY;
649     } else if ((state->slave_state == ICW1) || (state->slave_state == READY)) {
650         PrintDebug("8259 PIC: Setting IMR = %x (wr_Slave2)\n", cw);
651         state->slave_imr = cw;
652     } else {
653         PrintError("8259 PIC: Invalid State at write (wr_Slave2)\n");
654         return -1;
655     }
656
657     return 1;
658 }
659
660
661
662
663 static int read_elcr_port(struct guest_info * core, ushort_t port, void * dst, uint_t length, struct vm_device * dev) {
664     struct pic_internal * state = (struct pic_internal*)dev->private_data;
665     
666     if (length != 1) {
667         PrintError("ELCR read of invalid length %d\n", length);
668         return -1;
669     }
670
671     if (port == ELCR1_PORT) {
672         // master
673         *(uint8_t *)dst = state->master_elcr;
674     } else if (port == ELCR2_PORT) {
675         *(uint8_t *)dst = state->slave_elcr;
676     } else {
677         PrintError("Invalid port %x\n", port);
678         return -1;
679     }
680
681     return length;
682 }
683
684
685 static int write_elcr_port(struct guest_info * core, ushort_t port, void * src, uint_t length, struct vm_device * dev) {
686     struct pic_internal * state = (struct pic_internal*)dev->private_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         state->master_elcr  = (*(uint8_t *)src) & state->master_elcr_mask;
696     } else if (port == ELCR2_PORT) {
697         state->slave_elcr  = (*(uint8_t *)src) & state->slave_elcr_mask;
698     } else {
699         PrintError("Invalid port %x\n", port);
700         return -1;
701     }
702
703     return length;
704 }
705
706
707
708
709
710
711 static int pic_free(struct vm_device * dev) {
712     v3_dev_unhook_io(dev, MASTER_PORT1);
713     v3_dev_unhook_io(dev, MASTER_PORT2);
714     v3_dev_unhook_io(dev, SLAVE_PORT1);
715     v3_dev_unhook_io(dev, SLAVE_PORT2);
716
717     return 0;
718 }
719
720
721
722
723
724
725
726 static struct v3_device_ops dev_ops = {
727     .free = pic_free,
728     .reset = NULL,
729     .start = NULL,
730     .stop = NULL,
731 };
732
733
734
735 #include <palacios/vm_guest.h>
736
737 static int pic_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
738     struct pic_internal * state = NULL;
739     state = (struct pic_internal *)V3_Malloc(sizeof(struct pic_internal));
740     char * name = v3_cfg_val(cfg, "name");
741
742     // PIC is only usable in non-multicore environments
743     // just hardcode the core context
744     struct guest_info * core = &(vm->cores[0]);
745
746     V3_ASSERT(state != NULL);
747
748     struct vm_device * dev = v3_allocate_device(name, &dev_ops, state);
749
750     if (v3_attach_device(vm, dev) == -1) {
751         PrintError("Could not attach device %s\n", name);
752         return -1;
753     }
754
755
756     v3_register_intr_controller(core, &intr_ops, state);
757     v3_register_intr_router(vm, &router_ops, state);
758
759     state->master_irr = 0;
760     state->master_isr = 0;
761     state->master_elcr = 0;
762     state->master_elcr_mask = 0xf8;
763     state->master_icw1 = 0;
764     state->master_icw2 = 0;
765     state->master_icw3 = 0;
766     state->master_icw4 = 0;
767     state->master_imr = 0;
768     state->master_ocw2 = 0;
769     state->master_ocw3 = 0x02;
770     state->master_state = ICW1;
771
772
773     state->slave_irr = 0;
774     state->slave_isr = 0;
775     state->slave_elcr = 0;
776     state->slave_elcr_mask = 0xde;
777     state->slave_icw1 = 0;
778     state->slave_icw2 = 0;
779     state->slave_icw3 = 0;
780     state->slave_icw4 = 0;
781     state->slave_imr = 0;
782     state->slave_ocw2 = 0;
783     state->slave_ocw3 = 0x02;
784     state->slave_state = ICW1;
785
786
787     v3_dev_hook_io(dev, MASTER_PORT1, &read_master_port1, &write_master_port1);
788     v3_dev_hook_io(dev, MASTER_PORT2, &read_master_port2, &write_master_port2);
789     v3_dev_hook_io(dev, SLAVE_PORT1, &read_slave_port1, &write_slave_port1);
790     v3_dev_hook_io(dev, SLAVE_PORT2, &read_slave_port2, &write_slave_port2);
791
792
793     v3_dev_hook_io(dev, ELCR1_PORT, &read_elcr_port, &write_elcr_port);
794     v3_dev_hook_io(dev, ELCR2_PORT, &read_elcr_port, &write_elcr_port);
795
796     return 0;
797 }
798
799
800
801 device_register("8259A", pic_init);