1366f6083SPeter Grehan /*- 2366f6083SPeter Grehan * Copyright (c) 2011 NetApp, Inc. 3366f6083SPeter Grehan * All rights reserved. 4366f6083SPeter Grehan * 5366f6083SPeter Grehan * Redistribution and use in source and binary forms, with or without 6366f6083SPeter Grehan * modification, are permitted provided that the following conditions 7366f6083SPeter Grehan * are met: 8366f6083SPeter Grehan * 1. Redistributions of source code must retain the above copyright 9366f6083SPeter Grehan * notice, this list of conditions and the following disclaimer. 10366f6083SPeter Grehan * 2. Redistributions in binary form must reproduce the above copyright 11366f6083SPeter Grehan * notice, this list of conditions and the following disclaimer in the 12366f6083SPeter Grehan * documentation and/or other materials provided with the distribution. 13366f6083SPeter Grehan * 14366f6083SPeter Grehan * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND 15366f6083SPeter Grehan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16366f6083SPeter Grehan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17366f6083SPeter Grehan * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE 18366f6083SPeter Grehan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19366f6083SPeter Grehan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20366f6083SPeter Grehan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21366f6083SPeter Grehan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22366f6083SPeter Grehan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23366f6083SPeter Grehan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24366f6083SPeter Grehan * SUCH DAMAGE. 25366f6083SPeter Grehan * 26366f6083SPeter Grehan * $FreeBSD$ 27366f6083SPeter Grehan */ 28366f6083SPeter Grehan 29366f6083SPeter Grehan #include <sys/cdefs.h> 30366f6083SPeter Grehan __FBSDID("$FreeBSD$"); 31366f6083SPeter Grehan 32366f6083SPeter Grehan #include <sys/param.h> 33366f6083SPeter Grehan #include <sys/kernel.h> 34366f6083SPeter Grehan #include <sys/malloc.h> 35366f6083SPeter Grehan #include <sys/systm.h> 36a5615c90SPeter Grehan #include <sys/smp.h> 37366f6083SPeter Grehan 38366f6083SPeter Grehan #include <machine/clock.h> 392d3a73edSNeel Natu #include <x86/specialreg.h> 4034a6b2d6SJohn Baldwin #include <x86/apicreg.h> 41366f6083SPeter Grehan 42366f6083SPeter Grehan #include <machine/vmm.h> 43366f6083SPeter Grehan 44*77d8fd9bSNeel Natu #include "vmm_stat.h" 45366f6083SPeter Grehan #include "vmm_lapic.h" 46366f6083SPeter Grehan #include "vmm_ktr.h" 47366f6083SPeter Grehan #include "vdev.h" 48366f6083SPeter Grehan #include "vlapic.h" 49366f6083SPeter Grehan 50366f6083SPeter Grehan #define VLAPIC_CTR0(vlapic, format) \ 51366f6083SPeter Grehan VMM_CTR0((vlapic)->vm, (vlapic)->vcpuid, format) 52366f6083SPeter Grehan 53366f6083SPeter Grehan #define VLAPIC_CTR1(vlapic, format, p1) \ 54366f6083SPeter Grehan VMM_CTR1((vlapic)->vm, (vlapic)->vcpuid, format, p1) 55366f6083SPeter Grehan 56366f6083SPeter Grehan #define VLAPIC_CTR_IRR(vlapic, msg) \ 57366f6083SPeter Grehan do { \ 58366f6083SPeter Grehan uint32_t *irrptr = &(vlapic)->apic.irr0; \ 59366f6083SPeter Grehan irrptr[0] = irrptr[0]; /* silence compiler */ \ 60366f6083SPeter Grehan VLAPIC_CTR1((vlapic), msg " irr0 0x%08x", irrptr[0 << 2]); \ 61366f6083SPeter Grehan VLAPIC_CTR1((vlapic), msg " irr1 0x%08x", irrptr[1 << 2]); \ 62366f6083SPeter Grehan VLAPIC_CTR1((vlapic), msg " irr2 0x%08x", irrptr[2 << 2]); \ 63366f6083SPeter Grehan VLAPIC_CTR1((vlapic), msg " irr3 0x%08x", irrptr[3 << 2]); \ 64366f6083SPeter Grehan VLAPIC_CTR1((vlapic), msg " irr4 0x%08x", irrptr[4 << 2]); \ 65366f6083SPeter Grehan VLAPIC_CTR1((vlapic), msg " irr5 0x%08x", irrptr[5 << 2]); \ 66366f6083SPeter Grehan VLAPIC_CTR1((vlapic), msg " irr6 0x%08x", irrptr[6 << 2]); \ 67366f6083SPeter Grehan VLAPIC_CTR1((vlapic), msg " irr7 0x%08x", irrptr[7 << 2]); \ 68366f6083SPeter Grehan } while (0) 69366f6083SPeter Grehan 70366f6083SPeter Grehan #define VLAPIC_CTR_ISR(vlapic, msg) \ 71366f6083SPeter Grehan do { \ 72366f6083SPeter Grehan uint32_t *isrptr = &(vlapic)->apic.isr0; \ 73366f6083SPeter Grehan isrptr[0] = isrptr[0]; /* silence compiler */ \ 74366f6083SPeter Grehan VLAPIC_CTR1((vlapic), msg " isr0 0x%08x", isrptr[0 << 2]); \ 75366f6083SPeter Grehan VLAPIC_CTR1((vlapic), msg " isr1 0x%08x", isrptr[1 << 2]); \ 76366f6083SPeter Grehan VLAPIC_CTR1((vlapic), msg " isr2 0x%08x", isrptr[2 << 2]); \ 77366f6083SPeter Grehan VLAPIC_CTR1((vlapic), msg " isr3 0x%08x", isrptr[3 << 2]); \ 78366f6083SPeter Grehan VLAPIC_CTR1((vlapic), msg " isr4 0x%08x", isrptr[4 << 2]); \ 79366f6083SPeter Grehan VLAPIC_CTR1((vlapic), msg " isr5 0x%08x", isrptr[5 << 2]); \ 80366f6083SPeter Grehan VLAPIC_CTR1((vlapic), msg " isr6 0x%08x", isrptr[6 << 2]); \ 81366f6083SPeter Grehan VLAPIC_CTR1((vlapic), msg " isr7 0x%08x", isrptr[7 << 2]); \ 82366f6083SPeter Grehan } while (0) 83366f6083SPeter Grehan 84366f6083SPeter Grehan static MALLOC_DEFINE(M_VLAPIC, "vlapic", "vlapic"); 85366f6083SPeter Grehan 86366f6083SPeter Grehan #define PRIO(x) ((x) >> 4) 87366f6083SPeter Grehan 88366f6083SPeter Grehan #define VLAPIC_VERSION (16) 89366f6083SPeter Grehan #define VLAPIC_MAXLVT_ENTRIES (5) 90366f6083SPeter Grehan 91a2da7af6SNeel Natu #define x2apic(vlapic) (((vlapic)->msr_apicbase & APICBASE_X2APIC) ? 1 : 0) 922d3a73edSNeel Natu 93edf89256SNeel Natu enum boot_state { 94edf89256SNeel Natu BS_INIT, 95edf89256SNeel Natu BS_SIPI, 96edf89256SNeel Natu BS_RUNNING 97edf89256SNeel Natu }; 98edf89256SNeel Natu 99366f6083SPeter Grehan struct vlapic { 100366f6083SPeter Grehan struct vm *vm; 101366f6083SPeter Grehan int vcpuid; 102366f6083SPeter Grehan 103366f6083SPeter Grehan struct io_region *mmio; 104366f6083SPeter Grehan struct vdev_ops *ops; 105366f6083SPeter Grehan struct LAPIC apic; 106366f6083SPeter Grehan 107366f6083SPeter Grehan int esr_update; 108366f6083SPeter Grehan 109366f6083SPeter Grehan int divisor; 110366f6083SPeter Grehan int ccr_ticks; 111366f6083SPeter Grehan 112366f6083SPeter Grehan /* 113366f6083SPeter Grehan * The 'isrvec_stk' is a stack of vectors injected by the local apic. 114366f6083SPeter Grehan * A vector is popped from the stack when the processor does an EOI. 115366f6083SPeter Grehan * The vector on the top of the stack is used to compute the 116366f6083SPeter Grehan * Processor Priority in conjunction with the TPR. 117366f6083SPeter Grehan */ 118366f6083SPeter Grehan uint8_t isrvec_stk[ISRVEC_STK_SIZE]; 119366f6083SPeter Grehan int isrvec_stk_top; 1202d3a73edSNeel Natu 1212d3a73edSNeel Natu uint64_t msr_apicbase; 122edf89256SNeel Natu enum boot_state boot_state; 123366f6083SPeter Grehan }; 124366f6083SPeter Grehan 1252e25737aSNeel Natu #define VLAPIC_BUS_FREQ tsc_freq 1262e25737aSNeel Natu 1272e25737aSNeel Natu static int 1282e25737aSNeel Natu vlapic_timer_divisor(uint32_t dcr) 1292e25737aSNeel Natu { 1302e25737aSNeel Natu switch (dcr & 0xB) { 1312e25737aSNeel Natu case APIC_TDCR_2: 1322e25737aSNeel Natu return (2); 1332e25737aSNeel Natu case APIC_TDCR_4: 1342e25737aSNeel Natu return (4); 1352e25737aSNeel Natu case APIC_TDCR_8: 1362e25737aSNeel Natu return (8); 1372e25737aSNeel Natu case APIC_TDCR_16: 1382e25737aSNeel Natu return (16); 1392e25737aSNeel Natu case APIC_TDCR_32: 1402e25737aSNeel Natu return (32); 1412e25737aSNeel Natu case APIC_TDCR_64: 1422e25737aSNeel Natu return (64); 1432e25737aSNeel Natu case APIC_TDCR_128: 1442e25737aSNeel Natu return (128); 1452e25737aSNeel Natu default: 1462e25737aSNeel Natu panic("vlapic_timer_divisor: invalid dcr 0x%08x", dcr); 1472e25737aSNeel Natu } 1482e25737aSNeel Natu } 1492e25737aSNeel Natu 150366f6083SPeter Grehan static void 151366f6083SPeter Grehan vlapic_mask_lvts(uint32_t *lvts, int num_lvt) 152366f6083SPeter Grehan { 153366f6083SPeter Grehan int i; 154366f6083SPeter Grehan for (i = 0; i < num_lvt; i++) { 155366f6083SPeter Grehan *lvts |= APIC_LVT_M; 156366f6083SPeter Grehan lvts += 4; 157366f6083SPeter Grehan } 158366f6083SPeter Grehan } 159366f6083SPeter Grehan 160366f6083SPeter Grehan #if 0 161366f6083SPeter Grehan static inline void 162366f6083SPeter Grehan vlapic_dump_lvt(uint32_t offset, uint32_t *lvt) 163366f6083SPeter Grehan { 164366f6083SPeter Grehan printf("Offset %x: lvt %08x (V:%02x DS:%x M:%x)\n", offset, 165366f6083SPeter Grehan *lvt, *lvt & APIC_LVTT_VECTOR, *lvt & APIC_LVTT_DS, 166366f6083SPeter Grehan *lvt & APIC_LVTT_M); 167366f6083SPeter Grehan } 168366f6083SPeter Grehan #endif 169366f6083SPeter Grehan 170366f6083SPeter Grehan static uint64_t 171366f6083SPeter Grehan vlapic_get_ccr(struct vlapic *vlapic) 172366f6083SPeter Grehan { 173366f6083SPeter Grehan struct LAPIC *lapic = &vlapic->apic; 174366f6083SPeter Grehan return lapic->ccr_timer; 175366f6083SPeter Grehan } 176366f6083SPeter Grehan 177366f6083SPeter Grehan static void 178366f6083SPeter Grehan vlapic_update_errors(struct vlapic *vlapic) 179366f6083SPeter Grehan { 180366f6083SPeter Grehan struct LAPIC *lapic = &vlapic->apic; 181366f6083SPeter Grehan lapic->esr = 0; // XXX 182366f6083SPeter Grehan } 183366f6083SPeter Grehan 184366f6083SPeter Grehan static void 185366f6083SPeter Grehan vlapic_init_ipi(struct vlapic *vlapic) 186366f6083SPeter Grehan { 187366f6083SPeter Grehan struct LAPIC *lapic = &vlapic->apic; 188366f6083SPeter Grehan lapic->version = VLAPIC_VERSION; 189366f6083SPeter Grehan lapic->version |= (VLAPIC_MAXLVT_ENTRIES < MAXLVTSHIFT); 190366f6083SPeter Grehan lapic->dfr = 0xffffffff; 191366f6083SPeter Grehan lapic->svr = APIC_SVR_VECTOR; 192366f6083SPeter Grehan vlapic_mask_lvts(&lapic->lvt_timer, VLAPIC_MAXLVT_ENTRIES+1); 193366f6083SPeter Grehan } 194366f6083SPeter Grehan 195366f6083SPeter Grehan static int 196366f6083SPeter Grehan vlapic_op_reset(void* dev) 197366f6083SPeter Grehan { 198366f6083SPeter Grehan struct vlapic *vlapic = (struct vlapic*)dev; 199366f6083SPeter Grehan struct LAPIC *lapic = &vlapic->apic; 200366f6083SPeter Grehan 201366f6083SPeter Grehan memset(lapic, 0, sizeof(*lapic)); 202366f6083SPeter Grehan lapic->apr = vlapic->vcpuid; 203366f6083SPeter Grehan vlapic_init_ipi(vlapic); 2042e25737aSNeel Natu vlapic->divisor = vlapic_timer_divisor(lapic->dcr_timer); 205366f6083SPeter Grehan 206edf89256SNeel Natu if (vlapic->vcpuid == 0) 207edf89256SNeel Natu vlapic->boot_state = BS_RUNNING; /* BSP */ 208edf89256SNeel Natu else 209edf89256SNeel Natu vlapic->boot_state = BS_INIT; /* AP */ 210edf89256SNeel Natu 211366f6083SPeter Grehan return 0; 212366f6083SPeter Grehan 213366f6083SPeter Grehan } 214366f6083SPeter Grehan 215366f6083SPeter Grehan static int 216366f6083SPeter Grehan vlapic_op_init(void* dev) 217366f6083SPeter Grehan { 218366f6083SPeter Grehan struct vlapic *vlapic = (struct vlapic*)dev; 219366f6083SPeter Grehan vdev_register_region(vlapic->ops, vlapic, vlapic->mmio); 220366f6083SPeter Grehan return vlapic_op_reset(dev); 221366f6083SPeter Grehan } 222366f6083SPeter Grehan 223366f6083SPeter Grehan static int 224366f6083SPeter Grehan vlapic_op_halt(void* dev) 225366f6083SPeter Grehan { 226366f6083SPeter Grehan struct vlapic *vlapic = (struct vlapic*)dev; 227366f6083SPeter Grehan vdev_unregister_region(vlapic, vlapic->mmio); 228366f6083SPeter Grehan return 0; 229366f6083SPeter Grehan 230366f6083SPeter Grehan } 231366f6083SPeter Grehan 232366f6083SPeter Grehan void 233366f6083SPeter Grehan vlapic_set_intr_ready(struct vlapic *vlapic, int vector) 234366f6083SPeter Grehan { 235366f6083SPeter Grehan struct LAPIC *lapic = &vlapic->apic; 236366f6083SPeter Grehan uint32_t *irrptr; 237366f6083SPeter Grehan int idx; 238366f6083SPeter Grehan 239366f6083SPeter Grehan if (vector < 0 || vector >= 256) 240366f6083SPeter Grehan panic("vlapic_set_intr_ready: invalid vector %d\n", vector); 241366f6083SPeter Grehan 242366f6083SPeter Grehan idx = (vector / 32) * 4; 243366f6083SPeter Grehan irrptr = &lapic->irr0; 244366f6083SPeter Grehan atomic_set_int(&irrptr[idx], 1 << (vector % 32)); 245366f6083SPeter Grehan VLAPIC_CTR_IRR(vlapic, "vlapic_set_intr_ready"); 246366f6083SPeter Grehan } 247366f6083SPeter Grehan 248366f6083SPeter Grehan static void 249366f6083SPeter Grehan vlapic_start_timer(struct vlapic *vlapic, uint32_t elapsed) 250366f6083SPeter Grehan { 251366f6083SPeter Grehan uint32_t icr_timer; 252366f6083SPeter Grehan 253366f6083SPeter Grehan icr_timer = vlapic->apic.icr_timer; 254366f6083SPeter Grehan 255366f6083SPeter Grehan vlapic->ccr_ticks = ticks; 256366f6083SPeter Grehan if (elapsed < icr_timer) 257366f6083SPeter Grehan vlapic->apic.ccr_timer = icr_timer - elapsed; 258366f6083SPeter Grehan else { 259366f6083SPeter Grehan /* 260366f6083SPeter Grehan * This can happen when the guest is trying to run its local 261366f6083SPeter Grehan * apic timer higher that the setting of 'hz' in the host. 262366f6083SPeter Grehan * 263366f6083SPeter Grehan * We deal with this by running the guest local apic timer 264366f6083SPeter Grehan * at the rate of the host's 'hz' setting. 265366f6083SPeter Grehan */ 266366f6083SPeter Grehan vlapic->apic.ccr_timer = 0; 267366f6083SPeter Grehan } 268366f6083SPeter Grehan } 269366f6083SPeter Grehan 270366f6083SPeter Grehan static __inline uint32_t * 271366f6083SPeter Grehan vlapic_get_lvt(struct vlapic *vlapic, uint32_t offset) 272366f6083SPeter Grehan { 273366f6083SPeter Grehan struct LAPIC *lapic = &vlapic->apic; 274366f6083SPeter Grehan int i; 275366f6083SPeter Grehan 276366f6083SPeter Grehan if (offset < APIC_OFFSET_TIMER_LVT || offset > APIC_OFFSET_ERROR_LVT) { 277366f6083SPeter Grehan panic("vlapic_get_lvt: invalid LVT\n"); 278366f6083SPeter Grehan } 279366f6083SPeter Grehan i = (offset - APIC_OFFSET_TIMER_LVT) >> 2; 280366f6083SPeter Grehan return ((&lapic->lvt_timer) + i);; 281366f6083SPeter Grehan } 282366f6083SPeter Grehan 283366f6083SPeter Grehan #if 1 284366f6083SPeter Grehan static void 285366f6083SPeter Grehan dump_isrvec_stk(struct vlapic *vlapic) 286366f6083SPeter Grehan { 287366f6083SPeter Grehan int i; 288366f6083SPeter Grehan uint32_t *isrptr; 289366f6083SPeter Grehan 290366f6083SPeter Grehan isrptr = &vlapic->apic.isr0; 291366f6083SPeter Grehan for (i = 0; i < 8; i++) 292366f6083SPeter Grehan printf("ISR%d 0x%08x\n", i, isrptr[i * 4]); 293366f6083SPeter Grehan 294366f6083SPeter Grehan for (i = 0; i <= vlapic->isrvec_stk_top; i++) 295366f6083SPeter Grehan printf("isrvec_stk[%d] = %d\n", i, vlapic->isrvec_stk[i]); 296366f6083SPeter Grehan } 297366f6083SPeter Grehan #endif 298366f6083SPeter Grehan 299366f6083SPeter Grehan /* 300366f6083SPeter Grehan * Algorithm adopted from section "Interrupt, Task and Processor Priority" 301366f6083SPeter Grehan * in Intel Architecture Manual Vol 3a. 302366f6083SPeter Grehan */ 303366f6083SPeter Grehan static void 304366f6083SPeter Grehan vlapic_update_ppr(struct vlapic *vlapic) 305366f6083SPeter Grehan { 306366f6083SPeter Grehan int isrvec, tpr, ppr; 307366f6083SPeter Grehan 308366f6083SPeter Grehan /* 309366f6083SPeter Grehan * Note that the value on the stack at index 0 is always 0. 310366f6083SPeter Grehan * 311366f6083SPeter Grehan * This is a placeholder for the value of ISRV when none of the 312366f6083SPeter Grehan * bits is set in the ISRx registers. 313366f6083SPeter Grehan */ 314366f6083SPeter Grehan isrvec = vlapic->isrvec_stk[vlapic->isrvec_stk_top]; 315366f6083SPeter Grehan tpr = vlapic->apic.tpr; 316366f6083SPeter Grehan 317366f6083SPeter Grehan #if 1 318366f6083SPeter Grehan { 319366f6083SPeter Grehan int i, lastprio, curprio, vector, idx; 320366f6083SPeter Grehan uint32_t *isrptr; 321366f6083SPeter Grehan 322366f6083SPeter Grehan if (vlapic->isrvec_stk_top == 0 && isrvec != 0) 323366f6083SPeter Grehan panic("isrvec_stk is corrupted: %d", isrvec); 324366f6083SPeter Grehan 325366f6083SPeter Grehan /* 326366f6083SPeter Grehan * Make sure that the priority of the nested interrupts is 327366f6083SPeter Grehan * always increasing. 328366f6083SPeter Grehan */ 329366f6083SPeter Grehan lastprio = -1; 330366f6083SPeter Grehan for (i = 1; i <= vlapic->isrvec_stk_top; i++) { 331366f6083SPeter Grehan curprio = PRIO(vlapic->isrvec_stk[i]); 332366f6083SPeter Grehan if (curprio <= lastprio) { 333366f6083SPeter Grehan dump_isrvec_stk(vlapic); 334366f6083SPeter Grehan panic("isrvec_stk does not satisfy invariant"); 335366f6083SPeter Grehan } 336366f6083SPeter Grehan lastprio = curprio; 337366f6083SPeter Grehan } 338366f6083SPeter Grehan 339366f6083SPeter Grehan /* 340366f6083SPeter Grehan * Make sure that each bit set in the ISRx registers has a 341366f6083SPeter Grehan * corresponding entry on the isrvec stack. 342366f6083SPeter Grehan */ 343366f6083SPeter Grehan i = 1; 344366f6083SPeter Grehan isrptr = &vlapic->apic.isr0; 345366f6083SPeter Grehan for (vector = 0; vector < 256; vector++) { 346366f6083SPeter Grehan idx = (vector / 32) * 4; 347366f6083SPeter Grehan if (isrptr[idx] & (1 << (vector % 32))) { 348366f6083SPeter Grehan if (i > vlapic->isrvec_stk_top || 349366f6083SPeter Grehan vlapic->isrvec_stk[i] != vector) { 350366f6083SPeter Grehan dump_isrvec_stk(vlapic); 351366f6083SPeter Grehan panic("ISR and isrvec_stk out of sync"); 352366f6083SPeter Grehan } 353366f6083SPeter Grehan i++; 354366f6083SPeter Grehan } 355366f6083SPeter Grehan } 356366f6083SPeter Grehan } 357366f6083SPeter Grehan #endif 358366f6083SPeter Grehan 359366f6083SPeter Grehan if (PRIO(tpr) >= PRIO(isrvec)) 360366f6083SPeter Grehan ppr = tpr; 361366f6083SPeter Grehan else 362366f6083SPeter Grehan ppr = isrvec & 0xf0; 363366f6083SPeter Grehan 364366f6083SPeter Grehan vlapic->apic.ppr = ppr; 365366f6083SPeter Grehan VLAPIC_CTR1(vlapic, "vlapic_update_ppr 0x%02x", ppr); 366366f6083SPeter Grehan } 367366f6083SPeter Grehan 368366f6083SPeter Grehan static void 369366f6083SPeter Grehan vlapic_process_eoi(struct vlapic *vlapic) 370366f6083SPeter Grehan { 371366f6083SPeter Grehan struct LAPIC *lapic = &vlapic->apic; 372366f6083SPeter Grehan uint32_t *isrptr; 373366f6083SPeter Grehan int i, idx, bitpos; 374366f6083SPeter Grehan 375366f6083SPeter Grehan isrptr = &lapic->isr0; 376366f6083SPeter Grehan 377366f6083SPeter Grehan /* 378366f6083SPeter Grehan * The x86 architecture reserves the the first 32 vectors for use 379366f6083SPeter Grehan * by the processor. 380366f6083SPeter Grehan */ 381366f6083SPeter Grehan for (i = 7; i > 0; i--) { 382366f6083SPeter Grehan idx = i * 4; 383366f6083SPeter Grehan bitpos = fls(isrptr[idx]); 384366f6083SPeter Grehan if (bitpos != 0) { 385366f6083SPeter Grehan if (vlapic->isrvec_stk_top <= 0) { 386366f6083SPeter Grehan panic("invalid vlapic isrvec_stk_top %d", 387366f6083SPeter Grehan vlapic->isrvec_stk_top); 388366f6083SPeter Grehan } 389366f6083SPeter Grehan isrptr[idx] &= ~(1 << (bitpos - 1)); 390366f6083SPeter Grehan VLAPIC_CTR_ISR(vlapic, "vlapic_process_eoi"); 391366f6083SPeter Grehan vlapic->isrvec_stk_top--; 392366f6083SPeter Grehan vlapic_update_ppr(vlapic); 393366f6083SPeter Grehan return; 394366f6083SPeter Grehan } 395366f6083SPeter Grehan } 396366f6083SPeter Grehan } 397366f6083SPeter Grehan 398366f6083SPeter Grehan static __inline int 399366f6083SPeter Grehan vlapic_get_lvt_field(uint32_t *lvt, uint32_t mask) 400366f6083SPeter Grehan { 401366f6083SPeter Grehan return (*lvt & mask); 402366f6083SPeter Grehan } 403366f6083SPeter Grehan 404366f6083SPeter Grehan static __inline int 405366f6083SPeter Grehan vlapic_periodic_timer(struct vlapic *vlapic) 406366f6083SPeter Grehan { 407366f6083SPeter Grehan uint32_t *lvt; 408366f6083SPeter Grehan 409366f6083SPeter Grehan lvt = vlapic_get_lvt(vlapic, APIC_OFFSET_TIMER_LVT); 410366f6083SPeter Grehan 411366f6083SPeter Grehan return (vlapic_get_lvt_field(lvt, APIC_LVTT_TM_PERIODIC)); 412366f6083SPeter Grehan } 413366f6083SPeter Grehan 414*77d8fd9bSNeel Natu static VMM_STAT(VLAPIC_INTR_TIMER, "timer interrupts generated by vlapic"); 415*77d8fd9bSNeel Natu 416366f6083SPeter Grehan static void 417366f6083SPeter Grehan vlapic_fire_timer(struct vlapic *vlapic) 418366f6083SPeter Grehan { 419366f6083SPeter Grehan int vector; 420366f6083SPeter Grehan uint32_t *lvt; 421366f6083SPeter Grehan 422366f6083SPeter Grehan lvt = vlapic_get_lvt(vlapic, APIC_OFFSET_TIMER_LVT); 423366f6083SPeter Grehan 424366f6083SPeter Grehan if (!vlapic_get_lvt_field(lvt, APIC_LVTT_M)) { 425*77d8fd9bSNeel Natu vmm_stat_incr(vlapic->vm, vlapic->vcpuid, VLAPIC_INTR_TIMER, 1); 426366f6083SPeter Grehan vector = vlapic_get_lvt_field(lvt,APIC_LVTT_VECTOR); 427366f6083SPeter Grehan vlapic_set_intr_ready(vlapic, vector); 428366f6083SPeter Grehan } 429366f6083SPeter Grehan } 430366f6083SPeter Grehan 431366f6083SPeter Grehan static int 432366f6083SPeter Grehan lapic_process_icr(struct vlapic *vlapic, uint64_t icrval) 433366f6083SPeter Grehan { 434366f6083SPeter Grehan int i; 435a5615c90SPeter Grehan cpuset_t dmask; 436366f6083SPeter Grehan uint32_t dest, vec, mode; 437edf89256SNeel Natu struct vlapic *vlapic2; 438edf89256SNeel Natu struct vm_exit *vmexit; 439366f6083SPeter Grehan 440a2da7af6SNeel Natu if (x2apic(vlapic)) 441366f6083SPeter Grehan dest = icrval >> 32; 442a2da7af6SNeel Natu else 443a2da7af6SNeel Natu dest = icrval >> (32 + 24); 444366f6083SPeter Grehan vec = icrval & APIC_VECTOR_MASK; 445366f6083SPeter Grehan mode = icrval & APIC_DELMODE_MASK; 446366f6083SPeter Grehan 447366f6083SPeter Grehan if (mode == APIC_DELMODE_FIXED || mode == APIC_DELMODE_NMI) { 448366f6083SPeter Grehan switch (icrval & APIC_DEST_MASK) { 449366f6083SPeter Grehan case APIC_DEST_DESTFLD: 450a5615c90SPeter Grehan CPU_SETOF(dest, &dmask); 451366f6083SPeter Grehan break; 452366f6083SPeter Grehan case APIC_DEST_SELF: 453a5615c90SPeter Grehan CPU_SETOF(vlapic->vcpuid, &dmask); 454366f6083SPeter Grehan break; 455366f6083SPeter Grehan case APIC_DEST_ALLISELF: 456366f6083SPeter Grehan dmask = vm_active_cpus(vlapic->vm); 457366f6083SPeter Grehan break; 458366f6083SPeter Grehan case APIC_DEST_ALLESELF: 459a5615c90SPeter Grehan dmask = vm_active_cpus(vlapic->vm); 460a5615c90SPeter Grehan CPU_CLR(vlapic->vcpuid, &dmask); 461366f6083SPeter Grehan break; 462366f6083SPeter Grehan } 463366f6083SPeter Grehan 464a5615c90SPeter Grehan while ((i = cpusetobj_ffs(&dmask)) != 0) { 465a5615c90SPeter Grehan i--; 466a5615c90SPeter Grehan CPU_CLR(i, &dmask); 467366f6083SPeter Grehan if (mode == APIC_DELMODE_FIXED) 468366f6083SPeter Grehan lapic_set_intr(vlapic->vm, i, vec); 469366f6083SPeter Grehan else 470366f6083SPeter Grehan vm_inject_nmi(vlapic->vm, i); 471366f6083SPeter Grehan } 472366f6083SPeter Grehan 473366f6083SPeter Grehan return (0); /* handled completely in the kernel */ 474366f6083SPeter Grehan } 475366f6083SPeter Grehan 476edf89256SNeel Natu if (mode == APIC_DELMODE_INIT) { 477edf89256SNeel Natu if ((icrval & APIC_LEVEL_MASK) == APIC_LEVEL_DEASSERT) 478edf89256SNeel Natu return (0); 479edf89256SNeel Natu 480edf89256SNeel Natu if (vlapic->vcpuid == 0 && dest != 0 && dest < VM_MAXCPU) { 481edf89256SNeel Natu vlapic2 = vm_lapic(vlapic->vm, dest); 482edf89256SNeel Natu 483edf89256SNeel Natu /* move from INIT to waiting-for-SIPI state */ 484edf89256SNeel Natu if (vlapic2->boot_state == BS_INIT) { 485edf89256SNeel Natu vlapic2->boot_state = BS_SIPI; 486edf89256SNeel Natu } 487edf89256SNeel Natu 488edf89256SNeel Natu return (0); 489edf89256SNeel Natu } 490edf89256SNeel Natu } 491edf89256SNeel Natu 492edf89256SNeel Natu if (mode == APIC_DELMODE_STARTUP) { 493edf89256SNeel Natu if (vlapic->vcpuid == 0 && dest != 0 && dest < VM_MAXCPU) { 494edf89256SNeel Natu vlapic2 = vm_lapic(vlapic->vm, dest); 495edf89256SNeel Natu 496edf89256SNeel Natu /* 497edf89256SNeel Natu * Ignore SIPIs in any state other than wait-for-SIPI 498edf89256SNeel Natu */ 499edf89256SNeel Natu if (vlapic2->boot_state != BS_SIPI) 500edf89256SNeel Natu return (0); 501edf89256SNeel Natu 502edf89256SNeel Natu vmexit = vm_exitinfo(vlapic->vm, vlapic->vcpuid); 503edf89256SNeel Natu vmexit->exitcode = VM_EXITCODE_SPINUP_AP; 504edf89256SNeel Natu vmexit->u.spinup_ap.vcpu = dest; 505edf89256SNeel Natu vmexit->u.spinup_ap.rip = vec << PAGE_SHIFT; 506edf89256SNeel Natu 507366f6083SPeter Grehan /* 508366f6083SPeter Grehan * XXX this assumes that the startup IPI always succeeds 509366f6083SPeter Grehan */ 510edf89256SNeel Natu vlapic2->boot_state = BS_RUNNING; 511edf89256SNeel Natu vm_activate_cpu(vlapic2->vm, dest); 512edf89256SNeel Natu 513edf89256SNeel Natu return (0); 514edf89256SNeel Natu } 515edf89256SNeel Natu } 516366f6083SPeter Grehan 517366f6083SPeter Grehan /* 518366f6083SPeter Grehan * This will cause a return to userland. 519366f6083SPeter Grehan */ 520366f6083SPeter Grehan return (1); 521366f6083SPeter Grehan } 522366f6083SPeter Grehan 523366f6083SPeter Grehan int 524366f6083SPeter Grehan vlapic_pending_intr(struct vlapic *vlapic) 525366f6083SPeter Grehan { 526366f6083SPeter Grehan struct LAPIC *lapic = &vlapic->apic; 527366f6083SPeter Grehan int idx, i, bitpos, vector; 528366f6083SPeter Grehan uint32_t *irrptr, val; 529366f6083SPeter Grehan 530366f6083SPeter Grehan irrptr = &lapic->irr0; 531366f6083SPeter Grehan 532366f6083SPeter Grehan /* 533366f6083SPeter Grehan * The x86 architecture reserves the the first 32 vectors for use 534366f6083SPeter Grehan * by the processor. 535366f6083SPeter Grehan */ 536366f6083SPeter Grehan for (i = 7; i > 0; i--) { 537366f6083SPeter Grehan idx = i * 4; 538366f6083SPeter Grehan val = atomic_load_acq_int(&irrptr[idx]); 539366f6083SPeter Grehan bitpos = fls(val); 540366f6083SPeter Grehan if (bitpos != 0) { 541366f6083SPeter Grehan vector = i * 32 + (bitpos - 1); 542366f6083SPeter Grehan if (PRIO(vector) > PRIO(lapic->ppr)) { 543366f6083SPeter Grehan VLAPIC_CTR1(vlapic, "pending intr %d", vector); 544366f6083SPeter Grehan return (vector); 545366f6083SPeter Grehan } else 546366f6083SPeter Grehan break; 547366f6083SPeter Grehan } 548366f6083SPeter Grehan } 549366f6083SPeter Grehan VLAPIC_CTR0(vlapic, "no pending intr"); 550366f6083SPeter Grehan return (-1); 551366f6083SPeter Grehan } 552366f6083SPeter Grehan 553366f6083SPeter Grehan void 554366f6083SPeter Grehan vlapic_intr_accepted(struct vlapic *vlapic, int vector) 555366f6083SPeter Grehan { 556366f6083SPeter Grehan struct LAPIC *lapic = &vlapic->apic; 557366f6083SPeter Grehan uint32_t *irrptr, *isrptr; 558366f6083SPeter Grehan int idx, stk_top; 559366f6083SPeter Grehan 560366f6083SPeter Grehan /* 561366f6083SPeter Grehan * clear the ready bit for vector being accepted in irr 562366f6083SPeter Grehan * and set the vector as in service in isr. 563366f6083SPeter Grehan */ 564366f6083SPeter Grehan idx = (vector / 32) * 4; 565366f6083SPeter Grehan 566366f6083SPeter Grehan irrptr = &lapic->irr0; 567366f6083SPeter Grehan atomic_clear_int(&irrptr[idx], 1 << (vector % 32)); 568366f6083SPeter Grehan VLAPIC_CTR_IRR(vlapic, "vlapic_intr_accepted"); 569366f6083SPeter Grehan 570366f6083SPeter Grehan isrptr = &lapic->isr0; 571366f6083SPeter Grehan isrptr[idx] |= 1 << (vector % 32); 572366f6083SPeter Grehan VLAPIC_CTR_ISR(vlapic, "vlapic_intr_accepted"); 573366f6083SPeter Grehan 574366f6083SPeter Grehan /* 575366f6083SPeter Grehan * Update the PPR 576366f6083SPeter Grehan */ 577366f6083SPeter Grehan vlapic->isrvec_stk_top++; 578366f6083SPeter Grehan 579366f6083SPeter Grehan stk_top = vlapic->isrvec_stk_top; 580366f6083SPeter Grehan if (stk_top >= ISRVEC_STK_SIZE) 581366f6083SPeter Grehan panic("isrvec_stk_top overflow %d", stk_top); 582366f6083SPeter Grehan 583366f6083SPeter Grehan vlapic->isrvec_stk[stk_top] = vector; 584366f6083SPeter Grehan vlapic_update_ppr(vlapic); 585366f6083SPeter Grehan } 586366f6083SPeter Grehan 587366f6083SPeter Grehan int 588366f6083SPeter Grehan vlapic_op_mem_read(void* dev, uint64_t gpa, opsize_t size, uint64_t *data) 589366f6083SPeter Grehan { 590366f6083SPeter Grehan struct vlapic *vlapic = (struct vlapic*)dev; 591366f6083SPeter Grehan struct LAPIC *lapic = &vlapic->apic; 592366f6083SPeter Grehan uint64_t offset = gpa & ~(PAGE_SIZE); 593366f6083SPeter Grehan uint32_t *reg; 594366f6083SPeter Grehan int i; 595366f6083SPeter Grehan 596366f6083SPeter Grehan if (offset > sizeof(*lapic)) { 597366f6083SPeter Grehan *data = 0; 598366f6083SPeter Grehan return 0; 599366f6083SPeter Grehan } 600366f6083SPeter Grehan 601366f6083SPeter Grehan offset &= ~3; 602366f6083SPeter Grehan switch(offset) 603366f6083SPeter Grehan { 604366f6083SPeter Grehan case APIC_OFFSET_ID: 6052d3a73edSNeel Natu if (x2apic(vlapic)) 6062d3a73edSNeel Natu *data = vlapic->vcpuid; 6072d3a73edSNeel Natu else 6082d3a73edSNeel Natu *data = vlapic->vcpuid << 24; 609366f6083SPeter Grehan break; 610366f6083SPeter Grehan case APIC_OFFSET_VER: 611366f6083SPeter Grehan *data = lapic->version; 612366f6083SPeter Grehan break; 613366f6083SPeter Grehan case APIC_OFFSET_TPR: 614366f6083SPeter Grehan *data = lapic->tpr; 615366f6083SPeter Grehan break; 616366f6083SPeter Grehan case APIC_OFFSET_APR: 617366f6083SPeter Grehan *data = lapic->apr; 618366f6083SPeter Grehan break; 619366f6083SPeter Grehan case APIC_OFFSET_PPR: 620366f6083SPeter Grehan *data = lapic->ppr; 621366f6083SPeter Grehan break; 622366f6083SPeter Grehan case APIC_OFFSET_EOI: 623366f6083SPeter Grehan *data = lapic->eoi; 624366f6083SPeter Grehan break; 625366f6083SPeter Grehan case APIC_OFFSET_LDR: 626366f6083SPeter Grehan *data = lapic->ldr; 627366f6083SPeter Grehan break; 628366f6083SPeter Grehan case APIC_OFFSET_DFR: 629366f6083SPeter Grehan *data = lapic->dfr; 630366f6083SPeter Grehan break; 631366f6083SPeter Grehan case APIC_OFFSET_SVR: 632366f6083SPeter Grehan *data = lapic->svr; 633366f6083SPeter Grehan break; 634366f6083SPeter Grehan case APIC_OFFSET_ISR0 ... APIC_OFFSET_ISR7: 635366f6083SPeter Grehan i = (offset - APIC_OFFSET_ISR0) >> 2; 636366f6083SPeter Grehan reg = &lapic->isr0; 637366f6083SPeter Grehan *data = *(reg + i); 638366f6083SPeter Grehan break; 639366f6083SPeter Grehan case APIC_OFFSET_TMR0 ... APIC_OFFSET_TMR7: 640366f6083SPeter Grehan i = (offset - APIC_OFFSET_TMR0) >> 2; 641366f6083SPeter Grehan reg = &lapic->tmr0; 642366f6083SPeter Grehan *data = *(reg + i); 643366f6083SPeter Grehan break; 644366f6083SPeter Grehan case APIC_OFFSET_IRR0 ... APIC_OFFSET_IRR7: 645366f6083SPeter Grehan i = (offset - APIC_OFFSET_IRR0) >> 2; 646366f6083SPeter Grehan reg = &lapic->irr0; 647366f6083SPeter Grehan *data = atomic_load_acq_int(reg + i); 648366f6083SPeter Grehan break; 649366f6083SPeter Grehan case APIC_OFFSET_ESR: 650366f6083SPeter Grehan *data = lapic->esr; 651366f6083SPeter Grehan break; 652366f6083SPeter Grehan case APIC_OFFSET_ICR_LOW: 653366f6083SPeter Grehan *data = lapic->icr_lo; 654366f6083SPeter Grehan break; 655366f6083SPeter Grehan case APIC_OFFSET_ICR_HI: 656366f6083SPeter Grehan *data = lapic->icr_hi; 657366f6083SPeter Grehan break; 658366f6083SPeter Grehan case APIC_OFFSET_TIMER_LVT ... APIC_OFFSET_ERROR_LVT: 659366f6083SPeter Grehan reg = vlapic_get_lvt(vlapic, offset); 660366f6083SPeter Grehan *data = *(reg); 661366f6083SPeter Grehan break; 662366f6083SPeter Grehan case APIC_OFFSET_ICR: 663366f6083SPeter Grehan *data = lapic->icr_timer; 664366f6083SPeter Grehan break; 665366f6083SPeter Grehan case APIC_OFFSET_CCR: 666366f6083SPeter Grehan *data = vlapic_get_ccr(vlapic); 667366f6083SPeter Grehan break; 668366f6083SPeter Grehan case APIC_OFFSET_DCR: 669366f6083SPeter Grehan *data = lapic->dcr_timer; 670366f6083SPeter Grehan break; 671366f6083SPeter Grehan case APIC_OFFSET_RRR: 672366f6083SPeter Grehan default: 673366f6083SPeter Grehan *data = 0; 674366f6083SPeter Grehan break; 675366f6083SPeter Grehan } 676366f6083SPeter Grehan return 0; 677366f6083SPeter Grehan } 678366f6083SPeter Grehan 679366f6083SPeter Grehan int 680366f6083SPeter Grehan vlapic_op_mem_write(void* dev, uint64_t gpa, opsize_t size, uint64_t data) 681366f6083SPeter Grehan { 682366f6083SPeter Grehan struct vlapic *vlapic = (struct vlapic*)dev; 683366f6083SPeter Grehan struct LAPIC *lapic = &vlapic->apic; 684366f6083SPeter Grehan uint64_t offset = gpa & ~(PAGE_SIZE); 685366f6083SPeter Grehan uint32_t *reg; 686366f6083SPeter Grehan int retval; 687366f6083SPeter Grehan 688366f6083SPeter Grehan if (offset > sizeof(*lapic)) { 689366f6083SPeter Grehan return 0; 690366f6083SPeter Grehan } 691366f6083SPeter Grehan 692366f6083SPeter Grehan retval = 0; 693366f6083SPeter Grehan offset &= ~3; 694366f6083SPeter Grehan switch(offset) 695366f6083SPeter Grehan { 696366f6083SPeter Grehan case APIC_OFFSET_ID: 697366f6083SPeter Grehan break; 698366f6083SPeter Grehan case APIC_OFFSET_TPR: 699366f6083SPeter Grehan lapic->tpr = data & 0xff; 700366f6083SPeter Grehan vlapic_update_ppr(vlapic); 701366f6083SPeter Grehan break; 702366f6083SPeter Grehan case APIC_OFFSET_EOI: 703366f6083SPeter Grehan vlapic_process_eoi(vlapic); 704366f6083SPeter Grehan break; 705366f6083SPeter Grehan case APIC_OFFSET_LDR: 706366f6083SPeter Grehan break; 707366f6083SPeter Grehan case APIC_OFFSET_DFR: 708366f6083SPeter Grehan break; 709366f6083SPeter Grehan case APIC_OFFSET_SVR: 710366f6083SPeter Grehan lapic->svr = data; 711366f6083SPeter Grehan break; 712366f6083SPeter Grehan case APIC_OFFSET_ICR_LOW: 713a2da7af6SNeel Natu if (!x2apic(vlapic)) { 714a2da7af6SNeel Natu data &= 0xffffffff; 715a2da7af6SNeel Natu data |= (uint64_t)lapic->icr_hi << 32; 716a2da7af6SNeel Natu } 717366f6083SPeter Grehan retval = lapic_process_icr(vlapic, data); 718366f6083SPeter Grehan break; 719a2da7af6SNeel Natu case APIC_OFFSET_ICR_HI: 720a2da7af6SNeel Natu if (!x2apic(vlapic)) { 721a2da7af6SNeel Natu retval = 0; 722a2da7af6SNeel Natu lapic->icr_hi = data; 723a2da7af6SNeel Natu } 724a2da7af6SNeel Natu break; 725366f6083SPeter Grehan case APIC_OFFSET_TIMER_LVT ... APIC_OFFSET_ERROR_LVT: 726366f6083SPeter Grehan reg = vlapic_get_lvt(vlapic, offset); 727366f6083SPeter Grehan if (!(lapic->svr & APIC_SVR_ENABLE)) { 728366f6083SPeter Grehan data |= APIC_LVT_M; 729366f6083SPeter Grehan } 730366f6083SPeter Grehan *reg = data; 731366f6083SPeter Grehan // vlapic_dump_lvt(offset, reg); 732366f6083SPeter Grehan break; 733366f6083SPeter Grehan case APIC_OFFSET_ICR: 734366f6083SPeter Grehan lapic->icr_timer = data; 735366f6083SPeter Grehan vlapic_start_timer(vlapic, 0); 736366f6083SPeter Grehan break; 737366f6083SPeter Grehan 738366f6083SPeter Grehan case APIC_OFFSET_DCR: 739366f6083SPeter Grehan lapic->dcr_timer = data; 740366f6083SPeter Grehan vlapic->divisor = vlapic_timer_divisor(data); 741366f6083SPeter Grehan break; 742366f6083SPeter Grehan 743366f6083SPeter Grehan case APIC_OFFSET_ESR: 744366f6083SPeter Grehan vlapic_update_errors(vlapic); 745366f6083SPeter Grehan break; 746366f6083SPeter Grehan case APIC_OFFSET_VER: 747366f6083SPeter Grehan case APIC_OFFSET_APR: 748366f6083SPeter Grehan case APIC_OFFSET_PPR: 749366f6083SPeter Grehan case APIC_OFFSET_RRR: 750366f6083SPeter Grehan case APIC_OFFSET_ISR0 ... APIC_OFFSET_ISR7: 751366f6083SPeter Grehan case APIC_OFFSET_TMR0 ... APIC_OFFSET_TMR7: 752366f6083SPeter Grehan case APIC_OFFSET_IRR0 ... APIC_OFFSET_IRR7: 753366f6083SPeter Grehan case APIC_OFFSET_CCR: 754366f6083SPeter Grehan default: 755366f6083SPeter Grehan // Read only. 756366f6083SPeter Grehan break; 757366f6083SPeter Grehan } 758366f6083SPeter Grehan 759366f6083SPeter Grehan return (retval); 760366f6083SPeter Grehan } 761366f6083SPeter Grehan 7622e25737aSNeel Natu int 763366f6083SPeter Grehan vlapic_timer_tick(struct vlapic *vlapic) 764366f6083SPeter Grehan { 7652e25737aSNeel Natu int curticks, delta, periodic, fired; 766366f6083SPeter Grehan uint32_t ccr; 7672e25737aSNeel Natu uint32_t decrement, leftover; 768366f6083SPeter Grehan 7692e25737aSNeel Natu restart: 770366f6083SPeter Grehan curticks = ticks; 771366f6083SPeter Grehan delta = curticks - vlapic->ccr_ticks; 772366f6083SPeter Grehan 773366f6083SPeter Grehan /* Local APIC timer is disabled */ 774366f6083SPeter Grehan if (vlapic->apic.icr_timer == 0) 7752e25737aSNeel Natu return (-1); 776366f6083SPeter Grehan 777366f6083SPeter Grehan /* One-shot mode and timer has already counted down to zero */ 778366f6083SPeter Grehan periodic = vlapic_periodic_timer(vlapic); 779366f6083SPeter Grehan if (!periodic && vlapic->apic.ccr_timer == 0) 7802e25737aSNeel Natu return (-1); 781366f6083SPeter Grehan /* 782366f6083SPeter Grehan * The 'curticks' and 'ccr_ticks' are out of sync by more than 783366f6083SPeter Grehan * 2^31 ticks. We deal with this by restarting the timer. 784366f6083SPeter Grehan */ 785366f6083SPeter Grehan if (delta < 0) { 786366f6083SPeter Grehan vlapic_start_timer(vlapic, 0); 7872e25737aSNeel Natu goto restart; 788366f6083SPeter Grehan } 789366f6083SPeter Grehan 7902e25737aSNeel Natu fired = 0; 791366f6083SPeter Grehan decrement = (VLAPIC_BUS_FREQ / vlapic->divisor) / hz; 7922e25737aSNeel Natu 7932e25737aSNeel Natu vlapic->ccr_ticks = curticks; 7942e25737aSNeel Natu ccr = vlapic->apic.ccr_timer; 7952e25737aSNeel Natu 796366f6083SPeter Grehan while (delta-- > 0) { 7972e25737aSNeel Natu if (ccr > decrement) { 7982e25737aSNeel Natu ccr -= decrement; 7992e25737aSNeel Natu continue; 8002e25737aSNeel Natu } 8012e25737aSNeel Natu 8022e25737aSNeel Natu /* Trigger the local apic timer interrupt */ 803366f6083SPeter Grehan vlapic_fire_timer(vlapic); 804366f6083SPeter Grehan if (periodic) { 8052e25737aSNeel Natu leftover = decrement - ccr; 8062e25737aSNeel Natu vlapic_start_timer(vlapic, leftover); 807366f6083SPeter Grehan ccr = vlapic->apic.ccr_timer; 808366f6083SPeter Grehan } else { 809366f6083SPeter Grehan /* 810366f6083SPeter Grehan * One-shot timer has counted down to zero. 811366f6083SPeter Grehan */ 812366f6083SPeter Grehan ccr = 0; 8132e25737aSNeel Natu } 8142e25737aSNeel Natu fired = 1; 815366f6083SPeter Grehan break; 816366f6083SPeter Grehan } 817366f6083SPeter Grehan 818366f6083SPeter Grehan vlapic->apic.ccr_timer = ccr; 8192e25737aSNeel Natu 8202e25737aSNeel Natu if (!fired) 8212e25737aSNeel Natu return ((ccr / decrement) + 1); 8222e25737aSNeel Natu else 8232e25737aSNeel Natu return (0); 824366f6083SPeter Grehan } 825366f6083SPeter Grehan 826366f6083SPeter Grehan struct vdev_ops vlapic_dev_ops = { 827366f6083SPeter Grehan .name = "vlapic", 828366f6083SPeter Grehan .init = vlapic_op_init, 829366f6083SPeter Grehan .reset = vlapic_op_reset, 830366f6083SPeter Grehan .halt = vlapic_op_halt, 831366f6083SPeter Grehan .memread = vlapic_op_mem_read, 832366f6083SPeter Grehan .memwrite = vlapic_op_mem_write, 833366f6083SPeter Grehan }; 834366f6083SPeter Grehan static struct io_region vlapic_mmio[VM_MAXCPU]; 835366f6083SPeter Grehan 836366f6083SPeter Grehan struct vlapic * 837366f6083SPeter Grehan vlapic_init(struct vm *vm, int vcpuid) 838366f6083SPeter Grehan { 839366f6083SPeter Grehan struct vlapic *vlapic; 840366f6083SPeter Grehan 841366f6083SPeter Grehan vlapic = malloc(sizeof(struct vlapic), M_VLAPIC, M_WAITOK | M_ZERO); 842366f6083SPeter Grehan vlapic->vm = vm; 843366f6083SPeter Grehan vlapic->vcpuid = vcpuid; 8442d3a73edSNeel Natu 845a2da7af6SNeel Natu vlapic->msr_apicbase = DEFAULT_APIC_BASE | APICBASE_ENABLED; 8462d3a73edSNeel Natu 8472d3a73edSNeel Natu if (vcpuid == 0) 8482d3a73edSNeel Natu vlapic->msr_apicbase |= APICBASE_BSP; 8492d3a73edSNeel Natu 850366f6083SPeter Grehan vlapic->ops = &vlapic_dev_ops; 851366f6083SPeter Grehan 852366f6083SPeter Grehan vlapic->mmio = vlapic_mmio + vcpuid; 853366f6083SPeter Grehan vlapic->mmio->base = DEFAULT_APIC_BASE; 854366f6083SPeter Grehan vlapic->mmio->len = PAGE_SIZE; 855366f6083SPeter Grehan vlapic->mmio->attr = MMIO_READ|MMIO_WRITE; 856366f6083SPeter Grehan vlapic->mmio->vcpu = vcpuid; 857366f6083SPeter Grehan 858366f6083SPeter Grehan vdev_register(&vlapic_dev_ops, vlapic); 859366f6083SPeter Grehan 860366f6083SPeter Grehan vlapic_op_init(vlapic); 861366f6083SPeter Grehan 862366f6083SPeter Grehan return (vlapic); 863366f6083SPeter Grehan } 864366f6083SPeter Grehan 865366f6083SPeter Grehan void 866366f6083SPeter Grehan vlapic_cleanup(struct vlapic *vlapic) 867366f6083SPeter Grehan { 868cd942e0fSPeter Grehan vlapic_op_halt(vlapic); 869366f6083SPeter Grehan vdev_unregister(vlapic); 870366f6083SPeter Grehan free(vlapic, M_VLAPIC); 871366f6083SPeter Grehan } 8722d3a73edSNeel Natu 8732d3a73edSNeel Natu uint64_t 8742d3a73edSNeel Natu vlapic_get_apicbase(struct vlapic *vlapic) 8752d3a73edSNeel Natu { 8762d3a73edSNeel Natu 8772d3a73edSNeel Natu return (vlapic->msr_apicbase); 8782d3a73edSNeel Natu } 8792d3a73edSNeel Natu 8802d3a73edSNeel Natu void 8812d3a73edSNeel Natu vlapic_set_apicbase(struct vlapic *vlapic, uint64_t val) 8822d3a73edSNeel Natu { 883a2da7af6SNeel Natu int err; 884a2da7af6SNeel Natu enum x2apic_state state; 885a2da7af6SNeel Natu 886a2da7af6SNeel Natu err = vm_get_x2apic_state(vlapic->vm, vlapic->vcpuid, &state); 887a2da7af6SNeel Natu if (err) 888a2da7af6SNeel Natu panic("vlapic_set_apicbase: err %d fetching x2apic state", err); 889a2da7af6SNeel Natu 890a2da7af6SNeel Natu if (state == X2APIC_DISABLED) 891a2da7af6SNeel Natu val &= ~APICBASE_X2APIC; 8922d3a73edSNeel Natu 8932d3a73edSNeel Natu vlapic->msr_apicbase = val; 8942d3a73edSNeel Natu } 89573820fb0SNeel Natu 89673820fb0SNeel Natu void 89773820fb0SNeel Natu vlapic_set_x2apic_state(struct vm *vm, int vcpuid, enum x2apic_state state) 89873820fb0SNeel Natu { 89973820fb0SNeel Natu struct vlapic *vlapic; 90073820fb0SNeel Natu 90173820fb0SNeel Natu vlapic = vm_lapic(vm, vcpuid); 90273820fb0SNeel Natu 903485f986aSNeel Natu if (state == X2APIC_DISABLED) 90473820fb0SNeel Natu vlapic->msr_apicbase &= ~APICBASE_X2APIC; 90573820fb0SNeel Natu } 906