]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - sys/amd64/vmm/io/vatpic.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / sys / amd64 / vmm / io / vatpic.c
1 /*-
2  * Copyright (c) 2014 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29
30 #include <sys/param.h>
31 #include <sys/types.h>
32 #include <sys/queue.h>
33 #include <sys/kernel.h>
34 #include <sys/lock.h>
35 #include <sys/malloc.h>
36 #include <sys/mutex.h>
37 #include <sys/systm.h>
38
39 #include <x86/apicreg.h>
40 #include <dev/ic/i8259.h>
41
42 #include <machine/vmm.h>
43
44 #include "vmm_ktr.h"
45 #include "vmm_lapic.h"
46 #include "vioapic.h"
47 #include "vatpic.h"
48
49 static MALLOC_DEFINE(M_VATPIC, "atpic", "bhyve virtual atpic (8259)");
50
51 #define VATPIC_LOCK(vatpic)             mtx_lock_spin(&((vatpic)->mtx))
52 #define VATPIC_UNLOCK(vatpic)           mtx_unlock_spin(&((vatpic)->mtx))
53 #define VATPIC_LOCKED(vatpic)           mtx_owned(&((vatpic)->mtx))
54
55 enum irqstate {
56         IRQSTATE_ASSERT,
57         IRQSTATE_DEASSERT,
58         IRQSTATE_PULSE
59 };
60
61 struct atpic {
62         bool            ready;
63         int             icw_num;
64         int             rd_cmd_reg;
65
66         bool            aeoi;
67         bool            poll;
68         bool            rotate;
69         bool            sfn;            /* special fully-nested mode */
70
71         int             irq_base;
72         uint8_t         request;        /* Interrupt Request Register (IIR) */
73         uint8_t         service;        /* Interrupt Service (ISR) */
74         uint8_t         mask;           /* Interrupt Mask Register (IMR) */
75         uint8_t         smm;            /* special mask mode */
76
77         int             acnt[8];        /* sum of pin asserts and deasserts */
78         int             lowprio;        /* lowest priority irq */
79
80         bool            intr_raised;
81 };
82
83 struct vatpic {
84         struct vm       *vm;
85         struct mtx      mtx;
86         struct atpic    atpic[2];
87         uint8_t         elc[2];
88 };
89
90 #define VATPIC_CTR0(vatpic, fmt)                                        \
91         VM_CTR0((vatpic)->vm, fmt)
92
93 #define VATPIC_CTR1(vatpic, fmt, a1)                                    \
94         VM_CTR1((vatpic)->vm, fmt, a1)
95
96 #define VATPIC_CTR2(vatpic, fmt, a1, a2)                                \
97         VM_CTR2((vatpic)->vm, fmt, a1, a2)
98
99 #define VATPIC_CTR3(vatpic, fmt, a1, a2, a3)                            \
100         VM_CTR3((vatpic)->vm, fmt, a1, a2, a3)
101
102 #define VATPIC_CTR4(vatpic, fmt, a1, a2, a3, a4)                        \
103         VM_CTR4((vatpic)->vm, fmt, a1, a2, a3, a4)
104
105 /*
106  * Loop over all the pins in priority order from highest to lowest.
107  */
108 #define ATPIC_PIN_FOREACH(pinvar, atpic, tmpvar)                        \
109         for (tmpvar = 0, pinvar = (atpic->lowprio + 1) & 0x7;           \
110             tmpvar < 8;                                                 \
111             tmpvar++, pinvar = (pinvar + 1) & 0x7)
112
113 static void vatpic_set_pinstate(struct vatpic *vatpic, int pin, bool newstate);
114
115 static __inline bool
116 master_atpic(struct vatpic *vatpic, struct atpic *atpic)
117 {
118
119         if (atpic == &vatpic->atpic[0])
120                 return (true);
121         else
122                 return (false);
123 }
124
125 static __inline int
126 vatpic_get_highest_isrpin(struct atpic *atpic)
127 {
128         int bit, pin;
129         int i;
130
131         ATPIC_PIN_FOREACH(pin, atpic, i) {
132                 bit = (1 << pin);
133
134                 if (atpic->service & bit) {
135                         /*
136                          * An IS bit that is masked by an IMR bit will not be
137                          * cleared by a non-specific EOI in Special Mask Mode.
138                          */
139                         if (atpic->smm && (atpic->mask & bit) != 0)
140                                 continue;
141                         else
142                                 return (pin);
143                 }
144         }
145
146         return (-1);
147 }
148
149 static __inline int
150 vatpic_get_highest_irrpin(struct atpic *atpic)
151 {
152         int serviced;
153         int bit, pin, tmp;
154
155         /*
156          * In 'Special Fully-Nested Mode' when an interrupt request from
157          * a slave is in service, the slave is not locked out from the
158          * master's priority logic.
159          */
160         serviced = atpic->service;
161         if (atpic->sfn)
162                 serviced &= ~(1 << 2);
163
164         /*
165          * In 'Special Mask Mode', when a mask bit is set in OCW1 it inhibits
166          * further interrupts at that level and enables interrupts from all
167          * other levels that are not masked. In other words the ISR has no
168          * bearing on the levels that can generate interrupts.
169          */
170         if (atpic->smm)
171                 serviced = 0;
172
173         ATPIC_PIN_FOREACH(pin, atpic, tmp) {
174                 bit = 1 << pin;
175
176                 /*
177                  * If there is already an interrupt in service at the same
178                  * or higher priority then bail.
179                  */
180                 if ((serviced & bit) != 0)
181                         break;
182
183                 /*
184                  * If an interrupt is asserted and not masked then return
185                  * the corresponding 'pin' to the caller.
186                  */
187                 if ((atpic->request & bit) != 0 && (atpic->mask & bit) == 0)
188                         return (pin);
189         }
190
191         return (-1);
192 }
193
194 static void
195 vatpic_notify_intr(struct vatpic *vatpic)
196 {
197         struct atpic *atpic;
198         int pin;
199
200         KASSERT(VATPIC_LOCKED(vatpic), ("vatpic_notify_intr not locked"));
201
202         /*
203          * First check the slave.
204          */
205         atpic = &vatpic->atpic[1];
206         if (!atpic->intr_raised &&
207             (pin = vatpic_get_highest_irrpin(atpic)) != -1) {
208                 VATPIC_CTR4(vatpic, "atpic slave notify pin = %d "
209                     "(imr 0x%x irr 0x%x isr 0x%x)", pin,
210                     atpic->mask, atpic->request, atpic->service);
211
212                 /*
213                  * Cascade the request from the slave to the master.
214                  */
215                 atpic->intr_raised = true;
216                 vatpic_set_pinstate(vatpic, 2, true);
217                 vatpic_set_pinstate(vatpic, 2, false);
218         } else {
219                 VATPIC_CTR3(vatpic, "atpic slave no eligible interrupts "
220                     "(imr 0x%x irr 0x%x isr 0x%x)",
221                     atpic->mask, atpic->request, atpic->service);
222         }
223
224         /*
225          * Then check the master.
226          */
227         atpic = &vatpic->atpic[0];
228         if (!atpic->intr_raised &&
229             (pin = vatpic_get_highest_irrpin(atpic)) != -1) {
230                 VATPIC_CTR4(vatpic, "atpic master notify pin = %d "
231                     "(imr 0x%x irr 0x%x isr 0x%x)", pin,
232                     atpic->mask, atpic->request, atpic->service);
233
234                 /*
235                  * From Section 3.6.2, "Interrupt Modes", in the
236                  * MPtable Specification, Version 1.4
237                  *
238                  * PIC interrupts are routed to both the Local APIC
239                  * and the I/O APIC to support operation in 1 of 3
240                  * modes.
241                  *
242                  * 1. Legacy PIC Mode: the PIC effectively bypasses
243                  * all APIC components.  In this mode the local APIC is
244                  * disabled and LINT0 is reconfigured as INTR to
245                  * deliver the PIC interrupt directly to the CPU.
246                  *
247                  * 2. Virtual Wire Mode: the APIC is treated as a
248                  * virtual wire which delivers interrupts from the PIC
249                  * to the CPU.  In this mode LINT0 is programmed as
250                  * ExtINT to indicate that the PIC is the source of
251                  * the interrupt.
252                  *
253                  * 3. Virtual Wire Mode via I/O APIC: PIC interrupts are
254                  * fielded by the I/O APIC and delivered to the appropriate
255                  * CPU.  In this mode the I/O APIC input 0 is programmed
256                  * as ExtINT to indicate that the PIC is the source of the
257                  * interrupt.
258                  */
259                 atpic->intr_raised = true;
260                 lapic_set_local_intr(vatpic->vm, -1, APIC_LVT_LINT0);
261                 vioapic_pulse_irq(vatpic->vm, 0);
262         } else {
263                 VATPIC_CTR3(vatpic, "atpic master no eligible interrupts "
264                     "(imr 0x%x irr 0x%x isr 0x%x)",
265                     atpic->mask, atpic->request, atpic->service);
266         }
267 }
268
269 static int
270 vatpic_icw1(struct vatpic *vatpic, struct atpic *atpic, uint8_t val)
271 {
272         VATPIC_CTR1(vatpic, "atpic icw1 0x%x", val);
273
274         atpic->ready = false;
275
276         atpic->icw_num = 1;
277         atpic->request = 0;
278         atpic->mask = 0;
279         atpic->lowprio = 7;
280         atpic->rd_cmd_reg = 0;
281         atpic->poll = 0;
282         atpic->smm = 0;
283
284         if ((val & ICW1_SNGL) != 0) {
285                 VATPIC_CTR0(vatpic, "vatpic cascade mode required");
286                 return (-1);
287         }
288
289         if ((val & ICW1_IC4) == 0) {
290                 VATPIC_CTR0(vatpic, "vatpic icw4 required");
291                 return (-1);
292         }
293
294         atpic->icw_num++;
295
296         return (0);
297 }
298
299 static int
300 vatpic_icw2(struct vatpic *vatpic, struct atpic *atpic, uint8_t val)
301 {
302         VATPIC_CTR1(vatpic, "atpic icw2 0x%x", val);
303
304         atpic->irq_base = val & 0xf8;
305
306         atpic->icw_num++;
307
308         return (0);
309 }
310
311 static int
312 vatpic_icw3(struct vatpic *vatpic, struct atpic *atpic, uint8_t val)
313 {
314         VATPIC_CTR1(vatpic, "atpic icw3 0x%x", val);
315
316         atpic->icw_num++;
317
318         return (0);
319 }
320
321 static int
322 vatpic_icw4(struct vatpic *vatpic, struct atpic *atpic, uint8_t val)
323 {
324         VATPIC_CTR1(vatpic, "atpic icw4 0x%x", val);
325
326         if ((val & ICW4_8086) == 0) {
327                 VATPIC_CTR0(vatpic, "vatpic microprocessor mode required");
328                 return (-1);
329         }
330
331         if ((val & ICW4_AEOI) != 0)
332                 atpic->aeoi = true;
333
334         if ((val & ICW4_SFNM) != 0) {
335                 if (master_atpic(vatpic, atpic)) {
336                         atpic->sfn = true;
337                 } else {
338                         VATPIC_CTR1(vatpic, "Ignoring special fully nested "
339                             "mode on slave atpic: %#x", val);
340                 }
341         }
342
343         atpic->icw_num = 0;
344         atpic->ready = true;
345
346         return (0);
347 }
348
349 static int
350 vatpic_ocw1(struct vatpic *vatpic, struct atpic *atpic, uint8_t val)
351 {
352         VATPIC_CTR1(vatpic, "atpic ocw1 0x%x", val);
353
354         atpic->mask = val & 0xff;
355
356         return (0);
357 }
358
359 static int
360 vatpic_ocw2(struct vatpic *vatpic, struct atpic *atpic, uint8_t val)
361 {
362         VATPIC_CTR1(vatpic, "atpic ocw2 0x%x", val);
363
364         atpic->rotate = ((val & OCW2_R) != 0);
365
366         if ((val & OCW2_EOI) != 0) {
367                 int isr_bit;
368
369                 if ((val & OCW2_SL) != 0) {
370                         /* specific EOI */
371                         isr_bit = val & 0x7;
372                 } else {
373                         /* non-specific EOI */
374                         isr_bit = vatpic_get_highest_isrpin(atpic);
375                 }
376
377                 if (isr_bit != -1) {
378                         atpic->service &= ~(1 << isr_bit);
379
380                         if (atpic->rotate)
381                                 atpic->lowprio = isr_bit;
382                 }
383         } else if ((val & OCW2_SL) != 0 && atpic->rotate == true) {
384                 /* specific priority */
385                 atpic->lowprio = val & 0x7;
386         }
387
388         return (0);
389 }
390
391 static int
392 vatpic_ocw3(struct vatpic *vatpic, struct atpic *atpic, uint8_t val)
393 {
394         VATPIC_CTR1(vatpic, "atpic ocw3 0x%x", val);
395
396         if (val & OCW3_ESMM) {
397                 atpic->smm = val & OCW3_SMM ? 1 : 0;
398                 VATPIC_CTR2(vatpic, "%s atpic special mask mode %s",
399                     master_atpic(vatpic, atpic) ? "master" : "slave",
400                     atpic->smm ?  "enabled" : "disabled");
401         }
402
403         if (val & OCW3_RR) {
404                 /* read register command */
405                 atpic->rd_cmd_reg = val & OCW3_RIS;
406
407                 /* Polling mode */
408                 atpic->poll = ((val & OCW3_P) != 0);
409         }
410
411         return (0);
412 }
413
414 static void
415 vatpic_set_pinstate(struct vatpic *vatpic, int pin, bool newstate)
416 {
417         struct atpic *atpic;
418         int oldcnt, newcnt;
419         bool level;
420
421         KASSERT(pin >= 0 && pin < 16,
422             ("vatpic_set_pinstate: invalid pin number %d", pin));
423         KASSERT(VATPIC_LOCKED(vatpic),
424             ("vatpic_set_pinstate: vatpic is not locked"));
425
426         atpic = &vatpic->atpic[pin >> 3];
427
428         oldcnt = atpic->acnt[pin & 0x7];
429         if (newstate)
430                 atpic->acnt[pin & 0x7]++;
431         else
432                 atpic->acnt[pin & 0x7]--;
433         newcnt = atpic->acnt[pin & 0x7];
434
435         if (newcnt < 0) {
436                 VATPIC_CTR2(vatpic, "atpic pin%d: bad acnt %d", pin, newcnt);
437         }
438
439         level = ((vatpic->elc[pin >> 3] & (1 << (pin & 0x7))) != 0);
440
441         if ((oldcnt == 0 && newcnt == 1) || (newcnt > 0 && level == true)) {
442                 /* rising edge or level */
443                 VATPIC_CTR1(vatpic, "atpic pin%d: asserted", pin);
444                 atpic->request |= (1 << (pin & 0x7));
445         } else if (oldcnt == 1 && newcnt == 0) {
446                 /* falling edge */
447                 VATPIC_CTR1(vatpic, "atpic pin%d: deasserted", pin);
448                 if (level)
449                         atpic->request &= ~(1 << (pin & 0x7));
450         } else {
451                 VATPIC_CTR3(vatpic, "atpic pin%d: %s, ignored, acnt %d",
452                     pin, newstate ? "asserted" : "deasserted", newcnt);
453         }
454
455         vatpic_notify_intr(vatpic);
456 }
457
458 static int
459 vatpic_set_irqstate(struct vm *vm, int irq, enum irqstate irqstate)
460 {
461         struct vatpic *vatpic;
462         struct atpic *atpic;
463
464         if (irq < 0 || irq > 15)
465                 return (EINVAL);
466
467         vatpic = vm_atpic(vm);
468         atpic = &vatpic->atpic[irq >> 3];
469
470         if (atpic->ready == false)
471                 return (0);
472
473         VATPIC_LOCK(vatpic);
474         switch (irqstate) {
475         case IRQSTATE_ASSERT:
476                 vatpic_set_pinstate(vatpic, irq, true);
477                 break;
478         case IRQSTATE_DEASSERT:
479                 vatpic_set_pinstate(vatpic, irq, false);
480                 break;
481         case IRQSTATE_PULSE:
482                 vatpic_set_pinstate(vatpic, irq, true);
483                 vatpic_set_pinstate(vatpic, irq, false);
484                 break;
485         default:
486                 panic("vatpic_set_irqstate: invalid irqstate %d", irqstate);
487         }
488         VATPIC_UNLOCK(vatpic);
489
490         return (0);
491 }
492
493 int
494 vatpic_assert_irq(struct vm *vm, int irq)
495 {
496         return (vatpic_set_irqstate(vm, irq, IRQSTATE_ASSERT));
497 }
498
499 int
500 vatpic_deassert_irq(struct vm *vm, int irq)
501 {
502         return (vatpic_set_irqstate(vm, irq, IRQSTATE_DEASSERT));
503 }
504
505 int
506 vatpic_pulse_irq(struct vm *vm, int irq)
507 {
508         return (vatpic_set_irqstate(vm, irq, IRQSTATE_PULSE));
509 }
510
511 int
512 vatpic_set_irq_trigger(struct vm *vm, int irq, enum vm_intr_trigger trigger)
513 {
514         struct vatpic *vatpic;
515
516         if (irq < 0 || irq > 15)
517                 return (EINVAL);
518
519         /*
520          * See comment in vatpic_elc_handler.  These IRQs must be
521          * edge triggered.
522          */
523         if (trigger == LEVEL_TRIGGER) {
524                 switch (irq) {
525                 case 0:
526                 case 1:
527                 case 2:
528                 case 8:
529                 case 13:
530                         return (EINVAL);
531                 }
532         }
533
534         vatpic = vm_atpic(vm);
535
536         VATPIC_LOCK(vatpic);
537
538         if (trigger == LEVEL_TRIGGER)
539                 vatpic->elc[irq >> 3] |=  1 << (irq & 0x7);
540         else
541                 vatpic->elc[irq >> 3] &=  ~(1 << (irq & 0x7));
542
543         VATPIC_UNLOCK(vatpic);
544
545         return (0);
546 }
547
548 void
549 vatpic_pending_intr(struct vm *vm, int *vecptr)
550 {
551         struct vatpic *vatpic;
552         struct atpic *atpic;
553         int pin;
554
555         vatpic = vm_atpic(vm);
556
557         atpic = &vatpic->atpic[0];
558
559         VATPIC_LOCK(vatpic);
560
561         pin = vatpic_get_highest_irrpin(atpic);
562         if (pin == 2) {
563                 atpic = &vatpic->atpic[1];
564                 pin = vatpic_get_highest_irrpin(atpic);
565         }
566
567         /*
568          * If there are no pins active at this moment then return the spurious
569          * interrupt vector instead.
570          */
571         if (pin == -1)
572                 pin = 7;
573
574         KASSERT(pin >= 0 && pin <= 7, ("%s: invalid pin %d", __func__, pin));
575         *vecptr = atpic->irq_base + pin;
576
577         VATPIC_UNLOCK(vatpic);
578 }
579
580 static void
581 vatpic_pin_accepted(struct atpic *atpic, int pin)
582 {
583         atpic->intr_raised = false;
584
585         if (atpic->acnt[pin] == 0)
586                 atpic->request &= ~(1 << pin);
587
588         if (atpic->aeoi == true) {
589                 if (atpic->rotate == true)
590                         atpic->lowprio = pin;
591         } else {
592                 atpic->service |= (1 << pin);
593         }
594 }
595
596 void
597 vatpic_intr_accepted(struct vm *vm, int vector)
598 {
599         struct vatpic *vatpic;
600         int pin;
601
602         vatpic = vm_atpic(vm);
603
604         VATPIC_LOCK(vatpic);
605
606         pin = vector & 0x7;
607
608         if ((vector & ~0x7) == vatpic->atpic[1].irq_base) {
609                 vatpic_pin_accepted(&vatpic->atpic[1], pin);
610                 /*
611                  * If this vector originated from the slave,
612                  * accept the cascaded interrupt too.
613                  */
614                 vatpic_pin_accepted(&vatpic->atpic[0], 2);
615         } else {
616                 vatpic_pin_accepted(&vatpic->atpic[0], pin);
617         }
618
619         vatpic_notify_intr(vatpic);
620
621         VATPIC_UNLOCK(vatpic);
622 }
623
624 static int
625 vatpic_read(struct vatpic *vatpic, struct atpic *atpic, bool in, int port,
626             int bytes, uint32_t *eax)
627 {
628         int pin;
629
630         VATPIC_LOCK(vatpic);
631
632         if (atpic->poll) {
633                 atpic->poll = 0;
634                 pin = vatpic_get_highest_irrpin(atpic);
635                 if (pin >= 0) {
636                         vatpic_pin_accepted(atpic, pin);
637                         *eax = 0x80 | pin;
638                 } else {
639                         *eax = 0;
640                 }
641         } else {
642                 if (port & ICU_IMR_OFFSET) {
643                         /* read interrrupt mask register */
644                         *eax = atpic->mask;
645                 } else {
646                         if (atpic->rd_cmd_reg == OCW3_RIS) {
647                                 /* read interrupt service register */
648                                 *eax = atpic->service;
649                         } else {
650                                 /* read interrupt request register */
651                                 *eax = atpic->request;
652                         }
653                 }
654         }
655
656         VATPIC_UNLOCK(vatpic);
657
658         return (0);
659
660 }
661
662 static int
663 vatpic_write(struct vatpic *vatpic, struct atpic *atpic, bool in, int port,
664     int bytes, uint32_t *eax)
665 {
666         int error;
667         uint8_t val;
668
669         error = 0;
670         val = *eax;
671
672         VATPIC_LOCK(vatpic);
673
674         if (port & ICU_IMR_OFFSET) {
675                 switch (atpic->icw_num) {
676                 case 2:
677                         error = vatpic_icw2(vatpic, atpic, val);
678                         break;
679                 case 3:
680                         error = vatpic_icw3(vatpic, atpic, val);
681                         break;
682                 case 4:
683                         error = vatpic_icw4(vatpic, atpic, val);
684                         break;
685                 default:
686                         error = vatpic_ocw1(vatpic, atpic, val);
687                         break;
688                 }
689         } else {
690                 if (val & (1 << 4))
691                         error = vatpic_icw1(vatpic, atpic, val);
692
693                 if (atpic->ready) {
694                         if (val & (1 << 3))
695                                 error = vatpic_ocw3(vatpic, atpic, val);
696                         else
697                                 error = vatpic_ocw2(vatpic, atpic, val);
698                 }
699         }
700
701         if (atpic->ready)
702                 vatpic_notify_intr(vatpic);
703
704         VATPIC_UNLOCK(vatpic);
705
706         return (error);
707 }
708
709 int
710 vatpic_master_handler(struct vm *vm, int vcpuid, bool in, int port, int bytes,
711     uint32_t *eax)
712 {
713         struct vatpic *vatpic;
714         struct atpic *atpic;
715
716         vatpic = vm_atpic(vm);
717         atpic = &vatpic->atpic[0];
718
719         if (bytes != 1)
720                 return (-1);
721  
722         if (in) {
723                 return (vatpic_read(vatpic, atpic, in, port, bytes, eax));
724         }
725  
726         return (vatpic_write(vatpic, atpic, in, port, bytes, eax));
727 }
728
729 int
730 vatpic_slave_handler(struct vm *vm, int vcpuid, bool in, int port, int bytes,
731     uint32_t *eax)
732 {
733         struct vatpic *vatpic;
734         struct atpic *atpic;
735
736         vatpic = vm_atpic(vm);
737         atpic = &vatpic->atpic[1];
738
739         if (bytes != 1)
740                 return (-1);
741
742         if (in) {
743                 return (vatpic_read(vatpic, atpic, in, port, bytes, eax));
744         }
745
746         return (vatpic_write(vatpic, atpic, in, port, bytes, eax));
747 }
748
749 int
750 vatpic_elc_handler(struct vm *vm, int vcpuid, bool in, int port, int bytes,
751     uint32_t *eax)
752 {
753         struct vatpic *vatpic;
754         bool is_master;
755
756         vatpic = vm_atpic(vm);
757         is_master = (port == IO_ELCR1);
758
759         if (bytes != 1)
760                 return (-1);
761
762         VATPIC_LOCK(vatpic);
763
764         if (in) {
765                 if (is_master)
766                         *eax = vatpic->elc[0];
767                 else
768                         *eax = vatpic->elc[1];
769         } else {
770                 /*
771                  * For the master PIC the cascade channel (IRQ2), the
772                  * heart beat timer (IRQ0), and the keyboard
773                  * controller (IRQ1) cannot be programmed for level
774                  * mode.
775                  *
776                  * For the slave PIC the real time clock (IRQ8) and
777                  * the floating point error interrupt (IRQ13) cannot
778                  * be programmed for level mode.
779                  */
780                 if (is_master)
781                         vatpic->elc[0] = (*eax & 0xf8);
782                 else
783                         vatpic->elc[1] = (*eax & 0xde);
784         }
785
786         VATPIC_UNLOCK(vatpic);
787
788         return (0);
789 }
790
791 struct vatpic *
792 vatpic_init(struct vm *vm)
793 {
794         struct vatpic *vatpic;
795
796         vatpic = malloc(sizeof(struct vatpic), M_VATPIC, M_WAITOK | M_ZERO);
797         vatpic->vm = vm;
798
799         mtx_init(&vatpic->mtx, "vatpic lock", NULL, MTX_SPIN);
800
801         return (vatpic);
802 }
803
804 void
805 vatpic_cleanup(struct vatpic *vatpic)
806 {
807         free(vatpic, M_VATPIC);
808 }