The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/amd64/vmm/io/vatpic.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: a67272e3e27884e54a8fedd5aaeb5ee1


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.