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/vmm_lapic.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) 2011 NetApp, Inc.
    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 NETAPP, INC ``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 NETAPP, INC 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  * $FreeBSD$
   29  */
   30 
   31 #include <sys/cdefs.h>
   32 __FBSDID("$FreeBSD$");
   33 
   34 #include <sys/param.h>
   35 #include <sys/systm.h>
   36 #include <sys/smp.h>
   37 
   38 #include <x86/specialreg.h>
   39 #include <x86/apicreg.h>
   40 
   41 #include <machine/vmm.h>
   42 #include "vmm_ktr.h"
   43 #include "vmm_lapic.h"
   44 #include "vlapic.h"
   45 
   46 /*
   47  * Some MSI message definitions
   48  */
   49 #define MSI_X86_ADDR_MASK       0xfff00000
   50 #define MSI_X86_ADDR_BASE       0xfee00000
   51 #define MSI_X86_ADDR_RH         0x00000008      /* Redirection Hint */
   52 #define MSI_X86_ADDR_LOG        0x00000004      /* Destination Mode */
   53 
   54 int
   55 lapic_set_intr(struct vcpu *vcpu, int vector, bool level)
   56 {
   57         struct vlapic *vlapic;
   58 
   59         /*
   60          * According to section "Maskable Hardware Interrupts" in Intel SDM
   61          * vectors 16 through 255 can be delivered through the local APIC.
   62          */
   63         if (vector < 16 || vector > 255)
   64                 return (EINVAL);
   65 
   66         vlapic = vm_lapic(vcpu);
   67         if (vlapic_set_intr_ready(vlapic, vector, level))
   68                 vcpu_notify_event(vcpu, true);
   69         return (0);
   70 }
   71 
   72 int
   73 lapic_set_local_intr(struct vm *vm, struct vcpu *vcpu, int vector)
   74 {
   75         struct vlapic *vlapic;
   76         cpuset_t dmask;
   77         int cpu, error;
   78 
   79         if (vcpu == NULL) {
   80                 error = 0;
   81                 dmask = vm_active_cpus(vm);
   82                 CPU_FOREACH_ISSET(cpu, &dmask) {
   83                         vlapic = vm_lapic(vm_vcpu(vm, cpu));
   84                         error = vlapic_trigger_lvt(vlapic, vector);
   85                         if (error)
   86                                 break;
   87                 }
   88         } else {
   89                 vlapic = vm_lapic(vcpu);
   90                 error = vlapic_trigger_lvt(vlapic, vector);
   91         }
   92 
   93         return (error);
   94 }
   95 
   96 int
   97 lapic_intr_msi(struct vm *vm, uint64_t addr, uint64_t msg)
   98 {
   99         int delmode, vec;
  100         uint32_t dest;
  101         bool phys;
  102 
  103         VM_CTR2(vm, "lapic MSI addr: %#lx msg: %#lx", addr, msg);
  104 
  105         if ((addr & MSI_X86_ADDR_MASK) != MSI_X86_ADDR_BASE) {
  106                 VM_CTR1(vm, "lapic MSI invalid addr %#lx", addr);
  107                 return (-1);
  108         }
  109 
  110         /*
  111          * Extract the x86-specific fields from the MSI addr/msg
  112          * params according to the Intel Arch spec, Vol3 Ch 10.
  113          *
  114          * The PCI specification does not support level triggered
  115          * MSI/MSI-X so ignore trigger level in 'msg'.
  116          *
  117          * The 'dest' is interpreted as a logical APIC ID if both
  118          * the Redirection Hint and Destination Mode are '1' and
  119          * physical otherwise.
  120          */
  121         dest = (addr >> 12) & 0xff;
  122         phys = ((addr & (MSI_X86_ADDR_RH | MSI_X86_ADDR_LOG)) !=
  123             (MSI_X86_ADDR_RH | MSI_X86_ADDR_LOG));
  124         delmode = msg & APIC_DELMODE_MASK;
  125         vec = msg & 0xff;
  126 
  127         VM_CTR3(vm, "lapic MSI %s dest %#x, vec %d",
  128             phys ? "physical" : "logical", dest, vec);
  129 
  130         vlapic_deliver_intr(vm, LAPIC_TRIG_EDGE, dest, phys, delmode, vec);
  131         return (0);
  132 }
  133 
  134 static bool
  135 x2apic_msr(u_int msr)
  136 {
  137         return (msr >= 0x800 && msr <= 0xBFF);
  138 }
  139 
  140 static u_int
  141 x2apic_msr_to_regoff(u_int msr)
  142 {
  143 
  144         return ((msr - 0x800) << 4);
  145 }
  146 
  147 bool
  148 lapic_msr(u_int msr)
  149 {
  150 
  151         return (x2apic_msr(msr) || msr == MSR_APICBASE);
  152 }
  153 
  154 int
  155 lapic_rdmsr(struct vcpu *vcpu, u_int msr, uint64_t *rval, bool *retu)
  156 {
  157         int error;
  158         u_int offset;
  159         struct vlapic *vlapic;
  160 
  161         vlapic = vm_lapic(vcpu);
  162 
  163         if (msr == MSR_APICBASE) {
  164                 *rval = vlapic_get_apicbase(vlapic);
  165                 error = 0;
  166         } else {
  167                 offset = x2apic_msr_to_regoff(msr);
  168                 error = vlapic_read(vlapic, 0, offset, rval, retu);
  169         }
  170 
  171         return (error);
  172 }
  173 
  174 int
  175 lapic_wrmsr(struct vcpu *vcpu, u_int msr, uint64_t val, bool *retu)
  176 {
  177         int error;
  178         u_int offset;
  179         struct vlapic *vlapic;
  180 
  181         vlapic = vm_lapic(vcpu);
  182 
  183         if (msr == MSR_APICBASE) {
  184                 error = vlapic_set_apicbase(vlapic, val);
  185         } else {
  186                 offset = x2apic_msr_to_regoff(msr);
  187                 error = vlapic_write(vlapic, 0, offset, val, retu);
  188         }
  189 
  190         return (error);
  191 }
  192 
  193 int
  194 lapic_mmio_write(struct vcpu *vcpu, uint64_t gpa, uint64_t wval, int size,
  195                  void *arg)
  196 {
  197         int error;
  198         uint64_t off;
  199         struct vlapic *vlapic;
  200 
  201         off = gpa - DEFAULT_APIC_BASE;
  202 
  203         /*
  204          * Memory mapped local apic accesses must be 4 bytes wide and
  205          * aligned on a 16-byte boundary.
  206          */
  207         if (size != 4 || off & 0xf)
  208                 return (EINVAL);
  209 
  210         vlapic = vm_lapic(vcpu);
  211         error = vlapic_write(vlapic, 1, off, wval, arg);
  212         return (error);
  213 }
  214 
  215 int
  216 lapic_mmio_read(struct vcpu *vcpu, uint64_t gpa, uint64_t *rval, int size,
  217                 void *arg)
  218 {
  219         int error;
  220         uint64_t off;
  221         struct vlapic *vlapic;
  222 
  223         off = gpa - DEFAULT_APIC_BASE;
  224 
  225         /*
  226          * Memory mapped local apic accesses should be aligned on a
  227          * 16-byte boundary.  They are also suggested to be 4 bytes
  228          * wide, alas not all OSes follow suggestions.
  229          */
  230         off &= ~3;
  231         if (off & 0xf)
  232                 return (EINVAL);
  233 
  234         vlapic = vm_lapic(vcpu);
  235         error = vlapic_read(vlapic, 1, off, rval, arg);
  236         return (error);
  237 }

Cache object: fc33b738e3cc386ecd5c72d1e7cccc7f


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