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