xref: /freebsd/sys/amd64/vmm/io/vatpic.c (revision 3ccb02334bf5aee49a66dcff4b9229220bd0184b)
1762fd208STycho Nightingale /*-
24d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
3ebc3c37cSMarcelo Araujo  *
4762fd208STycho Nightingale  * Copyright (c) 2014 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com>
5762fd208STycho Nightingale  * All rights reserved.
6762fd208STycho Nightingale  *
7762fd208STycho Nightingale  * Redistribution and use in source and binary forms, with or without
8762fd208STycho Nightingale  * modification, are permitted provided that the following conditions
9762fd208STycho Nightingale  * are met:
10762fd208STycho Nightingale  * 1. Redistributions of source code must retain the above copyright
11762fd208STycho Nightingale  *    notice, this list of conditions and the following disclaimer.
12762fd208STycho Nightingale  * 2. Redistributions in binary form must reproduce the above copyright
13762fd208STycho Nightingale  *    notice, this list of conditions and the following disclaimer in the
14762fd208STycho Nightingale  *    documentation and/or other materials provided with the distribution.
15762fd208STycho Nightingale  *
16762fd208STycho Nightingale  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
17762fd208STycho Nightingale  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18762fd208STycho Nightingale  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19762fd208STycho Nightingale  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20762fd208STycho Nightingale  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21762fd208STycho Nightingale  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22762fd208STycho Nightingale  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23762fd208STycho Nightingale  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24762fd208STycho Nightingale  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25762fd208STycho Nightingale  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26762fd208STycho Nightingale  * SUCH DAMAGE.
27762fd208STycho Nightingale  */
28762fd208STycho Nightingale 
29762fd208STycho Nightingale #include <sys/cdefs.h>
30483d953aSJohn Baldwin #include "opt_bhyve_snapshot.h"
31483d953aSJohn Baldwin 
32762fd208STycho Nightingale #include <sys/param.h>
33762fd208STycho Nightingale #include <sys/types.h>
34762fd208STycho Nightingale #include <sys/queue.h>
35762fd208STycho Nightingale #include <sys/kernel.h>
36762fd208STycho Nightingale #include <sys/lock.h>
37762fd208STycho Nightingale #include <sys/malloc.h>
38762fd208STycho Nightingale #include <sys/mutex.h>
39762fd208STycho Nightingale #include <sys/systm.h>
40762fd208STycho Nightingale 
41762fd208STycho Nightingale #include <x86/apicreg.h>
42762fd208STycho Nightingale #include <machine/vmm.h>
43483d953aSJohn Baldwin #include <machine/vmm_snapshot.h>
44762fd208STycho Nightingale 
45*3ccb0233SMark Johnston #include <dev/ic/i8259.h>
46*3ccb0233SMark Johnston #include <dev/vmm/vmm_ktr.h>
47*3ccb0233SMark Johnston 
48762fd208STycho Nightingale #include "vmm_lapic.h"
49762fd208STycho Nightingale #include "vioapic.h"
50762fd208STycho Nightingale #include "vatpic.h"
51762fd208STycho Nightingale 
52762fd208STycho Nightingale static MALLOC_DEFINE(M_VATPIC, "atpic", "bhyve virtual atpic (8259)");
53762fd208STycho Nightingale 
54762fd208STycho Nightingale #define	VATPIC_LOCK(vatpic)		mtx_lock_spin(&((vatpic)->mtx))
55762fd208STycho Nightingale #define	VATPIC_UNLOCK(vatpic)		mtx_unlock_spin(&((vatpic)->mtx))
56762fd208STycho Nightingale #define	VATPIC_LOCKED(vatpic)		mtx_owned(&((vatpic)->mtx))
57762fd208STycho Nightingale 
58762fd208STycho Nightingale enum irqstate {
59762fd208STycho Nightingale 	IRQSTATE_ASSERT,
60762fd208STycho Nightingale 	IRQSTATE_DEASSERT,
61762fd208STycho Nightingale 	IRQSTATE_PULSE
62762fd208STycho Nightingale };
63762fd208STycho Nightingale 
64762fd208STycho Nightingale struct atpic {
65762fd208STycho Nightingale 	bool		ready;
66762fd208STycho Nightingale 	int		icw_num;
67762fd208STycho Nightingale 	int		rd_cmd_reg;
68762fd208STycho Nightingale 
69762fd208STycho Nightingale 	bool		aeoi;
70762fd208STycho Nightingale 	bool		poll;
71762fd208STycho Nightingale 	bool		rotate;
72b96be57aSTycho Nightingale 	bool		sfn;		/* special fully-nested mode */
73762fd208STycho Nightingale 
74762fd208STycho Nightingale 	int		irq_base;
75762fd208STycho Nightingale 	uint8_t		request;	/* Interrupt Request Register (IIR) */
76762fd208STycho Nightingale 	uint8_t		service;	/* Interrupt Service (ISR) */
77762fd208STycho Nightingale 	uint8_t		mask;		/* Interrupt Mask Register (IMR) */
781a5934efSNeel Natu 	uint8_t		smm;		/* special mask mode */
79762fd208STycho Nightingale 
80762fd208STycho Nightingale 	int		acnt[8];	/* sum of pin asserts and deasserts */
81e64c5af3SNeel Natu 	int		lowprio;	/* lowest priority irq */
82b96be57aSTycho Nightingale 
83b96be57aSTycho Nightingale 	bool		intr_raised;
84762fd208STycho Nightingale };
85762fd208STycho Nightingale 
86762fd208STycho Nightingale struct vatpic {
87762fd208STycho Nightingale 	struct vm	*vm;
88762fd208STycho Nightingale 	struct mtx	mtx;
89762fd208STycho Nightingale 	struct atpic	atpic[2];
90762fd208STycho Nightingale 	uint8_t		elc[2];
91762fd208STycho Nightingale };
92762fd208STycho Nightingale 
93762fd208STycho Nightingale #define	VATPIC_CTR0(vatpic, fmt)					\
94762fd208STycho Nightingale 	VM_CTR0((vatpic)->vm, fmt)
95762fd208STycho Nightingale 
96762fd208STycho Nightingale #define	VATPIC_CTR1(vatpic, fmt, a1)					\
97762fd208STycho Nightingale 	VM_CTR1((vatpic)->vm, fmt, a1)
98762fd208STycho Nightingale 
99762fd208STycho Nightingale #define	VATPIC_CTR2(vatpic, fmt, a1, a2)				\
100762fd208STycho Nightingale 	VM_CTR2((vatpic)->vm, fmt, a1, a2)
101762fd208STycho Nightingale 
102762fd208STycho Nightingale #define	VATPIC_CTR3(vatpic, fmt, a1, a2, a3)				\
103762fd208STycho Nightingale 	VM_CTR3((vatpic)->vm, fmt, a1, a2, a3)
104762fd208STycho Nightingale 
105762fd208STycho Nightingale #define	VATPIC_CTR4(vatpic, fmt, a1, a2, a3, a4)			\
106762fd208STycho Nightingale 	VM_CTR4((vatpic)->vm, fmt, a1, a2, a3, a4)
107762fd208STycho Nightingale 
108e64c5af3SNeel Natu /*
109e64c5af3SNeel Natu  * Loop over all the pins in priority order from highest to lowest.
110e64c5af3SNeel Natu  */
111e64c5af3SNeel Natu #define	ATPIC_PIN_FOREACH(pinvar, atpic, tmpvar)			\
112e64c5af3SNeel Natu 	for (tmpvar = 0, pinvar = (atpic->lowprio + 1) & 0x7;		\
113e64c5af3SNeel Natu 	    tmpvar < 8;							\
114e64c5af3SNeel Natu 	    tmpvar++, pinvar = (pinvar + 1) & 0x7)
115e64c5af3SNeel Natu 
116b96be57aSTycho Nightingale static void vatpic_set_pinstate(struct vatpic *vatpic, int pin, bool newstate);
117762fd208STycho Nightingale 
118ac721e53SNeel Natu static __inline bool
master_atpic(struct vatpic * vatpic,struct atpic * atpic)119ac721e53SNeel Natu master_atpic(struct vatpic *vatpic, struct atpic *atpic)
120ac721e53SNeel Natu {
121ac721e53SNeel Natu 
122ac721e53SNeel Natu 	if (atpic == &vatpic->atpic[0])
123ac721e53SNeel Natu 		return (true);
124ac721e53SNeel Natu 	else
125ac721e53SNeel Natu 		return (false);
126ac721e53SNeel Natu }
127ac721e53SNeel Natu 
128762fd208STycho Nightingale static __inline int
vatpic_get_highest_isrpin(struct atpic * atpic)129762fd208STycho Nightingale vatpic_get_highest_isrpin(struct atpic *atpic)
130762fd208STycho Nightingale {
131762fd208STycho Nightingale 	int bit, pin;
132762fd208STycho Nightingale 	int i;
133762fd208STycho Nightingale 
134e64c5af3SNeel Natu 	ATPIC_PIN_FOREACH(pin, atpic, i) {
135762fd208STycho Nightingale                 bit = (1 << pin);
136762fd208STycho Nightingale 
1371a5934efSNeel Natu 		if (atpic->service & bit) {
1381a5934efSNeel Natu 			/*
1391a5934efSNeel Natu 			 * An IS bit that is masked by an IMR bit will not be
1401a5934efSNeel Natu 			 * cleared by a non-specific EOI in Special Mask Mode.
1411a5934efSNeel Natu 			 */
1421a5934efSNeel Natu 			if (atpic->smm && (atpic->mask & bit) != 0)
1431a5934efSNeel Natu 				continue;
1441a5934efSNeel Natu 			else
145762fd208STycho Nightingale 				return (pin);
146762fd208STycho Nightingale 		}
1471a5934efSNeel Natu 	}
148762fd208STycho Nightingale 
149762fd208STycho Nightingale 	return (-1);
150762fd208STycho Nightingale }
151762fd208STycho Nightingale 
152762fd208STycho Nightingale static __inline int
vatpic_get_highest_irrpin(struct atpic * atpic)153762fd208STycho Nightingale vatpic_get_highest_irrpin(struct atpic *atpic)
154762fd208STycho Nightingale {
155b96be57aSTycho Nightingale 	int serviced;
156e64c5af3SNeel Natu 	int bit, pin, tmp;
157762fd208STycho Nightingale 
158b96be57aSTycho Nightingale 	/*
159b96be57aSTycho Nightingale 	 * In 'Special Fully-Nested Mode' when an interrupt request from
160b96be57aSTycho Nightingale 	 * a slave is in service, the slave is not locked out from the
161b96be57aSTycho Nightingale 	 * master's priority logic.
162b96be57aSTycho Nightingale 	 */
163b96be57aSTycho Nightingale 	serviced = atpic->service;
164b96be57aSTycho Nightingale 	if (atpic->sfn)
165b96be57aSTycho Nightingale 		serviced &= ~(1 << 2);
166b96be57aSTycho Nightingale 
1671a5934efSNeel Natu 	/*
1681a5934efSNeel Natu 	 * In 'Special Mask Mode', when a mask bit is set in OCW1 it inhibits
1691a5934efSNeel Natu 	 * further interrupts at that level and enables interrupts from all
1701a5934efSNeel Natu 	 * other levels that are not masked. In other words the ISR has no
1711a5934efSNeel Natu 	 * bearing on the levels that can generate interrupts.
1721a5934efSNeel Natu 	 */
1731a5934efSNeel Natu 	if (atpic->smm)
1741a5934efSNeel Natu 		serviced = 0;
1751a5934efSNeel Natu 
176e64c5af3SNeel Natu 	ATPIC_PIN_FOREACH(pin, atpic, tmp) {
177e64c5af3SNeel Natu 		bit = 1 << pin;
178762fd208STycho Nightingale 
179e64c5af3SNeel Natu 		/*
180e64c5af3SNeel Natu 		 * If there is already an interrupt in service at the same
181e64c5af3SNeel Natu 		 * or higher priority then bail.
182e64c5af3SNeel Natu 		 */
183e64c5af3SNeel Natu 		if ((serviced & bit) != 0)
184e64c5af3SNeel Natu 			break;
185e64c5af3SNeel Natu 
186e64c5af3SNeel Natu 		/*
187e64c5af3SNeel Natu 		 * If an interrupt is asserted and not masked then return
188e64c5af3SNeel Natu 		 * the corresponding 'pin' to the caller.
189e64c5af3SNeel Natu 		 */
190e64c5af3SNeel Natu 		if ((atpic->request & bit) != 0 && (atpic->mask & bit) == 0)
191762fd208STycho Nightingale 			return (pin);
192762fd208STycho Nightingale 	}
193762fd208STycho Nightingale 
194762fd208STycho Nightingale 	return (-1);
195762fd208STycho Nightingale }
196762fd208STycho Nightingale 
197762fd208STycho Nightingale static void
vatpic_notify_intr(struct vatpic * vatpic)198762fd208STycho Nightingale vatpic_notify_intr(struct vatpic *vatpic)
199762fd208STycho Nightingale {
200762fd208STycho Nightingale 	struct atpic *atpic;
201762fd208STycho Nightingale 	int pin;
202762fd208STycho Nightingale 
203762fd208STycho Nightingale 	KASSERT(VATPIC_LOCKED(vatpic), ("vatpic_notify_intr not locked"));
204762fd208STycho Nightingale 
205b96be57aSTycho Nightingale 	/*
206b96be57aSTycho Nightingale 	 * First check the slave.
207b96be57aSTycho Nightingale 	 */
208b96be57aSTycho Nightingale 	atpic = &vatpic->atpic[1];
209b96be57aSTycho Nightingale 	if (!atpic->intr_raised &&
210b96be57aSTycho Nightingale 	    (pin = vatpic_get_highest_irrpin(atpic)) != -1) {
211b96be57aSTycho Nightingale 		VATPIC_CTR4(vatpic, "atpic slave notify pin = %d "
212b96be57aSTycho Nightingale 		    "(imr 0x%x irr 0x%x isr 0x%x)", pin,
213b96be57aSTycho Nightingale 		    atpic->mask, atpic->request, atpic->service);
2140775fbb4STycho Nightingale 
215b96be57aSTycho Nightingale 		/*
216b96be57aSTycho Nightingale 		 * Cascade the request from the slave to the master.
217b96be57aSTycho Nightingale 		 */
218b96be57aSTycho Nightingale 		atpic->intr_raised = true;
219b96be57aSTycho Nightingale 		vatpic_set_pinstate(vatpic, 2, true);
220b96be57aSTycho Nightingale 		vatpic_set_pinstate(vatpic, 2, false);
221b96be57aSTycho Nightingale 	} else {
222b96be57aSTycho Nightingale 		VATPIC_CTR3(vatpic, "atpic slave no eligible interrupts "
223b96be57aSTycho Nightingale 		    "(imr 0x%x irr 0x%x isr 0x%x)",
224b96be57aSTycho Nightingale 		    atpic->mask, atpic->request, atpic->service);
225b96be57aSTycho Nightingale 	}
226b96be57aSTycho Nightingale 
227b96be57aSTycho Nightingale 	/*
228b96be57aSTycho Nightingale 	 * Then check the master.
229b96be57aSTycho Nightingale 	 */
230762fd208STycho Nightingale 	atpic = &vatpic->atpic[0];
231b96be57aSTycho Nightingale 	if (!atpic->intr_raised &&
232b96be57aSTycho Nightingale 	    (pin = vatpic_get_highest_irrpin(atpic)) != -1) {
233b96be57aSTycho Nightingale 		VATPIC_CTR4(vatpic, "atpic master notify pin = %d "
234762fd208STycho Nightingale 		    "(imr 0x%x irr 0x%x isr 0x%x)", pin,
235762fd208STycho Nightingale 		    atpic->mask, atpic->request, atpic->service);
2360775fbb4STycho Nightingale 
2370775fbb4STycho Nightingale 		/*
2384eec6021SNeel Natu 		 * From Section 3.6.2, "Interrupt Modes", in the
2394eec6021SNeel Natu 		 * MPtable Specification, Version 1.4
2404eec6021SNeel Natu 		 *
2410775fbb4STycho Nightingale 		 * PIC interrupts are routed to both the Local APIC
2420775fbb4STycho Nightingale 		 * and the I/O APIC to support operation in 1 of 3
2430775fbb4STycho Nightingale 		 * modes.
2440775fbb4STycho Nightingale 		 *
2450775fbb4STycho Nightingale 		 * 1. Legacy PIC Mode: the PIC effectively bypasses
2464eec6021SNeel Natu 		 * all APIC components.  In this mode the local APIC is
2470775fbb4STycho Nightingale 		 * disabled and LINT0 is reconfigured as INTR to
2480775fbb4STycho Nightingale 		 * deliver the PIC interrupt directly to the CPU.
2490775fbb4STycho Nightingale 		 *
2500775fbb4STycho Nightingale 		 * 2. Virtual Wire Mode: the APIC is treated as a
2510775fbb4STycho Nightingale 		 * virtual wire which delivers interrupts from the PIC
2524eec6021SNeel Natu 		 * to the CPU.  In this mode LINT0 is programmed as
2530775fbb4STycho Nightingale 		 * ExtINT to indicate that the PIC is the source of
2540775fbb4STycho Nightingale 		 * the interrupt.
2550775fbb4STycho Nightingale 		 *
2564eec6021SNeel Natu 		 * 3. Virtual Wire Mode via I/O APIC: PIC interrupts are
2574eec6021SNeel Natu 		 * fielded by the I/O APIC and delivered to the appropriate
2584eec6021SNeel Natu 		 * CPU.  In this mode the I/O APIC input 0 is programmed
2594eec6021SNeel Natu 		 * as ExtINT to indicate that the PIC is the source of the
2604eec6021SNeel Natu 		 * interrupt.
2610775fbb4STycho Nightingale 		 */
262b96be57aSTycho Nightingale 		atpic->intr_raised = true;
2633f0f4b15SJohn Baldwin 		lapic_set_local_intr(vatpic->vm, NULL, APIC_LVT_LINT0);
264762fd208STycho Nightingale 		vioapic_pulse_irq(vatpic->vm, 0);
265762fd208STycho Nightingale 	} else {
266b96be57aSTycho Nightingale 		VATPIC_CTR3(vatpic, "atpic master no eligible interrupts "
267762fd208STycho Nightingale 		    "(imr 0x%x irr 0x%x isr 0x%x)",
268762fd208STycho Nightingale 		    atpic->mask, atpic->request, atpic->service);
269762fd208STycho Nightingale 	}
270762fd208STycho Nightingale }
271762fd208STycho Nightingale 
272762fd208STycho Nightingale static int
vatpic_icw1(struct vatpic * vatpic,struct atpic * atpic,uint8_t val)273762fd208STycho Nightingale vatpic_icw1(struct vatpic *vatpic, struct atpic *atpic, uint8_t val)
274762fd208STycho Nightingale {
275762fd208STycho Nightingale 	VATPIC_CTR1(vatpic, "atpic icw1 0x%x", val);
276762fd208STycho Nightingale 
277762fd208STycho Nightingale 	atpic->ready = false;
278762fd208STycho Nightingale 
279762fd208STycho Nightingale 	atpic->icw_num = 1;
28076b3c718STycho Nightingale 	atpic->request = 0;
281762fd208STycho Nightingale 	atpic->mask = 0;
282e64c5af3SNeel Natu 	atpic->lowprio = 7;
283762fd208STycho Nightingale 	atpic->rd_cmd_reg = 0;
284ac721e53SNeel Natu 	atpic->poll = 0;
2851a5934efSNeel Natu 	atpic->smm = 0;
286762fd208STycho Nightingale 
287762fd208STycho Nightingale 	if ((val & ICW1_SNGL) != 0) {
288762fd208STycho Nightingale 		VATPIC_CTR0(vatpic, "vatpic cascade mode required");
289762fd208STycho Nightingale 		return (-1);
290762fd208STycho Nightingale 	}
291762fd208STycho Nightingale 
292762fd208STycho Nightingale 	if ((val & ICW1_IC4) == 0) {
293762fd208STycho Nightingale 		VATPIC_CTR0(vatpic, "vatpic icw4 required");
294762fd208STycho Nightingale 		return (-1);
295762fd208STycho Nightingale 	}
296762fd208STycho Nightingale 
297762fd208STycho Nightingale 	atpic->icw_num++;
298762fd208STycho Nightingale 
299762fd208STycho Nightingale 	return (0);
300762fd208STycho Nightingale }
301762fd208STycho Nightingale 
302762fd208STycho Nightingale static int
vatpic_icw2(struct vatpic * vatpic,struct atpic * atpic,uint8_t val)303762fd208STycho Nightingale vatpic_icw2(struct vatpic *vatpic, struct atpic *atpic, uint8_t val)
304762fd208STycho Nightingale {
305762fd208STycho Nightingale 	VATPIC_CTR1(vatpic, "atpic icw2 0x%x", val);
306762fd208STycho Nightingale 
307762fd208STycho Nightingale 	atpic->irq_base = val & 0xf8;
308762fd208STycho Nightingale 
309762fd208STycho Nightingale 	atpic->icw_num++;
310762fd208STycho Nightingale 
311762fd208STycho Nightingale 	return (0);
312762fd208STycho Nightingale }
313762fd208STycho Nightingale 
314762fd208STycho Nightingale static int
vatpic_icw3(struct vatpic * vatpic,struct atpic * atpic,uint8_t val)315762fd208STycho Nightingale vatpic_icw3(struct vatpic *vatpic, struct atpic *atpic, uint8_t val)
316762fd208STycho Nightingale {
317762fd208STycho Nightingale 	VATPIC_CTR1(vatpic, "atpic icw3 0x%x", val);
318762fd208STycho Nightingale 
319762fd208STycho Nightingale 	atpic->icw_num++;
320762fd208STycho Nightingale 
321762fd208STycho Nightingale 	return (0);
322762fd208STycho Nightingale }
323762fd208STycho Nightingale 
324762fd208STycho Nightingale static int
vatpic_icw4(struct vatpic * vatpic,struct atpic * atpic,uint8_t val)325762fd208STycho Nightingale vatpic_icw4(struct vatpic *vatpic, struct atpic *atpic, uint8_t val)
326762fd208STycho Nightingale {
327762fd208STycho Nightingale 	VATPIC_CTR1(vatpic, "atpic icw4 0x%x", val);
328762fd208STycho Nightingale 
329762fd208STycho Nightingale 	if ((val & ICW4_8086) == 0) {
330762fd208STycho Nightingale 		VATPIC_CTR0(vatpic, "vatpic microprocessor mode required");
331762fd208STycho Nightingale 		return (-1);
332762fd208STycho Nightingale 	}
333762fd208STycho Nightingale 
334762fd208STycho Nightingale 	if ((val & ICW4_AEOI) != 0)
335762fd208STycho Nightingale 		atpic->aeoi = true;
336762fd208STycho Nightingale 
337ac721e53SNeel Natu 	if ((val & ICW4_SFNM) != 0) {
338ac721e53SNeel Natu 		if (master_atpic(vatpic, atpic)) {
339ac721e53SNeel Natu 			atpic->sfn = true;
340ac721e53SNeel Natu 		} else {
341ac721e53SNeel Natu 			VATPIC_CTR1(vatpic, "Ignoring special fully nested "
342ac721e53SNeel Natu 			    "mode on slave atpic: %#x", val);
343ac721e53SNeel Natu 		}
344ac721e53SNeel Natu 	}
345ac721e53SNeel Natu 
346762fd208STycho Nightingale 	atpic->icw_num = 0;
347762fd208STycho Nightingale 	atpic->ready = true;
348762fd208STycho Nightingale 
349762fd208STycho Nightingale 	return (0);
350762fd208STycho Nightingale }
351762fd208STycho Nightingale 
352762fd208STycho Nightingale static int
vatpic_ocw1(struct vatpic * vatpic,struct atpic * atpic,uint8_t val)353762fd208STycho Nightingale vatpic_ocw1(struct vatpic *vatpic, struct atpic *atpic, uint8_t val)
354762fd208STycho Nightingale {
355762fd208STycho Nightingale 	VATPIC_CTR1(vatpic, "atpic ocw1 0x%x", val);
356762fd208STycho Nightingale 
357762fd208STycho Nightingale 	atpic->mask = val & 0xff;
358762fd208STycho Nightingale 
359762fd208STycho Nightingale 	return (0);
360762fd208STycho Nightingale }
361762fd208STycho Nightingale 
362762fd208STycho Nightingale static int
vatpic_ocw2(struct vatpic * vatpic,struct atpic * atpic,uint8_t val)363762fd208STycho Nightingale vatpic_ocw2(struct vatpic *vatpic, struct atpic *atpic, uint8_t val)
364762fd208STycho Nightingale {
365762fd208STycho Nightingale 	VATPIC_CTR1(vatpic, "atpic ocw2 0x%x", val);
366762fd208STycho Nightingale 
367762fd208STycho Nightingale 	atpic->rotate = ((val & OCW2_R) != 0);
368762fd208STycho Nightingale 
369762fd208STycho Nightingale 	if ((val & OCW2_EOI) != 0) {
370762fd208STycho Nightingale 		int isr_bit;
371762fd208STycho Nightingale 
372762fd208STycho Nightingale 		if ((val & OCW2_SL) != 0) {
373762fd208STycho Nightingale 			/* specific EOI */
374762fd208STycho Nightingale 			isr_bit = val & 0x7;
375762fd208STycho Nightingale 		} else {
376762fd208STycho Nightingale 			/* non-specific EOI */
377762fd208STycho Nightingale 			isr_bit = vatpic_get_highest_isrpin(atpic);
378762fd208STycho Nightingale 		}
379762fd208STycho Nightingale 
380762fd208STycho Nightingale 		if (isr_bit != -1) {
381762fd208STycho Nightingale 			atpic->service &= ~(1 << isr_bit);
382762fd208STycho Nightingale 
383762fd208STycho Nightingale 			if (atpic->rotate)
384e64c5af3SNeel Natu 				atpic->lowprio = isr_bit;
385762fd208STycho Nightingale 		}
386762fd208STycho Nightingale 	} else if ((val & OCW2_SL) != 0 && atpic->rotate == true) {
387762fd208STycho Nightingale 		/* specific priority */
388e64c5af3SNeel Natu 		atpic->lowprio = val & 0x7;
389762fd208STycho Nightingale 	}
390762fd208STycho Nightingale 
391762fd208STycho Nightingale 	return (0);
392762fd208STycho Nightingale }
393762fd208STycho Nightingale 
394762fd208STycho Nightingale static int
vatpic_ocw3(struct vatpic * vatpic,struct atpic * atpic,uint8_t val)395762fd208STycho Nightingale vatpic_ocw3(struct vatpic *vatpic, struct atpic *atpic, uint8_t val)
396762fd208STycho Nightingale {
397762fd208STycho Nightingale 	VATPIC_CTR1(vatpic, "atpic ocw3 0x%x", val);
398762fd208STycho Nightingale 
399ac721e53SNeel Natu 	if (val & OCW3_ESMM) {
4001a5934efSNeel Natu 		atpic->smm = val & OCW3_SMM ? 1 : 0;
4011a5934efSNeel Natu 		VATPIC_CTR2(vatpic, "%s atpic special mask mode %s",
4021a5934efSNeel Natu 		    master_atpic(vatpic, atpic) ? "master" : "slave",
4031a5934efSNeel Natu 		    atpic->smm ?  "enabled" : "disabled");
404ac721e53SNeel Natu 	}
405762fd208STycho Nightingale 
406762fd208STycho Nightingale 	if (val & OCW3_RR) {
407762fd208STycho Nightingale 		/* read register command */
408762fd208STycho Nightingale 		atpic->rd_cmd_reg = val & OCW3_RIS;
409ac721e53SNeel Natu 
410ac721e53SNeel Natu 		/* Polling mode */
411ac721e53SNeel Natu 		atpic->poll = ((val & OCW3_P) != 0);
412762fd208STycho Nightingale 	}
413762fd208STycho Nightingale 
414762fd208STycho Nightingale 	return (0);
415762fd208STycho Nightingale }
416762fd208STycho Nightingale 
417762fd208STycho Nightingale static void
vatpic_set_pinstate(struct vatpic * vatpic,int pin,bool newstate)418762fd208STycho Nightingale vatpic_set_pinstate(struct vatpic *vatpic, int pin, bool newstate)
419762fd208STycho Nightingale {
420762fd208STycho Nightingale 	struct atpic *atpic;
421762fd208STycho Nightingale 	int oldcnt, newcnt;
422762fd208STycho Nightingale 	bool level;
423762fd208STycho Nightingale 
424762fd208STycho Nightingale 	KASSERT(pin >= 0 && pin < 16,
425762fd208STycho Nightingale 	    ("vatpic_set_pinstate: invalid pin number %d", pin));
426762fd208STycho Nightingale 	KASSERT(VATPIC_LOCKED(vatpic),
427762fd208STycho Nightingale 	    ("vatpic_set_pinstate: vatpic is not locked"));
428762fd208STycho Nightingale 
429762fd208STycho Nightingale 	atpic = &vatpic->atpic[pin >> 3];
430762fd208STycho Nightingale 
431762fd208STycho Nightingale 	oldcnt = atpic->acnt[pin & 0x7];
432762fd208STycho Nightingale 	if (newstate)
433762fd208STycho Nightingale 		atpic->acnt[pin & 0x7]++;
434762fd208STycho Nightingale 	else
435762fd208STycho Nightingale 		atpic->acnt[pin & 0x7]--;
436762fd208STycho Nightingale 	newcnt = atpic->acnt[pin & 0x7];
437762fd208STycho Nightingale 
438762fd208STycho Nightingale 	if (newcnt < 0) {
439762fd208STycho Nightingale 		VATPIC_CTR2(vatpic, "atpic pin%d: bad acnt %d", pin, newcnt);
440762fd208STycho Nightingale 	}
441762fd208STycho Nightingale 
442762fd208STycho Nightingale 	level = ((vatpic->elc[pin >> 3] & (1 << (pin & 0x7))) != 0);
443762fd208STycho Nightingale 
444762fd208STycho Nightingale 	if ((oldcnt == 0 && newcnt == 1) || (newcnt > 0 && level == true)) {
445762fd208STycho Nightingale 		/* rising edge or level */
446762fd208STycho Nightingale 		VATPIC_CTR1(vatpic, "atpic pin%d: asserted", pin);
447762fd208STycho Nightingale 		atpic->request |= (1 << (pin & 0x7));
448762fd208STycho Nightingale 	} else if (oldcnt == 1 && newcnt == 0) {
449762fd208STycho Nightingale 		/* falling edge */
450762fd208STycho Nightingale 		VATPIC_CTR1(vatpic, "atpic pin%d: deasserted", pin);
45109eced25SNeel Natu 		if (level)
45209eced25SNeel Natu 			atpic->request &= ~(1 << (pin & 0x7));
453762fd208STycho Nightingale 	} else {
454762fd208STycho Nightingale 		VATPIC_CTR3(vatpic, "atpic pin%d: %s, ignored, acnt %d",
455762fd208STycho Nightingale 		    pin, newstate ? "asserted" : "deasserted", newcnt);
456762fd208STycho Nightingale 	}
457762fd208STycho Nightingale 
458762fd208STycho Nightingale 	vatpic_notify_intr(vatpic);
459762fd208STycho Nightingale }
460762fd208STycho Nightingale 
461762fd208STycho Nightingale static int
vatpic_set_irqstate(struct vm * vm,int irq,enum irqstate irqstate)462762fd208STycho Nightingale vatpic_set_irqstate(struct vm *vm, int irq, enum irqstate irqstate)
463762fd208STycho Nightingale {
464762fd208STycho Nightingale 	struct vatpic *vatpic;
465762fd208STycho Nightingale 	struct atpic *atpic;
466762fd208STycho Nightingale 
467762fd208STycho Nightingale 	if (irq < 0 || irq > 15)
468762fd208STycho Nightingale 		return (EINVAL);
469762fd208STycho Nightingale 
470762fd208STycho Nightingale 	vatpic = vm_atpic(vm);
471762fd208STycho Nightingale 	atpic = &vatpic->atpic[irq >> 3];
472762fd208STycho Nightingale 
473762fd208STycho Nightingale 	if (atpic->ready == false)
474762fd208STycho Nightingale 		return (0);
475762fd208STycho Nightingale 
476762fd208STycho Nightingale 	VATPIC_LOCK(vatpic);
477762fd208STycho Nightingale 	switch (irqstate) {
478762fd208STycho Nightingale 	case IRQSTATE_ASSERT:
479762fd208STycho Nightingale 		vatpic_set_pinstate(vatpic, irq, true);
480762fd208STycho Nightingale 		break;
481762fd208STycho Nightingale 	case IRQSTATE_DEASSERT:
482762fd208STycho Nightingale 		vatpic_set_pinstate(vatpic, irq, false);
483762fd208STycho Nightingale 		break;
484762fd208STycho Nightingale 	case IRQSTATE_PULSE:
485762fd208STycho Nightingale 		vatpic_set_pinstate(vatpic, irq, true);
486762fd208STycho Nightingale 		vatpic_set_pinstate(vatpic, irq, false);
487762fd208STycho Nightingale 		break;
488762fd208STycho Nightingale 	default:
489762fd208STycho Nightingale 		panic("vatpic_set_irqstate: invalid irqstate %d", irqstate);
490762fd208STycho Nightingale 	}
491762fd208STycho Nightingale 	VATPIC_UNLOCK(vatpic);
492762fd208STycho Nightingale 
493762fd208STycho Nightingale 	return (0);
494762fd208STycho Nightingale }
495762fd208STycho Nightingale 
496762fd208STycho Nightingale int
vatpic_assert_irq(struct vm * vm,int irq)497762fd208STycho Nightingale vatpic_assert_irq(struct vm *vm, int irq)
498762fd208STycho Nightingale {
499762fd208STycho Nightingale 	return (vatpic_set_irqstate(vm, irq, IRQSTATE_ASSERT));
500762fd208STycho Nightingale }
501762fd208STycho Nightingale 
502762fd208STycho Nightingale int
vatpic_deassert_irq(struct vm * vm,int irq)503762fd208STycho Nightingale vatpic_deassert_irq(struct vm *vm, int irq)
504762fd208STycho Nightingale {
505762fd208STycho Nightingale 	return (vatpic_set_irqstate(vm, irq, IRQSTATE_DEASSERT));
506762fd208STycho Nightingale }
507762fd208STycho Nightingale 
508762fd208STycho Nightingale int
vatpic_pulse_irq(struct vm * vm,int irq)509762fd208STycho Nightingale vatpic_pulse_irq(struct vm *vm, int irq)
510762fd208STycho Nightingale {
511762fd208STycho Nightingale 	return (vatpic_set_irqstate(vm, irq, IRQSTATE_PULSE));
512762fd208STycho Nightingale }
513762fd208STycho Nightingale 
514b3e9732aSJohn Baldwin int
vatpic_set_irq_trigger(struct vm * vm,int irq,enum vm_intr_trigger trigger)515b3e9732aSJohn Baldwin vatpic_set_irq_trigger(struct vm *vm, int irq, enum vm_intr_trigger trigger)
516b3e9732aSJohn Baldwin {
517b3e9732aSJohn Baldwin 	struct vatpic *vatpic;
518b3e9732aSJohn Baldwin 
519b3e9732aSJohn Baldwin 	if (irq < 0 || irq > 15)
520b3e9732aSJohn Baldwin 		return (EINVAL);
521b3e9732aSJohn Baldwin 
522b3e9732aSJohn Baldwin 	/*
523b3e9732aSJohn Baldwin 	 * See comment in vatpic_elc_handler.  These IRQs must be
524b3e9732aSJohn Baldwin 	 * edge triggered.
525b3e9732aSJohn Baldwin 	 */
526b3e9732aSJohn Baldwin 	if (trigger == LEVEL_TRIGGER) {
527b3e9732aSJohn Baldwin 		switch (irq) {
528b3e9732aSJohn Baldwin 		case 0:
529b3e9732aSJohn Baldwin 		case 1:
530b3e9732aSJohn Baldwin 		case 2:
531b3e9732aSJohn Baldwin 		case 8:
532b3e9732aSJohn Baldwin 		case 13:
533b3e9732aSJohn Baldwin 			return (EINVAL);
534b3e9732aSJohn Baldwin 		}
535b3e9732aSJohn Baldwin 	}
536b3e9732aSJohn Baldwin 
537b3e9732aSJohn Baldwin 	vatpic = vm_atpic(vm);
538b3e9732aSJohn Baldwin 
539b3e9732aSJohn Baldwin 	VATPIC_LOCK(vatpic);
540b3e9732aSJohn Baldwin 
541b3e9732aSJohn Baldwin 	if (trigger == LEVEL_TRIGGER)
542b3e9732aSJohn Baldwin 		vatpic->elc[irq >> 3] |=  1 << (irq & 0x7);
543b3e9732aSJohn Baldwin 	else
544b3e9732aSJohn Baldwin 		vatpic->elc[irq >> 3] &=  ~(1 << (irq & 0x7));
545b3e9732aSJohn Baldwin 
546b3e9732aSJohn Baldwin 	VATPIC_UNLOCK(vatpic);
547b3e9732aSJohn Baldwin 
548b3e9732aSJohn Baldwin 	return (0);
549b3e9732aSJohn Baldwin }
550b3e9732aSJohn Baldwin 
5510775fbb4STycho Nightingale void
vatpic_pending_intr(struct vm * vm,int * vecptr)552762fd208STycho Nightingale vatpic_pending_intr(struct vm *vm, int *vecptr)
553762fd208STycho Nightingale {
554762fd208STycho Nightingale 	struct vatpic *vatpic;
555762fd208STycho Nightingale 	struct atpic *atpic;
556762fd208STycho Nightingale 	int pin;
557762fd208STycho Nightingale 
558762fd208STycho Nightingale 	vatpic = vm_atpic(vm);
559762fd208STycho Nightingale 
560762fd208STycho Nightingale 	atpic = &vatpic->atpic[0];
561762fd208STycho Nightingale 
562762fd208STycho Nightingale 	VATPIC_LOCK(vatpic);
563762fd208STycho Nightingale 
564762fd208STycho Nightingale 	pin = vatpic_get_highest_irrpin(atpic);
565b96be57aSTycho Nightingale 	if (pin == 2) {
566b96be57aSTycho Nightingale 		atpic = &vatpic->atpic[1];
567b96be57aSTycho Nightingale 		pin = vatpic_get_highest_irrpin(atpic);
568b96be57aSTycho Nightingale 	}
569762fd208STycho Nightingale 
5707a244722SNeel Natu 	/*
5717a244722SNeel Natu 	 * If there are no pins active at this moment then return the spurious
5727a244722SNeel Natu 	 * interrupt vector instead.
5737a244722SNeel Natu 	 */
5747a244722SNeel Natu 	if (pin == -1)
5757a244722SNeel Natu 		pin = 7;
5767a244722SNeel Natu 
5777a244722SNeel Natu 	KASSERT(pin >= 0 && pin <= 7, ("%s: invalid pin %d", __func__, pin));
578762fd208STycho Nightingale 	*vecptr = atpic->irq_base + pin;
579762fd208STycho Nightingale 
580762fd208STycho Nightingale 	VATPIC_UNLOCK(vatpic);
581762fd208STycho Nightingale }
582762fd208STycho Nightingale 
583b96be57aSTycho Nightingale static void
vatpic_pin_accepted(struct atpic * atpic,int pin)584b96be57aSTycho Nightingale vatpic_pin_accepted(struct atpic *atpic, int pin)
585762fd208STycho Nightingale {
586b96be57aSTycho Nightingale 	atpic->intr_raised = false;
587762fd208STycho Nightingale 
588762fd208STycho Nightingale 	if (atpic->acnt[pin] == 0)
589762fd208STycho Nightingale 		atpic->request &= ~(1 << pin);
590762fd208STycho Nightingale 
591762fd208STycho Nightingale 	if (atpic->aeoi == true) {
592762fd208STycho Nightingale 		if (atpic->rotate == true)
593e64c5af3SNeel Natu 			atpic->lowprio = pin;
594762fd208STycho Nightingale 	} else {
595762fd208STycho Nightingale 		atpic->service |= (1 << pin);
596762fd208STycho Nightingale 	}
597b96be57aSTycho Nightingale }
598b96be57aSTycho Nightingale 
599b96be57aSTycho Nightingale void
vatpic_intr_accepted(struct vm * vm,int vector)600b96be57aSTycho Nightingale vatpic_intr_accepted(struct vm *vm, int vector)
601b96be57aSTycho Nightingale {
602b96be57aSTycho Nightingale 	struct vatpic *vatpic;
603b96be57aSTycho Nightingale 	int pin;
604b96be57aSTycho Nightingale 
605b96be57aSTycho Nightingale 	vatpic = vm_atpic(vm);
606b96be57aSTycho Nightingale 
607b96be57aSTycho Nightingale 	VATPIC_LOCK(vatpic);
608b96be57aSTycho Nightingale 
609b96be57aSTycho Nightingale 	pin = vector & 0x7;
610b96be57aSTycho Nightingale 
611b96be57aSTycho Nightingale 	if ((vector & ~0x7) == vatpic->atpic[1].irq_base) {
612b96be57aSTycho Nightingale 		vatpic_pin_accepted(&vatpic->atpic[1], pin);
613b96be57aSTycho Nightingale 		/*
614b96be57aSTycho Nightingale 		 * If this vector originated from the slave,
615b96be57aSTycho Nightingale 		 * accept the cascaded interrupt too.
616b96be57aSTycho Nightingale 		 */
617b96be57aSTycho Nightingale 		vatpic_pin_accepted(&vatpic->atpic[0], 2);
618b96be57aSTycho Nightingale 	} else {
619b96be57aSTycho Nightingale 		vatpic_pin_accepted(&vatpic->atpic[0], pin);
620b96be57aSTycho Nightingale 	}
621762fd208STycho Nightingale 
622762fd208STycho Nightingale 	vatpic_notify_intr(vatpic);
623762fd208STycho Nightingale 
624762fd208STycho Nightingale 	VATPIC_UNLOCK(vatpic);
625762fd208STycho Nightingale }
626762fd208STycho Nightingale 
627b96be57aSTycho Nightingale static int
vatpic_read(struct vatpic * vatpic,struct atpic * atpic,bool in,int port,int bytes,uint32_t * eax)628d6aa08c3STycho Nightingale vatpic_read(struct vatpic *vatpic, struct atpic *atpic, bool in, int port,
629d6aa08c3STycho Nightingale 	    int bytes, uint32_t *eax)
630762fd208STycho Nightingale {
631ac721e53SNeel Natu 	int pin;
632ac721e53SNeel Natu 
633762fd208STycho Nightingale 	VATPIC_LOCK(vatpic);
634b96be57aSTycho Nightingale 
635762fd208STycho Nightingale 	if (atpic->poll) {
636ac721e53SNeel Natu 		atpic->poll = 0;
637ac721e53SNeel Natu 		pin = vatpic_get_highest_irrpin(atpic);
638ac721e53SNeel Natu 		if (pin >= 0) {
639ac721e53SNeel Natu 			vatpic_pin_accepted(atpic, pin);
640ac721e53SNeel Natu 			*eax = 0x80 | pin;
641ac721e53SNeel Natu 		} else {
642ac721e53SNeel Natu 			*eax = 0;
643ac721e53SNeel Natu 		}
644762fd208STycho Nightingale 	} else {
645d6aa08c3STycho Nightingale 		if (port & ICU_IMR_OFFSET) {
646762fd208STycho Nightingale 			/* read interrrupt mask register */
647d6aa08c3STycho Nightingale 			*eax = atpic->mask;
648762fd208STycho Nightingale 		} else {
649762fd208STycho Nightingale 			if (atpic->rd_cmd_reg == OCW3_RIS) {
650762fd208STycho Nightingale 				/* read interrupt service register */
651d6aa08c3STycho Nightingale 				*eax = atpic->service;
652762fd208STycho Nightingale 			} else {
653762fd208STycho Nightingale 				/* read interrupt request register */
654d6aa08c3STycho Nightingale 				*eax = atpic->request;
655762fd208STycho Nightingale 			}
656762fd208STycho Nightingale 		}
657762fd208STycho Nightingale 	}
658b96be57aSTycho Nightingale 
659762fd208STycho Nightingale 	VATPIC_UNLOCK(vatpic);
660762fd208STycho Nightingale 
661762fd208STycho Nightingale 	return (0);
662b96be57aSTycho Nightingale 
663762fd208STycho Nightingale }
664762fd208STycho Nightingale 
665b96be57aSTycho Nightingale static int
vatpic_write(struct vatpic * vatpic,struct atpic * atpic,bool in,int port,int bytes,uint32_t * eax)666d6aa08c3STycho Nightingale vatpic_write(struct vatpic *vatpic, struct atpic *atpic, bool in, int port,
667d6aa08c3STycho Nightingale     int bytes, uint32_t *eax)
668b96be57aSTycho Nightingale {
669b96be57aSTycho Nightingale 	int error;
670b96be57aSTycho Nightingale 	uint8_t val;
671b96be57aSTycho Nightingale 
672c5e423ddSNeel Natu 	error = 0;
673d6aa08c3STycho Nightingale 	val = *eax;
674762fd208STycho Nightingale 
675762fd208STycho Nightingale 	VATPIC_LOCK(vatpic);
676762fd208STycho Nightingale 
677d6aa08c3STycho Nightingale 	if (port & ICU_IMR_OFFSET) {
678762fd208STycho Nightingale 		switch (atpic->icw_num) {
679762fd208STycho Nightingale 		case 2:
680762fd208STycho Nightingale 			error = vatpic_icw2(vatpic, atpic, val);
681762fd208STycho Nightingale 			break;
682762fd208STycho Nightingale 		case 3:
683762fd208STycho Nightingale 			error = vatpic_icw3(vatpic, atpic, val);
684762fd208STycho Nightingale 			break;
685762fd208STycho Nightingale 		case 4:
686762fd208STycho Nightingale 			error = vatpic_icw4(vatpic, atpic, val);
687762fd208STycho Nightingale 			break;
688a48c3338SPeter Grehan 		default:
689a48c3338SPeter Grehan 			error = vatpic_ocw1(vatpic, atpic, val);
690a48c3338SPeter Grehan 			break;
691762fd208STycho Nightingale 		}
692762fd208STycho Nightingale 	} else {
693762fd208STycho Nightingale 		if (val & (1 << 4))
694762fd208STycho Nightingale 			error = vatpic_icw1(vatpic, atpic, val);
695762fd208STycho Nightingale 
696762fd208STycho Nightingale 		if (atpic->ready) {
697762fd208STycho Nightingale 			if (val & (1 << 3))
698762fd208STycho Nightingale 				error = vatpic_ocw3(vatpic, atpic, val);
699762fd208STycho Nightingale 			else
700762fd208STycho Nightingale 				error = vatpic_ocw2(vatpic, atpic, val);
701762fd208STycho Nightingale 		}
702762fd208STycho Nightingale 	}
703762fd208STycho Nightingale 
704762fd208STycho Nightingale 	if (atpic->ready)
705762fd208STycho Nightingale 		vatpic_notify_intr(vatpic);
706762fd208STycho Nightingale 
707762fd208STycho Nightingale 	VATPIC_UNLOCK(vatpic);
708762fd208STycho Nightingale 
709762fd208STycho Nightingale 	return (error);
710762fd208STycho Nightingale }
711762fd208STycho Nightingale 
712762fd208STycho Nightingale int
vatpic_master_handler(struct vm * vm,bool in,int port,int bytes,uint32_t * eax)7139388bc1eSJohn Baldwin vatpic_master_handler(struct vm *vm, bool in, int port, int bytes,
714d6aa08c3STycho Nightingale     uint32_t *eax)
715762fd208STycho Nightingale {
716b96be57aSTycho Nightingale 	struct vatpic *vatpic;
717b96be57aSTycho Nightingale 	struct atpic *atpic;
718b96be57aSTycho Nightingale 
719b96be57aSTycho Nightingale 	vatpic = vm_atpic(vm);
720b96be57aSTycho Nightingale 	atpic = &vatpic->atpic[0];
721b96be57aSTycho Nightingale 
722d6aa08c3STycho Nightingale 	if (bytes != 1)
723762fd208STycho Nightingale 		return (-1);
724762fd208STycho Nightingale 
725d6aa08c3STycho Nightingale 	if (in) {
726d6aa08c3STycho Nightingale 		return (vatpic_read(vatpic, atpic, in, port, bytes, eax));
727762fd208STycho Nightingale 	}
728762fd208STycho Nightingale 
729d6aa08c3STycho Nightingale 	return (vatpic_write(vatpic, atpic, in, port, bytes, eax));
730b96be57aSTycho Nightingale }
731b96be57aSTycho Nightingale 
732b96be57aSTycho Nightingale int
vatpic_slave_handler(struct vm * vm,bool in,int port,int bytes,uint32_t * eax)7339388bc1eSJohn Baldwin vatpic_slave_handler(struct vm *vm, bool in, int port, int bytes,
734d6aa08c3STycho Nightingale     uint32_t *eax)
735b96be57aSTycho Nightingale {
736b96be57aSTycho Nightingale 	struct vatpic *vatpic;
737b96be57aSTycho Nightingale 	struct atpic *atpic;
738b96be57aSTycho Nightingale 
739b96be57aSTycho Nightingale 	vatpic = vm_atpic(vm);
740b96be57aSTycho Nightingale 	atpic = &vatpic->atpic[1];
741b96be57aSTycho Nightingale 
742d6aa08c3STycho Nightingale 	if (bytes != 1)
743b96be57aSTycho Nightingale 		return (-1);
744b96be57aSTycho Nightingale 
745d6aa08c3STycho Nightingale 	if (in) {
746d6aa08c3STycho Nightingale 		return (vatpic_read(vatpic, atpic, in, port, bytes, eax));
747b96be57aSTycho Nightingale 	}
748b96be57aSTycho Nightingale 
749d6aa08c3STycho Nightingale 	return (vatpic_write(vatpic, atpic, in, port, bytes, eax));
750762fd208STycho Nightingale }
751762fd208STycho Nightingale 
752762fd208STycho Nightingale int
vatpic_elc_handler(struct vm * vm,bool in,int port,int bytes,uint32_t * eax)7539388bc1eSJohn Baldwin vatpic_elc_handler(struct vm *vm, bool in, int port, int bytes,
754d6aa08c3STycho Nightingale     uint32_t *eax)
755762fd208STycho Nightingale {
756762fd208STycho Nightingale 	struct vatpic *vatpic;
757762fd208STycho Nightingale 	bool is_master;
758762fd208STycho Nightingale 
759762fd208STycho Nightingale 	vatpic = vm_atpic(vm);
760d6aa08c3STycho Nightingale 	is_master = (port == IO_ELCR1);
761762fd208STycho Nightingale 
762d6aa08c3STycho Nightingale 	if (bytes != 1)
763762fd208STycho Nightingale 		return (-1);
764762fd208STycho Nightingale 
765b96be57aSTycho Nightingale 	VATPIC_LOCK(vatpic);
766b96be57aSTycho Nightingale 
767d6aa08c3STycho Nightingale 	if (in) {
768762fd208STycho Nightingale 		if (is_master)
769d6aa08c3STycho Nightingale 			*eax = vatpic->elc[0];
770762fd208STycho Nightingale 		else
771d6aa08c3STycho Nightingale 			*eax = vatpic->elc[1];
772762fd208STycho Nightingale 	} else {
773762fd208STycho Nightingale 		/*
774762fd208STycho Nightingale 		 * For the master PIC the cascade channel (IRQ2), the
775762fd208STycho Nightingale 		 * heart beat timer (IRQ0), and the keyboard
776762fd208STycho Nightingale 		 * controller (IRQ1) cannot be programmed for level
777762fd208STycho Nightingale 		 * mode.
778762fd208STycho Nightingale 		 *
779762fd208STycho Nightingale 		 * For the slave PIC the real time clock (IRQ8) and
780762fd208STycho Nightingale 		 * the floating point error interrupt (IRQ13) cannot
781762fd208STycho Nightingale 		 * be programmed for level mode.
782762fd208STycho Nightingale 		 */
783762fd208STycho Nightingale 		if (is_master)
784d6aa08c3STycho Nightingale 			vatpic->elc[0] = (*eax & 0xf8);
785762fd208STycho Nightingale 		else
786d6aa08c3STycho Nightingale 			vatpic->elc[1] = (*eax & 0xde);
787762fd208STycho Nightingale 	}
788762fd208STycho Nightingale 
789b96be57aSTycho Nightingale 	VATPIC_UNLOCK(vatpic);
790b96be57aSTycho Nightingale 
791762fd208STycho Nightingale 	return (0);
792762fd208STycho Nightingale }
793762fd208STycho Nightingale 
794762fd208STycho Nightingale struct vatpic *
vatpic_init(struct vm * vm)795762fd208STycho Nightingale vatpic_init(struct vm *vm)
796762fd208STycho Nightingale {
797762fd208STycho Nightingale 	struct vatpic *vatpic;
798762fd208STycho Nightingale 
799762fd208STycho Nightingale 	vatpic = malloc(sizeof(struct vatpic), M_VATPIC, M_WAITOK | M_ZERO);
800762fd208STycho Nightingale 	vatpic->vm = vm;
801762fd208STycho Nightingale 
802762fd208STycho Nightingale 	mtx_init(&vatpic->mtx, "vatpic lock", NULL, MTX_SPIN);
803762fd208STycho Nightingale 
804762fd208STycho Nightingale 	return (vatpic);
805762fd208STycho Nightingale }
806762fd208STycho Nightingale 
807762fd208STycho Nightingale void
vatpic_cleanup(struct vatpic * vatpic)808762fd208STycho Nightingale vatpic_cleanup(struct vatpic *vatpic)
809762fd208STycho Nightingale {
81008ebb360SJohn Baldwin 	mtx_destroy(&vatpic->mtx);
811762fd208STycho Nightingale 	free(vatpic, M_VATPIC);
812762fd208STycho Nightingale }
813483d953aSJohn Baldwin 
814483d953aSJohn Baldwin #ifdef BHYVE_SNAPSHOT
815483d953aSJohn Baldwin int
vatpic_snapshot(struct vatpic * vatpic,struct vm_snapshot_meta * meta)816483d953aSJohn Baldwin vatpic_snapshot(struct vatpic *vatpic, struct vm_snapshot_meta *meta)
817483d953aSJohn Baldwin {
818483d953aSJohn Baldwin 	int ret;
819483d953aSJohn Baldwin 	int i;
820483d953aSJohn Baldwin 	struct atpic *atpic;
821483d953aSJohn Baldwin 
822483d953aSJohn Baldwin 	for (i = 0; i < nitems(vatpic->atpic); i++) {
823483d953aSJohn Baldwin 		atpic = &vatpic->atpic[i];
824483d953aSJohn Baldwin 
825483d953aSJohn Baldwin 		SNAPSHOT_VAR_OR_LEAVE(atpic->ready, meta, ret, done);
826483d953aSJohn Baldwin 		SNAPSHOT_VAR_OR_LEAVE(atpic->icw_num, meta, ret, done);
827483d953aSJohn Baldwin 		SNAPSHOT_VAR_OR_LEAVE(atpic->rd_cmd_reg, meta, ret, done);
828483d953aSJohn Baldwin 
829483d953aSJohn Baldwin 		SNAPSHOT_VAR_OR_LEAVE(atpic->aeoi, meta, ret, done);
830483d953aSJohn Baldwin 		SNAPSHOT_VAR_OR_LEAVE(atpic->poll, meta, ret, done);
831483d953aSJohn Baldwin 		SNAPSHOT_VAR_OR_LEAVE(atpic->rotate, meta, ret, done);
832483d953aSJohn Baldwin 		SNAPSHOT_VAR_OR_LEAVE(atpic->sfn, meta, ret, done);
833483d953aSJohn Baldwin 		SNAPSHOT_VAR_OR_LEAVE(atpic->irq_base, meta, ret, done);
834483d953aSJohn Baldwin 		SNAPSHOT_VAR_OR_LEAVE(atpic->request, meta, ret, done);
835483d953aSJohn Baldwin 		SNAPSHOT_VAR_OR_LEAVE(atpic->service, meta, ret, done);
836483d953aSJohn Baldwin 		SNAPSHOT_VAR_OR_LEAVE(atpic->mask, meta, ret, done);
837483d953aSJohn Baldwin 		SNAPSHOT_VAR_OR_LEAVE(atpic->smm, meta, ret, done);
838483d953aSJohn Baldwin 
839483d953aSJohn Baldwin 		SNAPSHOT_BUF_OR_LEAVE(atpic->acnt, sizeof(atpic->acnt),
840483d953aSJohn Baldwin 				      meta, ret, done);
841483d953aSJohn Baldwin 		SNAPSHOT_VAR_OR_LEAVE(atpic->lowprio, meta, ret, done);
842483d953aSJohn Baldwin 		SNAPSHOT_VAR_OR_LEAVE(atpic->intr_raised, meta, ret, done);
843483d953aSJohn Baldwin 	}
844483d953aSJohn Baldwin 
845483d953aSJohn Baldwin 	SNAPSHOT_BUF_OR_LEAVE(vatpic->elc, sizeof(vatpic->elc),
846483d953aSJohn Baldwin 			      meta, ret, done);
847483d953aSJohn Baldwin 
848483d953aSJohn Baldwin done:
849483d953aSJohn Baldwin 	return (ret);
850483d953aSJohn Baldwin }
851483d953aSJohn Baldwin #endif
852