1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 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 /* 29 * This file and its contents are supplied under the terms of the 30 * Common Development and Distribution License ("CDDL"), version 1.0. 31 * You may only use this file in accordance with the terms of version 32 * 1.0 of the CDDL. 33 * 34 * A full copy of the text of the CDDL should have accompanied this 35 * source. A copy of the CDDL is also available via the Internet at 36 * http://www.illumos.org/license/CDDL. 37 * 38 * Copyright 2014 Pluribus Networks Inc. 39 * Copyright 2020 Oxide Computer Company 40 */ 41 42 #include <sys/cdefs.h> 43 44 #include <sys/param.h> 45 #include <sys/systm.h> 46 #include <sys/cpuset.h> 47 48 #include <x86/specialreg.h> 49 #include <x86/apicreg.h> 50 51 #include <machine/vmm.h> 52 #include "vmm_lapic.h" 53 #include "vlapic.h" 54 55 /* 56 * Some MSI message definitions 57 */ 58 #define MSI_X86_ADDR_MASK 0xfff00000 59 #define MSI_X86_ADDR_BASE 0xfee00000 60 #define MSI_X86_ADDR_RH 0x00000008 /* Redirection Hint */ 61 #define MSI_X86_ADDR_LOG 0x00000004 /* Destination Mode */ 62 63 int 64 lapic_set_intr(struct vm *vm, int cpu, int vector, bool level) 65 { 66 struct vlapic *vlapic; 67 vcpu_notify_t notify; 68 69 if (cpu < 0 || cpu >= vm_get_maxcpus(vm)) 70 return (EINVAL); 71 72 /* 73 * According to section "Maskable Hardware Interrupts" in Intel SDM 74 * vectors 16 through 255 can be delivered through the local APIC. 75 */ 76 if (vector < 16 || vector > 255) 77 return (EINVAL); 78 79 vlapic = vm_lapic(vm, cpu); 80 notify = vlapic_set_intr_ready(vlapic, vector, level); 81 vcpu_notify_event_type(vm, cpu, notify); 82 return (0); 83 } 84 85 int 86 lapic_set_local_intr(struct vm *vm, int cpu, int vector) 87 { 88 struct vlapic *vlapic; 89 cpuset_t dmask; 90 int error; 91 92 if (cpu < -1 || cpu >= vm_get_maxcpus(vm)) 93 return (EINVAL); 94 95 if (cpu == -1) 96 dmask = vm_active_cpus(vm); 97 else 98 CPU_SETOF(cpu, &dmask); 99 error = 0; 100 while ((cpu = CPU_FFS(&dmask)) != 0) { 101 cpu--; 102 CPU_CLR(cpu, &dmask); 103 vlapic = vm_lapic(vm, cpu); 104 error = vlapic_trigger_lvt(vlapic, vector); 105 if (error) 106 break; 107 } 108 109 return (error); 110 } 111 112 int 113 lapic_intr_msi(struct vm *vm, uint64_t addr, uint64_t msg) 114 { 115 int delmode, vec; 116 uint32_t dest; 117 bool phys; 118 119 if ((addr & MSI_X86_ADDR_MASK) != MSI_X86_ADDR_BASE) { 120 /* Invalid MSI address */ 121 return (-1); 122 } 123 124 /* 125 * Extract the x86-specific fields from the MSI addr/msg params 126 * according to the Intel Arch spec, Vol3 Ch 10. 127 * 128 * The PCI specification does not support level triggered MSI/MSI-X so 129 * ignore trigger level in 'msg'. 130 * 131 * Certain kinds of interrupt broadcasts (physical or logical-clustered 132 * for destination 0xff) are prohibited when the redirection hint bit is 133 * set for a given message. Those edge cases are ignored for now. 134 */ 135 dest = (addr >> 12) & 0xff; 136 phys = (addr & MSI_X86_ADDR_LOG) == 0; 137 delmode = msg & APIC_DELMODE_MASK; 138 vec = msg & 0xff; 139 140 vlapic_deliver_intr(vm, LAPIC_TRIG_EDGE, dest, phys, delmode, vec); 141 return (0); 142 } 143