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 ---