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