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.


added device checkpoint hooks
[palacios.git] / palacios / src / devices / 8259a.c
1 /*
2  * This file is part of the Palacios Virtual Machine Monitor developed
3  * by the V3VEE Project with funding from the United States National 
4  * Science Foundation and the Department of Energy.  
5  *
6  * The V3VEE Project is a joint project between Northwestern University
7  * and the University of New Mexico.  You can find out more at 
8  * http://www.v3vee.org
9  *
10  * Copyright (c) 2008, Jack Lange <jarusl@cs.northwestern.edu> 
11  * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org> 
12  * All rights reserved.
13  *
14  * Author: Jack Lange <jarusl@cs.northwestern.edu>
15  *
16  * This is free software.  You are permitted to use,
17  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
18  */
19
20
21
22 #include <palacios/vmm_intr.h>
23 #include <palacios/vmm_types.h>
24 #include <palacios/vmm.h>
25 #include <palacios/vmm_dev_mgr.h>
26 #include <palacios/vm_guest.h>
27
28 #ifndef V3_CONFIG_DEBUG_PIC
29 #undef PrintDebug
30 #define PrintDebug(fmt, args...)
31 #endif
32
33
34 typedef enum {RESET, ICW1, ICW2, ICW3, ICW4,  READY} pic_state_t;
35
36 static const uint_t MASTER_PORT1 = 0x20;
37 static const uint_t MASTER_PORT2 = 0x21;
38 static const uint_t SLAVE_PORT1 = 0xA0;
39 static const uint_t SLAVE_PORT2 = 0xA1;
40
41 static const uint_t ELCR1_PORT = 0x4d0;
42 static const uint_t ELCR2_PORT = 0x4d1;
43
44
45 #define IS_ICW1(x) (((x & 0x10) >> 4) == 0x1)
46 #define IS_OCW2(x) (((x & 0x18) >> 3) == 0x0)
47 #define IS_OCW3(x) (((x & 0x18) >> 3) == 0x1)
48
49
50 struct icw1 {
51     uint_t ic4    : 1;  // ICW4 has to be read
52     uint_t sngl   : 1;  // single (only one PIC)
53     uint_t adi    : 1;  // call address interval
54     uint_t ltim   : 1;  // level interrupt mode
55     uint_t one    : 1;
56     uint_t rsvd   : 3;
57 };
58
59
60 struct icw2 {
61     uint_t rsvd   : 3;
62     uint_t vector : 5;
63 };
64
65
66 // Each bit that is set indicates that the IR input has a slave
67 struct icw3_master {
68     uint_t S0   : 1;
69     uint_t S1   : 1;
70     uint_t S2   : 1;
71     uint_t S3   : 1;
72     uint_t S4   : 1;
73     uint_t S5   : 1;
74     uint_t S6   : 1;
75     uint_t S7   : 1;
76 };
77
78 // The ID is the Slave device ID
79 struct icw3_slave {
80     uint_t id     : 3;
81     uint_t zeroes : 5;
82 };
83
84 struct icw4 {
85     uint_t uPM    : 1;  // 1=x86
86     uint_t AEOI   : 1;  // Automatic End of Interrupt
87     uint_t M_S    : 1;  // only if buffered 1=master,0=slave 
88     uint_t BUF    : 1;  // buffered mode
89     uint_t SFNM   : 1;  // special fully nexted mode
90     uint_t zeroes : 3;
91 };
92
93
94 struct ocw1 {
95     uint_t m0     : 1;
96     uint_t m1     : 1;
97     uint_t m2     : 1;
98     uint_t m3     : 1;
99     uint_t m4     : 1;
100     uint_t m5     : 1;
101     uint_t m6     : 1;
102     uint_t m7     : 1;
103 };
104
105 struct ocw2 {
106     uint_t level  : 3;
107     uint_t cw_code : 2; // should be 00
108     uint_t EOI    : 1;
109     uint_t SL     : 1;
110     uint_t R      : 1;
111 };
112
113 struct ocw3 {
114     uint_t RIS    : 1;
115     uint_t RR     : 1;
116     uint_t P      : 1;
117     uint_t cw_code : 2; // should be 01
118     uint_t smm    : 1;
119     uint_t esmm   : 1;
120     uint_t zero2  : 1;
121 };
122
123
124 struct pic_internal {
125
126
127     uchar_t master_irr;
128     uchar_t slave_irr;
129   
130     uchar_t master_isr;
131     uchar_t slave_isr;
132
133     uchar_t master_elcr;
134     uchar_t slave_elcr;
135     uchar_t master_elcr_mask;
136     uchar_t slave_elcr_mask;
137
138     uchar_t master_icw1;
139     uchar_t master_icw2;
140     uchar_t master_icw3;
141     uchar_t master_icw4;
142
143
144     uchar_t slave_icw1;
145     uchar_t slave_icw2;
146     uchar_t slave_icw3;
147     uchar_t slave_icw4;
148
149
150     uchar_t master_imr;
151     uchar_t slave_imr;
152     uchar_t master_ocw2;
153     uchar_t master_ocw3;
154     uchar_t slave_ocw2;
155     uchar_t slave_ocw3;
156
157     pic_state_t master_state;
158     pic_state_t slave_state;
159
160     struct guest_info * core;
161
162
163     void * router_handle;
164     void * controller_handle;
165 };
166
167
168 static void DumpPICState(struct pic_internal *p)
169 {
170
171     PrintDebug("8259 PIC: master_state=0x%x\n",p->master_state);
172     PrintDebug("8259 PIC: master_irr=0x%x\n",p->master_irr);
173     PrintDebug("8259 PIC: master_isr=0x%x\n",p->master_isr);
174     PrintDebug("8259 PIC: master_imr=0x%x\n",p->master_imr);
175
176     PrintDebug("8259 PIC: master_ocw2=0x%x\n",p->master_ocw2);
177     PrintDebug("8259 PIC: master_ocw3=0x%x\n",p->master_ocw3);
178
179     PrintDebug("8259 PIC: master_icw1=0x%x\n",p->master_icw1);
180     PrintDebug("8259 PIC: master_icw2=0x%x\n",p->master_icw2);
181     PrintDebug("8259 PIC: master_icw3=0x%x\n",p->master_icw3);
182     PrintDebug("8259 PIC: master_icw4=0x%x\n",p->master_icw4);
183
184     PrintDebug("8259 PIC: slave_state=0x%x\n",p->slave_state);
185     PrintDebug("8259 PIC: slave_irr=0x%x\n",p->slave_irr);
186     PrintDebug("8259 PIC: slave_isr=0x%x\n",p->slave_isr);
187     PrintDebug("8259 PIC: slave_imr=0x%x\n",p->slave_imr);
188
189     PrintDebug("8259 PIC: slave_ocw2=0x%x\n",p->slave_ocw2);
190     PrintDebug("8259 PIC: slave_ocw3=0x%x\n",p->slave_ocw3);
191
192     PrintDebug("8259 PIC: slave_icw1=0x%x\n",p->slave_icw1);
193     PrintDebug("8259 PIC: slave_icw2=0x%x\n",p->slave_icw2);
194     PrintDebug("8259 PIC: slave_icw3=0x%x\n",p->slave_icw3);
195     PrintDebug("8259 PIC: slave_icw4=0x%x\n",p->slave_icw4);
196
197 }
198
199
200 static int pic_raise_intr(struct v3_vm_info * vm, void * private_data, int irq) {
201     struct pic_internal * state = (struct pic_internal*)private_data;
202
203     if (irq == 2) {
204         irq = 9;
205         state->master_irr |= 0x04;  // PAD
206     }
207
208     PrintDebug("8259 PIC: Raising irq %d in the PIC\n", irq);
209
210     if (irq <= 7) {
211         state->master_irr |= 0x01 << irq;
212     } else if ((irq > 7) && (irq < 16)) {
213         state->slave_irr |= 0x01 << (irq - 8);  // PAD if -7 then irq 15=no irq
214     } else {
215         PrintDebug("8259 PIC: Invalid IRQ raised (%d)\n", irq);
216         return -1;
217     }
218
219 #ifdef V3_CONFIG_MULTITHREAD_OS
220     v3_interrupt_cpu(vm, 0, 0);
221 #endif
222
223     return 0;
224 }
225
226
227 static int pic_lower_intr(struct v3_vm_info * vm, void * private_data, int irq) {
228     struct pic_internal * state = (struct pic_internal*)private_data;
229
230     PrintDebug("[pic_lower_intr] IRQ line %d now low\n", irq);
231     if (irq <= 7) {
232
233         state->master_irr &= ~(1 << irq);
234         if ((state->master_irr & ~(state->master_imr)) == 0) {
235             PrintDebug("\t\tFIXME: Master maybe should do sth\n");
236         }
237     } else if ((irq > 7) && (irq < 16)) {
238
239         state->slave_irr &= ~(1 << (irq - 8));
240         if ((state->slave_irr & (~(state->slave_imr))) == 0) {
241             PrintDebug("\t\tFIXME: Slave maybe should do sth\n");
242         }
243     }
244     return 0;
245 }
246
247
248
249 static int pic_intr_pending(struct guest_info * info, void * private_data) {
250     struct pic_internal * state = (struct pic_internal*)private_data;
251
252     if ((state->master_irr & ~(state->master_imr)) || 
253         (state->slave_irr & ~(state->slave_imr))) {
254         return 1;
255     }
256
257     return 0;
258 }
259
260 static int pic_get_intr_number(struct guest_info * info, void * private_data) {
261     struct pic_internal * state = (struct pic_internal *)private_data;
262     int i = 0;
263     int irq = -1;
264
265     PrintDebug("8259 PIC: getnum: master_irr: 0x%x master_imr: 0x%x\n", state->master_irr, state->master_imr);
266     PrintDebug("8259 PIC: getnum: slave_irr: 0x%x slave_imr: 0x%x\n", state->slave_irr, state->slave_imr);
267
268     for (i = 0; i < 16; i++) {
269         if (i <= 7) {
270             if (((state->master_irr & ~(state->master_imr)) >> i) & 0x01) {
271                 //state->master_isr |= (0x1 << i);
272                 // reset the irr
273                 //state->master_irr &= ~(0x1 << i);
274                 PrintDebug("8259 PIC: IRQ: %d, master_icw2: %x\n", i, state->master_icw2);
275                 irq = i + state->master_icw2;
276                 break;
277             }
278         } else {
279             if (((state->slave_irr & ~(state->slave_imr)) >> (i - 8)) & 0x01) {
280                 //state->slave_isr |= (0x1 << (i - 8));
281                 //state->slave_irr &= ~(0x1 << (i - 8));
282                 PrintDebug("8259 PIC: IRQ: %d, slave_icw2: %x\n", i, state->slave_icw2);
283                 irq = (i - 8) + state->slave_icw2;
284                 break;
285             }
286         }
287     }
288
289 #if 1
290     if ((i == 15) || (i == 6)) { 
291         DumpPICState(state);
292     }
293 #endif
294   
295     if (i == 16) { 
296         return -1;
297     } else {
298         PrintDebug("8259 PIC: get num is returning %d\n",irq);
299         return irq;
300     }
301 }
302
303
304
305 /* The IRQ number is the number returned by pic_get_intr_number(), not the pin number */
306 static int pic_begin_irq(struct guest_info * info, void * private_data, int irq) {
307     struct pic_internal * state = (struct pic_internal*)private_data;
308     
309     if ((irq >= state->master_icw2) && (irq <= state->master_icw2 + 7)) {
310        irq &= 0x7;
311     } else if ((irq >= state->slave_icw2) && (irq <= state->slave_icw2 + 7)) {
312        irq &= 0x7;
313        irq += 8;
314     } else {
315        //    PrintError("8259 PIC: Could not find IRQ (0x%x) to Begin\n",irq);
316        return -1;
317     }
318     
319     if (irq <= 7) {
320         // This should always be true: See pic_get_intr_number
321        if (((state->master_irr & ~(state->master_imr)) >> irq) & 0x01) {
322            state->master_isr |= (0x1 << irq);
323
324            if (!(state->master_elcr & (0x1 << irq))) {
325                state->master_irr &= ~(0x1 << irq);
326            }
327        } else {
328            PrintDebug("8259 PIC: (master) Ignoring begin_irq for %d since I don't own it\n",irq);
329        }
330
331     } else {
332         // This should always be true: See pic_get_intr_number
333         if (((state->slave_irr & ~(state->slave_imr)) >> (irq - 8)) & 0x01) {
334            state->slave_isr |= (0x1 << (irq - 8));
335            
336            if (!(state->slave_elcr & (0x1 << (irq - 8)))) {
337                state->slave_irr &= ~(0x1 << (irq - 8));
338            }
339         } else {
340            PrintDebug("8259 PIC: (slave) Ignoring begin_irq for %d since I don't own it\n",irq);
341         }
342
343     }
344
345     return 0;
346 }
347
348
349 /*
350   static int pic_end_irq(void * private_data, int irq) {
351   return 0;
352   }
353 */
354
355
356
357 static struct intr_ctrl_ops intr_ops = {
358     .intr_pending = pic_intr_pending,
359     .get_intr_number = pic_get_intr_number,
360     .begin_irq = pic_begin_irq
361 };
362
363 static struct intr_router_ops router_ops = {
364     .raise_intr = pic_raise_intr,
365     .lower_intr = pic_lower_intr
366 };
367
368
369 static int read_master_port1(struct guest_info * core, ushort_t port, void * dst, uint_t length, void * priv_data) {
370     struct pic_internal * state = (struct pic_internal *)priv_data;
371
372     if (length != 1) {
373         PrintError("8259 PIC: Invalid Read length (rd_Master1)\n");
374         return -1;
375     }
376   
377     if ((state->master_ocw3 & 0x03) == 0x02) {
378         *(uchar_t *)dst = state->master_irr;
379     } else if ((state->master_ocw3 & 0x03) == 0x03) {
380         *(uchar_t *)dst = state->master_isr;
381     } else {
382         *(uchar_t *)dst = 0;
383     }
384   
385     return 1;
386 }
387
388 static int read_master_port2(struct guest_info * core, ushort_t port, void * dst, uint_t length, void * priv_data) {
389     struct pic_internal * state = (struct pic_internal *)priv_data;
390
391     if (length != 1) {
392         PrintError("8259 PIC: Invalid Read length (rd_Master2)\n");
393         return -1;
394     }
395
396     *(uchar_t *)dst = state->master_imr;
397
398     return 1;
399   
400 }
401
402 static int read_slave_port1(struct guest_info * core, ushort_t port, void * dst, uint_t length, void * priv_data) {
403     struct pic_internal * state = (struct pic_internal *)priv_data;
404
405     if (length != 1) {
406         PrintError("8259 PIC: Invalid Read length (rd_Slave1)\n");
407         return -1;
408     }
409   
410     if ((state->slave_ocw3 & 0x03) == 0x02) {
411         *(uchar_t*)dst = state->slave_irr;
412     } else if ((state->slave_ocw3 & 0x03) == 0x03) {
413         *(uchar_t *)dst = state->slave_isr;
414     } else {
415         *(uchar_t *)dst = 0;
416     }
417
418     return 1;
419 }
420
421 static int read_slave_port2(struct guest_info * core, ushort_t port, void * dst, uint_t length, void * priv_data) {
422     struct pic_internal * state = (struct pic_internal *)priv_data;
423
424     if (length != 1) {
425         PrintError("8259 PIC: Invalid Read length  (rd_Slave2)\n");
426         return -1;
427     }
428
429     *(uchar_t *)dst = state->slave_imr;
430
431     return 1;
432 }
433
434
435 static int write_master_port1(struct guest_info * core, ushort_t port, void * src, uint_t length, void * priv_data) {
436     struct pic_internal * state = (struct pic_internal *)priv_data;
437     uchar_t cw = *(uchar_t *)src;
438
439     PrintDebug("8259 PIC: Write master port 1 with 0x%x\n",cw);
440
441     if (length != 1) {
442         PrintError("8259 PIC: Invalid Write length (wr_Master1)\n");
443         return -1;
444     }
445
446     v3_clear_pending_intr(core);
447
448     if (IS_ICW1(cw)) {
449
450         PrintDebug("8259 PIC: Setting ICW1 = %x (wr_Master1)\n", cw);
451
452         state->master_icw1 = cw;
453         state->master_state = ICW2;
454
455     } else if (state->master_state == READY) {
456         if (IS_OCW2(cw)) {
457             // handle the EOI here
458             struct ocw2 * cw2 =  (struct ocw2*)&cw;
459
460             PrintDebug("8259 PIC: Handling OCW2 = %x (wr_Master1)\n", cw);
461
462             if ((cw2->EOI) && (!cw2->R) && (cw2->SL)) {
463                 // specific EOI;
464                 state->master_isr &= ~(0x01 << cw2->level);
465             } else if ((cw2->EOI) & (!cw2->R) && (!cw2->SL)) {
466                 int i;
467                 // Non-specific EOI
468                 PrintDebug("8259 PIC: Pre ISR = %x (wr_Master1)\n", state->master_isr);
469                 for (i = 0; i < 8; i++) {
470                     if (state->master_isr & (0x01 << i)) {
471                         state->master_isr &= ~(0x01 << i);
472                         break;
473                     }
474                 }       
475                 PrintDebug("8259 PIC: Post ISR = %x (wr_Master1)\n", state->master_isr);
476             } else if (!(cw2->EOI) && (cw2->R) && (cw2->SL)) {
477                 PrintDebug("8259 PIC: Ignoring set-priority, priorities not implemented (level=%d, wr_Master1)\n", cw2->level);
478             } else if (!(cw2->EOI) && !(cw2->R) && (cw2->SL)) {
479                 PrintDebug("8259 PIC: Ignoring no-op (level=%d, wr_Master1)\n", cw2->level);
480             } else {
481                 PrintError("8259 PIC: Command not handled, or in error (wr_Master1)\n");
482                 return -1;
483             }
484
485             state->master_ocw2 = cw;
486         } else if (IS_OCW3(cw)) {
487             PrintDebug("8259 PIC: Handling OCW3 = %x (wr_Master1)\n", cw);
488             state->master_ocw3 = cw;
489         } else {
490             PrintError("8259 PIC: Invalid OCW to PIC (wr_Master1)\n");
491             PrintError("8259 PIC: CW=%x\n", cw);
492             return -1;
493         }
494     } else {
495         PrintError("8259 PIC: Invalid PIC State (wr_Master1)\n");
496         PrintError("8259 PIC: CW=%x\n", cw);
497         return -1;
498     }
499
500     return 1;
501 }
502
503 static int write_master_port2(struct guest_info * core, ushort_t port, void * src, uint_t length, void * priv_data) {
504     struct pic_internal * state = (struct pic_internal *)priv_data;
505     uchar_t cw = *(uchar_t *)src;    
506
507     PrintDebug("8259 PIC: Write master port 2 with 0x%x\n",cw);
508
509     if (length != 1) {
510         PrintError("8259 PIC: Invalid Write length (wr_Master2)\n");
511         return -1;
512     }
513
514     v3_clear_pending_intr(core);
515
516     if (state->master_state == ICW2) {
517         struct icw1 * cw1 = (struct icw1 *)&(state->master_icw1);
518
519         PrintDebug("8259 PIC: Setting ICW2 = %x (wr_Master2)\n", cw);
520         state->master_icw2 = cw;
521
522
523
524         if (cw1->sngl == 0) {
525             state->master_state = ICW3;
526         } else if (cw1->ic4 == 1) {
527             state->master_state = ICW4;
528         } else {
529             state->master_state = READY;
530         }
531
532
533
534     } else if (state->master_state == ICW3) {
535         struct icw1 * cw1 = (struct icw1 *)&(state->master_icw1);
536
537         PrintDebug("8259 PIC: Setting ICW3 = %x (wr_Master2)\n", cw);
538
539         state->master_icw3 = cw;
540
541         if (cw1->ic4 == 1) {
542             state->master_state = ICW4;
543         } else {
544             state->master_state = READY;
545         }
546
547     } else if (state->master_state == ICW4) {
548         PrintDebug("8259 PIC: Setting ICW4 = %x (wr_Master2)\n", cw);
549         state->master_icw4 = cw;
550         state->master_state = READY;
551     } else if ((state->master_state == ICW1) || (state->master_state == READY)) {
552         PrintDebug("8259 PIC: Setting IMR = %x (wr_Master2)\n", cw);
553         state->master_imr = cw;
554     } else {
555         // error
556         PrintError("8259 PIC: Invalid master PIC State (wr_Master2) (state=%d)\n", 
557                 state->master_state);
558         return -1;
559     }
560
561     return 1;
562 }
563
564 static int write_slave_port1(struct guest_info * core, ushort_t port, void * src, uint_t length, void * priv_data) {
565     struct pic_internal * state = (struct pic_internal *)priv_data;
566     uchar_t cw = *(uchar_t *)src;
567
568     PrintDebug("8259 PIC: Write slave port 1 with 0x%x\n",cw);
569
570     if (length != 1) {
571         // error
572         PrintError("8259 PIC: Invalid Write length (wr_Slave1)\n");
573         return -1;
574     }
575
576     v3_clear_pending_intr(core);
577
578     if (IS_ICW1(cw)) {
579         PrintDebug("8259 PIC: Setting ICW1 = %x (wr_Slave1)\n", cw);
580         state->slave_icw1 = cw;
581         state->slave_state = ICW2;
582     } else if (state->slave_state == READY) {
583         if (IS_OCW2(cw)) {
584             // handle the EOI here
585             struct ocw2 * cw2 =  (struct ocw2 *)&cw;
586
587             PrintDebug("8259 PIC: Setting OCW2 = %x (wr_Slave1)\n", cw);
588
589             if ((cw2->EOI) && (!cw2->R) && (cw2->SL)) {
590                 // specific EOI;
591                 state->slave_isr &= ~(0x01 << cw2->level);
592             } else if ((cw2->EOI) & (!cw2->R) && (!cw2->SL)) {
593                 int i;
594                 // Non-specific EOI
595                 PrintDebug("8259 PIC: Pre ISR = %x (wr_Slave1)\n", state->slave_isr);
596                 for (i = 0; i < 8; i++) {
597                     if (state->slave_isr & (0x01 << i)) {
598                         state->slave_isr &= ~(0x01 << i);
599                         break;
600                     }
601                 }
602                 PrintDebug("8259 PIC: Post ISR = %x (wr_Slave1)\n", state->slave_isr);
603             } else {
604                 PrintError("8259 PIC: Command not handled or invalid  (wr_Slave1)\n");
605                 return -1;
606             }
607
608             state->slave_ocw2 = cw;
609         } else if (IS_OCW3(cw)) {
610             // Basically sets the IRR/ISR read flag
611             PrintDebug("8259 PIC: Setting OCW3 = %x (wr_Slave1)\n", cw);
612             state->slave_ocw3 = cw;
613         } else {
614             PrintError("8259 PIC: Invalid command work (wr_Slave1)\n");
615             return -1;
616         }
617     } else {
618         PrintError("8259 PIC: Invalid State writing (wr_Slave1)\n");
619         return -1;
620     }
621
622     return 1;
623 }
624
625 static int write_slave_port2(struct guest_info * core, ushort_t port, void * src, uint_t length, void * priv_data) {
626     struct pic_internal * state = (struct pic_internal *)priv_data;
627     uchar_t cw = *(uchar_t *)src;    
628
629     PrintDebug("8259 PIC: Write slave port 2 with 0x%x\n",cw);
630
631     if (length != 1) {
632         PrintError("8259 PIC: Invalid write length (wr_Slave2)\n");
633         return -1;
634     }
635
636     v3_clear_pending_intr(core);
637
638
639     if (state->slave_state == ICW2) {
640         struct icw1 * cw1 =  (struct icw1 *)&(state->master_icw1);
641
642         PrintDebug("8259 PIC: Setting ICW2 = %x (wr_Slave2)\n", cw);
643
644         state->slave_icw2 = cw;
645
646         if (cw1->sngl == 0) {
647             state->slave_state = ICW3;
648         } else if (cw1->ic4 == 1) {
649             state->slave_state = ICW4;
650         } else {
651             state->slave_state = READY;
652         }
653
654     } else if (state->slave_state == ICW3) {
655         struct icw1 * cw1 =  (struct icw1 *)&(state->master_icw1);
656
657         PrintDebug("8259 PIC: Setting ICW3 = %x (wr_Slave2)\n", cw);
658
659         state->slave_icw3 = cw;
660
661         if (cw1->ic4 == 1) {
662             state->slave_state = ICW4;
663         } else {
664             state->slave_state = READY;
665         }
666
667     } else if (state->slave_state == ICW4) {
668         PrintDebug("8259 PIC: Setting ICW4 = %x (wr_Slave2)\n", cw);
669         state->slave_icw4 = cw;
670         state->slave_state = READY;
671     } else if ((state->slave_state == ICW1) || (state->slave_state == READY)) {
672         PrintDebug("8259 PIC: Setting IMR = %x (wr_Slave2)\n", cw);
673         state->slave_imr = cw;
674     } else {
675         PrintError("8259 PIC: Invalid State at write (wr_Slave2)\n");
676         return -1;
677     }
678
679     return 1;
680 }
681
682
683
684
685 static int read_elcr_port(struct guest_info * core, ushort_t port, void * dst, uint_t length, void * priv_data) {
686     struct pic_internal * state = (struct pic_internal *)priv_data;
687     
688     if (length != 1) {
689         PrintError("ELCR read of invalid length %d\n", length);
690         return -1;
691     }
692
693     if (port == ELCR1_PORT) {
694         // master
695         *(uint8_t *)dst = state->master_elcr;
696     } else if (port == ELCR2_PORT) {
697         *(uint8_t *)dst = state->slave_elcr;
698     } else {
699         PrintError("Invalid port %x\n", port);
700         return -1;
701     }
702
703     return length;
704 }
705
706
707 static int write_elcr_port(struct guest_info * core, ushort_t port, void * src, uint_t length, void * priv_data) {
708     struct pic_internal * state = (struct pic_internal *)priv_data;
709     
710     if (length != 1) {
711         PrintError("ELCR read of invalid length %d\n", length);
712         return -1;
713     }
714
715     if (port == ELCR1_PORT) {
716         // master
717         state->master_elcr  = (*(uint8_t *)src) & state->master_elcr_mask;
718     } else if (port == ELCR2_PORT) {
719         state->slave_elcr  = (*(uint8_t *)src) & state->slave_elcr_mask;
720     } else {
721         PrintError("Invalid port %x\n", port);
722         return -1;
723     }
724
725     return length;
726 }
727
728
729
730 static int pic_free(struct pic_internal * state) {
731     struct guest_info * core = state->core;
732
733     v3_remove_intr_controller(core, state->controller_handle);
734     v3_remove_intr_router(core->vm_info, state->router_handle);
735
736     V3_Free(state);
737     return 0;
738 }
739
740 #ifdef V3_CONFIG_CHECKPOINT
741 static int pic_save(struct v3_chkpt_ctx * ctx, void * private_data) {
742     struct pic_internal * pic = (struct pic_internal *)private_data;
743
744     V3_CHKPT_STD_SAVE(ctx, pic->master_irr);
745     V3_CHKPT_STD_SAVE(ctx, pic->slave_irr);
746   
747     V3_CHKPT_STD_SAVE(ctx, pic->master_isr);
748     V3_CHKPT_STD_SAVE(ctx, pic->slave_isr);
749
750     V3_CHKPT_STD_SAVE(ctx, pic->master_elcr);
751     V3_CHKPT_STD_SAVE(ctx, pic->slave_elcr);
752     V3_CHKPT_STD_SAVE(ctx, pic->master_elcr_mask);
753     V3_CHKPT_STD_SAVE(ctx, pic->slave_elcr_mask);
754
755     V3_CHKPT_STD_SAVE(ctx, pic->master_icw1);
756     V3_CHKPT_STD_SAVE(ctx, pic->master_icw2);
757     V3_CHKPT_STD_SAVE(ctx, pic->master_icw3);
758     V3_CHKPT_STD_SAVE(ctx, pic->master_icw4);
759
760
761     V3_CHKPT_STD_SAVE(ctx, pic->slave_icw1);
762     V3_CHKPT_STD_SAVE(ctx, pic->slave_icw2);
763     V3_CHKPT_STD_SAVE(ctx, pic->slave_icw3);
764     V3_CHKPT_STD_SAVE(ctx, pic->slave_icw4);
765
766
767     V3_CHKPT_STD_SAVE(ctx, pic->master_imr);
768     V3_CHKPT_STD_SAVE(ctx, pic->slave_imr);
769     V3_CHKPT_STD_SAVE(ctx, pic->master_ocw2);
770     V3_CHKPT_STD_SAVE(ctx, pic->master_ocw3);
771     V3_CHKPT_STD_SAVE(ctx, pic->slave_ocw2);
772     V3_CHKPT_STD_SAVE(ctx, pic->slave_ocw3);
773
774     V3_CHKPT_STD_SAVE(ctx, pic->master_state);
775     V3_CHKPT_STD_SAVE(ctx, pic->slave_state);
776
777     
778     return 0;
779
780 }
781
782 static int pic_load(struct v3_chkpt_ctx * ctx, void * private_data) {
783     struct pic_internal * pic = (struct pic_internal *)private_data;
784
785     V3_CHKPT_STD_LOAD(ctx, pic->master_irr);
786     V3_CHKPT_STD_LOAD(ctx, pic->slave_irr);
787   
788     V3_CHKPT_STD_LOAD(ctx, pic->master_isr);
789     V3_CHKPT_STD_LOAD(ctx, pic->slave_isr);
790
791     V3_CHKPT_STD_LOAD(ctx, pic->master_elcr);
792     V3_CHKPT_STD_LOAD(ctx, pic->slave_elcr);
793     V3_CHKPT_STD_LOAD(ctx, pic->master_elcr_mask);
794     V3_CHKPT_STD_LOAD(ctx, pic->slave_elcr_mask);
795
796     V3_CHKPT_STD_LOAD(ctx, pic->master_icw1);
797     V3_CHKPT_STD_LOAD(ctx, pic->master_icw2);
798     V3_CHKPT_STD_LOAD(ctx, pic->master_icw3);
799     V3_CHKPT_STD_LOAD(ctx, pic->master_icw4);
800
801
802     V3_CHKPT_STD_LOAD(ctx, pic->slave_icw1);
803     V3_CHKPT_STD_LOAD(ctx, pic->slave_icw2);
804     V3_CHKPT_STD_LOAD(ctx, pic->slave_icw3);
805     V3_CHKPT_STD_LOAD(ctx, pic->slave_icw4);
806
807
808     V3_CHKPT_STD_LOAD(ctx, pic->master_imr);
809     V3_CHKPT_STD_LOAD(ctx, pic->slave_imr);
810     V3_CHKPT_STD_LOAD(ctx, pic->master_ocw2);
811     V3_CHKPT_STD_LOAD(ctx, pic->master_ocw3);
812     V3_CHKPT_STD_LOAD(ctx, pic->slave_ocw2);
813     V3_CHKPT_STD_LOAD(ctx, pic->slave_ocw3);
814
815     V3_CHKPT_STD_LOAD(ctx, pic->master_state);
816     V3_CHKPT_STD_LOAD(ctx, pic->slave_state);
817
818     return 0;
819 }
820
821 #endif
822
823
824 static struct v3_device_ops dev_ops = {
825     .free = (int (*)(void *))pic_free,
826 #ifdef V3_CONFIG_CHECKPOINT
827     .save = pic_save,
828     .load = pic_load
829 #endif
830 };
831
832
833
834
835
836 static int pic_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
837     struct pic_internal * state = NULL;
838     char * dev_id = v3_cfg_val(cfg, "ID");
839     int ret = 0;
840
841     // PIC is only usable in non-multicore environments
842     // just hardcode the core context
843     struct guest_info * core = &(vm->cores[0]);
844         
845     state = (struct pic_internal *)V3_Malloc(sizeof(struct pic_internal));
846
847     V3_ASSERT(state != NULL);
848
849     struct vm_device * dev = v3_add_device(vm, dev_id, &dev_ops, state);
850
851     if (dev == NULL) {
852         PrintError("Could not add device %s\n", dev_id);
853         V3_Free(state);
854         return -1;
855     }
856
857     state->core = core;
858
859     state->controller_handle = v3_register_intr_controller(core, &intr_ops, state);
860     state->router_handle = v3_register_intr_router(vm, &router_ops, state);
861
862     state->master_irr = 0;
863     state->master_isr = 0;
864     state->master_elcr = 0;
865     state->master_elcr_mask = 0xf8;
866     state->master_icw1 = 0;
867     state->master_icw2 = 0;
868     state->master_icw3 = 0;
869     state->master_icw4 = 0;
870     state->master_imr = 0;
871     state->master_ocw2 = 0;
872     state->master_ocw3 = 0x02;
873     state->master_state = ICW1;
874
875
876     state->slave_irr = 0;
877     state->slave_isr = 0;
878     state->slave_elcr = 0;
879     state->slave_elcr_mask = 0xde;
880     state->slave_icw1 = 0;
881     state->slave_icw2 = 0;
882     state->slave_icw3 = 0;
883     state->slave_icw4 = 0;
884     state->slave_imr = 0;
885     state->slave_ocw2 = 0;
886     state->slave_ocw3 = 0x02;
887     state->slave_state = ICW1;
888
889
890     ret |= v3_dev_hook_io(dev, MASTER_PORT1, &read_master_port1, &write_master_port1);
891     ret |= v3_dev_hook_io(dev, MASTER_PORT2, &read_master_port2, &write_master_port2);
892     ret |= v3_dev_hook_io(dev, SLAVE_PORT1, &read_slave_port1, &write_slave_port1);
893     ret |= v3_dev_hook_io(dev, SLAVE_PORT2, &read_slave_port2, &write_slave_port2);
894
895
896     ret |= v3_dev_hook_io(dev, ELCR1_PORT, &read_elcr_port, &write_elcr_port);
897     ret |= v3_dev_hook_io(dev, ELCR2_PORT, &read_elcr_port, &write_elcr_port);
898
899     if (ret != 0) {
900         PrintError("Error hooking io ports\n");
901         v3_remove_device(dev);
902         return -1;
903     }
904
905     return 0;
906 }
907
908
909
910 device_register("8259A", pic_init);