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> 39*2d3a73edSNeel Natu #include <x86/specialreg.h> 4034a6b2d6SJohn Baldwin #include <x86/apicreg.h> 41366f6083SPeter Grehan 42366f6083SPeter Grehan #include <machine/vmm.h> 43366f6083SPeter Grehan 44366f6083SPeter Grehan #include "vmm_lapic.h" 45366f6083SPeter Grehan #include "vmm_ktr.h" 46366f6083SPeter Grehan #include "vdev.h" 47366f6083SPeter Grehan #include "vlapic.h" 48366f6083SPeter Grehan 49366f6083SPeter Grehan #define VLAPIC_CTR0(vlapic, format) \ 50366f6083SPeter Grehan VMM_CTR0((vlapic)->vm, (vlapic)->vcpuid, format) 51366f6083SPeter Grehan 52366f6083SPeter Grehan #define VLAPIC_CTR1(vlapic, format, p1) \ 53366f6083SPeter Grehan VMM_CTR1((vlapic)->vm, (vlapic)->vcpuid, format, p1) 54366f6083SPeter Grehan 55366f6083SPeter Grehan #define VLAPIC_CTR_IRR(vlapic, msg) \ 56366f6083SPeter Grehan do { \ 57366f6083SPeter Grehan uint32_t *irrptr = &(vlapic)->apic.irr0; \ 58366f6083SPeter Grehan irrptr[0] = irrptr[0]; /* silence compiler */ \ 59366f6083SPeter Grehan VLAPIC_CTR1((vlapic), msg " irr0 0x%08x", irrptr[0 << 2]); \ 60366f6083SPeter Grehan VLAPIC_CTR1((vlapic), msg " irr1 0x%08x", irrptr[1 << 2]); \ 61366f6083SPeter Grehan VLAPIC_CTR1((vlapic), msg " irr2 0x%08x", irrptr[2 << 2]); \ 62366f6083SPeter Grehan VLAPIC_CTR1((vlapic), msg " irr3 0x%08x", irrptr[3 << 2]); \ 63366f6083SPeter Grehan VLAPIC_CTR1((vlapic), msg " irr4 0x%08x", irrptr[4 << 2]); \ 64366f6083SPeter Grehan VLAPIC_CTR1((vlapic), msg " irr5 0x%08x", irrptr[5 << 2]); \ 65366f6083SPeter Grehan VLAPIC_CTR1((vlapic), msg " irr6 0x%08x", irrptr[6 << 2]); \ 66366f6083SPeter Grehan VLAPIC_CTR1((vlapic), msg " irr7 0x%08x", irrptr[7 << 2]); \ 67366f6083SPeter Grehan } while (0) 68366f6083SPeter Grehan 69366f6083SPeter Grehan #define VLAPIC_CTR_ISR(vlapic, msg) \ 70366f6083SPeter Grehan do { \ 71366f6083SPeter Grehan uint32_t *isrptr = &(vlapic)->apic.isr0; \ 72366f6083SPeter Grehan isrptr[0] = isrptr[0]; /* silence compiler */ \ 73366f6083SPeter Grehan VLAPIC_CTR1((vlapic), msg " isr0 0x%08x", isrptr[0 << 2]); \ 74366f6083SPeter Grehan VLAPIC_CTR1((vlapic), msg " isr1 0x%08x", isrptr[1 << 2]); \ 75366f6083SPeter Grehan VLAPIC_CTR1((vlapic), msg " isr2 0x%08x", isrptr[2 << 2]); \ 76366f6083SPeter Grehan VLAPIC_CTR1((vlapic), msg " isr3 0x%08x", isrptr[3 << 2]); \ 77366f6083SPeter Grehan VLAPIC_CTR1((vlapic), msg " isr4 0x%08x", isrptr[4 << 2]); \ 78366f6083SPeter Grehan VLAPIC_CTR1((vlapic), msg " isr5 0x%08x", isrptr[5 << 2]); \ 79366f6083SPeter Grehan VLAPIC_CTR1((vlapic), msg " isr6 0x%08x", isrptr[6 << 2]); \ 80366f6083SPeter Grehan VLAPIC_CTR1((vlapic), msg " isr7 0x%08x", isrptr[7 << 2]); \ 81366f6083SPeter Grehan } while (0) 82366f6083SPeter Grehan 83366f6083SPeter Grehan static MALLOC_DEFINE(M_VLAPIC, "vlapic", "vlapic"); 84366f6083SPeter Grehan 85366f6083SPeter Grehan #define PRIO(x) ((x) >> 4) 86366f6083SPeter Grehan 87366f6083SPeter Grehan #define VLAPIC_VERSION (16) 88366f6083SPeter Grehan #define VLAPIC_MAXLVT_ENTRIES (5) 89366f6083SPeter Grehan 90*2d3a73edSNeel Natu #define x2apic(vlapic) ((vlapic)->msr_apicbase & APICBASE_X2APIC) 91*2d3a73edSNeel Natu 92366f6083SPeter Grehan struct vlapic { 93366f6083SPeter Grehan struct vm *vm; 94366f6083SPeter Grehan int vcpuid; 95366f6083SPeter Grehan 96366f6083SPeter Grehan struct io_region *mmio; 97366f6083SPeter Grehan struct vdev_ops *ops; 98366f6083SPeter Grehan struct LAPIC apic; 99366f6083SPeter Grehan 100366f6083SPeter Grehan int esr_update; 101366f6083SPeter Grehan 102366f6083SPeter Grehan int divisor; 103366f6083SPeter Grehan int ccr_ticks; 104366f6083SPeter Grehan 105366f6083SPeter Grehan /* 106366f6083SPeter Grehan * The 'isrvec_stk' is a stack of vectors injected by the local apic. 107366f6083SPeter Grehan * A vector is popped from the stack when the processor does an EOI. 108366f6083SPeter Grehan * The vector on the top of the stack is used to compute the 109366f6083SPeter Grehan * Processor Priority in conjunction with the TPR. 110366f6083SPeter Grehan */ 111366f6083SPeter Grehan uint8_t isrvec_stk[ISRVEC_STK_SIZE]; 112366f6083SPeter Grehan int isrvec_stk_top; 113*2d3a73edSNeel Natu 114*2d3a73edSNeel Natu uint64_t msr_apicbase; 115366f6083SPeter Grehan }; 116366f6083SPeter Grehan 117366f6083SPeter Grehan static void 118366f6083SPeter Grehan vlapic_mask_lvts(uint32_t *lvts, int num_lvt) 119366f6083SPeter Grehan { 120366f6083SPeter Grehan int i; 121366f6083SPeter Grehan for (i = 0; i < num_lvt; i++) { 122366f6083SPeter Grehan *lvts |= APIC_LVT_M; 123366f6083SPeter Grehan lvts += 4; 124366f6083SPeter Grehan } 125366f6083SPeter Grehan } 126366f6083SPeter Grehan 127366f6083SPeter Grehan #if 0 128366f6083SPeter Grehan static inline void 129366f6083SPeter Grehan vlapic_dump_lvt(uint32_t offset, uint32_t *lvt) 130366f6083SPeter Grehan { 131366f6083SPeter Grehan printf("Offset %x: lvt %08x (V:%02x DS:%x M:%x)\n", offset, 132366f6083SPeter Grehan *lvt, *lvt & APIC_LVTT_VECTOR, *lvt & APIC_LVTT_DS, 133366f6083SPeter Grehan *lvt & APIC_LVTT_M); 134366f6083SPeter Grehan } 135366f6083SPeter Grehan #endif 136366f6083SPeter Grehan 137366f6083SPeter Grehan static uint64_t 138366f6083SPeter Grehan vlapic_get_ccr(struct vlapic *vlapic) 139366f6083SPeter Grehan { 140366f6083SPeter Grehan struct LAPIC *lapic = &vlapic->apic; 141366f6083SPeter Grehan return lapic->ccr_timer; 142366f6083SPeter Grehan } 143366f6083SPeter Grehan 144366f6083SPeter Grehan static void 145366f6083SPeter Grehan vlapic_update_errors(struct vlapic *vlapic) 146366f6083SPeter Grehan { 147366f6083SPeter Grehan struct LAPIC *lapic = &vlapic->apic; 148366f6083SPeter Grehan lapic->esr = 0; // XXX 149366f6083SPeter Grehan } 150366f6083SPeter Grehan 151366f6083SPeter Grehan static void 152366f6083SPeter Grehan vlapic_init_ipi(struct vlapic *vlapic) 153366f6083SPeter Grehan { 154366f6083SPeter Grehan struct LAPIC *lapic = &vlapic->apic; 155366f6083SPeter Grehan lapic->version = VLAPIC_VERSION; 156366f6083SPeter Grehan lapic->version |= (VLAPIC_MAXLVT_ENTRIES < MAXLVTSHIFT); 157366f6083SPeter Grehan lapic->dfr = 0xffffffff; 158366f6083SPeter Grehan lapic->svr = APIC_SVR_VECTOR; 159366f6083SPeter Grehan vlapic_mask_lvts(&lapic->lvt_timer, VLAPIC_MAXLVT_ENTRIES+1); 160366f6083SPeter Grehan } 161366f6083SPeter Grehan 162366f6083SPeter Grehan static int 163366f6083SPeter Grehan vlapic_op_reset(void* dev) 164366f6083SPeter Grehan { 165366f6083SPeter Grehan struct vlapic *vlapic = (struct vlapic*)dev; 166366f6083SPeter Grehan struct LAPIC *lapic = &vlapic->apic; 167366f6083SPeter Grehan 168366f6083SPeter Grehan memset(lapic, 0, sizeof(*lapic)); 169366f6083SPeter Grehan lapic->apr = vlapic->vcpuid; 170366f6083SPeter Grehan vlapic_init_ipi(vlapic); 171366f6083SPeter Grehan 172366f6083SPeter Grehan return 0; 173366f6083SPeter Grehan 174366f6083SPeter Grehan } 175366f6083SPeter Grehan 176366f6083SPeter Grehan static int 177366f6083SPeter Grehan vlapic_op_init(void* dev) 178366f6083SPeter Grehan { 179366f6083SPeter Grehan struct vlapic *vlapic = (struct vlapic*)dev; 180366f6083SPeter Grehan vdev_register_region(vlapic->ops, vlapic, vlapic->mmio); 181366f6083SPeter Grehan return vlapic_op_reset(dev); 182366f6083SPeter Grehan } 183366f6083SPeter Grehan 184366f6083SPeter Grehan static int 185366f6083SPeter Grehan vlapic_op_halt(void* dev) 186366f6083SPeter Grehan { 187366f6083SPeter Grehan struct vlapic *vlapic = (struct vlapic*)dev; 188366f6083SPeter Grehan vdev_unregister_region(vlapic, vlapic->mmio); 189366f6083SPeter Grehan return 0; 190366f6083SPeter Grehan 191366f6083SPeter Grehan } 192366f6083SPeter Grehan 193366f6083SPeter Grehan void 194366f6083SPeter Grehan vlapic_set_intr_ready(struct vlapic *vlapic, int vector) 195366f6083SPeter Grehan { 196366f6083SPeter Grehan struct LAPIC *lapic = &vlapic->apic; 197366f6083SPeter Grehan uint32_t *irrptr; 198366f6083SPeter Grehan int idx; 199366f6083SPeter Grehan 200366f6083SPeter Grehan if (vector < 0 || vector >= 256) 201366f6083SPeter Grehan panic("vlapic_set_intr_ready: invalid vector %d\n", vector); 202366f6083SPeter Grehan 203366f6083SPeter Grehan idx = (vector / 32) * 4; 204366f6083SPeter Grehan irrptr = &lapic->irr0; 205366f6083SPeter Grehan atomic_set_int(&irrptr[idx], 1 << (vector % 32)); 206366f6083SPeter Grehan VLAPIC_CTR_IRR(vlapic, "vlapic_set_intr_ready"); 207366f6083SPeter Grehan } 208366f6083SPeter Grehan 209366f6083SPeter Grehan #define VLAPIC_BUS_FREQ tsc_freq 210366f6083SPeter Grehan #define VLAPIC_DCR(x) ((x->dcr_timer & 0x8) >> 1)|(x->dcr_timer & 0x3) 211366f6083SPeter Grehan 212366f6083SPeter Grehan static int 213366f6083SPeter Grehan vlapic_timer_divisor(uint32_t dcr) 214366f6083SPeter Grehan { 215366f6083SPeter Grehan switch (dcr & 0xB) { 216366f6083SPeter Grehan case APIC_TDCR_2: 217366f6083SPeter Grehan return (2); 218366f6083SPeter Grehan case APIC_TDCR_4: 219366f6083SPeter Grehan return (4); 220366f6083SPeter Grehan case APIC_TDCR_8: 221366f6083SPeter Grehan return (8); 222366f6083SPeter Grehan case APIC_TDCR_16: 223366f6083SPeter Grehan return (16); 224366f6083SPeter Grehan case APIC_TDCR_32: 225366f6083SPeter Grehan return (32); 226366f6083SPeter Grehan case APIC_TDCR_64: 227366f6083SPeter Grehan return (64); 228366f6083SPeter Grehan case APIC_TDCR_128: 229366f6083SPeter Grehan return (128); 230366f6083SPeter Grehan default: 231366f6083SPeter Grehan panic("vlapic_timer_divisor: invalid dcr 0x%08x", dcr); 232366f6083SPeter Grehan } 233366f6083SPeter Grehan } 234366f6083SPeter Grehan 235366f6083SPeter Grehan static void 236366f6083SPeter Grehan vlapic_start_timer(struct vlapic *vlapic, uint32_t elapsed) 237366f6083SPeter Grehan { 238366f6083SPeter Grehan uint32_t icr_timer; 239366f6083SPeter Grehan 240366f6083SPeter Grehan icr_timer = vlapic->apic.icr_timer; 241366f6083SPeter Grehan 242366f6083SPeter Grehan vlapic->ccr_ticks = ticks; 243366f6083SPeter Grehan if (elapsed < icr_timer) 244366f6083SPeter Grehan vlapic->apic.ccr_timer = icr_timer - elapsed; 245366f6083SPeter Grehan else { 246366f6083SPeter Grehan /* 247366f6083SPeter Grehan * This can happen when the guest is trying to run its local 248366f6083SPeter Grehan * apic timer higher that the setting of 'hz' in the host. 249366f6083SPeter Grehan * 250366f6083SPeter Grehan * We deal with this by running the guest local apic timer 251366f6083SPeter Grehan * at the rate of the host's 'hz' setting. 252366f6083SPeter Grehan */ 253366f6083SPeter Grehan vlapic->apic.ccr_timer = 0; 254366f6083SPeter Grehan } 255366f6083SPeter Grehan } 256366f6083SPeter Grehan 257366f6083SPeter Grehan static __inline uint32_t * 258366f6083SPeter Grehan vlapic_get_lvt(struct vlapic *vlapic, uint32_t offset) 259366f6083SPeter Grehan { 260366f6083SPeter Grehan struct LAPIC *lapic = &vlapic->apic; 261366f6083SPeter Grehan int i; 262366f6083SPeter Grehan 263366f6083SPeter Grehan if (offset < APIC_OFFSET_TIMER_LVT || offset > APIC_OFFSET_ERROR_LVT) { 264366f6083SPeter Grehan panic("vlapic_get_lvt: invalid LVT\n"); 265366f6083SPeter Grehan } 266366f6083SPeter Grehan i = (offset - APIC_OFFSET_TIMER_LVT) >> 2; 267366f6083SPeter Grehan return ((&lapic->lvt_timer) + i);; 268366f6083SPeter Grehan } 269366f6083SPeter Grehan 270366f6083SPeter Grehan #if 1 271366f6083SPeter Grehan static void 272366f6083SPeter Grehan dump_isrvec_stk(struct vlapic *vlapic) 273366f6083SPeter Grehan { 274366f6083SPeter Grehan int i; 275366f6083SPeter Grehan uint32_t *isrptr; 276366f6083SPeter Grehan 277366f6083SPeter Grehan isrptr = &vlapic->apic.isr0; 278366f6083SPeter Grehan for (i = 0; i < 8; i++) 279366f6083SPeter Grehan printf("ISR%d 0x%08x\n", i, isrptr[i * 4]); 280366f6083SPeter Grehan 281366f6083SPeter Grehan for (i = 0; i <= vlapic->isrvec_stk_top; i++) 282366f6083SPeter Grehan printf("isrvec_stk[%d] = %d\n", i, vlapic->isrvec_stk[i]); 283366f6083SPeter Grehan } 284366f6083SPeter Grehan #endif 285366f6083SPeter Grehan 286366f6083SPeter Grehan /* 287366f6083SPeter Grehan * Algorithm adopted from section "Interrupt, Task and Processor Priority" 288366f6083SPeter Grehan * in Intel Architecture Manual Vol 3a. 289366f6083SPeter Grehan */ 290366f6083SPeter Grehan static void 291366f6083SPeter Grehan vlapic_update_ppr(struct vlapic *vlapic) 292366f6083SPeter Grehan { 293366f6083SPeter Grehan int isrvec, tpr, ppr; 294366f6083SPeter Grehan 295366f6083SPeter Grehan /* 296366f6083SPeter Grehan * Note that the value on the stack at index 0 is always 0. 297366f6083SPeter Grehan * 298366f6083SPeter Grehan * This is a placeholder for the value of ISRV when none of the 299366f6083SPeter Grehan * bits is set in the ISRx registers. 300366f6083SPeter Grehan */ 301366f6083SPeter Grehan isrvec = vlapic->isrvec_stk[vlapic->isrvec_stk_top]; 302366f6083SPeter Grehan tpr = vlapic->apic.tpr; 303366f6083SPeter Grehan 304366f6083SPeter Grehan #if 1 305366f6083SPeter Grehan { 306366f6083SPeter Grehan int i, lastprio, curprio, vector, idx; 307366f6083SPeter Grehan uint32_t *isrptr; 308366f6083SPeter Grehan 309366f6083SPeter Grehan if (vlapic->isrvec_stk_top == 0 && isrvec != 0) 310366f6083SPeter Grehan panic("isrvec_stk is corrupted: %d", isrvec); 311366f6083SPeter Grehan 312366f6083SPeter Grehan /* 313366f6083SPeter Grehan * Make sure that the priority of the nested interrupts is 314366f6083SPeter Grehan * always increasing. 315366f6083SPeter Grehan */ 316366f6083SPeter Grehan lastprio = -1; 317366f6083SPeter Grehan for (i = 1; i <= vlapic->isrvec_stk_top; i++) { 318366f6083SPeter Grehan curprio = PRIO(vlapic->isrvec_stk[i]); 319366f6083SPeter Grehan if (curprio <= lastprio) { 320366f6083SPeter Grehan dump_isrvec_stk(vlapic); 321366f6083SPeter Grehan panic("isrvec_stk does not satisfy invariant"); 322366f6083SPeter Grehan } 323366f6083SPeter Grehan lastprio = curprio; 324366f6083SPeter Grehan } 325366f6083SPeter Grehan 326366f6083SPeter Grehan /* 327366f6083SPeter Grehan * Make sure that each bit set in the ISRx registers has a 328366f6083SPeter Grehan * corresponding entry on the isrvec stack. 329366f6083SPeter Grehan */ 330366f6083SPeter Grehan i = 1; 331366f6083SPeter Grehan isrptr = &vlapic->apic.isr0; 332366f6083SPeter Grehan for (vector = 0; vector < 256; vector++) { 333366f6083SPeter Grehan idx = (vector / 32) * 4; 334366f6083SPeter Grehan if (isrptr[idx] & (1 << (vector % 32))) { 335366f6083SPeter Grehan if (i > vlapic->isrvec_stk_top || 336366f6083SPeter Grehan vlapic->isrvec_stk[i] != vector) { 337366f6083SPeter Grehan dump_isrvec_stk(vlapic); 338366f6083SPeter Grehan panic("ISR and isrvec_stk out of sync"); 339366f6083SPeter Grehan } 340366f6083SPeter Grehan i++; 341366f6083SPeter Grehan } 342366f6083SPeter Grehan } 343366f6083SPeter Grehan } 344366f6083SPeter Grehan #endif 345366f6083SPeter Grehan 346366f6083SPeter Grehan if (PRIO(tpr) >= PRIO(isrvec)) 347366f6083SPeter Grehan ppr = tpr; 348366f6083SPeter Grehan else 349366f6083SPeter Grehan ppr = isrvec & 0xf0; 350366f6083SPeter Grehan 351366f6083SPeter Grehan vlapic->apic.ppr = ppr; 352366f6083SPeter Grehan VLAPIC_CTR1(vlapic, "vlapic_update_ppr 0x%02x", ppr); 353366f6083SPeter Grehan } 354366f6083SPeter Grehan 355366f6083SPeter Grehan static void 356366f6083SPeter Grehan vlapic_process_eoi(struct vlapic *vlapic) 357366f6083SPeter Grehan { 358366f6083SPeter Grehan struct LAPIC *lapic = &vlapic->apic; 359366f6083SPeter Grehan uint32_t *isrptr; 360366f6083SPeter Grehan int i, idx, bitpos; 361366f6083SPeter Grehan 362366f6083SPeter Grehan isrptr = &lapic->isr0; 363366f6083SPeter Grehan 364366f6083SPeter Grehan /* 365366f6083SPeter Grehan * The x86 architecture reserves the the first 32 vectors for use 366366f6083SPeter Grehan * by the processor. 367366f6083SPeter Grehan */ 368366f6083SPeter Grehan for (i = 7; i > 0; i--) { 369366f6083SPeter Grehan idx = i * 4; 370366f6083SPeter Grehan bitpos = fls(isrptr[idx]); 371366f6083SPeter Grehan if (bitpos != 0) { 372366f6083SPeter Grehan if (vlapic->isrvec_stk_top <= 0) { 373366f6083SPeter Grehan panic("invalid vlapic isrvec_stk_top %d", 374366f6083SPeter Grehan vlapic->isrvec_stk_top); 375366f6083SPeter Grehan } 376366f6083SPeter Grehan isrptr[idx] &= ~(1 << (bitpos - 1)); 377366f6083SPeter Grehan VLAPIC_CTR_ISR(vlapic, "vlapic_process_eoi"); 378366f6083SPeter Grehan vlapic->isrvec_stk_top--; 379366f6083SPeter Grehan vlapic_update_ppr(vlapic); 380366f6083SPeter Grehan return; 381366f6083SPeter Grehan } 382366f6083SPeter Grehan } 383366f6083SPeter Grehan } 384366f6083SPeter Grehan 385366f6083SPeter Grehan static __inline int 386366f6083SPeter Grehan vlapic_get_lvt_field(uint32_t *lvt, uint32_t mask) 387366f6083SPeter Grehan { 388366f6083SPeter Grehan return (*lvt & mask); 389366f6083SPeter Grehan } 390366f6083SPeter Grehan 391366f6083SPeter Grehan static __inline int 392366f6083SPeter Grehan vlapic_periodic_timer(struct vlapic *vlapic) 393366f6083SPeter Grehan { 394366f6083SPeter Grehan uint32_t *lvt; 395366f6083SPeter Grehan 396366f6083SPeter Grehan lvt = vlapic_get_lvt(vlapic, APIC_OFFSET_TIMER_LVT); 397366f6083SPeter Grehan 398366f6083SPeter Grehan return (vlapic_get_lvt_field(lvt, APIC_LVTT_TM_PERIODIC)); 399366f6083SPeter Grehan } 400366f6083SPeter Grehan 401366f6083SPeter Grehan static void 402366f6083SPeter Grehan vlapic_fire_timer(struct vlapic *vlapic) 403366f6083SPeter Grehan { 404366f6083SPeter Grehan int vector; 405366f6083SPeter Grehan uint32_t *lvt; 406366f6083SPeter Grehan 407366f6083SPeter Grehan lvt = vlapic_get_lvt(vlapic, APIC_OFFSET_TIMER_LVT); 408366f6083SPeter Grehan 409366f6083SPeter Grehan if (!vlapic_get_lvt_field(lvt, APIC_LVTT_M)) { 410366f6083SPeter Grehan vector = vlapic_get_lvt_field(lvt,APIC_LVTT_VECTOR); 411366f6083SPeter Grehan vlapic_set_intr_ready(vlapic, vector); 412366f6083SPeter Grehan } 413366f6083SPeter Grehan } 414366f6083SPeter Grehan 415366f6083SPeter Grehan static int 416366f6083SPeter Grehan lapic_process_icr(struct vlapic *vlapic, uint64_t icrval) 417366f6083SPeter Grehan { 418366f6083SPeter Grehan int i; 419a5615c90SPeter Grehan cpuset_t dmask; 420366f6083SPeter Grehan uint32_t dest, vec, mode; 421366f6083SPeter Grehan 422366f6083SPeter Grehan dest = icrval >> 32; 423366f6083SPeter Grehan vec = icrval & APIC_VECTOR_MASK; 424366f6083SPeter Grehan mode = icrval & APIC_DELMODE_MASK; 425366f6083SPeter Grehan 426366f6083SPeter Grehan if (mode == APIC_DELMODE_FIXED || mode == APIC_DELMODE_NMI) { 427366f6083SPeter Grehan switch (icrval & APIC_DEST_MASK) { 428366f6083SPeter Grehan case APIC_DEST_DESTFLD: 429a5615c90SPeter Grehan CPU_SETOF(dest, &dmask); 430366f6083SPeter Grehan break; 431366f6083SPeter Grehan case APIC_DEST_SELF: 432a5615c90SPeter Grehan CPU_SETOF(vlapic->vcpuid, &dmask); 433366f6083SPeter Grehan break; 434366f6083SPeter Grehan case APIC_DEST_ALLISELF: 435366f6083SPeter Grehan dmask = vm_active_cpus(vlapic->vm); 436366f6083SPeter Grehan break; 437366f6083SPeter Grehan case APIC_DEST_ALLESELF: 438a5615c90SPeter Grehan dmask = vm_active_cpus(vlapic->vm); 439a5615c90SPeter Grehan CPU_CLR(vlapic->vcpuid, &dmask); 440366f6083SPeter Grehan break; 441366f6083SPeter Grehan } 442366f6083SPeter Grehan 443a5615c90SPeter Grehan while ((i = cpusetobj_ffs(&dmask)) != 0) { 444a5615c90SPeter Grehan i--; 445a5615c90SPeter Grehan CPU_CLR(i, &dmask); 446366f6083SPeter Grehan if (mode == APIC_DELMODE_FIXED) 447366f6083SPeter Grehan lapic_set_intr(vlapic->vm, i, vec); 448366f6083SPeter Grehan else 449366f6083SPeter Grehan vm_inject_nmi(vlapic->vm, i); 450366f6083SPeter Grehan } 451366f6083SPeter Grehan 452366f6083SPeter Grehan return (0); /* handled completely in the kernel */ 453366f6083SPeter Grehan } 454366f6083SPeter Grehan 455366f6083SPeter Grehan /* 456366f6083SPeter Grehan * XXX this assumes that the startup IPI always succeeds 457366f6083SPeter Grehan */ 458366f6083SPeter Grehan if (mode == APIC_DELMODE_STARTUP) 459366f6083SPeter Grehan vm_activate_cpu(vlapic->vm, dest); 460366f6083SPeter Grehan 461366f6083SPeter Grehan /* 462366f6083SPeter Grehan * This will cause a return to userland. 463366f6083SPeter Grehan */ 464366f6083SPeter Grehan return (1); 465366f6083SPeter Grehan } 466366f6083SPeter Grehan 467366f6083SPeter Grehan int 468366f6083SPeter Grehan vlapic_pending_intr(struct vlapic *vlapic) 469366f6083SPeter Grehan { 470366f6083SPeter Grehan struct LAPIC *lapic = &vlapic->apic; 471366f6083SPeter Grehan int idx, i, bitpos, vector; 472366f6083SPeter Grehan uint32_t *irrptr, val; 473366f6083SPeter Grehan 474366f6083SPeter Grehan irrptr = &lapic->irr0; 475366f6083SPeter Grehan 476366f6083SPeter Grehan /* 477366f6083SPeter Grehan * The x86 architecture reserves the the first 32 vectors for use 478366f6083SPeter Grehan * by the processor. 479366f6083SPeter Grehan */ 480366f6083SPeter Grehan for (i = 7; i > 0; i--) { 481366f6083SPeter Grehan idx = i * 4; 482366f6083SPeter Grehan val = atomic_load_acq_int(&irrptr[idx]); 483366f6083SPeter Grehan bitpos = fls(val); 484366f6083SPeter Grehan if (bitpos != 0) { 485366f6083SPeter Grehan vector = i * 32 + (bitpos - 1); 486366f6083SPeter Grehan if (PRIO(vector) > PRIO(lapic->ppr)) { 487366f6083SPeter Grehan VLAPIC_CTR1(vlapic, "pending intr %d", vector); 488366f6083SPeter Grehan return (vector); 489366f6083SPeter Grehan } else 490366f6083SPeter Grehan break; 491366f6083SPeter Grehan } 492366f6083SPeter Grehan } 493366f6083SPeter Grehan VLAPIC_CTR0(vlapic, "no pending intr"); 494366f6083SPeter Grehan return (-1); 495366f6083SPeter Grehan } 496366f6083SPeter Grehan 497366f6083SPeter Grehan void 498366f6083SPeter Grehan vlapic_intr_accepted(struct vlapic *vlapic, int vector) 499366f6083SPeter Grehan { 500366f6083SPeter Grehan struct LAPIC *lapic = &vlapic->apic; 501366f6083SPeter Grehan uint32_t *irrptr, *isrptr; 502366f6083SPeter Grehan int idx, stk_top; 503366f6083SPeter Grehan 504366f6083SPeter Grehan /* 505366f6083SPeter Grehan * clear the ready bit for vector being accepted in irr 506366f6083SPeter Grehan * and set the vector as in service in isr. 507366f6083SPeter Grehan */ 508366f6083SPeter Grehan idx = (vector / 32) * 4; 509366f6083SPeter Grehan 510366f6083SPeter Grehan irrptr = &lapic->irr0; 511366f6083SPeter Grehan atomic_clear_int(&irrptr[idx], 1 << (vector % 32)); 512366f6083SPeter Grehan VLAPIC_CTR_IRR(vlapic, "vlapic_intr_accepted"); 513366f6083SPeter Grehan 514366f6083SPeter Grehan isrptr = &lapic->isr0; 515366f6083SPeter Grehan isrptr[idx] |= 1 << (vector % 32); 516366f6083SPeter Grehan VLAPIC_CTR_ISR(vlapic, "vlapic_intr_accepted"); 517366f6083SPeter Grehan 518366f6083SPeter Grehan /* 519366f6083SPeter Grehan * Update the PPR 520366f6083SPeter Grehan */ 521366f6083SPeter Grehan vlapic->isrvec_stk_top++; 522366f6083SPeter Grehan 523366f6083SPeter Grehan stk_top = vlapic->isrvec_stk_top; 524366f6083SPeter Grehan if (stk_top >= ISRVEC_STK_SIZE) 525366f6083SPeter Grehan panic("isrvec_stk_top overflow %d", stk_top); 526366f6083SPeter Grehan 527366f6083SPeter Grehan vlapic->isrvec_stk[stk_top] = vector; 528366f6083SPeter Grehan vlapic_update_ppr(vlapic); 529366f6083SPeter Grehan } 530366f6083SPeter Grehan 531366f6083SPeter Grehan int 532366f6083SPeter Grehan vlapic_op_mem_read(void* dev, uint64_t gpa, opsize_t size, uint64_t *data) 533366f6083SPeter Grehan { 534366f6083SPeter Grehan struct vlapic *vlapic = (struct vlapic*)dev; 535366f6083SPeter Grehan struct LAPIC *lapic = &vlapic->apic; 536366f6083SPeter Grehan uint64_t offset = gpa & ~(PAGE_SIZE); 537366f6083SPeter Grehan uint32_t *reg; 538366f6083SPeter Grehan int i; 539366f6083SPeter Grehan 540366f6083SPeter Grehan if (offset > sizeof(*lapic)) { 541366f6083SPeter Grehan *data = 0; 542366f6083SPeter Grehan return 0; 543366f6083SPeter Grehan } 544366f6083SPeter Grehan 545366f6083SPeter Grehan offset &= ~3; 546366f6083SPeter Grehan switch(offset) 547366f6083SPeter Grehan { 548366f6083SPeter Grehan case APIC_OFFSET_ID: 549*2d3a73edSNeel Natu if (x2apic(vlapic)) 550*2d3a73edSNeel Natu *data = vlapic->vcpuid; 551*2d3a73edSNeel Natu else 552*2d3a73edSNeel Natu *data = vlapic->vcpuid << 24; 553366f6083SPeter Grehan break; 554366f6083SPeter Grehan case APIC_OFFSET_VER: 555366f6083SPeter Grehan *data = lapic->version; 556366f6083SPeter Grehan break; 557366f6083SPeter Grehan case APIC_OFFSET_TPR: 558366f6083SPeter Grehan *data = lapic->tpr; 559366f6083SPeter Grehan break; 560366f6083SPeter Grehan case APIC_OFFSET_APR: 561366f6083SPeter Grehan *data = lapic->apr; 562366f6083SPeter Grehan break; 563366f6083SPeter Grehan case APIC_OFFSET_PPR: 564366f6083SPeter Grehan *data = lapic->ppr; 565366f6083SPeter Grehan break; 566366f6083SPeter Grehan case APIC_OFFSET_EOI: 567366f6083SPeter Grehan *data = lapic->eoi; 568366f6083SPeter Grehan break; 569366f6083SPeter Grehan case APIC_OFFSET_LDR: 570366f6083SPeter Grehan *data = lapic->ldr; 571366f6083SPeter Grehan break; 572366f6083SPeter Grehan case APIC_OFFSET_DFR: 573366f6083SPeter Grehan *data = lapic->dfr; 574366f6083SPeter Grehan break; 575366f6083SPeter Grehan case APIC_OFFSET_SVR: 576366f6083SPeter Grehan *data = lapic->svr; 577366f6083SPeter Grehan break; 578366f6083SPeter Grehan case APIC_OFFSET_ISR0 ... APIC_OFFSET_ISR7: 579366f6083SPeter Grehan i = (offset - APIC_OFFSET_ISR0) >> 2; 580366f6083SPeter Grehan reg = &lapic->isr0; 581366f6083SPeter Grehan *data = *(reg + i); 582366f6083SPeter Grehan break; 583366f6083SPeter Grehan case APIC_OFFSET_TMR0 ... APIC_OFFSET_TMR7: 584366f6083SPeter Grehan i = (offset - APIC_OFFSET_TMR0) >> 2; 585366f6083SPeter Grehan reg = &lapic->tmr0; 586366f6083SPeter Grehan *data = *(reg + i); 587366f6083SPeter Grehan break; 588366f6083SPeter Grehan case APIC_OFFSET_IRR0 ... APIC_OFFSET_IRR7: 589366f6083SPeter Grehan i = (offset - APIC_OFFSET_IRR0) >> 2; 590366f6083SPeter Grehan reg = &lapic->irr0; 591366f6083SPeter Grehan *data = atomic_load_acq_int(reg + i); 592366f6083SPeter Grehan break; 593366f6083SPeter Grehan case APIC_OFFSET_ESR: 594366f6083SPeter Grehan *data = lapic->esr; 595366f6083SPeter Grehan break; 596366f6083SPeter Grehan case APIC_OFFSET_ICR_LOW: 597366f6083SPeter Grehan *data = lapic->icr_lo; 598366f6083SPeter Grehan break; 599366f6083SPeter Grehan case APIC_OFFSET_ICR_HI: 600366f6083SPeter Grehan *data = lapic->icr_hi; 601366f6083SPeter Grehan break; 602366f6083SPeter Grehan case APIC_OFFSET_TIMER_LVT ... APIC_OFFSET_ERROR_LVT: 603366f6083SPeter Grehan reg = vlapic_get_lvt(vlapic, offset); 604366f6083SPeter Grehan *data = *(reg); 605366f6083SPeter Grehan break; 606366f6083SPeter Grehan case APIC_OFFSET_ICR: 607366f6083SPeter Grehan *data = lapic->icr_timer; 608366f6083SPeter Grehan break; 609366f6083SPeter Grehan case APIC_OFFSET_CCR: 610366f6083SPeter Grehan *data = vlapic_get_ccr(vlapic); 611366f6083SPeter Grehan break; 612366f6083SPeter Grehan case APIC_OFFSET_DCR: 613366f6083SPeter Grehan *data = lapic->dcr_timer; 614366f6083SPeter Grehan break; 615366f6083SPeter Grehan case APIC_OFFSET_RRR: 616366f6083SPeter Grehan default: 617366f6083SPeter Grehan *data = 0; 618366f6083SPeter Grehan break; 619366f6083SPeter Grehan } 620366f6083SPeter Grehan return 0; 621366f6083SPeter Grehan } 622366f6083SPeter Grehan 623366f6083SPeter Grehan int 624366f6083SPeter Grehan vlapic_op_mem_write(void* dev, uint64_t gpa, opsize_t size, uint64_t data) 625366f6083SPeter Grehan { 626366f6083SPeter Grehan struct vlapic *vlapic = (struct vlapic*)dev; 627366f6083SPeter Grehan struct LAPIC *lapic = &vlapic->apic; 628366f6083SPeter Grehan uint64_t offset = gpa & ~(PAGE_SIZE); 629366f6083SPeter Grehan uint32_t *reg; 630366f6083SPeter Grehan int retval; 631366f6083SPeter Grehan 632366f6083SPeter Grehan if (offset > sizeof(*lapic)) { 633366f6083SPeter Grehan return 0; 634366f6083SPeter Grehan } 635366f6083SPeter Grehan 636366f6083SPeter Grehan retval = 0; 637366f6083SPeter Grehan offset &= ~3; 638366f6083SPeter Grehan switch(offset) 639366f6083SPeter Grehan { 640366f6083SPeter Grehan case APIC_OFFSET_ID: 641366f6083SPeter Grehan break; 642366f6083SPeter Grehan case APIC_OFFSET_TPR: 643366f6083SPeter Grehan lapic->tpr = data & 0xff; 644366f6083SPeter Grehan vlapic_update_ppr(vlapic); 645366f6083SPeter Grehan break; 646366f6083SPeter Grehan case APIC_OFFSET_EOI: 647366f6083SPeter Grehan vlapic_process_eoi(vlapic); 648366f6083SPeter Grehan break; 649366f6083SPeter Grehan case APIC_OFFSET_LDR: 650366f6083SPeter Grehan break; 651366f6083SPeter Grehan case APIC_OFFSET_DFR: 652366f6083SPeter Grehan break; 653366f6083SPeter Grehan case APIC_OFFSET_SVR: 654366f6083SPeter Grehan lapic->svr = data; 655366f6083SPeter Grehan break; 656366f6083SPeter Grehan case APIC_OFFSET_ICR_LOW: 657366f6083SPeter Grehan retval = lapic_process_icr(vlapic, data); 658366f6083SPeter Grehan break; 659366f6083SPeter Grehan case APIC_OFFSET_TIMER_LVT ... APIC_OFFSET_ERROR_LVT: 660366f6083SPeter Grehan reg = vlapic_get_lvt(vlapic, offset); 661366f6083SPeter Grehan if (!(lapic->svr & APIC_SVR_ENABLE)) { 662366f6083SPeter Grehan data |= APIC_LVT_M; 663366f6083SPeter Grehan } 664366f6083SPeter Grehan *reg = data; 665366f6083SPeter Grehan // vlapic_dump_lvt(offset, reg); 666366f6083SPeter Grehan break; 667366f6083SPeter Grehan case APIC_OFFSET_ICR: 668366f6083SPeter Grehan lapic->icr_timer = data; 669366f6083SPeter Grehan vlapic_start_timer(vlapic, 0); 670366f6083SPeter Grehan break; 671366f6083SPeter Grehan 672366f6083SPeter Grehan case APIC_OFFSET_DCR: 673366f6083SPeter Grehan lapic->dcr_timer = data; 674366f6083SPeter Grehan vlapic->divisor = vlapic_timer_divisor(data); 675366f6083SPeter Grehan break; 676366f6083SPeter Grehan 677366f6083SPeter Grehan case APIC_OFFSET_ESR: 678366f6083SPeter Grehan vlapic_update_errors(vlapic); 679366f6083SPeter Grehan break; 680366f6083SPeter Grehan case APIC_OFFSET_VER: 681366f6083SPeter Grehan case APIC_OFFSET_APR: 682366f6083SPeter Grehan case APIC_OFFSET_PPR: 683366f6083SPeter Grehan case APIC_OFFSET_RRR: 684366f6083SPeter Grehan case APIC_OFFSET_ISR0 ... APIC_OFFSET_ISR7: 685366f6083SPeter Grehan case APIC_OFFSET_TMR0 ... APIC_OFFSET_TMR7: 686366f6083SPeter Grehan case APIC_OFFSET_IRR0 ... APIC_OFFSET_IRR7: 687366f6083SPeter Grehan case APIC_OFFSET_CCR: 688366f6083SPeter Grehan default: 689366f6083SPeter Grehan // Read only. 690366f6083SPeter Grehan break; 691366f6083SPeter Grehan } 692366f6083SPeter Grehan 693366f6083SPeter Grehan return (retval); 694366f6083SPeter Grehan } 695366f6083SPeter Grehan 696366f6083SPeter Grehan void 697366f6083SPeter Grehan vlapic_timer_tick(struct vlapic *vlapic) 698366f6083SPeter Grehan { 699366f6083SPeter Grehan int curticks, delta, periodic; 700366f6083SPeter Grehan uint32_t ccr; 701366f6083SPeter Grehan uint32_t decrement, remainder; 702366f6083SPeter Grehan 703366f6083SPeter Grehan curticks = ticks; 704366f6083SPeter Grehan 705366f6083SPeter Grehan /* Common case */ 706366f6083SPeter Grehan delta = curticks - vlapic->ccr_ticks; 707366f6083SPeter Grehan if (delta == 0) 708366f6083SPeter Grehan return; 709366f6083SPeter Grehan 710366f6083SPeter Grehan /* Local APIC timer is disabled */ 711366f6083SPeter Grehan if (vlapic->apic.icr_timer == 0) 712366f6083SPeter Grehan return; 713366f6083SPeter Grehan 714366f6083SPeter Grehan /* One-shot mode and timer has already counted down to zero */ 715366f6083SPeter Grehan periodic = vlapic_periodic_timer(vlapic); 716366f6083SPeter Grehan if (!periodic && vlapic->apic.ccr_timer == 0) 717366f6083SPeter Grehan return; 718366f6083SPeter Grehan /* 719366f6083SPeter Grehan * The 'curticks' and 'ccr_ticks' are out of sync by more than 720366f6083SPeter Grehan * 2^31 ticks. We deal with this by restarting the timer. 721366f6083SPeter Grehan */ 722366f6083SPeter Grehan if (delta < 0) { 723366f6083SPeter Grehan vlapic_start_timer(vlapic, 0); 724366f6083SPeter Grehan return; 725366f6083SPeter Grehan } 726366f6083SPeter Grehan 727366f6083SPeter Grehan ccr = vlapic->apic.ccr_timer; 728366f6083SPeter Grehan decrement = (VLAPIC_BUS_FREQ / vlapic->divisor) / hz; 729366f6083SPeter Grehan while (delta-- > 0) { 730366f6083SPeter Grehan if (ccr <= decrement) { 731366f6083SPeter Grehan remainder = decrement - ccr; 732366f6083SPeter Grehan vlapic_fire_timer(vlapic); 733366f6083SPeter Grehan if (periodic) { 734366f6083SPeter Grehan vlapic_start_timer(vlapic, remainder); 735366f6083SPeter Grehan ccr = vlapic->apic.ccr_timer; 736366f6083SPeter Grehan } else { 737366f6083SPeter Grehan /* 738366f6083SPeter Grehan * One-shot timer has counted down to zero. 739366f6083SPeter Grehan */ 740366f6083SPeter Grehan ccr = 0; 741366f6083SPeter Grehan break; 742366f6083SPeter Grehan } 743366f6083SPeter Grehan } else 744366f6083SPeter Grehan ccr -= decrement; 745366f6083SPeter Grehan } 746366f6083SPeter Grehan 747366f6083SPeter Grehan vlapic->ccr_ticks = curticks; 748366f6083SPeter Grehan vlapic->apic.ccr_timer = ccr; 749366f6083SPeter Grehan } 750366f6083SPeter Grehan 751366f6083SPeter Grehan struct vdev_ops vlapic_dev_ops = { 752366f6083SPeter Grehan .name = "vlapic", 753366f6083SPeter Grehan .init = vlapic_op_init, 754366f6083SPeter Grehan .reset = vlapic_op_reset, 755366f6083SPeter Grehan .halt = vlapic_op_halt, 756366f6083SPeter Grehan .memread = vlapic_op_mem_read, 757366f6083SPeter Grehan .memwrite = vlapic_op_mem_write, 758366f6083SPeter Grehan }; 759366f6083SPeter Grehan static struct io_region vlapic_mmio[VM_MAXCPU]; 760366f6083SPeter Grehan 761366f6083SPeter Grehan struct vlapic * 762366f6083SPeter Grehan vlapic_init(struct vm *vm, int vcpuid) 763366f6083SPeter Grehan { 764366f6083SPeter Grehan struct vlapic *vlapic; 765366f6083SPeter Grehan 766366f6083SPeter Grehan vlapic = malloc(sizeof(struct vlapic), M_VLAPIC, M_WAITOK | M_ZERO); 767366f6083SPeter Grehan vlapic->vm = vm; 768366f6083SPeter Grehan vlapic->vcpuid = vcpuid; 769*2d3a73edSNeel Natu 770*2d3a73edSNeel Natu vlapic->msr_apicbase = DEFAULT_APIC_BASE | 771*2d3a73edSNeel Natu APICBASE_ENABLED | 772*2d3a73edSNeel Natu APICBASE_X2APIC; 773*2d3a73edSNeel Natu 774*2d3a73edSNeel Natu if (vcpuid == 0) 775*2d3a73edSNeel Natu vlapic->msr_apicbase |= APICBASE_BSP; 776*2d3a73edSNeel Natu 777366f6083SPeter Grehan vlapic->ops = &vlapic_dev_ops; 778366f6083SPeter Grehan 779366f6083SPeter Grehan vlapic->mmio = vlapic_mmio + vcpuid; 780366f6083SPeter Grehan vlapic->mmio->base = DEFAULT_APIC_BASE; 781366f6083SPeter Grehan vlapic->mmio->len = PAGE_SIZE; 782366f6083SPeter Grehan vlapic->mmio->attr = MMIO_READ|MMIO_WRITE; 783366f6083SPeter Grehan vlapic->mmio->vcpu = vcpuid; 784366f6083SPeter Grehan 785366f6083SPeter Grehan vdev_register(&vlapic_dev_ops, vlapic); 786366f6083SPeter Grehan 787366f6083SPeter Grehan vlapic_op_init(vlapic); 788366f6083SPeter Grehan 789366f6083SPeter Grehan return (vlapic); 790366f6083SPeter Grehan } 791366f6083SPeter Grehan 792366f6083SPeter Grehan void 793366f6083SPeter Grehan vlapic_cleanup(struct vlapic *vlapic) 794366f6083SPeter Grehan { 795cd942e0fSPeter Grehan vlapic_op_halt(vlapic); 796366f6083SPeter Grehan vdev_unregister(vlapic); 797366f6083SPeter Grehan free(vlapic, M_VLAPIC); 798366f6083SPeter Grehan } 799*2d3a73edSNeel Natu 800*2d3a73edSNeel Natu uint64_t 801*2d3a73edSNeel Natu vlapic_get_apicbase(struct vlapic *vlapic) 802*2d3a73edSNeel Natu { 803*2d3a73edSNeel Natu 804*2d3a73edSNeel Natu return (vlapic->msr_apicbase); 805*2d3a73edSNeel Natu } 806*2d3a73edSNeel Natu 807*2d3a73edSNeel Natu void 808*2d3a73edSNeel Natu vlapic_set_apicbase(struct vlapic *vlapic, uint64_t val) 809*2d3a73edSNeel Natu { 810*2d3a73edSNeel Natu 811*2d3a73edSNeel Natu vlapic->msr_apicbase = val; 812*2d3a73edSNeel Natu } 813