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