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