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  * Copyright (c) 2011 NetApp, Inc.
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
   18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  *
   26  * $FreeBSD: releng/11.0/sys/amd64/vmm/vmm_lapic.c 281630 2015-04-16 22:44:51Z neel $
   27  */
   28 
   29 #include <sys/cdefs.h>
   30 __FBSDID("$FreeBSD: releng/11.0/sys/amd64/vmm/vmm_lapic.c 281630 2015-04-16 22:44:51Z neel $");
   31 
   32 #include <sys/param.h>
   33 #include <sys/systm.h>
   34 #include <sys/smp.h>
   35 
   36 #include <x86/specialreg.h>
   37 #include <x86/apicreg.h>
   38 
   39 #include <machine/vmm.h>
   40 #include "vmm_ktr.h"
   41 #include "vmm_lapic.h"
   42 #include "vlapic.h"
   43 
   44 /*
   45  * Some MSI message definitions
   46  */
   47 #define MSI_X86_ADDR_MASK       0xfff00000
   48 #define MSI_X86_ADDR_BASE       0xfee00000
   49 #define MSI_X86_ADDR_RH         0x00000008      /* Redirection Hint */
   50 #define MSI_X86_ADDR_LOG        0x00000004      /* Destination Mode */
   51 
   52 int
   53 lapic_set_intr(struct vm *vm, int cpu, int vector, bool level)
   54 {
   55         struct vlapic *vlapic;
   56 
   57         if (cpu < 0 || cpu >= VM_MAXCPU)
   58                 return (EINVAL);
   59 
   60         /*
   61          * According to section "Maskable Hardware Interrupts" in Intel SDM
   62          * vectors 16 through 255 can be delivered through the local APIC.
   63          */
   64         if (vector < 16 || vector > 255)
   65                 return (EINVAL);
   66 
   67         vlapic = vm_lapic(vm, cpu);
   68         if (vlapic_set_intr_ready(vlapic, vector, level))
   69                 vcpu_notify_event(vm, cpu, true);
   70         return (0);
   71 }
   72 
   73 int
   74 lapic_set_local_intr(struct vm *vm, int cpu, int vector)
   75 {
   76         struct vlapic *vlapic;
   77         cpuset_t dmask;
   78         int error;
   79 
   80         if (cpu < -1 || cpu >= VM_MAXCPU)
   81                 return (EINVAL);
   82 
   83         if (cpu == -1)
   84                 dmask = vm_active_cpus(vm);
   85         else
   86                 CPU_SETOF(cpu, &dmask);
   87         error = 0;
   88         while ((cpu = CPU_FFS(&dmask)) != 0) {
   89                 cpu--;
   90                 CPU_CLR(cpu, &dmask);
   91                 vlapic = vm_lapic(vm, cpu);
   92                 error = vlapic_trigger_lvt(vlapic, vector);
   93                 if (error)
   94                         break;
   95         }
   96 
   97         return (error);
   98 }
   99 
  100 int
  101 lapic_intr_msi(struct vm *vm, uint64_t addr, uint64_t msg)
  102 {
  103         int delmode, vec;
  104         uint32_t dest;
  105         bool phys;
  106 
  107         VM_CTR2(vm, "lapic MSI addr: %#lx msg: %#lx", addr, msg);
  108 
  109         if ((addr & MSI_X86_ADDR_MASK) != MSI_X86_ADDR_BASE) {
  110                 VM_CTR1(vm, "lapic MSI invalid addr %#lx", addr);
  111                 return (-1);
  112         }
  113 
  114         /*
  115          * Extract the x86-specific fields from the MSI addr/msg
  116          * params according to the Intel Arch spec, Vol3 Ch 10.
  117          *
  118          * The PCI specification does not support level triggered
  119          * MSI/MSI-X so ignore trigger level in 'msg'.
  120          *
  121          * The 'dest' is interpreted as a logical APIC ID if both
  122          * the Redirection Hint and Destination Mode are '1' and
  123          * physical otherwise.
  124          */
  125         dest = (addr >> 12) & 0xff;
  126         phys = ((addr & (MSI_X86_ADDR_RH | MSI_X86_ADDR_LOG)) !=
  127             (MSI_X86_ADDR_RH | MSI_X86_ADDR_LOG));
  128         delmode = msg & APIC_DELMODE_MASK;
  129         vec = msg & 0xff;
  130 
  131         VM_CTR3(vm, "lapic MSI %s dest %#x, vec %d",
  132             phys ? "physical" : "logical", dest, vec);
  133 
  134         vlapic_deliver_intr(vm, LAPIC_TRIG_EDGE, dest, phys, delmode, vec);
  135         return (0);
  136 }
  137 
  138 static boolean_t
  139 x2apic_msr(u_int msr)
  140 {
  141         if (msr >= 0x800 && msr <= 0xBFF)
  142                 return (TRUE);
  143         else
  144                 return (FALSE);
  145 }
  146 
  147 static u_int
  148 x2apic_msr_to_regoff(u_int msr)
  149 {
  150 
  151         return ((msr - 0x800) << 4);
  152 }
  153 
  154 boolean_t
  155 lapic_msr(u_int msr)
  156 {
  157 
  158         if (x2apic_msr(msr) || (msr == MSR_APICBASE))
  159                 return (TRUE);
  160         else
  161                 return (FALSE);
  162 }
  163 
  164 int
  165 lapic_rdmsr(struct vm *vm, int cpu, u_int msr, uint64_t *rval, bool *retu)
  166 {
  167         int error;
  168         u_int offset;
  169         struct vlapic *vlapic;
  170 
  171         vlapic = vm_lapic(vm, cpu);
  172 
  173         if (msr == MSR_APICBASE) {
  174                 *rval = vlapic_get_apicbase(vlapic);
  175                 error = 0;
  176         } else {
  177                 offset = x2apic_msr_to_regoff(msr);
  178                 error = vlapic_read(vlapic, 0, offset, rval, retu);
  179         }
  180 
  181         return (error);
  182 }
  183 
  184 int
  185 lapic_wrmsr(struct vm *vm, int cpu, u_int msr, uint64_t val, bool *retu)
  186 {
  187         int error;
  188         u_int offset;
  189         struct vlapic *vlapic;
  190 
  191         vlapic = vm_lapic(vm, cpu);
  192 
  193         if (msr == MSR_APICBASE) {
  194                 error = vlapic_set_apicbase(vlapic, val);
  195         } else {
  196                 offset = x2apic_msr_to_regoff(msr);
  197                 error = vlapic_write(vlapic, 0, offset, val, retu);
  198         }
  199 
  200         return (error);
  201 }
  202 
  203 int
  204 lapic_mmio_write(void *vm, int cpu, uint64_t gpa, uint64_t wval, int size,
  205                  void *arg)
  206 {
  207         int error;
  208         uint64_t off;
  209         struct vlapic *vlapic;
  210 
  211         off = gpa - DEFAULT_APIC_BASE;
  212 
  213         /*
  214          * Memory mapped local apic accesses must be 4 bytes wide and
  215          * aligned on a 16-byte boundary.
  216          */
  217         if (size != 4 || off & 0xf)
  218                 return (EINVAL);
  219 
  220         vlapic = vm_lapic(vm, cpu);
  221         error = vlapic_write(vlapic, 1, off, wval, arg);
  222         return (error);
  223 }
  224 
  225 int
  226 lapic_mmio_read(void *vm, int cpu, uint64_t gpa, uint64_t *rval, int size,
  227                 void *arg)
  228 {
  229         int error;
  230         uint64_t off;
  231         struct vlapic *vlapic;
  232 
  233         off = gpa - DEFAULT_APIC_BASE;
  234 
  235         /*
  236          * Memory mapped local apic accesses should be aligned on a
  237          * 16-byte boundary.  They are also suggested to be 4 bytes
  238          * wide, alas not all OSes follow suggestions.
  239          */
  240         off &= ~3;
  241         if (off & 0xf)
  242                 return (EINVAL);
  243 
  244         vlapic = vm_lapic(vm, cpu);
  245         error = vlapic_read(vlapic, 1, off, rval, arg);
  246         return (error);
  247 }

Cache object: d5748cb4c6ba54d97a1807d133113202


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