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.


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