vatpic.c (201b1ccc22c1a188b58b9ba7c4b7b3157705d46d) | vatpic.c (b96be57a2d1892e7ce46b2259453ef91665f6822) |
---|---|
1/*- 2 * Copyright (c) 2014 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright --- 53 unchanged lines hidden (view full) --- 62struct atpic { 63 bool ready; 64 int icw_num; 65 int rd_cmd_reg; 66 67 bool aeoi; 68 bool poll; 69 bool rotate; | 1/*- 2 * Copyright (c) 2014 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright --- 53 unchanged lines hidden (view full) --- 62struct atpic { 63 bool ready; 64 int icw_num; 65 int rd_cmd_reg; 66 67 bool aeoi; 68 bool poll; 69 bool rotate; |
70 bool sfn; /* special fully-nested mode */ |
|
70 71 int irq_base; 72 uint8_t request; /* Interrupt Request Register (IIR) */ 73 uint8_t service; /* Interrupt Service (ISR) */ 74 uint8_t mask; /* Interrupt Mask Register (IMR) */ 75 76 int acnt[8]; /* sum of pin asserts and deasserts */ 77 int priority; /* current pin priority */ | 71 72 int irq_base; 73 uint8_t request; /* Interrupt Request Register (IIR) */ 74 uint8_t service; /* Interrupt Service (ISR) */ 75 uint8_t mask; /* Interrupt Mask Register (IMR) */ 76 77 int acnt[8]; /* sum of pin asserts and deasserts */ 78 int priority; /* current pin priority */ |
79 80 bool intr_raised; |
|
78}; 79 80struct vatpic { 81 struct vm *vm; 82 struct mtx mtx; 83 struct atpic atpic[2]; 84 uint8_t elc[2]; | 81}; 82 83struct vatpic { 84 struct vm *vm; 85 struct mtx mtx; 86 struct atpic atpic[2]; 87 uint8_t elc[2]; |
85 86 bool intr_raised; | |
87}; 88 89#define VATPIC_CTR0(vatpic, fmt) \ 90 VM_CTR0((vatpic)->vm, fmt) 91 92#define VATPIC_CTR1(vatpic, fmt, a1) \ 93 VM_CTR1((vatpic)->vm, fmt, a1) 94 95#define VATPIC_CTR2(vatpic, fmt, a1, a2) \ 96 VM_CTR2((vatpic)->vm, fmt, a1, a2) 97 98#define VATPIC_CTR3(vatpic, fmt, a1, a2, a3) \ 99 VM_CTR3((vatpic)->vm, fmt, a1, a2, a3) 100 101#define VATPIC_CTR4(vatpic, fmt, a1, a2, a3, a4) \ 102 VM_CTR4((vatpic)->vm, fmt, a1, a2, a3, a4) 103 | 88}; 89 90#define VATPIC_CTR0(vatpic, fmt) \ 91 VM_CTR0((vatpic)->vm, fmt) 92 93#define VATPIC_CTR1(vatpic, fmt, a1) \ 94 VM_CTR1((vatpic)->vm, fmt, a1) 95 96#define VATPIC_CTR2(vatpic, fmt, a1, a2) \ 97 VM_CTR2((vatpic)->vm, fmt, a1, a2) 98 99#define VATPIC_CTR3(vatpic, fmt, a1, a2, a3) \ 100 VM_CTR3((vatpic)->vm, fmt, a1, a2, a3) 101 102#define VATPIC_CTR4(vatpic, fmt, a1, a2, a3, a4) \ 103 VM_CTR4((vatpic)->vm, fmt, a1, a2, a3, a4) 104 |
105static void vatpic_set_pinstate(struct vatpic *vatpic, int pin, bool newstate); |
|
104 105static __inline int 106vatpic_get_highest_isrpin(struct atpic *atpic) 107{ 108 int bit, pin; 109 int i; 110 111 for (i = 0; i <= 7; i++) { --- 5 unchanged lines hidden (view full) --- 117 } 118 119 return (-1); 120} 121 122static __inline int 123vatpic_get_highest_irrpin(struct atpic *atpic) 124{ | 106 107static __inline int 108vatpic_get_highest_isrpin(struct atpic *atpic) 109{ 110 int bit, pin; 111 int i; 112 113 for (i = 0; i <= 7; i++) { --- 5 unchanged lines hidden (view full) --- 119 } 120 121 return (-1); 122} 123 124static __inline int 125vatpic_get_highest_irrpin(struct atpic *atpic) 126{ |
127 int serviced; |
|
125 int bit, pin; 126 int i, j; 127 | 128 int bit, pin; 129 int i, j; 130 |
131 /* 132 * In 'Special Fully-Nested Mode' when an interrupt request from 133 * a slave is in service, the slave is not locked out from the 134 * master's priority logic. 135 */ 136 serviced = atpic->service; 137 if (atpic->sfn) 138 serviced &= ~(1 << 2); 139 |
|
128 for (i = 0; i <= 7; i++) { 129 pin = ((i + 7 - atpic->priority) & 0x7); 130 bit = (1 << pin); | 140 for (i = 0; i <= 7; i++) { 141 pin = ((i + 7 - atpic->priority) & 0x7); 142 bit = (1 << pin); |
131 if (atpic->service & bit) | 143 if (serviced & bit) |
132 break; 133 } 134 135 for (j = 0; j < i; j++) { 136 pin = ((j + 7 - atpic->priority) & 0x7); 137 bit = (1 << pin); 138 if (atpic->request & bit && (~atpic->mask & bit)) 139 return (pin); --- 5 unchanged lines hidden (view full) --- 145static void 146vatpic_notify_intr(struct vatpic *vatpic) 147{ 148 struct atpic *atpic; 149 int pin; 150 151 KASSERT(VATPIC_LOCKED(vatpic), ("vatpic_notify_intr not locked")); 152 | 144 break; 145 } 146 147 for (j = 0; j < i; j++) { 148 pin = ((j + 7 - atpic->priority) & 0x7); 149 bit = (1 << pin); 150 if (atpic->request & bit && (~atpic->mask & bit)) 151 return (pin); --- 5 unchanged lines hidden (view full) --- 157static void 158vatpic_notify_intr(struct vatpic *vatpic) 159{ 160 struct atpic *atpic; 161 int pin; 162 163 KASSERT(VATPIC_LOCKED(vatpic), ("vatpic_notify_intr not locked")); 164 |
153 if (vatpic->intr_raised == true) 154 return; | 165 /* 166 * First check the slave. 167 */ 168 atpic = &vatpic->atpic[1]; 169 if (!atpic->intr_raised && 170 (pin = vatpic_get_highest_irrpin(atpic)) != -1) { 171 VATPIC_CTR4(vatpic, "atpic slave notify pin = %d " 172 "(imr 0x%x irr 0x%x isr 0x%x)", pin, 173 atpic->mask, atpic->request, atpic->service); |
155 | 174 |
156 /* XXX master only */ 157 atpic = &vatpic->atpic[0]; | 175 /* 176 * Cascade the request from the slave to the master. 177 */ 178 atpic->intr_raised = true; 179 vatpic_set_pinstate(vatpic, 2, true); 180 vatpic_set_pinstate(vatpic, 2, false); 181 } else { 182 VATPIC_CTR3(vatpic, "atpic slave no eligible interrupts " 183 "(imr 0x%x irr 0x%x isr 0x%x)", 184 atpic->mask, atpic->request, atpic->service); 185 } |
158 | 186 |
159 if ((pin = vatpic_get_highest_irrpin(atpic)) != -1) { 160 VATPIC_CTR4(vatpic, "atpic notify pin = %d " | 187 /* 188 * Then check the master. 189 */ 190 atpic = &vatpic->atpic[0]; 191 if (!atpic->intr_raised && 192 (pin = vatpic_get_highest_irrpin(atpic)) != -1) { 193 VATPIC_CTR4(vatpic, "atpic master notify pin = %d " |
161 "(imr 0x%x irr 0x%x isr 0x%x)", pin, 162 atpic->mask, atpic->request, atpic->service); 163 164 /* 165 * PIC interrupts are routed to both the Local APIC 166 * and the I/O APIC to support operation in 1 of 3 167 * modes. 168 * --- 9 unchanged lines hidden (view full) --- 178 * the interrupt. 179 * 180 * 3. Symmetric I/O Mode: PIC interrupts are fielded 181 * by the I/O APIC and delivered to the appropriate 182 * CPU. In mode '3' the I/O APIC input 0 is 183 * programmed as ExtINT to indicate that the PIC is 184 * the source of the interrupt. 185 */ | 194 "(imr 0x%x irr 0x%x isr 0x%x)", pin, 195 atpic->mask, atpic->request, atpic->service); 196 197 /* 198 * PIC interrupts are routed to both the Local APIC 199 * and the I/O APIC to support operation in 1 of 3 200 * modes. 201 * --- 9 unchanged lines hidden (view full) --- 211 * the interrupt. 212 * 213 * 3. Symmetric I/O Mode: PIC interrupts are fielded 214 * by the I/O APIC and delivered to the appropriate 215 * CPU. In mode '3' the I/O APIC input 0 is 216 * programmed as ExtINT to indicate that the PIC is 217 * the source of the interrupt. 218 */ |
219 atpic->intr_raised = true; |
|
186 lapic_set_local_intr(vatpic->vm, -1, APIC_LVT_LINT0); 187 vioapic_pulse_irq(vatpic->vm, 0); | 220 lapic_set_local_intr(vatpic->vm, -1, APIC_LVT_LINT0); 221 vioapic_pulse_irq(vatpic->vm, 0); |
188 vatpic->intr_raised = true; | |
189 } else { | 222 } else { |
190 VATPIC_CTR3(vatpic, "atpic no eligible interrupts " | 223 VATPIC_CTR3(vatpic, "atpic master no eligible interrupts " |
191 "(imr 0x%x irr 0x%x isr 0x%x)", 192 atpic->mask, atpic->request, atpic->service); 193 } 194} 195 196static int 197vatpic_icw1(struct vatpic *vatpic, struct atpic *atpic, uint8_t val) 198{ --- 218 unchanged lines hidden (view full) --- 417vatpic_pending_intr(struct vm *vm, int *vecptr) 418{ 419 struct vatpic *vatpic; 420 struct atpic *atpic; 421 int pin; 422 423 vatpic = vm_atpic(vm); 424 | 224 "(imr 0x%x irr 0x%x isr 0x%x)", 225 atpic->mask, atpic->request, atpic->service); 226 } 227} 228 229static int 230vatpic_icw1(struct vatpic *vatpic, struct atpic *atpic, uint8_t val) 231{ --- 218 unchanged lines hidden (view full) --- 450vatpic_pending_intr(struct vm *vm, int *vecptr) 451{ 452 struct vatpic *vatpic; 453 struct atpic *atpic; 454 int pin; 455 456 vatpic = vm_atpic(vm); 457 |
425 /* XXX master only */ | |
426 atpic = &vatpic->atpic[0]; 427 428 VATPIC_LOCK(vatpic); 429 430 pin = vatpic_get_highest_irrpin(atpic); 431 if (pin == -1) 432 pin = 7; | 458 atpic = &vatpic->atpic[0]; 459 460 VATPIC_LOCK(vatpic); 461 462 pin = vatpic_get_highest_irrpin(atpic); 463 if (pin == -1) 464 pin = 7; |
465 if (pin == 2) { 466 atpic = &vatpic->atpic[1]; 467 pin = vatpic_get_highest_irrpin(atpic); 468 } |
|
433 434 *vecptr = atpic->irq_base + pin; 435 436 VATPIC_UNLOCK(vatpic); 437} 438 | 469 470 *vecptr = atpic->irq_base + pin; 471 472 VATPIC_UNLOCK(vatpic); 473} 474 |
475static void 476vatpic_pin_accepted(struct atpic *atpic, int pin) 477{ 478 atpic->intr_raised = false; 479 480 if (atpic->acnt[pin] == 0) 481 atpic->request &= ~(1 << pin); 482 483 if (atpic->aeoi == true) { 484 if (atpic->rotate == true) 485 atpic->priority = pin; 486 } else { 487 atpic->service |= (1 << pin); 488 } 489} 490 |
|
439void 440vatpic_intr_accepted(struct vm *vm, int vector) 441{ 442 struct vatpic *vatpic; | 491void 492vatpic_intr_accepted(struct vm *vm, int vector) 493{ 494 struct vatpic *vatpic; |
443 struct atpic *atpic; | |
444 int pin; 445 446 vatpic = vm_atpic(vm); 447 | 495 int pin; 496 497 vatpic = vm_atpic(vm); 498 |
448 /* XXX master only */ 449 atpic = &vatpic->atpic[0]; 450 | |
451 VATPIC_LOCK(vatpic); | 499 VATPIC_LOCK(vatpic); |
452 vatpic->intr_raised = false; | |
453 454 pin = vector & 0x7; 455 | 500 501 pin = vector & 0x7; 502 |
456 if (atpic->acnt[pin] == 0) 457 atpic->request &= ~(1 << pin); 458 459 if (atpic->aeoi == true) { 460 if (atpic->rotate == true) 461 atpic->priority = pin; | 503 if ((vector & ~0x7) == vatpic->atpic[1].irq_base) { 504 vatpic_pin_accepted(&vatpic->atpic[1], pin); 505 /* 506 * If this vector originated from the slave, 507 * accept the cascaded interrupt too. 508 */ 509 vatpic_pin_accepted(&vatpic->atpic[0], 2); |
462 } else { | 510 } else { |
463 atpic->service |= (1 << pin); | 511 vatpic_pin_accepted(&vatpic->atpic[0], pin); |
464 } 465 466 vatpic_notify_intr(vatpic); 467 468 VATPIC_UNLOCK(vatpic); 469} 470 | 512 } 513 514 vatpic_notify_intr(vatpic); 515 516 VATPIC_UNLOCK(vatpic); 517} 518 |
471int 472vatpic_master_handler(void *vm, int vcpuid, struct vm_exit *vmexit) | 519static int 520vatpic_read(struct vatpic *vatpic, struct atpic *atpic, struct vm_exit *vmexit) |
473{ | 521{ |
474 struct vatpic *vatpic; 475 struct atpic *atpic; 476 int error; 477 uint8_t val; | 522 VATPIC_LOCK(vatpic); |
478 | 523 |
479 error = 0; 480 vatpic = vm_atpic(vm); 481 atpic = &vatpic->atpic[0]; 482 483 if (vmexit->u.inout.bytes != 1) | 524 if (atpic->poll) { 525 VATPIC_CTR0(vatpic, "vatpic polled mode not supported"); 526 VATPIC_UNLOCK(vatpic); |
484 return (-1); | 527 return (-1); |
485 486 if (vmexit->u.inout.in) { 487 VATPIC_LOCK(vatpic); 488 if (atpic->poll) { 489 VATPIC_CTR0(vatpic, "vatpic polled mode not " 490 "supported"); 491 VATPIC_UNLOCK(vatpic); 492 return (-1); | 528 } else { 529 if (vmexit->u.inout.port & ICU_IMR_OFFSET) { 530 /* read interrrupt mask register */ 531 vmexit->u.inout.eax = atpic->mask; |
493 } else { | 532 } else { |
494 if (vmexit->u.inout.port & ICU_IMR_OFFSET) { 495 /* read interrrupt mask register */ 496 vmexit->u.inout.eax = atpic->mask; | 533 if (atpic->rd_cmd_reg == OCW3_RIS) { 534 /* read interrupt service register */ 535 vmexit->u.inout.eax = atpic->service; |
497 } else { | 536 } else { |
498 if (atpic->rd_cmd_reg == OCW3_RIS) { 499 /* read interrupt service register */ 500 vmexit->u.inout.eax = atpic->service; 501 } else { 502 /* read interrupt request register */ 503 vmexit->u.inout.eax = atpic->request; 504 } | 537 /* read interrupt request register */ 538 vmexit->u.inout.eax = atpic->request; |
505 } 506 } | 539 } 540 } |
507 VATPIC_UNLOCK(vatpic); 508 509 return (0); | |
510 } 511 | 541 } 542 |
543 VATPIC_UNLOCK(vatpic); 544 545 return (0); 546 547} 548 549static int 550vatpic_write(struct vatpic *vatpic, struct atpic *atpic, 551 struct vm_exit *vmexit) 552{ 553 int error; 554 uint8_t val; 555 |
|
512 val = vmexit->u.inout.eax; 513 514 VATPIC_LOCK(vatpic); 515 516 if (vmexit->u.inout.port & ICU_IMR_OFFSET) { 517 if (atpic->ready) { 518 error = vatpic_ocw1(vatpic, atpic, val); 519 } else { --- 25 unchanged lines hidden (view full) --- 545 vatpic_notify_intr(vatpic); 546 547 VATPIC_UNLOCK(vatpic); 548 549 return (error); 550} 551 552int | 556 val = vmexit->u.inout.eax; 557 558 VATPIC_LOCK(vatpic); 559 560 if (vmexit->u.inout.port & ICU_IMR_OFFSET) { 561 if (atpic->ready) { 562 error = vatpic_ocw1(vatpic, atpic, val); 563 } else { --- 25 unchanged lines hidden (view full) --- 589 vatpic_notify_intr(vatpic); 590 591 VATPIC_UNLOCK(vatpic); 592 593 return (error); 594} 595 596int |
553vatpic_slave_handler(void *vm, int vcpuid, struct vm_exit *vmexit) | 597vatpic_master_handler(void *vm, int vcpuid, struct vm_exit *vmexit) |
554{ | 598{ |
599 struct vatpic *vatpic; 600 struct atpic *atpic; 601 602 vatpic = vm_atpic(vm); 603 atpic = &vatpic->atpic[0]; 604 |
|
555 if (vmexit->u.inout.bytes != 1) 556 return (-1); 557 558 if (vmexit->u.inout.in) { | 605 if (vmexit->u.inout.bytes != 1) 606 return (-1); 607 608 if (vmexit->u.inout.in) { |
559 if (vmexit->u.inout.port & ICU_IMR_OFFSET) { 560 /* all interrupts masked */ 561 vmexit->u.inout.eax = 0xff; 562 } else { 563 vmexit->u.inout.eax = 0x00; 564 } | 609 return (vatpic_read(vatpic, atpic, vmexit)); |
565 } 566 | 610 } 611 |
567 /* Pretend all accesses to the slave 8259 are alright */ 568 return (0); | 612 return (vatpic_write(vatpic, atpic, vmexit)); |
569} 570 571int | 613} 614 615int |
616vatpic_slave_handler(void *vm, int vcpuid, struct vm_exit *vmexit) 617{ 618 struct vatpic *vatpic; 619 struct atpic *atpic; 620 621 vatpic = vm_atpic(vm); 622 atpic = &vatpic->atpic[1]; 623 624 if (vmexit->u.inout.bytes != 1) 625 return (-1); 626 627 if (vmexit->u.inout.in) { 628 return (vatpic_read(vatpic, atpic, vmexit)); 629 } 630 631 return (vatpic_write(vatpic, atpic, vmexit)); 632} 633 634int |
|
572vatpic_elc_handler(void *vm, int vcpuid, struct vm_exit *vmexit) 573{ 574 struct vatpic *vatpic; 575 bool is_master; 576 577 vatpic = vm_atpic(vm); 578 is_master = (vmexit->u.inout.port == IO_ELCR1); 579 580 if (vmexit->u.inout.bytes != 1) 581 return (-1); 582 | 635vatpic_elc_handler(void *vm, int vcpuid, struct vm_exit *vmexit) 636{ 637 struct vatpic *vatpic; 638 bool is_master; 639 640 vatpic = vm_atpic(vm); 641 is_master = (vmexit->u.inout.port == IO_ELCR1); 642 643 if (vmexit->u.inout.bytes != 1) 644 return (-1); 645 |
646 VATPIC_LOCK(vatpic); 647 |
|
583 if (vmexit->u.inout.in) { 584 if (is_master) 585 vmexit->u.inout.eax = vatpic->elc[0]; 586 else 587 vmexit->u.inout.eax = vatpic->elc[1]; 588 } else { 589 /* 590 * For the master PIC the cascade channel (IRQ2), the --- 6 unchanged lines hidden (view full) --- 597 * be programmed for level mode. 598 */ 599 if (is_master) 600 vatpic->elc[0] = (vmexit->u.inout.eax & 0xf8); 601 else 602 vatpic->elc[1] = (vmexit->u.inout.eax & 0xde); 603 } 604 | 648 if (vmexit->u.inout.in) { 649 if (is_master) 650 vmexit->u.inout.eax = vatpic->elc[0]; 651 else 652 vmexit->u.inout.eax = vatpic->elc[1]; 653 } else { 654 /* 655 * For the master PIC the cascade channel (IRQ2), the --- 6 unchanged lines hidden (view full) --- 662 * be programmed for level mode. 663 */ 664 if (is_master) 665 vatpic->elc[0] = (vmexit->u.inout.eax & 0xf8); 666 else 667 vatpic->elc[1] = (vmexit->u.inout.eax & 0xde); 668 } 669 |
670 VATPIC_UNLOCK(vatpic); 671 |
|
605 return (0); 606} 607 608struct vatpic * 609vatpic_init(struct vm *vm) 610{ 611 struct vatpic *vatpic; 612 --- 13 unchanged lines hidden --- | 672 return (0); 673} 674 675struct vatpic * 676vatpic_init(struct vm *vm) 677{ 678 struct vatpic *vatpic; 679 --- 13 unchanged lines hidden --- |