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