diff options
author | Neel Natu <neel@FreeBSD.org> | 2014-12-28 00:53:52 +0000 |
---|---|---|
committer | Neel Natu <neel@FreeBSD.org> | 2014-12-28 00:53:52 +0000 |
commit | 1a5934ef8ea80bfbce7d064d77324ddb55c02656 (patch) | |
tree | 19fe56d35a0835c51bb7f1d43ffefc1ddaf54536 /sys/amd64 | |
parent | 4cc6942f3755395a7bb368b4c5316f9ce8d4e6bf (diff) | |
download | src-1a5934ef8ea80bfbce7d064d77324ddb55c02656.tar.gz src-1a5934ef8ea80bfbce7d064d77324ddb55c02656.zip |
Implement "special mask mode" in vatpic.
OpenBSD guests always enable "special mask mode" during boot. As a result of
r275952 this is flagged as an error and the guest cannot boot.
Reviewed by: grehan
Differential Revision: https://reviews.freebsd.org/D1384
MFC after: 1 week
Notes
Notes:
svn path=/head/; revision=276323
Diffstat (limited to 'sys/amd64')
-rw-r--r-- | sys/amd64/vmm/io/vatpic.c | 29 |
1 files changed, 25 insertions, 4 deletions
diff --git a/sys/amd64/vmm/io/vatpic.c b/sys/amd64/vmm/io/vatpic.c index 74a70279eb21..328c35f700b8 100644 --- a/sys/amd64/vmm/io/vatpic.c +++ b/sys/amd64/vmm/io/vatpic.c @@ -73,6 +73,7 @@ struct atpic { uint8_t request; /* Interrupt Request Register (IIR) */ uint8_t service; /* Interrupt Service (ISR) */ uint8_t mask; /* Interrupt Mask Register (IMR) */ + uint8_t smm; /* special mask mode */ int acnt[8]; /* sum of pin asserts and deasserts */ int lowprio; /* lowest priority irq */ @@ -131,8 +132,16 @@ vatpic_get_highest_isrpin(struct atpic *atpic) ATPIC_PIN_FOREACH(pin, atpic, i) { bit = (1 << pin); - if (atpic->service & bit) - return (pin); + if (atpic->service & bit) { + /* + * An IS bit that is masked by an IMR bit will not be + * cleared by a non-specific EOI in Special Mask Mode. + */ + if (atpic->smm && (atpic->mask & bit) != 0) + continue; + else + return (pin); + } } return (-1); @@ -153,6 +162,15 @@ vatpic_get_highest_irrpin(struct atpic *atpic) if (atpic->sfn) serviced &= ~(1 << 2); + /* + * In 'Special Mask Mode', when a mask bit is set in OCW1 it inhibits + * further interrupts at that level and enables interrupts from all + * other levels that are not masked. In other words the ISR has no + * bearing on the levels that can generate interrupts. + */ + if (atpic->smm) + serviced = 0; + ATPIC_PIN_FOREACH(pin, atpic, tmp) { bit = 1 << pin; @@ -261,6 +279,7 @@ vatpic_icw1(struct vatpic *vatpic, struct atpic *atpic, uint8_t val) atpic->lowprio = 7; atpic->rd_cmd_reg = 0; atpic->poll = 0; + atpic->smm = 0; if ((val & ICW1_SNGL) != 0) { VATPIC_CTR0(vatpic, "vatpic cascade mode required"); @@ -375,8 +394,10 @@ vatpic_ocw3(struct vatpic *vatpic, struct atpic *atpic, uint8_t val) VATPIC_CTR1(vatpic, "atpic ocw3 0x%x", val); if (val & OCW3_ESMM) { - VATPIC_CTR0(vatpic, "atpic special mask mode not implemented"); - return (-1); + atpic->smm = val & OCW3_SMM ? 1 : 0; + VATPIC_CTR2(vatpic, "%s atpic special mask mode %s", + master_atpic(vatpic, atpic) ? "master" : "slave", + atpic->smm ? "enabled" : "disabled"); } if (val & OCW3_RR) { |