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