xref: /freebsd/sys/amd64/vmm/io/vatpic.c (revision af23369a6deaaeb612ab266eb88b8bb8d560c322)
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, NULL, 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, 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, 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, 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 	mtx_destroy(&vatpic->mtx);
813 	free(vatpic, M_VATPIC);
814 }
815 
816 #ifdef BHYVE_SNAPSHOT
817 int
818 vatpic_snapshot(struct vatpic *vatpic, struct vm_snapshot_meta *meta)
819 {
820 	int ret;
821 	int i;
822 	struct atpic *atpic;
823 
824 	for (i = 0; i < nitems(vatpic->atpic); i++) {
825 		atpic = &vatpic->atpic[i];
826 
827 		SNAPSHOT_VAR_OR_LEAVE(atpic->ready, meta, ret, done);
828 		SNAPSHOT_VAR_OR_LEAVE(atpic->icw_num, meta, ret, done);
829 		SNAPSHOT_VAR_OR_LEAVE(atpic->rd_cmd_reg, meta, ret, done);
830 
831 		SNAPSHOT_VAR_OR_LEAVE(atpic->aeoi, meta, ret, done);
832 		SNAPSHOT_VAR_OR_LEAVE(atpic->poll, meta, ret, done);
833 		SNAPSHOT_VAR_OR_LEAVE(atpic->rotate, meta, ret, done);
834 		SNAPSHOT_VAR_OR_LEAVE(atpic->sfn, meta, ret, done);
835 		SNAPSHOT_VAR_OR_LEAVE(atpic->irq_base, meta, ret, done);
836 		SNAPSHOT_VAR_OR_LEAVE(atpic->request, meta, ret, done);
837 		SNAPSHOT_VAR_OR_LEAVE(atpic->service, meta, ret, done);
838 		SNAPSHOT_VAR_OR_LEAVE(atpic->mask, meta, ret, done);
839 		SNAPSHOT_VAR_OR_LEAVE(atpic->smm, meta, ret, done);
840 
841 		SNAPSHOT_BUF_OR_LEAVE(atpic->acnt, sizeof(atpic->acnt),
842 				      meta, ret, done);
843 		SNAPSHOT_VAR_OR_LEAVE(atpic->lowprio, meta, ret, done);
844 		SNAPSHOT_VAR_OR_LEAVE(atpic->intr_raised, meta, ret, done);
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
854