1*565bbb86SNeel Natu /*- 2*565bbb86SNeel Natu * Copyright (c) 2013 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com> 3*565bbb86SNeel Natu * Copyright (c) 2013 Neel Natu <neel@freebsd.org> 4*565bbb86SNeel Natu * All rights reserved. 5*565bbb86SNeel Natu * 6*565bbb86SNeel Natu * Redistribution and use in source and binary forms, with or without 7*565bbb86SNeel Natu * modification, are permitted provided that the following conditions 8*565bbb86SNeel Natu * are met: 9*565bbb86SNeel Natu * 1. Redistributions of source code must retain the above copyright 10*565bbb86SNeel Natu * notice, this list of conditions and the following disclaimer. 11*565bbb86SNeel Natu * 2. Redistributions in binary form must reproduce the above copyright 12*565bbb86SNeel Natu * notice, this list of conditions and the following disclaimer in the 13*565bbb86SNeel Natu * documentation and/or other materials provided with the distribution. 14*565bbb86SNeel Natu * 15*565bbb86SNeel Natu * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND 16*565bbb86SNeel Natu * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17*565bbb86SNeel Natu * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18*565bbb86SNeel Natu * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE 19*565bbb86SNeel Natu * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20*565bbb86SNeel Natu * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21*565bbb86SNeel Natu * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22*565bbb86SNeel Natu * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23*565bbb86SNeel Natu * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24*565bbb86SNeel Natu * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25*565bbb86SNeel Natu * SUCH DAMAGE. 26*565bbb86SNeel Natu * 27*565bbb86SNeel Natu * $FreeBSD$ 28*565bbb86SNeel Natu */ 29*565bbb86SNeel Natu 30*565bbb86SNeel Natu #include <sys/cdefs.h> 31*565bbb86SNeel Natu __FBSDID("$FreeBSD$"); 32*565bbb86SNeel Natu 33*565bbb86SNeel Natu #include <sys/param.h> 34*565bbb86SNeel Natu #include <sys/queue.h> 35*565bbb86SNeel Natu #include <sys/cpuset.h> 36*565bbb86SNeel Natu #include <sys/lock.h> 37*565bbb86SNeel Natu #include <sys/mutex.h> 38*565bbb86SNeel Natu #include <sys/systm.h> 39*565bbb86SNeel Natu #include <sys/kernel.h> 40*565bbb86SNeel Natu #include <sys/malloc.h> 41*565bbb86SNeel Natu 42*565bbb86SNeel Natu #include <x86/apicreg.h> 43*565bbb86SNeel Natu #include <machine/vmm.h> 44*565bbb86SNeel Natu 45*565bbb86SNeel Natu #include "vmm_ktr.h" 46*565bbb86SNeel Natu #include "vmm_lapic.h" 47*565bbb86SNeel Natu #include "vioapic.h" 48*565bbb86SNeel Natu 49*565bbb86SNeel Natu #define IOREGSEL 0x00 50*565bbb86SNeel Natu #define IOWIN 0x10 51*565bbb86SNeel Natu 52*565bbb86SNeel Natu #define REDIR_ENTRIES 16 53*565bbb86SNeel Natu #define INTR_ASSERTED(vioapic, pin) ((vioapic)->rtbl[(pin)].pinstate == true) 54*565bbb86SNeel Natu 55*565bbb86SNeel Natu struct vioapic { 56*565bbb86SNeel Natu struct vm *vm; 57*565bbb86SNeel Natu struct mtx mtx; 58*565bbb86SNeel Natu uint32_t id; 59*565bbb86SNeel Natu uint32_t ioregsel; 60*565bbb86SNeel Natu struct { 61*565bbb86SNeel Natu uint64_t reg; 62*565bbb86SNeel Natu bool pinstate; 63*565bbb86SNeel Natu bool pending; 64*565bbb86SNeel Natu } rtbl[REDIR_ENTRIES]; 65*565bbb86SNeel Natu }; 66*565bbb86SNeel Natu 67*565bbb86SNeel Natu #define VIOAPIC_LOCK(vioapic) mtx_lock(&((vioapic)->mtx)) 68*565bbb86SNeel Natu #define VIOAPIC_UNLOCK(vioapic) mtx_unlock(&((vioapic)->mtx)) 69*565bbb86SNeel Natu #define VIOAPIC_LOCKED(vioapic) mtx_owned(&((vioapic)->mtx)) 70*565bbb86SNeel Natu 71*565bbb86SNeel Natu static MALLOC_DEFINE(M_VIOAPIC, "vioapic", "bhyve virtual ioapic"); 72*565bbb86SNeel Natu 73*565bbb86SNeel Natu #define VIOAPIC_CTR1(vioapic, fmt, a1) \ 74*565bbb86SNeel Natu VM_CTR1((vioapic)->vm, fmt, a1) 75*565bbb86SNeel Natu 76*565bbb86SNeel Natu #define VIOAPIC_CTR2(vioapic, fmt, a1, a2) \ 77*565bbb86SNeel Natu VM_CTR2((vioapic)->vm, fmt, a1, a2) 78*565bbb86SNeel Natu 79*565bbb86SNeel Natu #define VIOAPIC_CTR3(vioapic, fmt, a1, a2, a3) \ 80*565bbb86SNeel Natu VM_CTR3((vioapic)->vm, fmt, a1, a2, a3) 81*565bbb86SNeel Natu 82*565bbb86SNeel Natu #ifdef KTR 83*565bbb86SNeel Natu static const char * 84*565bbb86SNeel Natu pinstate_str(bool asserted) 85*565bbb86SNeel Natu { 86*565bbb86SNeel Natu 87*565bbb86SNeel Natu if (asserted) 88*565bbb86SNeel Natu return ("asserted"); 89*565bbb86SNeel Natu else 90*565bbb86SNeel Natu return ("deasserted"); 91*565bbb86SNeel Natu } 92*565bbb86SNeel Natu #endif 93*565bbb86SNeel Natu 94*565bbb86SNeel Natu static void 95*565bbb86SNeel Natu vioapic_set_pinstate(struct vioapic *vioapic, int pin, bool newstate) 96*565bbb86SNeel Natu { 97*565bbb86SNeel Natu int vector, apicid, vcpuid; 98*565bbb86SNeel Natu uint32_t low, high; 99*565bbb86SNeel Natu cpuset_t dmask; 100*565bbb86SNeel Natu 101*565bbb86SNeel Natu KASSERT(pin >= 0 && pin < REDIR_ENTRIES, 102*565bbb86SNeel Natu ("vioapic_set_pinstate: invalid pin number %d", pin)); 103*565bbb86SNeel Natu 104*565bbb86SNeel Natu KASSERT(VIOAPIC_LOCKED(vioapic), 105*565bbb86SNeel Natu ("vioapic_set_pinstate: vioapic is not locked")); 106*565bbb86SNeel Natu 107*565bbb86SNeel Natu VIOAPIC_CTR2(vioapic, "ioapic pin%d %s", pin, pinstate_str(newstate)); 108*565bbb86SNeel Natu 109*565bbb86SNeel Natu /* Nothing to do if interrupt pin has not changed state */ 110*565bbb86SNeel Natu if (vioapic->rtbl[pin].pinstate == newstate) 111*565bbb86SNeel Natu return; 112*565bbb86SNeel Natu 113*565bbb86SNeel Natu vioapic->rtbl[pin].pinstate = newstate; /* record it */ 114*565bbb86SNeel Natu 115*565bbb86SNeel Natu /* Nothing to do if interrupt pin is deasserted */ 116*565bbb86SNeel Natu if (!INTR_ASSERTED(vioapic, pin)) 117*565bbb86SNeel Natu return; 118*565bbb86SNeel Natu 119*565bbb86SNeel Natu /* 120*565bbb86SNeel Natu * XXX 121*565bbb86SNeel Natu * We only deal with: 122*565bbb86SNeel Natu * - edge triggered interrupts 123*565bbb86SNeel Natu * - fixed delivery mode 124*565bbb86SNeel Natu * Level-triggered sources will work so long as there is no sharing. 125*565bbb86SNeel Natu */ 126*565bbb86SNeel Natu low = vioapic->rtbl[pin].reg; 127*565bbb86SNeel Natu high = vioapic->rtbl[pin].reg >> 32; 128*565bbb86SNeel Natu if ((low & IOART_INTMASK) == IOART_INTMCLR && 129*565bbb86SNeel Natu (low & IOART_DESTMOD) == IOART_DESTPHY && 130*565bbb86SNeel Natu (low & IOART_DELMOD) == IOART_DELFIXED) { 131*565bbb86SNeel Natu vector = low & IOART_INTVEC; 132*565bbb86SNeel Natu apicid = high >> APIC_ID_SHIFT; 133*565bbb86SNeel Natu if (apicid != 0xff) { 134*565bbb86SNeel Natu /* unicast */ 135*565bbb86SNeel Natu vcpuid = vm_apicid2vcpuid(vioapic->vm, apicid); 136*565bbb86SNeel Natu VIOAPIC_CTR3(vioapic, "ioapic pin%d triggering " 137*565bbb86SNeel Natu "intr vector %d on vcpuid %d", pin, vector, vcpuid); 138*565bbb86SNeel Natu lapic_set_intr(vioapic->vm, vcpuid, vector); 139*565bbb86SNeel Natu } else { 140*565bbb86SNeel Natu /* broadcast */ 141*565bbb86SNeel Natu VIOAPIC_CTR2(vioapic, "ioapic pin%d triggering intr " 142*565bbb86SNeel Natu "vector %d on all vcpus", pin, vector); 143*565bbb86SNeel Natu dmask = vm_active_cpus(vioapic->vm); 144*565bbb86SNeel Natu while ((vcpuid = CPU_FFS(&dmask)) != 0) { 145*565bbb86SNeel Natu vcpuid--; 146*565bbb86SNeel Natu CPU_CLR(vcpuid, &dmask); 147*565bbb86SNeel Natu lapic_set_intr(vioapic->vm, vcpuid, vector); 148*565bbb86SNeel Natu } 149*565bbb86SNeel Natu } 150*565bbb86SNeel Natu } else if ((low & IOART_INTMASK) != IOART_INTMCLR && 151*565bbb86SNeel Natu (low & IOART_TRGRLVL) != 0) { 152*565bbb86SNeel Natu /* 153*565bbb86SNeel Natu * For level-triggered interrupts that have been 154*565bbb86SNeel Natu * masked, set the pending bit so that an interrupt 155*565bbb86SNeel Natu * will be generated on unmask and if the level is 156*565bbb86SNeel Natu * still asserted 157*565bbb86SNeel Natu */ 158*565bbb86SNeel Natu VIOAPIC_CTR1(vioapic, "ioapic pin%d interrupt pending", pin); 159*565bbb86SNeel Natu vioapic->rtbl[pin].pending = true; 160*565bbb86SNeel Natu } 161*565bbb86SNeel Natu } 162*565bbb86SNeel Natu 163*565bbb86SNeel Natu static int 164*565bbb86SNeel Natu vioapic_set_irqstate(struct vm *vm, int irq, bool state) 165*565bbb86SNeel Natu { 166*565bbb86SNeel Natu struct vioapic *vioapic; 167*565bbb86SNeel Natu 168*565bbb86SNeel Natu if (irq < 0 || irq >= REDIR_ENTRIES) 169*565bbb86SNeel Natu return (EINVAL); 170*565bbb86SNeel Natu 171*565bbb86SNeel Natu vioapic = vm_ioapic(vm); 172*565bbb86SNeel Natu 173*565bbb86SNeel Natu VIOAPIC_LOCK(vioapic); 174*565bbb86SNeel Natu vioapic_set_pinstate(vioapic, irq, state); 175*565bbb86SNeel Natu VIOAPIC_UNLOCK(vioapic); 176*565bbb86SNeel Natu 177*565bbb86SNeel Natu return (0); 178*565bbb86SNeel Natu } 179*565bbb86SNeel Natu 180*565bbb86SNeel Natu int 181*565bbb86SNeel Natu vioapic_assert_irq(struct vm *vm, int irq) 182*565bbb86SNeel Natu { 183*565bbb86SNeel Natu 184*565bbb86SNeel Natu return (vioapic_set_irqstate(vm, irq, true)); 185*565bbb86SNeel Natu } 186*565bbb86SNeel Natu 187*565bbb86SNeel Natu int 188*565bbb86SNeel Natu vioapic_deassert_irq(struct vm *vm, int irq) 189*565bbb86SNeel Natu { 190*565bbb86SNeel Natu 191*565bbb86SNeel Natu return (vioapic_set_irqstate(vm, irq, false)); 192*565bbb86SNeel Natu } 193*565bbb86SNeel Natu 194*565bbb86SNeel Natu static uint32_t 195*565bbb86SNeel Natu vioapic_read(struct vioapic *vioapic, uint32_t addr) 196*565bbb86SNeel Natu { 197*565bbb86SNeel Natu int regnum, pin, rshift; 198*565bbb86SNeel Natu 199*565bbb86SNeel Natu regnum = addr & 0xff; 200*565bbb86SNeel Natu switch (regnum) { 201*565bbb86SNeel Natu case IOAPIC_ID: 202*565bbb86SNeel Natu return (vioapic->id); 203*565bbb86SNeel Natu break; 204*565bbb86SNeel Natu case IOAPIC_VER: 205*565bbb86SNeel Natu return ((REDIR_ENTRIES << MAXREDIRSHIFT) | 0x11); 206*565bbb86SNeel Natu break; 207*565bbb86SNeel Natu case IOAPIC_ARB: 208*565bbb86SNeel Natu return (vioapic->id); 209*565bbb86SNeel Natu break; 210*565bbb86SNeel Natu default: 211*565bbb86SNeel Natu break; 212*565bbb86SNeel Natu } 213*565bbb86SNeel Natu 214*565bbb86SNeel Natu /* redirection table entries */ 215*565bbb86SNeel Natu if (regnum >= IOAPIC_REDTBL && 216*565bbb86SNeel Natu regnum < IOAPIC_REDTBL + REDIR_ENTRIES * 2) { 217*565bbb86SNeel Natu pin = (regnum - IOAPIC_REDTBL) / 2; 218*565bbb86SNeel Natu if ((regnum - IOAPIC_REDTBL) % 2) 219*565bbb86SNeel Natu rshift = 32; 220*565bbb86SNeel Natu else 221*565bbb86SNeel Natu rshift = 0; 222*565bbb86SNeel Natu 223*565bbb86SNeel Natu return (vioapic->rtbl[pin].reg >> rshift); 224*565bbb86SNeel Natu } 225*565bbb86SNeel Natu 226*565bbb86SNeel Natu return (0); 227*565bbb86SNeel Natu } 228*565bbb86SNeel Natu 229*565bbb86SNeel Natu static void 230*565bbb86SNeel Natu vioapic_write(struct vioapic *vioapic, uint32_t addr, uint32_t data) 231*565bbb86SNeel Natu { 232*565bbb86SNeel Natu int regnum, pin, lshift; 233*565bbb86SNeel Natu 234*565bbb86SNeel Natu regnum = addr & 0xff; 235*565bbb86SNeel Natu switch (regnum) { 236*565bbb86SNeel Natu case IOAPIC_ID: 237*565bbb86SNeel Natu vioapic->id = data & APIC_ID_MASK; 238*565bbb86SNeel Natu break; 239*565bbb86SNeel Natu case IOAPIC_VER: 240*565bbb86SNeel Natu case IOAPIC_ARB: 241*565bbb86SNeel Natu /* readonly */ 242*565bbb86SNeel Natu break; 243*565bbb86SNeel Natu default: 244*565bbb86SNeel Natu break; 245*565bbb86SNeel Natu } 246*565bbb86SNeel Natu 247*565bbb86SNeel Natu /* redirection table entries */ 248*565bbb86SNeel Natu if (regnum >= IOAPIC_REDTBL && 249*565bbb86SNeel Natu regnum < IOAPIC_REDTBL + REDIR_ENTRIES * 2) { 250*565bbb86SNeel Natu pin = (regnum - IOAPIC_REDTBL) / 2; 251*565bbb86SNeel Natu if ((regnum - IOAPIC_REDTBL) % 2) 252*565bbb86SNeel Natu lshift = 32; 253*565bbb86SNeel Natu else 254*565bbb86SNeel Natu lshift = 0; 255*565bbb86SNeel Natu 256*565bbb86SNeel Natu vioapic->rtbl[pin].reg &= ~((uint64_t)0xffffffff << lshift); 257*565bbb86SNeel Natu vioapic->rtbl[pin].reg |= ((uint64_t)data << lshift); 258*565bbb86SNeel Natu 259*565bbb86SNeel Natu VIOAPIC_CTR2(vioapic, "ioapic pin%d redir table entry %#lx", 260*565bbb86SNeel Natu pin, vioapic->rtbl[pin].reg); 261*565bbb86SNeel Natu 262*565bbb86SNeel Natu if (vioapic->rtbl[pin].pending && 263*565bbb86SNeel Natu ((vioapic->rtbl[pin].reg & IOART_INTMASK) == 264*565bbb86SNeel Natu IOART_INTMCLR)) { 265*565bbb86SNeel Natu vioapic->rtbl[pin].pending = false; 266*565bbb86SNeel Natu /* 267*565bbb86SNeel Natu * Inject the deferred level-triggered int if it is 268*565bbb86SNeel Natu * still asserted. Simulate by toggling the pin 269*565bbb86SNeel Natu * off and then on. 270*565bbb86SNeel Natu */ 271*565bbb86SNeel Natu if (vioapic->rtbl[pin].pinstate == true) { 272*565bbb86SNeel Natu VIOAPIC_CTR1(vioapic, "ioapic pin%d pending " 273*565bbb86SNeel Natu "interrupt delivered", pin); 274*565bbb86SNeel Natu vioapic_set_pinstate(vioapic, pin, false); 275*565bbb86SNeel Natu vioapic_set_pinstate(vioapic, pin, true); 276*565bbb86SNeel Natu } else { 277*565bbb86SNeel Natu VIOAPIC_CTR1(vioapic, "ioapic pin%d pending " 278*565bbb86SNeel Natu "interrupt dismissed", pin); 279*565bbb86SNeel Natu } 280*565bbb86SNeel Natu } 281*565bbb86SNeel Natu } 282*565bbb86SNeel Natu } 283*565bbb86SNeel Natu 284*565bbb86SNeel Natu static int 285*565bbb86SNeel Natu vioapic_mmio_rw(struct vioapic *vioapic, uint64_t gpa, uint64_t *data, 286*565bbb86SNeel Natu int size, bool doread) 287*565bbb86SNeel Natu { 288*565bbb86SNeel Natu uint64_t offset; 289*565bbb86SNeel Natu 290*565bbb86SNeel Natu offset = gpa - VIOAPIC_BASE; 291*565bbb86SNeel Natu 292*565bbb86SNeel Natu /* 293*565bbb86SNeel Natu * The IOAPIC specification allows 32-bit wide accesses to the 294*565bbb86SNeel Natu * IOREGSEL (offset 0) and IOWIN (offset 16) registers. 295*565bbb86SNeel Natu */ 296*565bbb86SNeel Natu if (size != 4 || (offset != IOREGSEL && offset != IOWIN)) { 297*565bbb86SNeel Natu if (doread) 298*565bbb86SNeel Natu *data = 0; 299*565bbb86SNeel Natu return (0); 300*565bbb86SNeel Natu } 301*565bbb86SNeel Natu 302*565bbb86SNeel Natu VIOAPIC_LOCK(vioapic); 303*565bbb86SNeel Natu if (offset == IOREGSEL) { 304*565bbb86SNeel Natu if (doread) 305*565bbb86SNeel Natu *data = vioapic->ioregsel; 306*565bbb86SNeel Natu else 307*565bbb86SNeel Natu vioapic->ioregsel = *data; 308*565bbb86SNeel Natu } else { 309*565bbb86SNeel Natu if (doread) 310*565bbb86SNeel Natu *data = vioapic_read(vioapic, vioapic->ioregsel); 311*565bbb86SNeel Natu else 312*565bbb86SNeel Natu vioapic_write(vioapic, vioapic->ioregsel, *data); 313*565bbb86SNeel Natu } 314*565bbb86SNeel Natu VIOAPIC_UNLOCK(vioapic); 315*565bbb86SNeel Natu 316*565bbb86SNeel Natu return (0); 317*565bbb86SNeel Natu } 318*565bbb86SNeel Natu 319*565bbb86SNeel Natu int 320*565bbb86SNeel Natu vioapic_mmio_read(void *vm, int vcpuid, uint64_t gpa, uint64_t *rval, 321*565bbb86SNeel Natu int size, void *arg) 322*565bbb86SNeel Natu { 323*565bbb86SNeel Natu int error; 324*565bbb86SNeel Natu struct vioapic *vioapic; 325*565bbb86SNeel Natu 326*565bbb86SNeel Natu vioapic = vm_ioapic(vm); 327*565bbb86SNeel Natu error = vioapic_mmio_rw(vioapic, gpa, rval, size, true); 328*565bbb86SNeel Natu return (error); 329*565bbb86SNeel Natu } 330*565bbb86SNeel Natu 331*565bbb86SNeel Natu int 332*565bbb86SNeel Natu vioapic_mmio_write(void *vm, int vcpuid, uint64_t gpa, uint64_t wval, 333*565bbb86SNeel Natu int size, void *arg) 334*565bbb86SNeel Natu { 335*565bbb86SNeel Natu int error; 336*565bbb86SNeel Natu struct vioapic *vioapic; 337*565bbb86SNeel Natu 338*565bbb86SNeel Natu vioapic = vm_ioapic(vm); 339*565bbb86SNeel Natu error = vioapic_mmio_rw(vioapic, gpa, &wval, size, false); 340*565bbb86SNeel Natu return (error); 341*565bbb86SNeel Natu } 342*565bbb86SNeel Natu 343*565bbb86SNeel Natu struct vioapic * 344*565bbb86SNeel Natu vioapic_init(struct vm *vm) 345*565bbb86SNeel Natu { 346*565bbb86SNeel Natu int i; 347*565bbb86SNeel Natu struct vioapic *vioapic; 348*565bbb86SNeel Natu 349*565bbb86SNeel Natu vioapic = malloc(sizeof(struct vioapic), M_VIOAPIC, M_WAITOK | M_ZERO); 350*565bbb86SNeel Natu 351*565bbb86SNeel Natu vioapic->vm = vm; 352*565bbb86SNeel Natu mtx_init(&vioapic->mtx, "vioapic lock", NULL, MTX_DEF); 353*565bbb86SNeel Natu 354*565bbb86SNeel Natu /* Initialize all redirection entries to mask all interrupts */ 355*565bbb86SNeel Natu for (i = 0; i < REDIR_ENTRIES; i++) 356*565bbb86SNeel Natu vioapic->rtbl[i].reg = 0x0001000000010000UL; 357*565bbb86SNeel Natu 358*565bbb86SNeel Natu return (vioapic); 359*565bbb86SNeel Natu } 360*565bbb86SNeel Natu 361*565bbb86SNeel Natu void 362*565bbb86SNeel Natu vioapic_cleanup(struct vioapic *vioapic) 363*565bbb86SNeel Natu { 364*565bbb86SNeel Natu 365*565bbb86SNeel Natu free(vioapic, M_VIOAPIC); 366*565bbb86SNeel Natu } 367