vmm_lapic.c revision 284899
1221828Sgrehan/*- 2221828Sgrehan * Copyright (c) 2011 NetApp, Inc. 3221828Sgrehan * All rights reserved. 4221828Sgrehan * 5221828Sgrehan * Redistribution and use in source and binary forms, with or without 6221828Sgrehan * modification, are permitted provided that the following conditions 7221828Sgrehan * are met: 8221828Sgrehan * 1. Redistributions of source code must retain the above copyright 9221828Sgrehan * notice, this list of conditions and the following disclaimer. 10221828Sgrehan * 2. Redistributions in binary form must reproduce the above copyright 11221828Sgrehan * notice, this list of conditions and the following disclaimer in the 12221828Sgrehan * documentation and/or other materials provided with the distribution. 13221828Sgrehan * 14221828Sgrehan * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND 15221828Sgrehan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16221828Sgrehan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17221828Sgrehan * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE 18221828Sgrehan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19221828Sgrehan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20221828Sgrehan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21221828Sgrehan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22221828Sgrehan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23221828Sgrehan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24221828Sgrehan * SUCH DAMAGE. 25221828Sgrehan * 26221828Sgrehan * $FreeBSD: stable/10/sys/amd64/vmm/vmm_lapic.c 284899 2015-06-28 01:21:55Z neel $ 27221828Sgrehan */ 28221828Sgrehan 29221828Sgrehan#include <sys/cdefs.h> 30221828Sgrehan__FBSDID("$FreeBSD: stable/10/sys/amd64/vmm/vmm_lapic.c 284899 2015-06-28 01:21:55Z neel $"); 31221828Sgrehan 32221828Sgrehan#include <sys/param.h> 33221828Sgrehan#include <sys/systm.h> 34223621Sgrehan#include <sys/smp.h> 35221828Sgrehan 36240772Sneel#include <x86/specialreg.h> 37243640Sneel#include <x86/apicreg.h> 38240772Sneel 39221828Sgrehan#include <machine/vmm.h> 40221828Sgrehan#include "vmm_ipi.h" 41262350Sjhb#include "vmm_ktr.h" 42221828Sgrehan#include "vmm_lapic.h" 43221828Sgrehan#include "vlapic.h" 44221828Sgrehan 45262350Sjhb/* 46262350Sjhb * Some MSI message definitions 47262350Sjhb */ 48262350Sjhb#define MSI_X86_ADDR_MASK 0xfff00000 49262350Sjhb#define MSI_X86_ADDR_BASE 0xfee00000 50262350Sjhb#define MSI_X86_ADDR_RH 0x00000008 /* Redirection Hint */ 51262350Sjhb#define MSI_X86_ADDR_LOG 0x00000004 /* Destination Mode */ 52262350Sjhb 53221828Sgrehanint 54261088Sjhblapic_set_intr(struct vm *vm, int cpu, int vector, bool level) 55221828Sgrehan{ 56221828Sgrehan struct vlapic *vlapic; 57221828Sgrehan 58221828Sgrehan if (cpu < 0 || cpu >= VM_MAXCPU) 59221828Sgrehan return (EINVAL); 60221828Sgrehan 61284899Sneel /* 62284899Sneel * According to section "Maskable Hardware Interrupts" in Intel SDM 63284899Sneel * vectors 16 through 255 can be delivered through the local APIC. 64284899Sneel */ 65284899Sneel if (vector < 16 || vector > 255) 66221828Sgrehan return (EINVAL); 67221828Sgrehan 68221828Sgrehan vlapic = vm_lapic(vm, cpu); 69266339Sjhb if (vlapic_set_intr_ready(vlapic, vector, level)) 70266339Sjhb vcpu_notify_event(vm, cpu, true); 71221828Sgrehan return (0); 72221828Sgrehan} 73221828Sgrehan 74241766Sneelint 75262350Sjhblapic_set_local_intr(struct vm *vm, int cpu, int vector) 76221828Sgrehan{ 77221828Sgrehan struct vlapic *vlapic; 78262350Sjhb cpuset_t dmask; 79262350Sjhb int error; 80221828Sgrehan 81262350Sjhb if (cpu < -1 || cpu >= VM_MAXCPU) 82262350Sjhb return (EINVAL); 83221828Sgrehan 84262350Sjhb if (cpu == -1) 85262350Sjhb dmask = vm_active_cpus(vm); 86262350Sjhb else 87262350Sjhb CPU_SETOF(cpu, &dmask); 88262350Sjhb error = 0; 89262350Sjhb while ((cpu = CPU_FFS(&dmask)) != 0) { 90262350Sjhb cpu--; 91262350Sjhb CPU_CLR(cpu, &dmask); 92262350Sjhb vlapic = vm_lapic(vm, cpu); 93262350Sjhb error = vlapic_trigger_lvt(vlapic, vector); 94262350Sjhb if (error) 95262350Sjhb break; 96262350Sjhb } 97262350Sjhb 98262350Sjhb return (error); 99221828Sgrehan} 100240772Sneel 101262350Sjhbint 102262350Sjhblapic_intr_msi(struct vm *vm, uint64_t addr, uint64_t msg) 103262350Sjhb{ 104262350Sjhb int delmode, vec; 105262350Sjhb uint32_t dest; 106262350Sjhb bool phys; 107262350Sjhb 108262350Sjhb VM_CTR2(vm, "lapic MSI addr: %#lx msg: %#lx", addr, msg); 109262350Sjhb 110262350Sjhb if ((addr & MSI_X86_ADDR_MASK) != MSI_X86_ADDR_BASE) { 111262350Sjhb VM_CTR1(vm, "lapic MSI invalid addr %#lx", addr); 112262350Sjhb return (-1); 113262350Sjhb } 114262350Sjhb 115262350Sjhb /* 116262350Sjhb * Extract the x86-specific fields from the MSI addr/msg 117262350Sjhb * params according to the Intel Arch spec, Vol3 Ch 10. 118262350Sjhb * 119262350Sjhb * The PCI specification does not support level triggered 120262350Sjhb * MSI/MSI-X so ignore trigger level in 'msg'. 121262350Sjhb * 122262350Sjhb * The 'dest' is interpreted as a logical APIC ID if both 123262350Sjhb * the Redirection Hint and Destination Mode are '1' and 124262350Sjhb * physical otherwise. 125262350Sjhb */ 126262350Sjhb dest = (addr >> 12) & 0xff; 127262350Sjhb phys = ((addr & (MSI_X86_ADDR_RH | MSI_X86_ADDR_LOG)) != 128262350Sjhb (MSI_X86_ADDR_RH | MSI_X86_ADDR_LOG)); 129262350Sjhb delmode = msg & APIC_DELMODE_MASK; 130262350Sjhb vec = msg & 0xff; 131262350Sjhb 132262350Sjhb VM_CTR3(vm, "lapic MSI %s dest %#x, vec %d", 133262350Sjhb phys ? "physical" : "logical", dest, vec); 134262350Sjhb 135262350Sjhb vlapic_deliver_intr(vm, LAPIC_TRIG_EDGE, dest, phys, delmode, vec); 136262350Sjhb return (0); 137262350Sjhb} 138262350Sjhb 139240772Sneelstatic boolean_t 140240772Sneelx2apic_msr(u_int msr) 141240772Sneel{ 142240772Sneel if (msr >= 0x800 && msr <= 0xBFF) 143240772Sneel return (TRUE); 144240772Sneel else 145240772Sneel return (FALSE); 146240772Sneel} 147240772Sneel 148240772Sneelstatic u_int 149240772Sneelx2apic_msr_to_regoff(u_int msr) 150240772Sneel{ 151240772Sneel 152240772Sneel return ((msr - 0x800) << 4); 153240772Sneel} 154240772Sneel 155240772Sneelboolean_t 156240772Sneellapic_msr(u_int msr) 157240772Sneel{ 158240772Sneel 159240772Sneel if (x2apic_msr(msr) || (msr == MSR_APICBASE)) 160240772Sneel return (TRUE); 161240772Sneel else 162240772Sneel return (FALSE); 163240772Sneel} 164240772Sneel 165240772Sneelint 166262350Sjhblapic_rdmsr(struct vm *vm, int cpu, u_int msr, uint64_t *rval, bool *retu) 167240772Sneel{ 168243650Sneel int error; 169243650Sneel u_int offset; 170240772Sneel struct vlapic *vlapic; 171240772Sneel 172240772Sneel vlapic = vm_lapic(vm, cpu); 173240772Sneel 174240772Sneel if (msr == MSR_APICBASE) { 175240772Sneel *rval = vlapic_get_apicbase(vlapic); 176243650Sneel error = 0; 177243650Sneel } else { 178243650Sneel offset = x2apic_msr_to_regoff(msr); 179267447Sjhb error = vlapic_read(vlapic, 0, offset, rval, retu); 180243650Sneel } 181240772Sneel 182243650Sneel return (error); 183240772Sneel} 184240772Sneel 185240772Sneelint 186262350Sjhblapic_wrmsr(struct vm *vm, int cpu, u_int msr, uint64_t val, bool *retu) 187240772Sneel{ 188243650Sneel int error; 189243650Sneel u_int offset; 190240772Sneel struct vlapic *vlapic; 191240772Sneel 192240772Sneel vlapic = vm_lapic(vm, cpu); 193240772Sneel 194240772Sneel if (msr == MSR_APICBASE) { 195267447Sjhb error = vlapic_set_apicbase(vlapic, val); 196243650Sneel } else { 197243650Sneel offset = x2apic_msr_to_regoff(msr); 198267447Sjhb error = vlapic_write(vlapic, 0, offset, val, retu); 199243650Sneel } 200240772Sneel 201243650Sneel return (error); 202240772Sneel} 203240941Sneel 204240941Sneelint 205243640Sneellapic_mmio_write(void *vm, int cpu, uint64_t gpa, uint64_t wval, int size, 206243640Sneel void *arg) 207240941Sneel{ 208243640Sneel int error; 209243640Sneel uint64_t off; 210240941Sneel struct vlapic *vlapic; 211240941Sneel 212243640Sneel off = gpa - DEFAULT_APIC_BASE; 213240941Sneel 214240941Sneel /* 215243640Sneel * Memory mapped local apic accesses must be 4 bytes wide and 216243640Sneel * aligned on a 16-byte boundary. 217240941Sneel */ 218243640Sneel if (size != 4 || off & 0xf) 219243640Sneel return (EINVAL); 220240941Sneel 221243640Sneel vlapic = vm_lapic(vm, cpu); 222267447Sjhb error = vlapic_write(vlapic, 1, off, wval, arg); 223243640Sneel return (error); 224243640Sneel} 225240941Sneel 226243640Sneelint 227243640Sneellapic_mmio_read(void *vm, int cpu, uint64_t gpa, uint64_t *rval, int size, 228243640Sneel void *arg) 229243640Sneel{ 230243640Sneel int error; 231243640Sneel uint64_t off; 232243640Sneel struct vlapic *vlapic; 233240941Sneel 234243640Sneel off = gpa - DEFAULT_APIC_BASE; 235240941Sneel 236243640Sneel /* 237268953Sjhb * Memory mapped local apic accesses should be aligned on a 238268953Sjhb * 16-byte boundary. They are also suggested to be 4 bytes 239268953Sjhb * wide, alas not all OSes follow suggestions. 240243640Sneel */ 241268953Sjhb off &= ~3; 242268953Sjhb if (off & 0xf) 243243640Sneel return (EINVAL); 244240941Sneel 245243640Sneel vlapic = vm_lapic(vm, cpu); 246267447Sjhb error = vlapic_read(vlapic, 1, off, rval, arg); 247243640Sneel return (error); 248240941Sneel} 249