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 854