1 /* 2 * Copyright (c) 2018-2019 Maxime Villard, All rights reserved. 3 * 4 * NetBSD Virtual Machine Monitor (NVMM) accelerator for QEMU. 5 * 6 * This work is licensed under the terms of the GNU GPL, version 2 or later. 7 * See the COPYING file in the top-level directory. 8 */ 9 10 #include "qemu/osdep.h" 11 #include "cpu.h" 12 #include "exec/address-spaces.h" 13 #include "exec/ioport.h" 14 #include "qemu-common.h" 15 #include "qemu/accel.h" 16 #include "sysemu/nvmm.h" 17 #include "sysemu/cpus.h" 18 #include "sysemu/runstate.h" 19 #include "qemu/main-loop.h" 20 #include "qemu/error-report.h" 21 #include "qapi/error.h" 22 #include "qemu/queue.h" 23 #include "migration/blocker.h" 24 #include "strings.h" 25 26 #include "nvmm-accel-ops.h" 27 28 #include <nvmm.h> 29 30 struct qemu_vcpu { 31 struct nvmm_vcpu vcpu; 32 uint8_t tpr; 33 bool stop; 34 35 /* Window-exiting for INTs/NMIs. */ 36 bool int_window_exit; 37 bool nmi_window_exit; 38 39 /* The guest is in an interrupt shadow (POP SS, etc). */ 40 bool int_shadow; 41 }; 42 43 struct qemu_machine { 44 struct nvmm_capability cap; 45 struct nvmm_machine mach; 46 }; 47 48 /* -------------------------------------------------------------------------- */ 49 50 static bool nvmm_allowed; 51 static struct qemu_machine qemu_mach; 52 53 static struct qemu_vcpu * 54 get_qemu_vcpu(CPUState *cpu) 55 { 56 return (struct qemu_vcpu *)cpu->hax_vcpu; 57 } 58 59 static struct nvmm_machine * 60 get_nvmm_mach(void) 61 { 62 return &qemu_mach.mach; 63 } 64 65 /* -------------------------------------------------------------------------- */ 66 67 static void 68 nvmm_set_segment(struct nvmm_x64_state_seg *nseg, const SegmentCache *qseg) 69 { 70 uint32_t attrib = qseg->flags; 71 72 nseg->selector = qseg->selector; 73 nseg->limit = qseg->limit; 74 nseg->base = qseg->base; 75 nseg->attrib.type = __SHIFTOUT(attrib, DESC_TYPE_MASK); 76 nseg->attrib.s = __SHIFTOUT(attrib, DESC_S_MASK); 77 nseg->attrib.dpl = __SHIFTOUT(attrib, DESC_DPL_MASK); 78 nseg->attrib.p = __SHIFTOUT(attrib, DESC_P_MASK); 79 nseg->attrib.avl = __SHIFTOUT(attrib, DESC_AVL_MASK); 80 nseg->attrib.l = __SHIFTOUT(attrib, DESC_L_MASK); 81 nseg->attrib.def = __SHIFTOUT(attrib, DESC_B_MASK); 82 nseg->attrib.g = __SHIFTOUT(attrib, DESC_G_MASK); 83 } 84 85 static void 86 nvmm_set_registers(CPUState *cpu) 87 { 88 CPUX86State *env = cpu->env_ptr; 89 struct nvmm_machine *mach = get_nvmm_mach(); 90 struct qemu_vcpu *qcpu = get_qemu_vcpu(cpu); 91 struct nvmm_vcpu *vcpu = &qcpu->vcpu; 92 struct nvmm_x64_state *state = vcpu->state; 93 uint64_t bitmap; 94 size_t i; 95 int ret; 96 97 assert(cpu_is_stopped(cpu) || qemu_cpu_is_self(cpu)); 98 99 /* GPRs. */ 100 state->gprs[NVMM_X64_GPR_RAX] = env->regs[R_EAX]; 101 state->gprs[NVMM_X64_GPR_RCX] = env->regs[R_ECX]; 102 state->gprs[NVMM_X64_GPR_RDX] = env->regs[R_EDX]; 103 state->gprs[NVMM_X64_GPR_RBX] = env->regs[R_EBX]; 104 state->gprs[NVMM_X64_GPR_RSP] = env->regs[R_ESP]; 105 state->gprs[NVMM_X64_GPR_RBP] = env->regs[R_EBP]; 106 state->gprs[NVMM_X64_GPR_RSI] = env->regs[R_ESI]; 107 state->gprs[NVMM_X64_GPR_RDI] = env->regs[R_EDI]; 108 #ifdef TARGET_X86_64 109 state->gprs[NVMM_X64_GPR_R8] = env->regs[R_R8]; 110 state->gprs[NVMM_X64_GPR_R9] = env->regs[R_R9]; 111 state->gprs[NVMM_X64_GPR_R10] = env->regs[R_R10]; 112 state->gprs[NVMM_X64_GPR_R11] = env->regs[R_R11]; 113 state->gprs[NVMM_X64_GPR_R12] = env->regs[R_R12]; 114 state->gprs[NVMM_X64_GPR_R13] = env->regs[R_R13]; 115 state->gprs[NVMM_X64_GPR_R14] = env->regs[R_R14]; 116 state->gprs[NVMM_X64_GPR_R15] = env->regs[R_R15]; 117 #endif 118 119 /* RIP and RFLAGS. */ 120 state->gprs[NVMM_X64_GPR_RIP] = env->eip; 121 state->gprs[NVMM_X64_GPR_RFLAGS] = env->eflags; 122 123 /* Segments. */ 124 nvmm_set_segment(&state->segs[NVMM_X64_SEG_CS], &env->segs[R_CS]); 125 nvmm_set_segment(&state->segs[NVMM_X64_SEG_DS], &env->segs[R_DS]); 126 nvmm_set_segment(&state->segs[NVMM_X64_SEG_ES], &env->segs[R_ES]); 127 nvmm_set_segment(&state->segs[NVMM_X64_SEG_FS], &env->segs[R_FS]); 128 nvmm_set_segment(&state->segs[NVMM_X64_SEG_GS], &env->segs[R_GS]); 129 nvmm_set_segment(&state->segs[NVMM_X64_SEG_SS], &env->segs[R_SS]); 130 131 /* Special segments. */ 132 nvmm_set_segment(&state->segs[NVMM_X64_SEG_GDT], &env->gdt); 133 nvmm_set_segment(&state->segs[NVMM_X64_SEG_LDT], &env->ldt); 134 nvmm_set_segment(&state->segs[NVMM_X64_SEG_TR], &env->tr); 135 nvmm_set_segment(&state->segs[NVMM_X64_SEG_IDT], &env->idt); 136 137 /* Control registers. */ 138 state->crs[NVMM_X64_CR_CR0] = env->cr[0]; 139 state->crs[NVMM_X64_CR_CR2] = env->cr[2]; 140 state->crs[NVMM_X64_CR_CR3] = env->cr[3]; 141 state->crs[NVMM_X64_CR_CR4] = env->cr[4]; 142 state->crs[NVMM_X64_CR_CR8] = qcpu->tpr; 143 state->crs[NVMM_X64_CR_XCR0] = env->xcr0; 144 145 /* Debug registers. */ 146 state->drs[NVMM_X64_DR_DR0] = env->dr[0]; 147 state->drs[NVMM_X64_DR_DR1] = env->dr[1]; 148 state->drs[NVMM_X64_DR_DR2] = env->dr[2]; 149 state->drs[NVMM_X64_DR_DR3] = env->dr[3]; 150 state->drs[NVMM_X64_DR_DR6] = env->dr[6]; 151 state->drs[NVMM_X64_DR_DR7] = env->dr[7]; 152 153 /* FPU. */ 154 state->fpu.fx_cw = env->fpuc; 155 state->fpu.fx_sw = (env->fpus & ~0x3800) | ((env->fpstt & 0x7) << 11); 156 state->fpu.fx_tw = 0; 157 for (i = 0; i < 8; i++) { 158 state->fpu.fx_tw |= (!env->fptags[i]) << i; 159 } 160 state->fpu.fx_opcode = env->fpop; 161 state->fpu.fx_ip.fa_64 = env->fpip; 162 state->fpu.fx_dp.fa_64 = env->fpdp; 163 state->fpu.fx_mxcsr = env->mxcsr; 164 state->fpu.fx_mxcsr_mask = 0x0000FFFF; 165 assert(sizeof(state->fpu.fx_87_ac) == sizeof(env->fpregs)); 166 memcpy(state->fpu.fx_87_ac, env->fpregs, sizeof(env->fpregs)); 167 for (i = 0; i < CPU_NB_REGS; i++) { 168 memcpy(&state->fpu.fx_xmm[i].xmm_bytes[0], 169 &env->xmm_regs[i].ZMM_Q(0), 8); 170 memcpy(&state->fpu.fx_xmm[i].xmm_bytes[8], 171 &env->xmm_regs[i].ZMM_Q(1), 8); 172 } 173 174 /* MSRs. */ 175 state->msrs[NVMM_X64_MSR_EFER] = env->efer; 176 state->msrs[NVMM_X64_MSR_STAR] = env->star; 177 #ifdef TARGET_X86_64 178 state->msrs[NVMM_X64_MSR_LSTAR] = env->lstar; 179 state->msrs[NVMM_X64_MSR_CSTAR] = env->cstar; 180 state->msrs[NVMM_X64_MSR_SFMASK] = env->fmask; 181 state->msrs[NVMM_X64_MSR_KERNELGSBASE] = env->kernelgsbase; 182 #endif 183 state->msrs[NVMM_X64_MSR_SYSENTER_CS] = env->sysenter_cs; 184 state->msrs[NVMM_X64_MSR_SYSENTER_ESP] = env->sysenter_esp; 185 state->msrs[NVMM_X64_MSR_SYSENTER_EIP] = env->sysenter_eip; 186 state->msrs[NVMM_X64_MSR_PAT] = env->pat; 187 state->msrs[NVMM_X64_MSR_TSC] = env->tsc; 188 189 bitmap = 190 NVMM_X64_STATE_SEGS | 191 NVMM_X64_STATE_GPRS | 192 NVMM_X64_STATE_CRS | 193 NVMM_X64_STATE_DRS | 194 NVMM_X64_STATE_MSRS | 195 NVMM_X64_STATE_FPU; 196 197 ret = nvmm_vcpu_setstate(mach, vcpu, bitmap); 198 if (ret == -1) { 199 error_report("NVMM: Failed to set virtual processor context," 200 " error=%d", errno); 201 } 202 } 203 204 static void 205 nvmm_get_segment(SegmentCache *qseg, const struct nvmm_x64_state_seg *nseg) 206 { 207 qseg->selector = nseg->selector; 208 qseg->limit = nseg->limit; 209 qseg->base = nseg->base; 210 211 qseg->flags = 212 __SHIFTIN((uint32_t)nseg->attrib.type, DESC_TYPE_MASK) | 213 __SHIFTIN((uint32_t)nseg->attrib.s, DESC_S_MASK) | 214 __SHIFTIN((uint32_t)nseg->attrib.dpl, DESC_DPL_MASK) | 215 __SHIFTIN((uint32_t)nseg->attrib.p, DESC_P_MASK) | 216 __SHIFTIN((uint32_t)nseg->attrib.avl, DESC_AVL_MASK) | 217 __SHIFTIN((uint32_t)nseg->attrib.l, DESC_L_MASK) | 218 __SHIFTIN((uint32_t)nseg->attrib.def, DESC_B_MASK) | 219 __SHIFTIN((uint32_t)nseg->attrib.g, DESC_G_MASK); 220 } 221 222 static void 223 nvmm_get_registers(CPUState *cpu) 224 { 225 CPUX86State *env = cpu->env_ptr; 226 struct nvmm_machine *mach = get_nvmm_mach(); 227 struct qemu_vcpu *qcpu = get_qemu_vcpu(cpu); 228 struct nvmm_vcpu *vcpu = &qcpu->vcpu; 229 X86CPU *x86_cpu = X86_CPU(cpu); 230 struct nvmm_x64_state *state = vcpu->state; 231 uint64_t bitmap, tpr; 232 size_t i; 233 int ret; 234 235 assert(cpu_is_stopped(cpu) || qemu_cpu_is_self(cpu)); 236 237 bitmap = 238 NVMM_X64_STATE_SEGS | 239 NVMM_X64_STATE_GPRS | 240 NVMM_X64_STATE_CRS | 241 NVMM_X64_STATE_DRS | 242 NVMM_X64_STATE_MSRS | 243 NVMM_X64_STATE_FPU; 244 245 ret = nvmm_vcpu_getstate(mach, vcpu, bitmap); 246 if (ret == -1) { 247 error_report("NVMM: Failed to get virtual processor context," 248 " error=%d", errno); 249 } 250 251 /* GPRs. */ 252 env->regs[R_EAX] = state->gprs[NVMM_X64_GPR_RAX]; 253 env->regs[R_ECX] = state->gprs[NVMM_X64_GPR_RCX]; 254 env->regs[R_EDX] = state->gprs[NVMM_X64_GPR_RDX]; 255 env->regs[R_EBX] = state->gprs[NVMM_X64_GPR_RBX]; 256 env->regs[R_ESP] = state->gprs[NVMM_X64_GPR_RSP]; 257 env->regs[R_EBP] = state->gprs[NVMM_X64_GPR_RBP]; 258 env->regs[R_ESI] = state->gprs[NVMM_X64_GPR_RSI]; 259 env->regs[R_EDI] = state->gprs[NVMM_X64_GPR_RDI]; 260 #ifdef TARGET_X86_64 261 env->regs[R_R8] = state->gprs[NVMM_X64_GPR_R8]; 262 env->regs[R_R9] = state->gprs[NVMM_X64_GPR_R9]; 263 env->regs[R_R10] = state->gprs[NVMM_X64_GPR_R10]; 264 env->regs[R_R11] = state->gprs[NVMM_X64_GPR_R11]; 265 env->regs[R_R12] = state->gprs[NVMM_X64_GPR_R12]; 266 env->regs[R_R13] = state->gprs[NVMM_X64_GPR_R13]; 267 env->regs[R_R14] = state->gprs[NVMM_X64_GPR_R14]; 268 env->regs[R_R15] = state->gprs[NVMM_X64_GPR_R15]; 269 #endif 270 271 /* RIP and RFLAGS. */ 272 env->eip = state->gprs[NVMM_X64_GPR_RIP]; 273 env->eflags = state->gprs[NVMM_X64_GPR_RFLAGS]; 274 275 /* Segments. */ 276 nvmm_get_segment(&env->segs[R_ES], &state->segs[NVMM_X64_SEG_ES]); 277 nvmm_get_segment(&env->segs[R_CS], &state->segs[NVMM_X64_SEG_CS]); 278 nvmm_get_segment(&env->segs[R_SS], &state->segs[NVMM_X64_SEG_SS]); 279 nvmm_get_segment(&env->segs[R_DS], &state->segs[NVMM_X64_SEG_DS]); 280 nvmm_get_segment(&env->segs[R_FS], &state->segs[NVMM_X64_SEG_FS]); 281 nvmm_get_segment(&env->segs[R_GS], &state->segs[NVMM_X64_SEG_GS]); 282 283 /* Special segments. */ 284 nvmm_get_segment(&env->gdt, &state->segs[NVMM_X64_SEG_GDT]); 285 nvmm_get_segment(&env->ldt, &state->segs[NVMM_X64_SEG_LDT]); 286 nvmm_get_segment(&env->tr, &state->segs[NVMM_X64_SEG_TR]); 287 nvmm_get_segment(&env->idt, &state->segs[NVMM_X64_SEG_IDT]); 288 289 /* Control registers. */ 290 env->cr[0] = state->crs[NVMM_X64_CR_CR0]; 291 env->cr[2] = state->crs[NVMM_X64_CR_CR2]; 292 env->cr[3] = state->crs[NVMM_X64_CR_CR3]; 293 env->cr[4] = state->crs[NVMM_X64_CR_CR4]; 294 tpr = state->crs[NVMM_X64_CR_CR8]; 295 if (tpr != qcpu->tpr) { 296 qcpu->tpr = tpr; 297 cpu_set_apic_tpr(x86_cpu->apic_state, tpr); 298 } 299 env->xcr0 = state->crs[NVMM_X64_CR_XCR0]; 300 301 /* Debug registers. */ 302 env->dr[0] = state->drs[NVMM_X64_DR_DR0]; 303 env->dr[1] = state->drs[NVMM_X64_DR_DR1]; 304 env->dr[2] = state->drs[NVMM_X64_DR_DR2]; 305 env->dr[3] = state->drs[NVMM_X64_DR_DR3]; 306 env->dr[6] = state->drs[NVMM_X64_DR_DR6]; 307 env->dr[7] = state->drs[NVMM_X64_DR_DR7]; 308 309 /* FPU. */ 310 env->fpuc = state->fpu.fx_cw; 311 env->fpstt = (state->fpu.fx_sw >> 11) & 0x7; 312 env->fpus = state->fpu.fx_sw & ~0x3800; 313 for (i = 0; i < 8; i++) { 314 env->fptags[i] = !((state->fpu.fx_tw >> i) & 1); 315 } 316 env->fpop = state->fpu.fx_opcode; 317 env->fpip = state->fpu.fx_ip.fa_64; 318 env->fpdp = state->fpu.fx_dp.fa_64; 319 env->mxcsr = state->fpu.fx_mxcsr; 320 assert(sizeof(state->fpu.fx_87_ac) == sizeof(env->fpregs)); 321 memcpy(env->fpregs, state->fpu.fx_87_ac, sizeof(env->fpregs)); 322 for (i = 0; i < CPU_NB_REGS; i++) { 323 memcpy(&env->xmm_regs[i].ZMM_Q(0), 324 &state->fpu.fx_xmm[i].xmm_bytes[0], 8); 325 memcpy(&env->xmm_regs[i].ZMM_Q(1), 326 &state->fpu.fx_xmm[i].xmm_bytes[8], 8); 327 } 328 329 /* MSRs. */ 330 env->efer = state->msrs[NVMM_X64_MSR_EFER]; 331 env->star = state->msrs[NVMM_X64_MSR_STAR]; 332 #ifdef TARGET_X86_64 333 env->lstar = state->msrs[NVMM_X64_MSR_LSTAR]; 334 env->cstar = state->msrs[NVMM_X64_MSR_CSTAR]; 335 env->fmask = state->msrs[NVMM_X64_MSR_SFMASK]; 336 env->kernelgsbase = state->msrs[NVMM_X64_MSR_KERNELGSBASE]; 337 #endif 338 env->sysenter_cs = state->msrs[NVMM_X64_MSR_SYSENTER_CS]; 339 env->sysenter_esp = state->msrs[NVMM_X64_MSR_SYSENTER_ESP]; 340 env->sysenter_eip = state->msrs[NVMM_X64_MSR_SYSENTER_EIP]; 341 env->pat = state->msrs[NVMM_X64_MSR_PAT]; 342 env->tsc = state->msrs[NVMM_X64_MSR_TSC]; 343 344 x86_update_hflags(env); 345 } 346 347 static bool 348 nvmm_can_take_int(CPUState *cpu) 349 { 350 CPUX86State *env = cpu->env_ptr; 351 struct qemu_vcpu *qcpu = get_qemu_vcpu(cpu); 352 struct nvmm_vcpu *vcpu = &qcpu->vcpu; 353 struct nvmm_machine *mach = get_nvmm_mach(); 354 355 if (qcpu->int_window_exit) { 356 return false; 357 } 358 359 if (qcpu->int_shadow || !(env->eflags & IF_MASK)) { 360 struct nvmm_x64_state *state = vcpu->state; 361 362 /* Exit on interrupt window. */ 363 nvmm_vcpu_getstate(mach, vcpu, NVMM_X64_STATE_INTR); 364 state->intr.int_window_exiting = 1; 365 nvmm_vcpu_setstate(mach, vcpu, NVMM_X64_STATE_INTR); 366 367 return false; 368 } 369 370 return true; 371 } 372 373 static bool 374 nvmm_can_take_nmi(CPUState *cpu) 375 { 376 struct qemu_vcpu *qcpu = get_qemu_vcpu(cpu); 377 378 /* 379 * Contrary to INTs, NMIs always schedule an exit when they are 380 * completed. Therefore, if window-exiting is enabled, it means 381 * NMIs are blocked. 382 */ 383 if (qcpu->nmi_window_exit) { 384 return false; 385 } 386 387 return true; 388 } 389 390 /* 391 * Called before the VCPU is run. We inject events generated by the I/O 392 * thread, and synchronize the guest TPR. 393 */ 394 static void 395 nvmm_vcpu_pre_run(CPUState *cpu) 396 { 397 CPUX86State *env = cpu->env_ptr; 398 struct nvmm_machine *mach = get_nvmm_mach(); 399 struct qemu_vcpu *qcpu = get_qemu_vcpu(cpu); 400 struct nvmm_vcpu *vcpu = &qcpu->vcpu; 401 X86CPU *x86_cpu = X86_CPU(cpu); 402 struct nvmm_x64_state *state = vcpu->state; 403 struct nvmm_vcpu_event *event = vcpu->event; 404 bool has_event = false; 405 bool sync_tpr = false; 406 uint8_t tpr; 407 int ret; 408 409 qemu_mutex_lock_iothread(); 410 411 tpr = cpu_get_apic_tpr(x86_cpu->apic_state); 412 if (tpr != qcpu->tpr) { 413 qcpu->tpr = tpr; 414 sync_tpr = true; 415 } 416 417 /* 418 * Force the VCPU out of its inner loop to process any INIT requests 419 * or commit pending TPR access. 420 */ 421 if (cpu->interrupt_request & (CPU_INTERRUPT_INIT | CPU_INTERRUPT_TPR)) { 422 cpu->exit_request = 1; 423 } 424 425 if (!has_event && (cpu->interrupt_request & CPU_INTERRUPT_NMI)) { 426 if (nvmm_can_take_nmi(cpu)) { 427 cpu->interrupt_request &= ~CPU_INTERRUPT_NMI; 428 event->type = NVMM_VCPU_EVENT_INTR; 429 event->vector = 2; 430 has_event = true; 431 } 432 } 433 434 if (!has_event && (cpu->interrupt_request & CPU_INTERRUPT_HARD)) { 435 if (nvmm_can_take_int(cpu)) { 436 cpu->interrupt_request &= ~CPU_INTERRUPT_HARD; 437 event->type = NVMM_VCPU_EVENT_INTR; 438 event->vector = cpu_get_pic_interrupt(env); 439 has_event = true; 440 } 441 } 442 443 /* Don't want SMIs. */ 444 if (cpu->interrupt_request & CPU_INTERRUPT_SMI) { 445 cpu->interrupt_request &= ~CPU_INTERRUPT_SMI; 446 } 447 448 if (sync_tpr) { 449 ret = nvmm_vcpu_getstate(mach, vcpu, NVMM_X64_STATE_CRS); 450 if (ret == -1) { 451 error_report("NVMM: Failed to get CPU state," 452 " error=%d", errno); 453 } 454 455 state->crs[NVMM_X64_CR_CR8] = qcpu->tpr; 456 457 ret = nvmm_vcpu_setstate(mach, vcpu, NVMM_X64_STATE_CRS); 458 if (ret == -1) { 459 error_report("NVMM: Failed to set CPU state," 460 " error=%d", errno); 461 } 462 } 463 464 if (has_event) { 465 ret = nvmm_vcpu_inject(mach, vcpu); 466 if (ret == -1) { 467 error_report("NVMM: Failed to inject event," 468 " error=%d", errno); 469 } 470 } 471 472 qemu_mutex_unlock_iothread(); 473 } 474 475 /* 476 * Called after the VCPU ran. We synchronize the host view of the TPR and 477 * RFLAGS. 478 */ 479 static void 480 nvmm_vcpu_post_run(CPUState *cpu, struct nvmm_vcpu_exit *exit) 481 { 482 struct qemu_vcpu *qcpu = get_qemu_vcpu(cpu); 483 CPUX86State *env = cpu->env_ptr; 484 X86CPU *x86_cpu = X86_CPU(cpu); 485 uint64_t tpr; 486 487 env->eflags = exit->exitstate.rflags; 488 qcpu->int_shadow = exit->exitstate.int_shadow; 489 qcpu->int_window_exit = exit->exitstate.int_window_exiting; 490 qcpu->nmi_window_exit = exit->exitstate.nmi_window_exiting; 491 492 tpr = exit->exitstate.cr8; 493 if (qcpu->tpr != tpr) { 494 qcpu->tpr = tpr; 495 qemu_mutex_lock_iothread(); 496 cpu_set_apic_tpr(x86_cpu->apic_state, qcpu->tpr); 497 qemu_mutex_unlock_iothread(); 498 } 499 } 500 501 /* -------------------------------------------------------------------------- */ 502 503 static void 504 nvmm_io_callback(struct nvmm_io *io) 505 { 506 MemTxAttrs attrs = { 0 }; 507 int ret; 508 509 ret = address_space_rw(&address_space_io, io->port, attrs, io->data, 510 io->size, !io->in); 511 if (ret != MEMTX_OK) { 512 error_report("NVMM: I/O Transaction Failed " 513 "[%s, port=%u, size=%zu]", (io->in ? "in" : "out"), 514 io->port, io->size); 515 } 516 517 /* Needed, otherwise infinite loop. */ 518 current_cpu->vcpu_dirty = false; 519 } 520 521 static void 522 nvmm_mem_callback(struct nvmm_mem *mem) 523 { 524 cpu_physical_memory_rw(mem->gpa, mem->data, mem->size, mem->write); 525 526 /* Needed, otherwise infinite loop. */ 527 current_cpu->vcpu_dirty = false; 528 } 529 530 static struct nvmm_assist_callbacks nvmm_callbacks = { 531 .io = nvmm_io_callback, 532 .mem = nvmm_mem_callback 533 }; 534 535 /* -------------------------------------------------------------------------- */ 536 537 static int 538 nvmm_handle_mem(struct nvmm_machine *mach, struct nvmm_vcpu *vcpu) 539 { 540 int ret; 541 542 ret = nvmm_assist_mem(mach, vcpu); 543 if (ret == -1) { 544 error_report("NVMM: Mem Assist Failed [gpa=%p]", 545 (void *)vcpu->exit->u.mem.gpa); 546 } 547 548 return ret; 549 } 550 551 static int 552 nvmm_handle_io(struct nvmm_machine *mach, struct nvmm_vcpu *vcpu) 553 { 554 int ret; 555 556 ret = nvmm_assist_io(mach, vcpu); 557 if (ret == -1) { 558 error_report("NVMM: I/O Assist Failed [port=%d]", 559 (int)vcpu->exit->u.io.port); 560 } 561 562 return ret; 563 } 564 565 static int 566 nvmm_handle_rdmsr(struct nvmm_machine *mach, CPUState *cpu, 567 struct nvmm_vcpu_exit *exit) 568 { 569 struct qemu_vcpu *qcpu = get_qemu_vcpu(cpu); 570 struct nvmm_vcpu *vcpu = &qcpu->vcpu; 571 X86CPU *x86_cpu = X86_CPU(cpu); 572 struct nvmm_x64_state *state = vcpu->state; 573 uint64_t val; 574 int ret; 575 576 switch (exit->u.rdmsr.msr) { 577 case MSR_IA32_APICBASE: 578 val = cpu_get_apic_base(x86_cpu->apic_state); 579 break; 580 case MSR_MTRRcap: 581 case MSR_MTRRdefType: 582 case MSR_MCG_CAP: 583 case MSR_MCG_STATUS: 584 val = 0; 585 break; 586 default: /* More MSRs to add? */ 587 val = 0; 588 error_report("NVMM: Unexpected RDMSR 0x%x, ignored", 589 exit->u.rdmsr.msr); 590 break; 591 } 592 593 ret = nvmm_vcpu_getstate(mach, vcpu, NVMM_X64_STATE_GPRS); 594 if (ret == -1) { 595 return -1; 596 } 597 598 state->gprs[NVMM_X64_GPR_RAX] = (val & 0xFFFFFFFF); 599 state->gprs[NVMM_X64_GPR_RDX] = (val >> 32); 600 state->gprs[NVMM_X64_GPR_RIP] = exit->u.rdmsr.npc; 601 602 ret = nvmm_vcpu_setstate(mach, vcpu, NVMM_X64_STATE_GPRS); 603 if (ret == -1) { 604 return -1; 605 } 606 607 return 0; 608 } 609 610 static int 611 nvmm_handle_wrmsr(struct nvmm_machine *mach, CPUState *cpu, 612 struct nvmm_vcpu_exit *exit) 613 { 614 struct qemu_vcpu *qcpu = get_qemu_vcpu(cpu); 615 struct nvmm_vcpu *vcpu = &qcpu->vcpu; 616 X86CPU *x86_cpu = X86_CPU(cpu); 617 struct nvmm_x64_state *state = vcpu->state; 618 uint64_t val; 619 int ret; 620 621 val = exit->u.wrmsr.val; 622 623 switch (exit->u.wrmsr.msr) { 624 case MSR_IA32_APICBASE: 625 cpu_set_apic_base(x86_cpu->apic_state, val); 626 break; 627 case MSR_MTRRdefType: 628 case MSR_MCG_STATUS: 629 break; 630 default: /* More MSRs to add? */ 631 error_report("NVMM: Unexpected WRMSR 0x%x [val=0x%lx], ignored", 632 exit->u.wrmsr.msr, val); 633 break; 634 } 635 636 ret = nvmm_vcpu_getstate(mach, vcpu, NVMM_X64_STATE_GPRS); 637 if (ret == -1) { 638 return -1; 639 } 640 641 state->gprs[NVMM_X64_GPR_RIP] = exit->u.wrmsr.npc; 642 643 ret = nvmm_vcpu_setstate(mach, vcpu, NVMM_X64_STATE_GPRS); 644 if (ret == -1) { 645 return -1; 646 } 647 648 return 0; 649 } 650 651 static int 652 nvmm_handle_halted(struct nvmm_machine *mach, CPUState *cpu, 653 struct nvmm_vcpu_exit *exit) 654 { 655 CPUX86State *env = cpu->env_ptr; 656 int ret = 0; 657 658 qemu_mutex_lock_iothread(); 659 660 if (!((cpu->interrupt_request & CPU_INTERRUPT_HARD) && 661 (env->eflags & IF_MASK)) && 662 !(cpu->interrupt_request & CPU_INTERRUPT_NMI)) { 663 cpu->exception_index = EXCP_HLT; 664 cpu->halted = true; 665 ret = 1; 666 } 667 668 qemu_mutex_unlock_iothread(); 669 670 return ret; 671 } 672 673 static int 674 nvmm_inject_ud(struct nvmm_machine *mach, struct nvmm_vcpu *vcpu) 675 { 676 struct nvmm_vcpu_event *event = vcpu->event; 677 678 event->type = NVMM_VCPU_EVENT_EXCP; 679 event->vector = 6; 680 event->u.excp.error = 0; 681 682 return nvmm_vcpu_inject(mach, vcpu); 683 } 684 685 static int 686 nvmm_vcpu_loop(CPUState *cpu) 687 { 688 CPUX86State *env = cpu->env_ptr; 689 struct nvmm_machine *mach = get_nvmm_mach(); 690 struct qemu_vcpu *qcpu = get_qemu_vcpu(cpu); 691 struct nvmm_vcpu *vcpu = &qcpu->vcpu; 692 X86CPU *x86_cpu = X86_CPU(cpu); 693 struct nvmm_vcpu_exit *exit = vcpu->exit; 694 int ret; 695 696 /* 697 * Some asynchronous events must be handled outside of the inner 698 * VCPU loop. They are handled here. 699 */ 700 if (cpu->interrupt_request & CPU_INTERRUPT_INIT) { 701 nvmm_cpu_synchronize_state(cpu); 702 do_cpu_init(x86_cpu); 703 /* set int/nmi windows back to the reset state */ 704 } 705 if (cpu->interrupt_request & CPU_INTERRUPT_POLL) { 706 cpu->interrupt_request &= ~CPU_INTERRUPT_POLL; 707 apic_poll_irq(x86_cpu->apic_state); 708 } 709 if (((cpu->interrupt_request & CPU_INTERRUPT_HARD) && 710 (env->eflags & IF_MASK)) || 711 (cpu->interrupt_request & CPU_INTERRUPT_NMI)) { 712 cpu->halted = false; 713 } 714 if (cpu->interrupt_request & CPU_INTERRUPT_SIPI) { 715 nvmm_cpu_synchronize_state(cpu); 716 do_cpu_sipi(x86_cpu); 717 } 718 if (cpu->interrupt_request & CPU_INTERRUPT_TPR) { 719 cpu->interrupt_request &= ~CPU_INTERRUPT_TPR; 720 nvmm_cpu_synchronize_state(cpu); 721 apic_handle_tpr_access_report(x86_cpu->apic_state, env->eip, 722 env->tpr_access_type); 723 } 724 725 if (cpu->halted) { 726 cpu->exception_index = EXCP_HLT; 727 qatomic_set(&cpu->exit_request, false); 728 return 0; 729 } 730 731 qemu_mutex_unlock_iothread(); 732 cpu_exec_start(cpu); 733 734 /* 735 * Inner VCPU loop. 736 */ 737 do { 738 if (cpu->vcpu_dirty) { 739 nvmm_set_registers(cpu); 740 cpu->vcpu_dirty = false; 741 } 742 743 if (qcpu->stop) { 744 cpu->exception_index = EXCP_INTERRUPT; 745 qcpu->stop = false; 746 ret = 1; 747 break; 748 } 749 750 nvmm_vcpu_pre_run(cpu); 751 752 if (qatomic_read(&cpu->exit_request)) { 753 #if NVMM_USER_VERSION >= 2 754 nvmm_vcpu_stop(vcpu); 755 #else 756 qemu_cpu_kick_self(); 757 #endif 758 } 759 760 /* Read exit_request before the kernel reads the immediate exit flag */ 761 smp_rmb(); 762 ret = nvmm_vcpu_run(mach, vcpu); 763 if (ret == -1) { 764 error_report("NVMM: Failed to exec a virtual processor," 765 " error=%d", errno); 766 break; 767 } 768 769 nvmm_vcpu_post_run(cpu, exit); 770 771 switch (exit->reason) { 772 case NVMM_VCPU_EXIT_NONE: 773 break; 774 #if NVMM_USER_VERSION >= 2 775 case NVMM_VCPU_EXIT_STOPPED: 776 /* 777 * The kernel cleared the immediate exit flag; cpu->exit_request 778 * must be cleared after 779 */ 780 smp_wmb(); 781 qcpu->stop = true; 782 break; 783 #endif 784 case NVMM_VCPU_EXIT_MEMORY: 785 ret = nvmm_handle_mem(mach, vcpu); 786 break; 787 case NVMM_VCPU_EXIT_IO: 788 ret = nvmm_handle_io(mach, vcpu); 789 break; 790 case NVMM_VCPU_EXIT_INT_READY: 791 case NVMM_VCPU_EXIT_NMI_READY: 792 case NVMM_VCPU_EXIT_TPR_CHANGED: 793 break; 794 case NVMM_VCPU_EXIT_HALTED: 795 ret = nvmm_handle_halted(mach, cpu, exit); 796 break; 797 case NVMM_VCPU_EXIT_SHUTDOWN: 798 qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); 799 cpu->exception_index = EXCP_INTERRUPT; 800 ret = 1; 801 break; 802 case NVMM_VCPU_EXIT_RDMSR: 803 ret = nvmm_handle_rdmsr(mach, cpu, exit); 804 break; 805 case NVMM_VCPU_EXIT_WRMSR: 806 ret = nvmm_handle_wrmsr(mach, cpu, exit); 807 break; 808 case NVMM_VCPU_EXIT_MONITOR: 809 case NVMM_VCPU_EXIT_MWAIT: 810 ret = nvmm_inject_ud(mach, vcpu); 811 break; 812 default: 813 error_report("NVMM: Unexpected VM exit code 0x%lx [hw=0x%lx]", 814 exit->reason, exit->u.inv.hwcode); 815 nvmm_get_registers(cpu); 816 qemu_mutex_lock_iothread(); 817 qemu_system_guest_panicked(cpu_get_crash_info(cpu)); 818 qemu_mutex_unlock_iothread(); 819 ret = -1; 820 break; 821 } 822 } while (ret == 0); 823 824 cpu_exec_end(cpu); 825 qemu_mutex_lock_iothread(); 826 827 qatomic_set(&cpu->exit_request, false); 828 829 return ret < 0; 830 } 831 832 /* -------------------------------------------------------------------------- */ 833 834 static void 835 do_nvmm_cpu_synchronize_state(CPUState *cpu, run_on_cpu_data arg) 836 { 837 nvmm_get_registers(cpu); 838 cpu->vcpu_dirty = true; 839 } 840 841 static void 842 do_nvmm_cpu_synchronize_post_reset(CPUState *cpu, run_on_cpu_data arg) 843 { 844 nvmm_set_registers(cpu); 845 cpu->vcpu_dirty = false; 846 } 847 848 static void 849 do_nvmm_cpu_synchronize_post_init(CPUState *cpu, run_on_cpu_data arg) 850 { 851 nvmm_set_registers(cpu); 852 cpu->vcpu_dirty = false; 853 } 854 855 static void 856 do_nvmm_cpu_synchronize_pre_loadvm(CPUState *cpu, run_on_cpu_data arg) 857 { 858 cpu->vcpu_dirty = true; 859 } 860 861 void nvmm_cpu_synchronize_state(CPUState *cpu) 862 { 863 if (!cpu->vcpu_dirty) { 864 run_on_cpu(cpu, do_nvmm_cpu_synchronize_state, RUN_ON_CPU_NULL); 865 } 866 } 867 868 void nvmm_cpu_synchronize_post_reset(CPUState *cpu) 869 { 870 run_on_cpu(cpu, do_nvmm_cpu_synchronize_post_reset, RUN_ON_CPU_NULL); 871 } 872 873 void nvmm_cpu_synchronize_post_init(CPUState *cpu) 874 { 875 run_on_cpu(cpu, do_nvmm_cpu_synchronize_post_init, RUN_ON_CPU_NULL); 876 } 877 878 void nvmm_cpu_synchronize_pre_loadvm(CPUState *cpu) 879 { 880 run_on_cpu(cpu, do_nvmm_cpu_synchronize_pre_loadvm, RUN_ON_CPU_NULL); 881 } 882 883 /* -------------------------------------------------------------------------- */ 884 885 static Error *nvmm_migration_blocker; 886 887 /* 888 * The nvmm_vcpu_stop() mechanism breaks races between entering the VMM 889 * and another thread signaling the vCPU thread to exit. 890 */ 891 892 static void 893 nvmm_ipi_signal(int sigcpu) 894 { 895 if (current_cpu) { 896 struct qemu_vcpu *qcpu = get_qemu_vcpu(current_cpu); 897 #if NVMM_USER_VERSION >= 2 898 struct nvmm_vcpu *vcpu = &qcpu->vcpu; 899 nvmm_vcpu_stop(vcpu); 900 #else 901 qcpu->stop = true; 902 #endif 903 } 904 } 905 906 static void 907 nvmm_init_cpu_signals(void) 908 { 909 struct sigaction sigact; 910 sigset_t set; 911 912 /* Install the IPI handler. */ 913 memset(&sigact, 0, sizeof(sigact)); 914 sigact.sa_handler = nvmm_ipi_signal; 915 sigaction(SIG_IPI, &sigact, NULL); 916 917 /* Allow IPIs on the current thread. */ 918 sigprocmask(SIG_BLOCK, NULL, &set); 919 sigdelset(&set, SIG_IPI); 920 pthread_sigmask(SIG_SETMASK, &set, NULL); 921 } 922 923 int 924 nvmm_init_vcpu(CPUState *cpu) 925 { 926 struct nvmm_machine *mach = get_nvmm_mach(); 927 struct nvmm_vcpu_conf_cpuid cpuid; 928 struct nvmm_vcpu_conf_tpr tpr; 929 Error *local_error = NULL; 930 struct qemu_vcpu *qcpu; 931 int ret, err; 932 933 nvmm_init_cpu_signals(); 934 935 if (nvmm_migration_blocker == NULL) { 936 error_setg(&nvmm_migration_blocker, 937 "NVMM: Migration not supported"); 938 939 if (migrate_add_blocker(nvmm_migration_blocker, &local_error) < 0) { 940 error_report_err(local_error); 941 error_free(nvmm_migration_blocker); 942 return -EINVAL; 943 } 944 } 945 946 qcpu = g_malloc0(sizeof(*qcpu)); 947 if (qcpu == NULL) { 948 error_report("NVMM: Failed to allocate VCPU context."); 949 return -ENOMEM; 950 } 951 952 ret = nvmm_vcpu_create(mach, cpu->cpu_index, &qcpu->vcpu); 953 if (ret == -1) { 954 err = errno; 955 error_report("NVMM: Failed to create a virtual processor," 956 " error=%d", err); 957 g_free(qcpu); 958 return -err; 959 } 960 961 memset(&cpuid, 0, sizeof(cpuid)); 962 cpuid.mask = 1; 963 cpuid.leaf = 0x00000001; 964 cpuid.u.mask.set.edx = CPUID_MCE | CPUID_MCA | CPUID_MTRR; 965 ret = nvmm_vcpu_configure(mach, &qcpu->vcpu, NVMM_VCPU_CONF_CPUID, 966 &cpuid); 967 if (ret == -1) { 968 err = errno; 969 error_report("NVMM: Failed to configure a virtual processor," 970 " error=%d", err); 971 g_free(qcpu); 972 return -err; 973 } 974 975 ret = nvmm_vcpu_configure(mach, &qcpu->vcpu, NVMM_VCPU_CONF_CALLBACKS, 976 &nvmm_callbacks); 977 if (ret == -1) { 978 err = errno; 979 error_report("NVMM: Failed to configure a virtual processor," 980 " error=%d", err); 981 g_free(qcpu); 982 return -err; 983 } 984 985 if (qemu_mach.cap.arch.vcpu_conf_support & NVMM_CAP_ARCH_VCPU_CONF_TPR) { 986 memset(&tpr, 0, sizeof(tpr)); 987 tpr.exit_changed = 1; 988 ret = nvmm_vcpu_configure(mach, &qcpu->vcpu, NVMM_VCPU_CONF_TPR, &tpr); 989 if (ret == -1) { 990 err = errno; 991 error_report("NVMM: Failed to configure a virtual processor," 992 " error=%d", err); 993 g_free(qcpu); 994 return -err; 995 } 996 } 997 998 cpu->vcpu_dirty = true; 999 cpu->hax_vcpu = (struct hax_vcpu_state *)qcpu; 1000 1001 return 0; 1002 } 1003 1004 int 1005 nvmm_vcpu_exec(CPUState *cpu) 1006 { 1007 int ret, fatal; 1008 1009 while (1) { 1010 if (cpu->exception_index >= EXCP_INTERRUPT) { 1011 ret = cpu->exception_index; 1012 cpu->exception_index = -1; 1013 break; 1014 } 1015 1016 fatal = nvmm_vcpu_loop(cpu); 1017 1018 if (fatal) { 1019 error_report("NVMM: Failed to execute a VCPU."); 1020 abort(); 1021 } 1022 } 1023 1024 return ret; 1025 } 1026 1027 void 1028 nvmm_destroy_vcpu(CPUState *cpu) 1029 { 1030 struct nvmm_machine *mach = get_nvmm_mach(); 1031 struct qemu_vcpu *qcpu = get_qemu_vcpu(cpu); 1032 1033 nvmm_vcpu_destroy(mach, &qcpu->vcpu); 1034 g_free(cpu->hax_vcpu); 1035 } 1036 1037 /* -------------------------------------------------------------------------- */ 1038 1039 static void 1040 nvmm_update_mapping(hwaddr start_pa, ram_addr_t size, uintptr_t hva, 1041 bool add, bool rom, const char *name) 1042 { 1043 struct nvmm_machine *mach = get_nvmm_mach(); 1044 int ret, prot; 1045 1046 if (add) { 1047 prot = PROT_READ | PROT_EXEC; 1048 if (!rom) { 1049 prot |= PROT_WRITE; 1050 } 1051 ret = nvmm_gpa_map(mach, hva, start_pa, size, prot); 1052 } else { 1053 ret = nvmm_gpa_unmap(mach, hva, start_pa, size); 1054 } 1055 1056 if (ret == -1) { 1057 error_report("NVMM: Failed to %s GPA range '%s' PA:%p, " 1058 "Size:%p bytes, HostVA:%p, error=%d", 1059 (add ? "map" : "unmap"), name, (void *)(uintptr_t)start_pa, 1060 (void *)size, (void *)hva, errno); 1061 } 1062 } 1063 1064 static void 1065 nvmm_process_section(MemoryRegionSection *section, int add) 1066 { 1067 MemoryRegion *mr = section->mr; 1068 hwaddr start_pa = section->offset_within_address_space; 1069 ram_addr_t size = int128_get64(section->size); 1070 unsigned int delta; 1071 uintptr_t hva; 1072 1073 if (!memory_region_is_ram(mr)) { 1074 return; 1075 } 1076 1077 /* Adjust start_pa and size so that they are page-aligned. */ 1078 delta = qemu_real_host_page_size() - (start_pa & ~qemu_real_host_page_mask()); 1079 delta &= ~qemu_real_host_page_mask(); 1080 if (delta > size) { 1081 return; 1082 } 1083 start_pa += delta; 1084 size -= delta; 1085 size &= qemu_real_host_page_mask(); 1086 if (!size || (start_pa & ~qemu_real_host_page_mask())) { 1087 return; 1088 } 1089 1090 hva = (uintptr_t)memory_region_get_ram_ptr(mr) + 1091 section->offset_within_region + delta; 1092 1093 nvmm_update_mapping(start_pa, size, hva, add, 1094 memory_region_is_rom(mr), mr->name); 1095 } 1096 1097 static void 1098 nvmm_region_add(MemoryListener *listener, MemoryRegionSection *section) 1099 { 1100 memory_region_ref(section->mr); 1101 nvmm_process_section(section, 1); 1102 } 1103 1104 static void 1105 nvmm_region_del(MemoryListener *listener, MemoryRegionSection *section) 1106 { 1107 nvmm_process_section(section, 0); 1108 memory_region_unref(section->mr); 1109 } 1110 1111 static void 1112 nvmm_transaction_begin(MemoryListener *listener) 1113 { 1114 /* nothing */ 1115 } 1116 1117 static void 1118 nvmm_transaction_commit(MemoryListener *listener) 1119 { 1120 /* nothing */ 1121 } 1122 1123 static void 1124 nvmm_log_sync(MemoryListener *listener, MemoryRegionSection *section) 1125 { 1126 MemoryRegion *mr = section->mr; 1127 1128 if (!memory_region_is_ram(mr)) { 1129 return; 1130 } 1131 1132 memory_region_set_dirty(mr, 0, int128_get64(section->size)); 1133 } 1134 1135 static MemoryListener nvmm_memory_listener = { 1136 .name = "nvmm", 1137 .begin = nvmm_transaction_begin, 1138 .commit = nvmm_transaction_commit, 1139 .region_add = nvmm_region_add, 1140 .region_del = nvmm_region_del, 1141 .log_sync = nvmm_log_sync, 1142 .priority = 10, 1143 }; 1144 1145 static void 1146 nvmm_ram_block_added(RAMBlockNotifier *n, void *host, size_t size, 1147 size_t max_size) 1148 { 1149 struct nvmm_machine *mach = get_nvmm_mach(); 1150 uintptr_t hva = (uintptr_t)host; 1151 int ret; 1152 1153 ret = nvmm_hva_map(mach, hva, max_size); 1154 1155 if (ret == -1) { 1156 error_report("NVMM: Failed to map HVA, HostVA:%p " 1157 "Size:%p bytes, error=%d", 1158 (void *)hva, (void *)size, errno); 1159 } 1160 } 1161 1162 static struct RAMBlockNotifier nvmm_ram_notifier = { 1163 .ram_block_added = nvmm_ram_block_added 1164 }; 1165 1166 /* -------------------------------------------------------------------------- */ 1167 1168 static int 1169 nvmm_accel_init(MachineState *ms) 1170 { 1171 int ret, err; 1172 1173 ret = nvmm_init(); 1174 if (ret == -1) { 1175 err = errno; 1176 error_report("NVMM: Initialization failed, error=%d", errno); 1177 return -err; 1178 } 1179 1180 ret = nvmm_capability(&qemu_mach.cap); 1181 if (ret == -1) { 1182 err = errno; 1183 error_report("NVMM: Unable to fetch capability, error=%d", errno); 1184 return -err; 1185 } 1186 if (qemu_mach.cap.version < NVMM_KERN_VERSION) { 1187 error_report("NVMM: Unsupported version %u", qemu_mach.cap.version); 1188 return -EPROGMISMATCH; 1189 } 1190 if (qemu_mach.cap.state_size != sizeof(struct nvmm_x64_state)) { 1191 error_report("NVMM: Wrong state size %u", qemu_mach.cap.state_size); 1192 return -EPROGMISMATCH; 1193 } 1194 1195 ret = nvmm_machine_create(&qemu_mach.mach); 1196 if (ret == -1) { 1197 err = errno; 1198 error_report("NVMM: Machine creation failed, error=%d", errno); 1199 return -err; 1200 } 1201 1202 memory_listener_register(&nvmm_memory_listener, &address_space_memory); 1203 ram_block_notifier_add(&nvmm_ram_notifier); 1204 1205 printf("NetBSD Virtual Machine Monitor accelerator is operational\n"); 1206 return 0; 1207 } 1208 1209 int 1210 nvmm_enabled(void) 1211 { 1212 return nvmm_allowed; 1213 } 1214 1215 static void 1216 nvmm_accel_class_init(ObjectClass *oc, void *data) 1217 { 1218 AccelClass *ac = ACCEL_CLASS(oc); 1219 ac->name = "NVMM"; 1220 ac->init_machine = nvmm_accel_init; 1221 ac->allowed = &nvmm_allowed; 1222 } 1223 1224 static const TypeInfo nvmm_accel_type = { 1225 .name = ACCEL_CLASS_NAME("nvmm"), 1226 .parent = TYPE_ACCEL, 1227 .class_init = nvmm_accel_class_init, 1228 }; 1229 1230 static void 1231 nvmm_type_init(void) 1232 { 1233 type_register_static(&nvmm_accel_type); 1234 } 1235 1236 type_init(nvmm_type_init); 1237