Author: tychon
Date: Mon Apr 14 19:00:20 2014
New Revision: 264468
URL: http://svnweb.freebsd.org/changeset/base/264468

Log:
  Add support for emulating the slave PIC.
  
  Reviewed by:  grehan, jhb
  Approved by:  grehan (co-mentor)

Modified:
  head/lib/libvmmapi/vmmapi.h
  head/sys/amd64/vmm/io/vatpic.c
  head/usr.sbin/bhyve/pm.c

Modified: head/lib/libvmmapi/vmmapi.h
==============================================================================
--- head/lib/libvmmapi/vmmapi.h Mon Apr 14 18:38:14 2014        (r264467)
+++ head/lib/libvmmapi/vmmapi.h Mon Apr 14 19:00:20 2014        (r264468)
@@ -72,9 +72,9 @@ int   vm_ioapic_assert_irq(struct vmctx *c
 int    vm_ioapic_deassert_irq(struct vmctx *ctx, int irq);
 int    vm_ioapic_pulse_irq(struct vmctx *ctx, int irq);
 int    vm_ioapic_pincount(struct vmctx *ctx, int *pincount);
+int    vm_isa_assert_irq(struct vmctx *ctx, int atpic_irq, int ioapic_irq);
 int    vm_isa_deassert_irq(struct vmctx *ctx, int atpic_irq, int ioapic_irq);
 int    vm_isa_pulse_irq(struct vmctx *ctx, int atpic_irq, int ioapic_irq);
-int    vm_isa_pulse_irq(struct vmctx *ctx, int atpic_irq, int ioapic_irq);
 int    vm_inject_nmi(struct vmctx *ctx, int vcpu);
 int    vm_capability_name2type(const char *capname);
 const char *vm_capability_type2name(int type);

Modified: head/sys/amd64/vmm/io/vatpic.c
==============================================================================
--- head/sys/amd64/vmm/io/vatpic.c      Mon Apr 14 18:38:14 2014        
(r264467)
+++ head/sys/amd64/vmm/io/vatpic.c      Mon Apr 14 19:00:20 2014        
(r264468)
@@ -67,6 +67,7 @@ struct atpic {
        bool            aeoi;
        bool            poll;
        bool            rotate;
+       bool            sfn;            /* special fully-nested mode */
 
        int             irq_base;
        uint8_t         request;        /* Interrupt Request Register (IIR) */
@@ -75,6 +76,8 @@ struct atpic {
 
        int             acnt[8];        /* sum of pin asserts and deasserts */
        int             priority;       /* current pin priority */
+
+       bool            intr_raised;
 };
 
 struct vatpic {
@@ -82,8 +85,6 @@ struct vatpic {
        struct mtx      mtx;
        struct atpic    atpic[2];
        uint8_t         elc[2];
-
-       bool            intr_raised;
 };
 
 #define        VATPIC_CTR0(vatpic, fmt)                                        
\
@@ -101,6 +102,7 @@ struct vatpic {
 #define        VATPIC_CTR4(vatpic, fmt, a1, a2, a3, a4)                        
\
        VM_CTR4((vatpic)->vm, fmt, a1, a2, a3, a4)
 
+static void vatpic_set_pinstate(struct vatpic *vatpic, int pin, bool newstate);
 
 static __inline int
 vatpic_get_highest_isrpin(struct atpic *atpic)
@@ -122,13 +124,23 @@ vatpic_get_highest_isrpin(struct atpic *
 static __inline int
 vatpic_get_highest_irrpin(struct atpic *atpic)
 {
+       int serviced;
        int bit, pin;
        int i, j;
 
+       /*
+        * In 'Special Fully-Nested Mode' when an interrupt request from
+        * a slave is in service, the slave is not locked out from the
+        * master's priority logic.
+        */
+       serviced = atpic->service;
+       if (atpic->sfn)
+               serviced &= ~(1 << 2);
+
        for (i = 0; i <= 7; i++) {
                pin = ((i + 7 - atpic->priority) & 0x7);
                bit = (1 << pin);
-               if (atpic->service & bit)
+               if (serviced & bit)
                        break;
        }
 
@@ -150,14 +162,35 @@ vatpic_notify_intr(struct vatpic *vatpic
 
        KASSERT(VATPIC_LOCKED(vatpic), ("vatpic_notify_intr not locked"));
 
-       if (vatpic->intr_raised == true)
-               return;
+       /*
+        * First check the slave.
+        */
+       atpic = &vatpic->atpic[1];
+       if (!atpic->intr_raised &&
+           (pin = vatpic_get_highest_irrpin(atpic)) != -1) {
+               VATPIC_CTR4(vatpic, "atpic slave notify pin = %d "
+                   "(imr 0x%x irr 0x%x isr 0x%x)", pin,
+                   atpic->mask, atpic->request, atpic->service);
 
-       /* XXX master only */
-       atpic = &vatpic->atpic[0];
+               /*
+                * Cascade the request from the slave to the master.
+                */
+               atpic->intr_raised = true;
+               vatpic_set_pinstate(vatpic, 2, true);
+               vatpic_set_pinstate(vatpic, 2, false);
+       } else {
+               VATPIC_CTR3(vatpic, "atpic slave no eligible interrupts "
+                   "(imr 0x%x irr 0x%x isr 0x%x)",
+                   atpic->mask, atpic->request, atpic->service);
+       }
 
-       if ((pin = vatpic_get_highest_irrpin(atpic)) != -1) {
-               VATPIC_CTR4(vatpic, "atpic notify pin = %d "
+       /*
+        * Then check the master.
+        */
+       atpic = &vatpic->atpic[0];
+       if (!atpic->intr_raised &&
+           (pin = vatpic_get_highest_irrpin(atpic)) != -1) {
+               VATPIC_CTR4(vatpic, "atpic master notify pin = %d "
                    "(imr 0x%x irr 0x%x isr 0x%x)", pin,
                    atpic->mask, atpic->request, atpic->service);
 
@@ -183,11 +216,11 @@ vatpic_notify_intr(struct vatpic *vatpic
                 * programmed as ExtINT to indicate that the PIC is
                 * the source of the interrupt.
                 */
+               atpic->intr_raised = true;
                lapic_set_local_intr(vatpic->vm, -1, APIC_LVT_LINT0);
                vioapic_pulse_irq(vatpic->vm, 0);
-               vatpic->intr_raised = true;
        } else {
-               VATPIC_CTR3(vatpic, "atpic no eligible interrupts "
+               VATPIC_CTR3(vatpic, "atpic master no eligible interrupts "
                    "(imr 0x%x irr 0x%x isr 0x%x)",
                    atpic->mask, atpic->request, atpic->service);
        }
@@ -422,7 +455,6 @@ vatpic_pending_intr(struct vm *vm, int *
 
        vatpic = vm_atpic(vm);
 
-       /* XXX master only */
        atpic = &vatpic->atpic[0];
 
        VATPIC_LOCK(vatpic);
@@ -430,37 +462,53 @@ vatpic_pending_intr(struct vm *vm, int *
        pin = vatpic_get_highest_irrpin(atpic);
        if (pin == -1)
                pin = 7;
+       if (pin == 2) {
+               atpic = &vatpic->atpic[1];
+               pin = vatpic_get_highest_irrpin(atpic);
+       }
 
        *vecptr = atpic->irq_base + pin;
 
        VATPIC_UNLOCK(vatpic);
 }
 
+static void
+vatpic_pin_accepted(struct atpic *atpic, int pin)
+{
+       atpic->intr_raised = false;
+
+       if (atpic->acnt[pin] == 0)
+               atpic->request &= ~(1 << pin);
+
+       if (atpic->aeoi == true) {
+               if (atpic->rotate == true)
+                       atpic->priority = pin;
+       } else {
+               atpic->service |= (1 << pin);
+       }
+}
+
 void
 vatpic_intr_accepted(struct vm *vm, int vector)
 {
        struct vatpic *vatpic;
-       struct atpic *atpic;
        int pin;
 
        vatpic = vm_atpic(vm);
 
-       /* XXX master only */
-       atpic = &vatpic->atpic[0];
-
        VATPIC_LOCK(vatpic);
-       vatpic->intr_raised = false;
 
        pin = vector & 0x7;
 
-       if (atpic->acnt[pin] == 0)
-               atpic->request &= ~(1 << pin);
-
-       if (atpic->aeoi == true) {
-               if (atpic->rotate == true)
-                       atpic->priority = pin;
+       if ((vector & ~0x7) == vatpic->atpic[1].irq_base) {
+               vatpic_pin_accepted(&vatpic->atpic[1], pin);
+               /*
+                * If this vector originated from the slave,
+                * accept the cascaded interrupt too.
+                */
+               vatpic_pin_accepted(&vatpic->atpic[0], 2);
        } else {
-               atpic->service |= (1 << pin);
+               vatpic_pin_accepted(&vatpic->atpic[0], pin);
        }
 
        vatpic_notify_intr(vatpic);
@@ -468,47 +516,43 @@ vatpic_intr_accepted(struct vm *vm, int 
        VATPIC_UNLOCK(vatpic);
 }
 
-int
-vatpic_master_handler(void *vm, int vcpuid, struct vm_exit *vmexit)
+static int
+vatpic_read(struct vatpic *vatpic, struct atpic *atpic, struct vm_exit *vmexit)
 {
-       struct vatpic *vatpic;
-       struct atpic *atpic;
-       int error;
-       uint8_t val;
-
-       error = 0;
-       vatpic = vm_atpic(vm);
-       atpic = &vatpic->atpic[0];
+       VATPIC_LOCK(vatpic);
 
-       if (vmexit->u.inout.bytes != 1)
+       if (atpic->poll) {
+               VATPIC_CTR0(vatpic, "vatpic polled mode not supported");
+               VATPIC_UNLOCK(vatpic);
                return (-1);
-
-       if (vmexit->u.inout.in) {
-               VATPIC_LOCK(vatpic);
-               if (atpic->poll) {
-                       VATPIC_CTR0(vatpic, "vatpic polled mode not "
-                           "supported");
-                       VATPIC_UNLOCK(vatpic);
-                       return (-1);
+       } else {
+               if (vmexit->u.inout.port & ICU_IMR_OFFSET) {
+                       /* read interrrupt mask register */
+                       vmexit->u.inout.eax = atpic->mask;
                } else {
-                       if (vmexit->u.inout.port & ICU_IMR_OFFSET) {
-                               /* read interrrupt mask register */
-                               vmexit->u.inout.eax = atpic->mask;
+                       if (atpic->rd_cmd_reg == OCW3_RIS) {
+                               /* read interrupt service register */
+                               vmexit->u.inout.eax = atpic->service;
                        } else {
-                               if (atpic->rd_cmd_reg == OCW3_RIS) {
-                                       /* read interrupt service register */
-                                       vmexit->u.inout.eax = atpic->service;
-                               } else {
-                                       /* read interrupt request register */
-                                       vmexit->u.inout.eax = atpic->request;
-                               }
+                               /* read interrupt request register */
+                               vmexit->u.inout.eax = atpic->request;
                        }
                }
-               VATPIC_UNLOCK(vatpic);
-
-               return (0);
        }
 
+       VATPIC_UNLOCK(vatpic);
+
+       return (0);
+
+}
+
+static int
+vatpic_write(struct vatpic *vatpic, struct atpic *atpic,
+    struct vm_exit *vmexit)
+{
+       int error;
+       uint8_t val;
+
        val = vmexit->u.inout.eax;
 
        VATPIC_LOCK(vatpic);
@@ -550,22 +594,41 @@ vatpic_master_handler(void *vm, int vcpu
 }
 
 int
-vatpic_slave_handler(void *vm, int vcpuid, struct vm_exit *vmexit)
+vatpic_master_handler(void *vm, int vcpuid, struct vm_exit *vmexit)
 {
+       struct vatpic *vatpic;
+       struct atpic *atpic;
+
+       vatpic = vm_atpic(vm);
+       atpic = &vatpic->atpic[0];
+
        if (vmexit->u.inout.bytes != 1)
                return (-1);
  
        if (vmexit->u.inout.in) {
-               if (vmexit->u.inout.port & ICU_IMR_OFFSET) {
-                       /* all interrupts masked */
-                       vmexit->u.inout.eax = 0xff;
-               } else {
-                       vmexit->u.inout.eax = 0x00;
-               }
+               return (vatpic_read(vatpic, atpic, vmexit));
        }
  
-       /* Pretend all accesses to the slave 8259 are alright */
-       return (0);
+       return (vatpic_write(vatpic, atpic, vmexit));
+}
+
+int
+vatpic_slave_handler(void *vm, int vcpuid, struct vm_exit *vmexit)
+{
+       struct vatpic *vatpic;
+       struct atpic *atpic;
+
+       vatpic = vm_atpic(vm);
+       atpic = &vatpic->atpic[1];
+
+       if (vmexit->u.inout.bytes != 1)
+               return (-1);
+
+       if (vmexit->u.inout.in) {
+               return (vatpic_read(vatpic, atpic, vmexit));
+       }
+
+       return (vatpic_write(vatpic, atpic, vmexit));
 }
 
 int
@@ -580,6 +643,8 @@ vatpic_elc_handler(void *vm, int vcpuid,
        if (vmexit->u.inout.bytes != 1)
                return (-1);
 
+       VATPIC_LOCK(vatpic);
+
        if (vmexit->u.inout.in) {
                if (is_master)
                        vmexit->u.inout.eax = vatpic->elc[0];
@@ -602,6 +667,8 @@ vatpic_elc_handler(void *vm, int vcpuid,
                        vatpic->elc[1] = (vmexit->u.inout.eax & 0xde);
        }
 
+       VATPIC_UNLOCK(vatpic);
+
        return (0);
 }
 

Modified: head/usr.sbin/bhyve/pm.c
==============================================================================
--- head/usr.sbin/bhyve/pm.c    Mon Apr 14 18:38:14 2014        (r264467)
+++ head/usr.sbin/bhyve/pm.c    Mon Apr 14 19:00:20 2014        (r264468)
@@ -83,7 +83,7 @@ sci_assert(struct vmctx *ctx)
 
        if (sci_active)
                return;
-       vm_ioapic_assert_irq(ctx, SCI_INT);
+       vm_isa_assert_irq(ctx, SCI_INT, SCI_INT);
        sci_active = 1;
 }
 
@@ -93,7 +93,7 @@ sci_deassert(struct vmctx *ctx)
 
        if (!sci_active)
                return;
-       vm_ioapic_deassert_irq(ctx, SCI_INT);
+       vm_isa_deassert_irq(ctx, SCI_INT, SCI_INT);
        sci_active = 0;
 }
 
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to