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.


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