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