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.


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