xref: /illumos-gate/usr/src/uts/intel/io/vmm/io/vatpic.c (revision 1e56f352c1c208679012bca47d552e127f5b1072)
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  * This file and its contents are supplied under the terms of the
30  * Common Development and Distribution License ("CDDL"), version 1.0.
31  * You may only use this file in accordance with the terms of version
32  * 1.0 of the CDDL.
33  *
34  * A full copy of the text of the CDDL should have accompanied this
35  * source.  A copy of the CDDL is also available via the Internet at
36  * http://www.illumos.org/license/CDDL.
37  *
38  * Copyright 2021 Oxide Computer Company
39  */
40 
41 #include <sys/cdefs.h>
42 __FBSDID("$FreeBSD$");
43 
44 #include <sys/param.h>
45 #include <sys/types.h>
46 #include <sys/queue.h>
47 #include <sys/kernel.h>
48 #include <sys/kmem.h>
49 #include <sys/mutex.h>
50 #include <sys/systm.h>
51 
52 #include <x86/apicreg.h>
53 #include <dev/ic/i8259.h>
54 
55 #include <machine/vmm.h>
56 
57 #include "vmm_lapic.h"
58 #include "vioapic.h"
59 #include "vatpic.h"
60 
61 #define	VATPIC_LOCK(vatpic)		mutex_enter(&((vatpic)->lock))
62 #define	VATPIC_UNLOCK(vatpic)		mutex_exit(&((vatpic)->lock))
63 #define	VATPIC_LOCKED(vatpic)		MUTEX_HELD(&((vatpic)->lock))
64 
65 #define	IRQ_BASE_MASK	0xf8
66 
67 enum irqstate {
68 	IRQSTATE_ASSERT,
69 	IRQSTATE_DEASSERT,
70 	IRQSTATE_PULSE
71 };
72 
73 enum icw_state {
74 	IS_ICW1 = 0,
75 	IS_ICW2,
76 	IS_ICW3,
77 	IS_ICW4,
78 };
79 
80 struct atpic {
81 	enum icw_state	icw_state;
82 
83 	bool		ready;
84 	bool		auto_eoi;
85 	bool		poll;
86 	bool		rotate;
87 	bool		special_full_nested;
88 	bool		read_isr_next;
89 	bool		intr_raised;
90 	bool		special_mask_mode;
91 
92 	uint8_t		reg_irr;	/* Interrupt Request Register (IIR) */
93 	uint8_t		reg_isr;	/* Interrupt Service (ISR) */
94 	uint8_t		reg_imr;	/* Interrupt Mask Register (IMR) */
95 	uint8_t		irq_base;	/* base interrupt vector */
96 	uint8_t		lowprio;	/* lowest priority irq */
97 	uint8_t		elc;		/* level-triggered mode bits */
98 
99 	uint_t		acnt[8];	/* sum of pin asserts and deasserts */
100 };
101 
102 struct atpic_stats {
103 	uint64_t	as_interrupts;
104 	uint64_t	as_saturate_low;
105 	uint64_t	as_saturate_high;
106 };
107 
108 struct vatpic {
109 	struct vm	*vm;
110 	kmutex_t	lock;
111 	struct atpic	atpic[2];
112 	struct atpic_stats stats;
113 };
114 
115 /*
116  * Loop over all the pins in priority order from highest to lowest.
117  */
118 #define	ATPIC_PIN_FOREACH(pinvar, atpic, tmpvar)			\
119 	for (tmpvar = 0, pinvar = (atpic->lowprio + 1) & 0x7;		\
120 	    tmpvar < 8;							\
121 	    tmpvar++, pinvar = (pinvar + 1) & 0x7)
122 
123 static int vatpic_set_pinstate(struct vatpic *vatpic, int pin, bool newstate);
124 
125 static __inline bool
126 master_atpic(struct vatpic *vatpic, struct atpic *atpic)
127 {
128 
129 	if (atpic == &vatpic->atpic[0])
130 		return (true);
131 	else
132 		return (false);
133 }
134 
135 static __inline int
136 vatpic_get_highest_isrpin(struct atpic *atpic)
137 {
138 	int bit, pin;
139 	int i;
140 
141 	ATPIC_PIN_FOREACH(pin, atpic, i) {
142 		bit = (1 << pin);
143 
144 		if (atpic->reg_isr & bit) {
145 			/*
146 			 * An IS bit that is masked by an IMR bit will not be
147 			 * cleared by a non-specific EOI in Special Mask Mode.
148 			 */
149 			if (atpic->special_mask_mode &&
150 			    (atpic->reg_imr & bit) != 0) {
151 				continue;
152 			} else {
153 				return (pin);
154 			}
155 		}
156 	}
157 
158 	return (-1);
159 }
160 
161 static __inline int
162 vatpic_get_highest_irrpin(struct atpic *atpic)
163 {
164 	int serviced;
165 	int bit, pin, tmp;
166 
167 	/*
168 	 * In 'Special Fully-Nested Mode' when an interrupt request from
169 	 * a slave is in service, the slave is not locked out from the
170 	 * master's priority logic.
171 	 */
172 	serviced = atpic->reg_isr;
173 	if (atpic->special_full_nested)
174 		serviced &= ~(1 << 2);
175 
176 	/*
177 	 * In 'Special Mask Mode', when a mask bit is set in OCW1 it inhibits
178 	 * further interrupts at that level and enables interrupts from all
179 	 * other levels that are not masked. In other words the ISR has no
180 	 * bearing on the levels that can generate interrupts.
181 	 */
182 	if (atpic->special_mask_mode)
183 		serviced = 0;
184 
185 	ATPIC_PIN_FOREACH(pin, atpic, tmp) {
186 		bit = 1 << pin;
187 
188 		/*
189 		 * If there is already an interrupt in service at the same
190 		 * or higher priority then bail.
191 		 */
192 		if ((serviced & bit) != 0)
193 			break;
194 
195 		/*
196 		 * If an interrupt is asserted and not masked then return
197 		 * the corresponding 'pin' to the caller.
198 		 */
199 		if ((atpic->reg_irr & bit) != 0 && (atpic->reg_imr & bit) == 0)
200 			return (pin);
201 	}
202 
203 	return (-1);
204 }
205 
206 static void
207 vatpic_notify_intr(struct vatpic *vatpic)
208 {
209 	struct atpic *atpic;
210 	int pin;
211 
212 	ASSERT(VATPIC_LOCKED(vatpic));
213 
214 	/*
215 	 * First check the slave.
216 	 */
217 	atpic = &vatpic->atpic[1];
218 	if (!atpic->intr_raised &&
219 	    (pin = vatpic_get_highest_irrpin(atpic)) != -1) {
220 		/*
221 		 * Cascade the request from the slave to the master.
222 		 */
223 		atpic->intr_raised = true;
224 		if (vatpic_set_pinstate(vatpic, 2, true) == 0) {
225 			(void) vatpic_set_pinstate(vatpic, 2, false);
226 		}
227 	} else {
228 		/* No eligible interrupts on slave chip */
229 	}
230 
231 	/*
232 	 * Then check the master.
233 	 */
234 	atpic = &vatpic->atpic[0];
235 	if (!atpic->intr_raised &&
236 	    (pin = vatpic_get_highest_irrpin(atpic)) != -1) {
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 		(void) lapic_set_local_intr(vatpic->vm, -1, APIC_LVT_LINT0);
264 		(void) vioapic_pulse_irq(vatpic->vm, 0);
265 		vatpic->stats.as_interrupts++;
266 	} else {
267 		/* No eligible interrupts on master chip */
268 	}
269 }
270 
271 static int
272 vatpic_icw1(struct vatpic *vatpic, struct atpic *atpic, uint8_t val)
273 {
274 	atpic->ready = false;
275 
276 	atpic->icw_state = IS_ICW1;
277 	atpic->reg_irr = 0;
278 	atpic->reg_imr = 0;
279 	atpic->lowprio = 7;
280 	atpic->read_isr_next = false;
281 	atpic->poll = false;
282 	atpic->special_mask_mode = false;
283 
284 	if ((val & ICW1_SNGL) != 0) {
285 		/* Cascade mode reqired */
286 		return (-1);
287 	}
288 
289 	if ((val & ICW1_IC4) == 0) {
290 		/* ICW4 reqired */
291 		return (-1);
292 	}
293 
294 	atpic->icw_state = IS_ICW2;
295 
296 	return (0);
297 }
298 
299 static int
300 vatpic_icw2(struct vatpic *vatpic, struct atpic *atpic, uint8_t val)
301 {
302 	atpic->irq_base = val & IRQ_BASE_MASK;
303 	atpic->icw_state = IS_ICW3;
304 
305 	return (0);
306 }
307 
308 static int
309 vatpic_icw3(struct vatpic *vatpic, struct atpic *atpic, uint8_t val)
310 {
311 	atpic->icw_state = IS_ICW4;
312 
313 	return (0);
314 }
315 
316 static int
317 vatpic_icw4(struct vatpic *vatpic, struct atpic *atpic, uint8_t val)
318 {
319 	if ((val & ICW4_8086) == 0) {
320 		/* Microprocessor mode required */
321 		return (-1);
322 	}
323 
324 	atpic->auto_eoi = (val & ICW4_AEOI) != 0;
325 	if (master_atpic(vatpic, atpic)) {
326 		atpic->special_full_nested = (val & ICW4_SFNM) != 0;
327 	}
328 
329 	atpic->icw_state = IS_ICW1;
330 	atpic->ready = true;
331 
332 	return (0);
333 }
334 
335 static int
336 vatpic_ocw1(struct vatpic *vatpic, struct atpic *atpic, uint8_t val)
337 {
338 	atpic->reg_imr = val;
339 
340 	return (0);
341 }
342 
343 static int
344 vatpic_ocw2(struct vatpic *vatpic, struct atpic *atpic, uint8_t val)
345 {
346 	atpic->rotate = (val & OCW2_R) != 0;
347 
348 	if ((val & OCW2_EOI) != 0) {
349 		int isr_bit;
350 
351 		if ((val & OCW2_SL) != 0) {
352 			/* specific EOI */
353 			isr_bit = val & 0x7;
354 		} else {
355 			/* non-specific EOI */
356 			isr_bit = vatpic_get_highest_isrpin(atpic);
357 		}
358 
359 		if (isr_bit != -1) {
360 			atpic->reg_isr &= ~(1 << isr_bit);
361 
362 			if (atpic->rotate)
363 				atpic->lowprio = isr_bit;
364 		}
365 	} else if ((val & OCW2_SL) != 0 && atpic->rotate) {
366 		/* specific priority */
367 		atpic->lowprio = val & 0x7;
368 	}
369 
370 	return (0);
371 }
372 
373 static int
374 vatpic_ocw3(struct vatpic *vatpic, struct atpic *atpic, uint8_t val)
375 {
376 	if ((val & OCW3_ESMM) != 0) {
377 		atpic->special_mask_mode = (val & OCW3_SMM) != 0;
378 	}
379 	if ((val & OCW3_RR) != 0) {
380 		atpic->read_isr_next = (val & OCW3_RIS) != 0;
381 	}
382 	if ((val & OCW3_P) != 0) {
383 		atpic->poll = true;
384 	}
385 
386 	return (0);
387 }
388 
389 static int
390 vatpic_set_pinstate(struct vatpic *vatpic, int pin, bool newstate)
391 {
392 	struct atpic *atpic;
393 	uint_t oldcnt, newcnt;
394 	int err = 0;
395 
396 	VERIFY(pin >= 0 && pin < 16);
397 	ASSERT(VATPIC_LOCKED(vatpic));
398 
399 	const int lpin = pin & 0x7;
400 	atpic = &vatpic->atpic[pin >> 3];
401 
402 	oldcnt = newcnt = atpic->acnt[lpin];
403 	if (newstate) {
404 		if (newcnt != UINT_MAX) {
405 			newcnt++;
406 		} else {
407 			err = E2BIG;
408 			DTRACE_PROBE2(vatpic__sat_high, struct vatpic *, vatpic,
409 			    int, pin);
410 			vatpic->stats.as_saturate_high++;
411 		}
412 	} else {
413 		if (newcnt != 0) {
414 			newcnt--;
415 		} else {
416 			err = ERANGE;
417 			DTRACE_PROBE2(vatpic__sat_low, struct vatpic *, vatpic,
418 			    int, pin);
419 			vatpic->stats.as_saturate_low++;
420 		}
421 	}
422 	atpic->acnt[lpin] = newcnt;
423 
424 	const bool level = ((atpic->elc & (1 << (lpin))) != 0);
425 	if ((oldcnt == 0 && newcnt == 1) || (newcnt > 0 && level == true)) {
426 		/* rising edge or level */
427 		DTRACE_PROBE2(vatpic__assert, struct vatpic *, vatpic,
428 		    int, pin);
429 		atpic->reg_irr |= (1 << lpin);
430 	} else if (oldcnt == 1 && newcnt == 0) {
431 		/* falling edge */
432 		DTRACE_PROBE2(vatpic__deassert, struct vatpic *, vatpic,
433 		    int, pin);
434 		if (level) {
435 			atpic->reg_irr &= ~(1 << lpin);
436 		}
437 	}
438 
439 	vatpic_notify_intr(vatpic);
440 	return (err);
441 }
442 
443 static int
444 vatpic_set_irqstate(struct vm *vm, int irq, enum irqstate irqstate)
445 {
446 	struct vatpic *vatpic;
447 	struct atpic *atpic;
448 	int err = 0;
449 
450 	if (irq < 0 || irq > 15)
451 		return (EINVAL);
452 
453 	vatpic = vm_atpic(vm);
454 	atpic = &vatpic->atpic[irq >> 3];
455 
456 	if (!atpic->ready)
457 		return (0);
458 
459 	VATPIC_LOCK(vatpic);
460 	switch (irqstate) {
461 	case IRQSTATE_ASSERT:
462 		err = vatpic_set_pinstate(vatpic, irq, true);
463 		break;
464 	case IRQSTATE_DEASSERT:
465 		err = vatpic_set_pinstate(vatpic, irq, false);
466 		break;
467 	case IRQSTATE_PULSE:
468 		err = vatpic_set_pinstate(vatpic, irq, true);
469 		if (err == 0) {
470 			err = vatpic_set_pinstate(vatpic, irq, false);
471 		}
472 		break;
473 	default:
474 		panic("vatpic_set_irqstate: invalid irqstate %d", irqstate);
475 	}
476 	VATPIC_UNLOCK(vatpic);
477 
478 	return (err);
479 }
480 
481 int
482 vatpic_assert_irq(struct vm *vm, int irq)
483 {
484 	return (vatpic_set_irqstate(vm, irq, IRQSTATE_ASSERT));
485 }
486 
487 int
488 vatpic_deassert_irq(struct vm *vm, int irq)
489 {
490 	return (vatpic_set_irqstate(vm, irq, IRQSTATE_DEASSERT));
491 }
492 
493 int
494 vatpic_pulse_irq(struct vm *vm, int irq)
495 {
496 	return (vatpic_set_irqstate(vm, irq, IRQSTATE_PULSE));
497 }
498 
499 int
500 vatpic_set_irq_trigger(struct vm *vm, int irq, enum vm_intr_trigger trigger)
501 {
502 	if (irq < 0 || irq > 15)
503 		return (EINVAL);
504 
505 	/*
506 	 * See comments in vatpic_elc_handler.
507 	 * These IRQs must be edge triggered.
508 	 */
509 	if (trigger == LEVEL_TRIGGER) {
510 		switch (irq) {
511 		case 0:
512 		case 1:
513 		case 2:
514 		case 8:
515 		case 13:
516 			return (EINVAL);
517 		}
518 	}
519 
520 	struct vatpic *vatpic = vm_atpic(vm);
521 	struct atpic *atpic = &vatpic->atpic[irq >> 3];
522 	const int pin = irq & 0x7;
523 
524 	VATPIC_LOCK(vatpic);
525 	if (trigger == LEVEL_TRIGGER) {
526 		atpic->elc |= (1 << pin);
527 	} else {
528 		atpic->elc &= ~(1 << pin);
529 	}
530 	VATPIC_UNLOCK(vatpic);
531 
532 	return (0);
533 }
534 
535 void
536 vatpic_pending_intr(struct vm *vm, int *vecptr)
537 {
538 	struct vatpic *vatpic;
539 	struct atpic *atpic;
540 	int pin;
541 
542 	vatpic = vm_atpic(vm);
543 
544 	atpic = &vatpic->atpic[0];
545 
546 	VATPIC_LOCK(vatpic);
547 
548 	pin = vatpic_get_highest_irrpin(atpic);
549 	if (pin == 2) {
550 		atpic = &vatpic->atpic[1];
551 		pin = vatpic_get_highest_irrpin(atpic);
552 	}
553 
554 	/*
555 	 * If there are no pins active at this moment then return the spurious
556 	 * interrupt vector instead.
557 	 */
558 	if (pin == -1)
559 		pin = 7;
560 
561 	KASSERT(pin >= 0 && pin <= 7, ("%s: invalid pin %d", __func__, pin));
562 	*vecptr = atpic->irq_base + pin;
563 
564 	VATPIC_UNLOCK(vatpic);
565 }
566 
567 static void
568 vatpic_pin_accepted(struct atpic *atpic, int pin)
569 {
570 	ASSERT(pin >= 0 && pin < 8);
571 
572 	atpic->intr_raised = false;
573 
574 	if (atpic->acnt[pin] == 0)
575 		atpic->reg_irr &= ~(1 << pin);
576 
577 	if (atpic->auto_eoi) {
578 		if (atpic->rotate)
579 			atpic->lowprio = pin;
580 	} else {
581 		atpic->reg_isr |= (1 << pin);
582 	}
583 }
584 
585 void
586 vatpic_intr_accepted(struct vm *vm, int vector)
587 {
588 	struct vatpic *vatpic;
589 	int pin;
590 
591 	vatpic = vm_atpic(vm);
592 
593 	VATPIC_LOCK(vatpic);
594 
595 	pin = vector & 0x7;
596 
597 	if ((vector & IRQ_BASE_MASK) == vatpic->atpic[1].irq_base) {
598 		vatpic_pin_accepted(&vatpic->atpic[1], pin);
599 		/*
600 		 * If this vector originated from the slave,
601 		 * accept the cascaded interrupt too.
602 		 */
603 		vatpic_pin_accepted(&vatpic->atpic[0], 2);
604 	} else {
605 		vatpic_pin_accepted(&vatpic->atpic[0], pin);
606 	}
607 
608 	vatpic_notify_intr(vatpic);
609 
610 	VATPIC_UNLOCK(vatpic);
611 }
612 
613 static int
614 vatpic_read(struct vatpic *vatpic, struct atpic *atpic, bool in, int port,
615     int bytes, uint32_t *eax)
616 {
617 	int pin;
618 
619 	VATPIC_LOCK(vatpic);
620 
621 	if (atpic->poll) {
622 		atpic->poll = false;
623 		pin = vatpic_get_highest_irrpin(atpic);
624 		if (pin >= 0) {
625 			vatpic_pin_accepted(atpic, pin);
626 			*eax = 0x80 | pin;
627 		} else {
628 			*eax = 0;
629 		}
630 	} else {
631 		if (port & ICU_IMR_OFFSET) {
632 			/* read interrrupt mask register */
633 			*eax = atpic->reg_imr;
634 		} else {
635 			if (atpic->read_isr_next) {
636 				/* read interrupt service register */
637 				*eax = atpic->reg_isr;
638 			} else {
639 				/* read interrupt request register */
640 				*eax = atpic->reg_irr;
641 			}
642 		}
643 	}
644 
645 	VATPIC_UNLOCK(vatpic);
646 
647 	return (0);
648 
649 }
650 
651 static int
652 vatpic_write(struct vatpic *vatpic, struct atpic *atpic, bool in, int port,
653     int bytes, uint32_t *eax)
654 {
655 	int error;
656 	uint8_t val;
657 
658 	error = 0;
659 	val = *eax;
660 
661 	VATPIC_LOCK(vatpic);
662 
663 	if (port & ICU_IMR_OFFSET) {
664 		switch (atpic->icw_state) {
665 		case IS_ICW2:
666 			error = vatpic_icw2(vatpic, atpic, val);
667 			break;
668 		case IS_ICW3:
669 			error = vatpic_icw3(vatpic, atpic, val);
670 			break;
671 		case IS_ICW4:
672 			error = vatpic_icw4(vatpic, atpic, val);
673 			break;
674 		default:
675 			error = vatpic_ocw1(vatpic, atpic, val);
676 			break;
677 		}
678 	} else {
679 		if (val & (1 << 4))
680 			error = vatpic_icw1(vatpic, atpic, val);
681 
682 		if (atpic->ready) {
683 			if (val & (1 << 3))
684 				error = vatpic_ocw3(vatpic, atpic, val);
685 			else
686 				error = vatpic_ocw2(vatpic, atpic, val);
687 		}
688 	}
689 
690 	if (atpic->ready)
691 		vatpic_notify_intr(vatpic);
692 
693 	VATPIC_UNLOCK(vatpic);
694 
695 	return (error);
696 }
697 
698 int
699 vatpic_master_handler(void *arg, bool in, uint16_t port, uint8_t bytes,
700     uint32_t *eax)
701 {
702 	struct vatpic *vatpic = arg;
703 	struct atpic *atpic = &vatpic->atpic[0];
704 
705 	if (bytes != 1)
706 		return (-1);
707 
708 	if (in) {
709 		return (vatpic_read(vatpic, atpic, in, port, bytes, eax));
710 	}
711 
712 	return (vatpic_write(vatpic, atpic, in, port, bytes, eax));
713 }
714 
715 int
716 vatpic_slave_handler(void *arg, bool in, uint16_t port, uint8_t bytes,
717     uint32_t *eax)
718 {
719 	struct vatpic *vatpic = arg;
720 	struct atpic *atpic = &vatpic->atpic[1];
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 static const uint8_t vatpic_elc_mask[2] = {
733 	/*
734 	 * For the master PIC the cascade channel (IRQ2), the heart beat timer
735 	 * (IRQ0), and the keyboard controller (IRQ1) cannot be programmed for
736 	 * level mode.
737 	 */
738 	0xf8,
739 	/*
740 	 * For the slave PIC the real time clock (IRQ8) and the floating point
741 	 * error interrupt (IRQ13) cannot be programmed for level mode.
742 	 */
743 	0xde
744 };
745 
746 int
747 vatpic_elc_handler(void *arg, bool in, uint16_t port, uint8_t bytes,
748     uint32_t *eax)
749 {
750 	struct vatpic *vatpic = arg;
751 	struct atpic *atpic = NULL;
752 	uint8_t elc_mask = 0;
753 
754 	switch (port) {
755 	case IO_ELCR1:
756 		atpic = &vatpic->atpic[0];
757 		elc_mask = vatpic_elc_mask[0];
758 		break;
759 	case IO_ELCR2:
760 		atpic = &vatpic->atpic[1];
761 		elc_mask = vatpic_elc_mask[1];
762 		break;
763 	default:
764 		return (-1);
765 	}
766 
767 	if (bytes != 1)
768 		return (-1);
769 
770 	VATPIC_LOCK(vatpic);
771 	if (in) {
772 		*eax = atpic->elc;
773 	} else {
774 		atpic->elc = *eax & elc_mask;
775 	}
776 	VATPIC_UNLOCK(vatpic);
777 
778 	return (0);
779 }
780 
781 struct vatpic *
782 vatpic_init(struct vm *vm)
783 {
784 	struct vatpic *vatpic;
785 
786 	vatpic = kmem_zalloc(sizeof (struct vatpic), KM_SLEEP);
787 	vatpic->vm = vm;
788 
789 	mutex_init(&vatpic->lock, NULL, MUTEX_ADAPTIVE, NULL);
790 
791 	return (vatpic);
792 }
793 
794 void
795 vatpic_cleanup(struct vatpic *vatpic)
796 {
797 	mutex_destroy(&vatpic->lock);
798 	kmem_free(vatpic, sizeof (*vatpic));
799 }
800 
801 static int
802 vatpic_data_read(void *datap, const vmm_data_req_t *req)
803 {
804 	VERIFY3U(req->vdr_class, ==, VDC_ATPIC);
805 	VERIFY3U(req->vdr_version, ==, 1);
806 	VERIFY3U(req->vdr_len, >=, sizeof (struct vdi_atpic_v1));
807 
808 	struct vatpic *vatpic = datap;
809 	struct vdi_atpic_v1 *out = req->vdr_data;
810 
811 	VATPIC_LOCK(vatpic);
812 	for (uint_t i = 0; i < 2; i++) {
813 		const struct atpic *src = &vatpic->atpic[i];
814 		struct vdi_atpic_chip_v1 *chip = &out->va_chip[i];
815 
816 		chip->vac_icw_state = src->icw_state;
817 		chip->vac_status =
818 		    (src->ready ? (1 << 0) : 0) |
819 		    (src->auto_eoi ? (1 << 1) : 0) |
820 		    (src->poll ? (1 << 2) : 0) |
821 		    (src->rotate ? (1 << 3) : 0) |
822 		    (src->special_full_nested ? (1 << 4) : 0) |
823 		    (src->read_isr_next ? (1 << 5) : 0) |
824 		    (src->intr_raised ? (1 << 6) : 0) |
825 		    (src->special_mask_mode ? (1 << 7) : 0);
826 		chip->vac_reg_irr = src->reg_irr;
827 		chip->vac_reg_isr = src->reg_isr;
828 		chip->vac_reg_imr = src->reg_imr;
829 		chip->vac_irq_base = src->irq_base;
830 		chip->vac_lowprio = src->lowprio;
831 		chip->vac_elc = src->elc;
832 		for (uint_t j = 0; j < 8; j++) {
833 			chip->vac_level[j] = src->acnt[j];
834 		}
835 	}
836 	VATPIC_UNLOCK(vatpic);
837 
838 	return (0);
839 }
840 
841 static bool
842 vatpic_data_validate(const struct vdi_atpic_v1 *src)
843 {
844 	for (uint_t i = 0; i < 2; i++) {
845 		const struct vdi_atpic_chip_v1 *chip = &src->va_chip[i];
846 
847 		if (chip->vac_icw_state > IS_ICW4) {
848 			return (false);
849 		}
850 		if ((chip->vac_elc & ~vatpic_elc_mask[i]) != 0) {
851 			return (false);
852 		}
853 		/*
854 		 * TODO: The state of `intr_raised` could be checked what
855 		 * resides in the ISR/IRR registers.
856 		 */
857 	}
858 
859 	return (true);
860 }
861 
862 static int
863 vatpic_data_write(void *datap, const vmm_data_req_t *req)
864 {
865 	VERIFY3U(req->vdr_class, ==, VDC_ATPIC);
866 	VERIFY3U(req->vdr_version, ==, 1);
867 	VERIFY3U(req->vdr_len, >=, sizeof (struct vdi_atpic_v1));
868 
869 	struct vatpic *vatpic = datap;
870 	const struct vdi_atpic_v1 *src = req->vdr_data;
871 	if (!vatpic_data_validate(src)) {
872 		return (EINVAL);
873 	}
874 
875 	VATPIC_LOCK(vatpic);
876 	for (uint_t i = 0; i < 2; i++) {
877 		const struct vdi_atpic_chip_v1 *chip = &src->va_chip[i];
878 		struct atpic *out = &vatpic->atpic[i];
879 
880 		out->icw_state = chip->vac_icw_state;
881 
882 		out->ready = (chip->vac_status & (1 << 0)) != 0;
883 		out->auto_eoi = (chip->vac_status & (1 << 1)) != 0;
884 		out->poll = (chip->vac_status & (1 << 2)) != 0;
885 		out->rotate = (chip->vac_status & (1 << 3)) != 0;
886 		out->special_full_nested = (chip->vac_status & (1 << 4)) != 0;
887 		out->read_isr_next = (chip->vac_status & (1 << 5)) != 0;
888 		out->intr_raised = (chip->vac_status & (1 << 6)) != 0;
889 		out->special_mask_mode = (chip->vac_status & (1 << 7)) != 0;
890 
891 		out->reg_irr = chip->vac_reg_irr;
892 		out->reg_isr = chip->vac_reg_isr;
893 		out->reg_imr = chip->vac_reg_imr;
894 		out->irq_base = chip->vac_irq_base;
895 		out->lowprio = chip->vac_lowprio;
896 		out->elc = chip->vac_elc;
897 		for (uint_t j = 0; j < 8; j++) {
898 			out->acnt[j] = chip->vac_level[j];
899 		}
900 	}
901 	VATPIC_UNLOCK(vatpic);
902 
903 	return (0);
904 }
905 
906 static const vmm_data_version_entry_t atpic_v1 = {
907 	.vdve_class = VDC_ATPIC,
908 	.vdve_version = 1,
909 	.vdve_len_expect = sizeof (struct vdi_atpic_v1),
910 	.vdve_readf = vatpic_data_read,
911 	.vdve_writef = vatpic_data_write,
912 };
913 VMM_DATA_VERSION(atpic_v1);
914