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