Lines Matching +full:suspend +full:- +full:to +full:- +full:ram

7  * See the COPYING file in the top-level directory.
13 #include "system/address-spaces.h"
17 #include "accel/accel-ops.h"
21 #include "qemu/main-loop.h"
25 #include "qemu/error-report.h"
27 #include "qapi/qapi-types-common.h"
28 #include "qapi/qapi-visit-common.h"
30 #include "host-cpu.h"
31 #include "accel/accel-cpu-target.h"
34 #include "whpx-internal.h"
35 #include "whpx-accel-ops.h"
156 * in RFLAGS, causing the CPU to raise an INT1 after each instruction.
157 * This corresponds to the WHvX64ExceptionTypeDebugTrapOrFault exception.
170 * to the stack, clear the TF flag, and let the guest execute the
172 * that will continue single-stepping.
174 * 3. Debuggers running on the guest may wish to set TF to do instruction
176 * as long as the gdb is connected to QEMU.
179 * 1. Stepping through flags-modifying instructions may cause gdb to
187 * at the same time may lead to unexpected effects. Removing all
189 * with the guest-level debuggers.
194 * defined in the "Combined Volume Set of Intel 64 and IA-32
196 * fair amount of corner cases due to compatibility with real mode,
197 * virtual 8086 mode, and differences between 64-bit and 32-bit modes.
206 * d. Update the exception exit bitmap to only catch the
210 * Note that handling all corner cases related to IDT/GDT is harder
214 * 3. In order to properly support guest-level debugging in parallel with
215 * the QEMU-level debugging, we would need to be able to pass some INT1
216 * events to the guest. This could be done via the following methods:
218 * it seems to only work for interrupts and not software
224 * RFLAGS, and pushing the old values to stack). This is even more
266 unsigned flags = qs->flags; in whpx_seg_q2h()
268 hs.Base = qs->base; in whpx_seg_q2h()
269 hs.Limit = qs->limit; in whpx_seg_q2h()
270 hs.Selector = qs->selector; in whpx_seg_q2h()
294 qs.base = hs->Base; in whpx_seg_h2q()
295 qs.limit = hs->Limit; in whpx_seg_h2q()
296 qs.selector = hs->Selector; in whpx_seg_h2q()
298 qs.flags = ((uint32_t)hs->Attributes) << DESC_TYPE_SHIFT; in whpx_seg_h2q()
316 xcr0.Reg64 = cpu_env(cpu)->xcr0; in whpx_set_xcrs()
318 whpx->partition, cpu->cpu_index, &xcr0_name, 1, &xcr0); in whpx_set_xcrs()
320 error_report("WHPX: Failed to set register xcr0, hr=%08lx", hr); in whpx_set_xcrs()
332 * Suspend the partition prior to setting the TSC to reduce the variance in whpx_set_tsc()
333 * in TSC across vCPUs. When the first vCPU runs post suspend, the in whpx_set_tsc()
339 * Unable to suspend partition while setting TSC is not a fatal in whpx_set_tsc()
341 * vCPUs and some guest OS are able to handle that just fine. in whpx_set_tsc()
343 hr = whp_dispatch.WHvSuspendPartitionTime(whpx->partition); in whpx_set_tsc()
345 warn_report("WHPX: Failed to suspend partition, hr=%08lx", hr); in whpx_set_tsc()
349 tsc_val.Reg64 = cpu_env(cpu)->tsc; in whpx_set_tsc()
351 whpx->partition, cpu->cpu_index, &tsc_reg, 1, &tsc_val); in whpx_set_tsc()
353 error_report("WHPX: Failed to set TSC, hr=%08lx", hr); in whpx_set_tsc()
354 return -1; in whpx_set_tsc()
361 * The CR8 register in the CPU is mapped to the TPR register of the APIC,
367 * and IA-32 Architectures Software Developer's Manual.
369 * The functions below translate the value of CR8 to TPR and vice versa.
385 AccelCPUState *vcpu = cpu->accel; in whpx_set_registers()
387 CPUX86State *env = &x86_cpu->env; in whpx_set_registers()
399 * runtime. Limit them to full state update. in whpx_set_registers()
407 v86 = (env->eflags & VM_MASK); in whpx_set_registers()
408 r86 = !(env->cr[0] & CR0_PE_MASK); in whpx_set_registers()
410 vcpu->tpr = whpx_apic_tpr_to_cr8(cpu_get_apic_tpr(x86_cpu->apic_state)); in whpx_set_registers()
411 vcpu->apic_base = cpu_get_apic_base(x86_cpu->apic_state); in whpx_set_registers()
418 vcxt.values[idx].Reg64 = (uint64_t)env->regs[idx]; in whpx_set_registers()
424 vcxt.values[idx++].Reg64 = env->eip; in whpx_set_registers()
427 vcxt.values[idx++].Reg64 = env->eflags; in whpx_set_registers()
432 vcxt.values[idx].Segment = whpx_seg_q2h(&env->segs[i], v86, r86); in whpx_set_registers()
436 vcxt.values[idx++].Segment = whpx_seg_q2h(&env->ldt, 0, 0); in whpx_set_registers()
439 vcxt.values[idx++].Segment = whpx_seg_q2h(&env->tr, 0, 0); in whpx_set_registers()
442 vcxt.values[idx].Table.Base = env->idt.base; in whpx_set_registers()
443 vcxt.values[idx].Table.Limit = env->idt.limit; in whpx_set_registers()
447 vcxt.values[idx].Table.Base = env->gdt.base; in whpx_set_registers()
448 vcxt.values[idx].Table.Limit = env->gdt.limit; in whpx_set_registers()
453 vcxt.values[idx++].Reg64 = env->cr[0]; in whpx_set_registers()
455 vcxt.values[idx++].Reg64 = env->cr[2]; in whpx_set_registers()
457 vcxt.values[idx++].Reg64 = env->cr[3]; in whpx_set_registers()
459 vcxt.values[idx++].Reg64 = env->cr[4]; in whpx_set_registers()
461 vcxt.values[idx++].Reg64 = vcpu->tpr; in whpx_set_registers()
463 /* 8 Debug Registers - Skipped */ in whpx_set_registers()
466 * Extended control registers needs to be handled separately depending in whpx_set_registers()
474 for (i = 0; i < sizeof(env->xmm_regs) / sizeof(ZMMReg); i += 1, idx += 1) { in whpx_set_registers()
475 vcxt.values[idx].Reg128.Low64 = env->xmm_regs[i].ZMM_Q(0); in whpx_set_registers()
476 vcxt.values[idx].Reg128.High64 = env->xmm_regs[i].ZMM_Q(1); in whpx_set_registers()
483 vcxt.values[idx].Fp.AsUINT128.Low64 = env->fpregs[i].mmx.MMX_Q(0); in whpx_set_registers()
485 env->fpregs[i].mmx.MMX_Q(1); in whpx_set_registers()
491 vcxt.values[idx].FpControlStatus.FpControl = env->fpuc; in whpx_set_registers()
493 (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11; in whpx_set_registers()
496 vcxt.values[idx].FpControlStatus.FpTag |= (!env->fptags[i]) << i; in whpx_set_registers()
499 vcxt.values[idx].FpControlStatus.LastFpOp = env->fpop; in whpx_set_registers()
500 vcxt.values[idx].FpControlStatus.LastFpRip = env->fpip; in whpx_set_registers()
506 vcxt.values[idx].XmmControlStatus.XmmStatusControl = env->mxcsr; in whpx_set_registers()
512 vcxt.values[idx++].Reg64 = env->efer; in whpx_set_registers()
515 vcxt.values[idx++].Reg64 = env->kernelgsbase; in whpx_set_registers()
519 vcxt.values[idx++].Reg64 = vcpu->apic_base; in whpx_set_registers()
521 /* WHvX64RegisterPat - Skipped */ in whpx_set_registers()
524 vcxt.values[idx++].Reg64 = env->sysenter_cs; in whpx_set_registers()
526 vcxt.values[idx++].Reg64 = env->sysenter_eip; in whpx_set_registers()
528 vcxt.values[idx++].Reg64 = env->sysenter_esp; in whpx_set_registers()
530 vcxt.values[idx++].Reg64 = env->star; in whpx_set_registers()
533 vcxt.values[idx++].Reg64 = env->lstar; in whpx_set_registers()
535 vcxt.values[idx++].Reg64 = env->cstar; in whpx_set_registers()
537 vcxt.values[idx++].Reg64 = env->fmask; in whpx_set_registers()
540 /* Interrupt / Event Registers - Skipped */ in whpx_set_registers()
545 whpx->partition, cpu->cpu_index, in whpx_set_registers()
551 error_report("WHPX: Failed to set virtual processor context, hr=%08lx", in whpx_set_registers()
564 whpx->partition, cpu->cpu_index, &tsc_reg, 1, &tsc_val); in whpx_get_tsc()
566 error_report("WHPX: Failed to get TSC, hr=%08lx", hr); in whpx_get_tsc()
567 return -1; in whpx_get_tsc()
570 cpu_env(cpu)->tsc = tsc_val.Reg64; in whpx_get_tsc()
588 whpx->partition, cpu->cpu_index, &xcr0_name, 1, &xcr0); in whpx_get_xcrs()
590 error_report("WHPX: Failed to get register xcr0, hr=%08lx", hr); in whpx_get_xcrs()
594 cpu_env(cpu)->xcr0 = xcr0.Reg64; in whpx_get_xcrs()
600 AccelCPUState *vcpu = cpu->accel; in whpx_get_registers()
602 CPUX86State *env = &x86_cpu->env; in whpx_get_registers()
612 if (!env->tsc_valid) { in whpx_get_registers()
614 env->tsc_valid = !runstate_is_running(); in whpx_get_registers()
618 whpx->partition, cpu->cpu_index, in whpx_get_registers()
623 error_report("WHPX: Failed to get virtual processor context, hr=%08lx", in whpx_get_registers()
633 whpx_apic_get(x86_cpu->apic_state); in whpx_get_registers()
634 vcpu->tpr = whpx_apic_tpr_to_cr8( in whpx_get_registers()
635 cpu_get_apic_tpr(x86_cpu->apic_state)); in whpx_get_registers()
643 env->regs[idx] = vcxt.values[idx].Reg64; in whpx_get_registers()
649 env->eip = vcxt.values[idx++].Reg64; in whpx_get_registers()
651 env->eflags = vcxt.values[idx++].Reg64; in whpx_get_registers()
656 env->segs[i] = whpx_seg_h2q(&vcxt.values[idx].Segment); in whpx_get_registers()
660 env->ldt = whpx_seg_h2q(&vcxt.values[idx++].Segment); in whpx_get_registers()
662 env->tr = whpx_seg_h2q(&vcxt.values[idx++].Segment); in whpx_get_registers()
664 env->idt.base = vcxt.values[idx].Table.Base; in whpx_get_registers()
665 env->idt.limit = vcxt.values[idx].Table.Limit; in whpx_get_registers()
668 env->gdt.base = vcxt.values[idx].Table.Base; in whpx_get_registers()
669 env->gdt.limit = vcxt.values[idx].Table.Limit; in whpx_get_registers()
674 env->cr[0] = vcxt.values[idx++].Reg64; in whpx_get_registers()
676 env->cr[2] = vcxt.values[idx++].Reg64; in whpx_get_registers()
678 env->cr[3] = vcxt.values[idx++].Reg64; in whpx_get_registers()
680 env->cr[4] = vcxt.values[idx++].Reg64; in whpx_get_registers()
683 if (tpr != vcpu->tpr) { in whpx_get_registers()
684 vcpu->tpr = tpr; in whpx_get_registers()
685 cpu_set_apic_tpr(x86_cpu->apic_state, whpx_cr8_to_apic_tpr(tpr)); in whpx_get_registers()
688 /* 8 Debug Registers - Skipped */ in whpx_get_registers()
691 * Extended control registers needs to be handled separately depending in whpx_get_registers()
699 for (i = 0; i < sizeof(env->xmm_regs) / sizeof(ZMMReg); i += 1, idx += 1) { in whpx_get_registers()
700 env->xmm_regs[i].ZMM_Q(0) = vcxt.values[idx].Reg128.Low64; in whpx_get_registers()
701 env->xmm_regs[i].ZMM_Q(1) = vcxt.values[idx].Reg128.High64; in whpx_get_registers()
708 env->fpregs[i].mmx.MMX_Q(0) = vcxt.values[idx].Fp.AsUINT128.Low64; in whpx_get_registers()
709 /* env->fpregs[i].mmx.MMX_Q(1) = in whpx_get_registers()
716 env->fpuc = vcxt.values[idx].FpControlStatus.FpControl; in whpx_get_registers()
717 env->fpstt = (vcxt.values[idx].FpControlStatus.FpStatus >> 11) & 0x7; in whpx_get_registers()
718 env->fpus = vcxt.values[idx].FpControlStatus.FpStatus & ~0x3800; in whpx_get_registers()
720 env->fptags[i] = !((vcxt.values[idx].FpControlStatus.FpTag >> i) & 1); in whpx_get_registers()
722 env->fpop = vcxt.values[idx].FpControlStatus.LastFpOp; in whpx_get_registers()
723 env->fpip = vcxt.values[idx].FpControlStatus.LastFpRip; in whpx_get_registers()
728 env->mxcsr = vcxt.values[idx].XmmControlStatus.XmmStatusControl; in whpx_get_registers()
733 env->efer = vcxt.values[idx++].Reg64; in whpx_get_registers()
736 env->kernelgsbase = vcxt.values[idx++].Reg64; in whpx_get_registers()
741 if (apic_base != vcpu->apic_base) { in whpx_get_registers()
742 vcpu->apic_base = apic_base; in whpx_get_registers()
743 cpu_set_apic_base(x86_cpu->apic_state, vcpu->apic_base); in whpx_get_registers()
746 /* WHvX64RegisterPat - Skipped */ in whpx_get_registers()
749 env->sysenter_cs = vcxt.values[idx++].Reg64; in whpx_get_registers()
751 env->sysenter_eip = vcxt.values[idx++].Reg64; in whpx_get_registers()
753 env->sysenter_esp = vcxt.values[idx++].Reg64; in whpx_get_registers()
755 env->star = vcxt.values[idx++].Reg64; in whpx_get_registers()
758 env->lstar = vcxt.values[idx++].Reg64; in whpx_get_registers()
760 env->cstar = vcxt.values[idx++].Reg64; in whpx_get_registers()
762 env->fmask = vcxt.values[idx++].Reg64; in whpx_get_registers()
765 /* Interrupt / Event Registers - Skipped */ in whpx_get_registers()
770 whpx_apic_get(x86_cpu->apic_state); in whpx_get_registers()
781 address_space_rw(&address_space_io, IoAccess->Port, attrs, in whpx_emu_ioport_callback()
782 &IoAccess->Data, IoAccess->AccessSize, in whpx_emu_ioport_callback()
783 IoAccess->Direction); in whpx_emu_ioport_callback()
791 cpu_physical_memory_rw(ma->GpaAddress, ma->Data, ma->AccessSize, in whpx_emu_mmio_callback()
792 ma->Direction); in whpx_emu_mmio_callback()
807 whpx->partition, cpu->cpu_index, in whpx_emu_getreg_callback()
811 error_report("WHPX: Failed to get virtual processor registers," in whpx_emu_getreg_callback()
829 whpx->partition, cpu->cpu_index, in whpx_emu_setreg_callback()
833 error_report("WHPX: Failed to set virtual processor registers," in whpx_emu_setreg_callback()
841 cpu->vcpu_dirty = false; in whpx_emu_setreg_callback()
858 hr = whp_dispatch.WHvTranslateGva(whpx->partition, cpu->cpu_index, in whpx_emu_translate_callback()
861 error_report("WHPX: Failed to translate GVA, hr=%08lx", hr); in whpx_emu_translate_callback()
881 AccelCPUState *vcpu = cpu->accel; in whpx_handle_mmio()
885 vcpu->emulator, cpu, in whpx_handle_mmio()
886 &vcpu->exit_ctx.VpContext, ctx, in whpx_handle_mmio()
889 error_report("WHPX: Failed to parse MMIO access, hr=%08lx", hr); in whpx_handle_mmio()
890 return -1; in whpx_handle_mmio()
894 error_report("WHPX: Failed to emulate MMIO access with" in whpx_handle_mmio()
896 return -1; in whpx_handle_mmio()
906 AccelCPUState *vcpu = cpu->accel; in whpx_handle_portio()
910 vcpu->emulator, cpu, in whpx_handle_portio()
911 &vcpu->exit_ctx.VpContext, ctx, in whpx_handle_portio()
914 error_report("WHPX: Failed to parse PortIO access, hr=%08lx", hr); in whpx_handle_portio()
915 return -1; in whpx_handle_portio()
919 error_report("WHPX: Failed to emulate PortIO access with" in whpx_handle_portio()
921 return -1; in whpx_handle_portio()
929 * namely breakpoint/single-step events.
940 if (exceptions == whpx->exception_exit_bitmap) { in whpx_set_exception_exit_bitmap()
947 whpx->partition, in whpx_set_exception_exit_bitmap()
953 whpx->exception_exit_bitmap = exceptions; in whpx_set_exception_exit_bitmap()
962 * It will update the CPU registers to arm/disarm the instruction stepping
975 * If we are trying to step over a single instruction, we need to set the in whpx_vcpu_configure_single_stepping()
980 whpx->partition, in whpx_vcpu_configure_single_stepping()
981 cpu->cpu_index, in whpx_vcpu_configure_single_stepping()
987 error_report("WHPX: Failed to get rflags, hr=%08lx", hr); in whpx_vcpu_configure_single_stepping()
1007 whpx->partition, in whpx_vcpu_configure_single_stepping()
1008 cpu->cpu_index, in whpx_vcpu_configure_single_stepping()
1014 error_report("WHPX: Failed to set rflags," in whpx_vcpu_configure_single_stepping()
1023 /* Suspend delivery of hardware interrupts during single-stepping. */ in whpx_vcpu_configure_single_stepping()
1027 whpx->partition, in whpx_vcpu_configure_single_stepping()
1028 cpu->cpu_index, in whpx_vcpu_configure_single_stepping()
1034 error_report("WHPX: Failed to set InterruptState," in whpx_vcpu_configure_single_stepping()
1044 * We need to now hide the INT1 from the guest, in whpx_vcpu_configure_single_stepping()
1050 whpx->partition, in whpx_vcpu_configure_single_stepping()
1051 cpu->cpu_index, in whpx_vcpu_configure_single_stepping()
1057 error_report("WHPX: Failed to get pending debug exceptions," in whpx_vcpu_configure_single_stepping()
1066 whpx->partition, in whpx_vcpu_configure_single_stepping()
1067 cpu->cpu_index, in whpx_vcpu_configure_single_stepping()
1073 error_report("WHPX: Failed to clear pending debug exceptions," in whpx_vcpu_configure_single_stepping()
1084 /* Tries to find a breakpoint at the specified address. */
1090 if (whpx->breakpoints.breakpoints) { in whpx_lookup_breakpoint_by_addr()
1091 for (i = 0; i < whpx->breakpoints.breakpoints->used; i++) { in whpx_lookup_breakpoint_by_addr()
1092 if (address == whpx->breakpoints.breakpoints->data[i].address) { in whpx_lookup_breakpoint_by_addr()
1093 return &whpx->breakpoints.breakpoints->data[i]; in whpx_lookup_breakpoint_by_addr()
1103 * debugging user-mode applications. Since the WHPX API does not offer
1104 * an easy way to pass the intercepted exception back to the guest, we
1105 * resort to using INT1 instead, and let the guest always handle INT3.
1112 * issues that need to be carefully handled:
1119 * 2. Writing arbitrary virtual memory may fail if it's not mapped to a valid
1121 * theoretically fail at any time. We need to keep track of it.
1123 * The function below rebuilds a list of low-level breakpoints (one per
1125 * high-level breakpoints (set via cpu_breakpoint_insert()).
1127 * In order to optimize performance, this function stores the list of
1128 * high-level breakpoints (a.k.a. CPU breakpoints) used to compute the
1129 * low-level ones, so that it won't be re-invoked until these breakpoints
1144 breakpoints->original_addresses = in whpx_translate_cpu_breakpoints()
1145 g_renew(vaddr, breakpoints->original_addresses, cpu_breakpoint_count); in whpx_translate_cpu_breakpoints()
1147 breakpoints->original_address_count = cpu_breakpoint_count; in whpx_translate_cpu_breakpoints()
1150 (breakpoints->breakpoints ? breakpoints->breakpoints->used : 0); in whpx_translate_cpu_breakpoints()
1156 new_breakpoints->allocated = max_breakpoints; in whpx_translate_cpu_breakpoints()
1157 new_breakpoints->used = 0; in whpx_translate_cpu_breakpoints()
1163 if (breakpoints->breakpoints) { in whpx_translate_cpu_breakpoints()
1165 for (i = 0; i < breakpoints->breakpoints->used; i++) { in whpx_translate_cpu_breakpoints()
1166 if (breakpoints->breakpoints->data[i].state != WHPX_BP_CLEARED) { in whpx_translate_cpu_breakpoints()
1167 new_breakpoints->data[new_breakpoints->used++] = in whpx_translate_cpu_breakpoints()
1168 breakpoints->breakpoints->data[i]; in whpx_translate_cpu_breakpoints()
1173 /* 2. Map all CPU breakpoints to WHPX breakpoints */ in whpx_translate_cpu_breakpoints()
1174 QTAILQ_FOREACH(bp, &cpu->breakpoints, entry) { in whpx_translate_cpu_breakpoints()
1178 /* This will be used to detect changed CPU breakpoints later. */ in whpx_translate_cpu_breakpoints()
1179 breakpoints->original_addresses[cpu_bp_index++] = bp->pc; in whpx_translate_cpu_breakpoints()
1181 for (i = 0; i < new_breakpoints->used; i++) { in whpx_translate_cpu_breakpoints()
1185 * real-world scenarios, since it only needs to run once after in whpx_translate_cpu_breakpoints()
1188 * high-level breakpoint objects in a tree or hash map. in whpx_translate_cpu_breakpoints()
1191 if (new_breakpoints->data[i].address == bp->pc) { in whpx_translate_cpu_breakpoints()
1193 if (new_breakpoints->data[i].state == WHPX_BP_CLEAR_PENDING) { in whpx_translate_cpu_breakpoints()
1194 new_breakpoints->data[i].state = WHPX_BP_SET; in whpx_translate_cpu_breakpoints()
1195 } else if (new_breakpoints->data[i].state == WHPX_BP_SET) { in whpx_translate_cpu_breakpoints()
1196 new_breakpoints->data[i].state = WHPX_BP_SET_PENDING; in whpx_translate_cpu_breakpoints()
1204 if (!found && new_breakpoints->used < new_breakpoints->allocated) { in whpx_translate_cpu_breakpoints()
1206 new_breakpoints->data[new_breakpoints->used].address = bp->pc; in whpx_translate_cpu_breakpoints()
1207 new_breakpoints->data[new_breakpoints->used].state = in whpx_translate_cpu_breakpoints()
1209 new_breakpoints->used++; in whpx_translate_cpu_breakpoints()
1218 g_free(breakpoints->breakpoints); in whpx_translate_cpu_breakpoints()
1220 breakpoints->breakpoints = new_breakpoints; in whpx_translate_cpu_breakpoints()
1227 * Passing resuming=true will try to set all previously unset breakpoints.
1240 for (i = 0; i < breakpoints->used; i++) { in whpx_apply_breakpoints()
1241 /* Decide what to do right now based on the last known state. */ in whpx_apply_breakpoints()
1242 WhpxBreakpointState state = breakpoints->data[i].state; in whpx_apply_breakpoints()
1269 breakpoints->data[i].address, in whpx_apply_breakpoints()
1270 &breakpoints->data[i].original_instruction, in whpx_apply_breakpoints()
1277 breakpoints->data[i].address, in whpx_apply_breakpoints()
1292 breakpoints->data[i].address, in whpx_apply_breakpoints()
1293 &breakpoints->data[i].original_instruction, in whpx_apply_breakpoints()
1302 breakpoints->data[i].state = state; in whpx_apply_breakpoints()
1307 * This function is called when the a VCPU is about to start and no other
1309 * arbitrary, it doesn't have to be VCPU#0.
1311 * It is used to commit the breakpoints into memory, and configure WHPX
1312 * to intercept debug exceptions.
1315 * more VCPUs are already running, so this is the best place to do it.
1324 if (!QTAILQ_EMPTY(&cpu->breakpoints) || in whpx_first_vcpu_starting()
1325 (whpx->breakpoints.breakpoints && in whpx_first_vcpu_starting()
1326 whpx->breakpoints.breakpoints->used)) { in whpx_first_vcpu_starting()
1331 QTAILQ_FOREACH(bp, &cpu->breakpoints, entry) { in whpx_first_vcpu_starting()
1332 if (i >= whpx->breakpoints.original_address_count || in whpx_first_vcpu_starting()
1333 bp->pc != whpx->breakpoints.original_addresses[i]) { in whpx_first_vcpu_starting()
1340 if (i != whpx->breakpoints.original_address_count) { in whpx_first_vcpu_starting()
1346 * The CPU breakpoints have changed since the last call to in whpx_first_vcpu_starting()
1350 whpx_translate_cpu_breakpoints(&whpx->breakpoints, cpu, i); in whpx_first_vcpu_starting()
1354 whpx_apply_breakpoints(whpx->breakpoints.breakpoints, cpu, true); in whpx_first_vcpu_starting()
1358 if (whpx->step_pending || in whpx_first_vcpu_starting()
1359 (whpx->breakpoints.breakpoints && in whpx_first_vcpu_starting()
1360 whpx->breakpoints.breakpoints->used)) { in whpx_first_vcpu_starting()
1362 * We are either attempting to single-step one or more CPUs, or in whpx_first_vcpu_starting()
1375 error_report("WHPX: Failed to update exception exit mask," in whpx_first_vcpu_starting()
1385 * It is used to remove any previously set breakpoints from memory.
1393 /* Returns the address of the next instruction that is about to be executed. */
1396 if (cpu->vcpu_dirty) { in whpx_vcpu_get_pc()
1398 return cpu_env(cpu)->eip; in whpx_vcpu_get_pc()
1405 AccelCPUState *vcpu = cpu->accel; in whpx_vcpu_get_pc()
1406 return vcpu->exit_ctx.VpContext.Rip; in whpx_vcpu_get_pc()
1409 * The CPU registers have been modified by a call to in whpx_vcpu_get_pc()
1410 * WHvSetVirtualProcessorRegisters() and must be re-queried from in whpx_vcpu_get_pc()
1419 whpx->partition, in whpx_vcpu_get_pc()
1420 cpu->cpu_index, in whpx_vcpu_get_pc()
1426 error_report("WHPX: Failed to get PC, hr=%08lx", hr); in whpx_vcpu_get_pc()
1439 if (!((cpu->interrupt_request & CPU_INTERRUPT_HARD) && in whpx_handle_halt()
1440 (cpu_env(cpu)->eflags & IF_MASK)) && in whpx_handle_halt()
1441 !(cpu->interrupt_request & CPU_INTERRUPT_NMI)) { in whpx_handle_halt()
1442 cpu->exception_index = EXCP_HLT; in whpx_handle_halt()
1443 cpu->halted = true; in whpx_handle_halt()
1455 AccelCPUState *vcpu = cpu->accel; in whpx_vcpu_pre_run()
1457 CPUX86State *env = &x86_cpu->env; in whpx_vcpu_pre_run()
1471 if (!vcpu->interruption_pending && in whpx_vcpu_pre_run()
1472 cpu->interrupt_request & (CPU_INTERRUPT_NMI | CPU_INTERRUPT_SMI)) { in whpx_vcpu_pre_run()
1473 if (cpu->interrupt_request & CPU_INTERRUPT_NMI) { in whpx_vcpu_pre_run()
1474 cpu->interrupt_request &= ~CPU_INTERRUPT_NMI; in whpx_vcpu_pre_run()
1475 vcpu->interruptable = false; in whpx_vcpu_pre_run()
1480 if (cpu->interrupt_request & CPU_INTERRUPT_SMI) { in whpx_vcpu_pre_run()
1481 cpu->interrupt_request &= ~CPU_INTERRUPT_SMI; in whpx_vcpu_pre_run()
1486 * Force the VCPU out of its inner loop to process any INIT requests or in whpx_vcpu_pre_run()
1489 if (cpu->interrupt_request & (CPU_INTERRUPT_INIT | CPU_INTERRUPT_TPR)) { in whpx_vcpu_pre_run()
1490 if ((cpu->interrupt_request & CPU_INTERRUPT_INIT) && in whpx_vcpu_pre_run()
1491 !(env->hflags & HF_SMM_MASK)) { in whpx_vcpu_pre_run()
1492 cpu->exit_request = 1; in whpx_vcpu_pre_run()
1494 if (cpu->interrupt_request & CPU_INTERRUPT_TPR) { in whpx_vcpu_pre_run()
1495 cpu->exit_request = 1; in whpx_vcpu_pre_run()
1501 if (!vcpu->interruption_pending && in whpx_vcpu_pre_run()
1502 vcpu->interruptable && (env->eflags & IF_MASK)) { in whpx_vcpu_pre_run()
1504 if (cpu->interrupt_request & CPU_INTERRUPT_HARD) { in whpx_vcpu_pre_run()
1505 cpu->interrupt_request &= ~CPU_INTERRUPT_HARD; in whpx_vcpu_pre_run()
1521 } else if (vcpu->ready_for_pic_interrupt && in whpx_vcpu_pre_run()
1522 (cpu->interrupt_request & CPU_INTERRUPT_HARD)) { in whpx_vcpu_pre_run()
1523 cpu->interrupt_request &= ~CPU_INTERRUPT_HARD; in whpx_vcpu_pre_run()
1537 /* Sync the TPR to the CR8 if was modified during the intercept */ in whpx_vcpu_pre_run()
1538 tpr = whpx_apic_tpr_to_cr8(cpu_get_apic_tpr(x86_cpu->apic_state)); in whpx_vcpu_pre_run()
1539 if (tpr != vcpu->tpr) { in whpx_vcpu_pre_run()
1540 vcpu->tpr = tpr; in whpx_vcpu_pre_run()
1542 cpu->exit_request = 1; in whpx_vcpu_pre_run()
1548 if (!vcpu->window_registered && in whpx_vcpu_pre_run()
1549 cpu->interrupt_request & CPU_INTERRUPT_HARD) { in whpx_vcpu_pre_run()
1554 vcpu->window_registered = 1; in whpx_vcpu_pre_run()
1560 vcpu->ready_for_pic_interrupt = false; in whpx_vcpu_pre_run()
1564 whpx->partition, cpu->cpu_index, in whpx_vcpu_pre_run()
1567 error_report("WHPX: Failed to set interrupt state registers," in whpx_vcpu_pre_run()
1575 AccelCPUState *vcpu = cpu->accel; in whpx_vcpu_post_run()
1577 CPUX86State *env = &x86_cpu->env; in whpx_vcpu_post_run()
1579 env->eflags = vcpu->exit_ctx.VpContext.Rflags; in whpx_vcpu_post_run()
1581 uint64_t tpr = vcpu->exit_ctx.VpContext.Cr8; in whpx_vcpu_post_run()
1582 if (vcpu->tpr != tpr) { in whpx_vcpu_post_run()
1583 vcpu->tpr = tpr; in whpx_vcpu_post_run()
1585 cpu_set_apic_tpr(x86_cpu->apic_state, whpx_cr8_to_apic_tpr(vcpu->tpr)); in whpx_vcpu_post_run()
1589 vcpu->interruption_pending = in whpx_vcpu_post_run()
1590 vcpu->exit_ctx.VpContext.ExecutionState.InterruptionPending; in whpx_vcpu_post_run()
1592 vcpu->interruptable = in whpx_vcpu_post_run()
1593 !vcpu->exit_ctx.VpContext.ExecutionState.InterruptShadow; in whpx_vcpu_post_run()
1599 CPUX86State *env = &x86_cpu->env; in whpx_vcpu_process_async_events()
1600 AccelCPUState *vcpu = cpu->accel; in whpx_vcpu_process_async_events()
1602 if ((cpu->interrupt_request & CPU_INTERRUPT_INIT) && in whpx_vcpu_process_async_events()
1603 !(env->hflags & HF_SMM_MASK)) { in whpx_vcpu_process_async_events()
1606 vcpu->interruptable = true; in whpx_vcpu_process_async_events()
1609 if (cpu->interrupt_request & CPU_INTERRUPT_POLL) { in whpx_vcpu_process_async_events()
1610 cpu->interrupt_request &= ~CPU_INTERRUPT_POLL; in whpx_vcpu_process_async_events()
1611 apic_poll_irq(x86_cpu->apic_state); in whpx_vcpu_process_async_events()
1614 if (((cpu->interrupt_request & CPU_INTERRUPT_HARD) && in whpx_vcpu_process_async_events()
1615 (env->eflags & IF_MASK)) || in whpx_vcpu_process_async_events()
1616 (cpu->interrupt_request & CPU_INTERRUPT_NMI)) { in whpx_vcpu_process_async_events()
1617 cpu->halted = false; in whpx_vcpu_process_async_events()
1620 if (cpu->interrupt_request & CPU_INTERRUPT_SIPI) { in whpx_vcpu_process_async_events()
1625 if (cpu->interrupt_request & CPU_INTERRUPT_TPR) { in whpx_vcpu_process_async_events()
1626 cpu->interrupt_request &= ~CPU_INTERRUPT_TPR; in whpx_vcpu_process_async_events()
1628 apic_handle_tpr_access_report(x86_cpu->apic_state, env->eip, in whpx_vcpu_process_async_events()
1629 env->tpr_access_type); in whpx_vcpu_process_async_events()
1637 AccelCPUState *vcpu = cpu->accel; in whpx_vcpu_run()
1644 if (whpx->running_cpus++ == 0) { in whpx_vcpu_run()
1652 if (whpx->breakpoints.breakpoints && in whpx_vcpu_run()
1653 whpx->breakpoints.breakpoints->used > 0) in whpx_vcpu_run()
1657 if (stepped_over_bp && stepped_over_bp->state != WHPX_BP_SET) { in whpx_vcpu_run()
1663 * We are trying to run the instruction overwritten by an active in whpx_vcpu_run()
1664 * breakpoint. We will temporarily disable the breakpoint, suspend in whpx_vcpu_run()
1673 if (cpu->halted && !whpx_apic_in_platform()) { in whpx_vcpu_run()
1674 cpu->exception_index = EXCP_HLT; in whpx_vcpu_run()
1675 qatomic_set(&cpu->exit_request, false); in whpx_vcpu_run()
1685 g_assert(!cpu->running); in whpx_vcpu_run()
1686 cpu->running = true; in whpx_vcpu_run()
1691 error_report("WHPX: Failed to update exception exit mask, " in whpx_vcpu_run()
1699 stepped_over_bp->address, in whpx_vcpu_run()
1700 &stepped_over_bp->original_instruction, in whpx_vcpu_run()
1709 if (cpu->vcpu_dirty) { in whpx_vcpu_run()
1711 cpu->vcpu_dirty = false; in whpx_vcpu_run()
1717 if (qatomic_read(&cpu->exit_request)) { in whpx_vcpu_run()
1722 if (exclusive_step_mode != WHPX_STEP_NONE || cpu->singlestep_enabled) { in whpx_vcpu_run()
1727 whpx->partition, cpu->cpu_index, in whpx_vcpu_run()
1728 &vcpu->exit_ctx, sizeof(vcpu->exit_ctx)); in whpx_vcpu_run()
1731 error_report("WHPX: Failed to exec a virtual processor," in whpx_vcpu_run()
1733 ret = -1; in whpx_vcpu_run()
1737 if (exclusive_step_mode != WHPX_STEP_NONE || cpu->singlestep_enabled) { in whpx_vcpu_run()
1740 &vcpu->exit_ctx.VpContext.Rflags); in whpx_vcpu_run()
1745 switch (vcpu->exit_ctx.ExitReason) { in whpx_vcpu_run()
1747 ret = whpx_handle_mmio(cpu, &vcpu->exit_ctx.MemoryAccess); in whpx_vcpu_run()
1751 ret = whpx_handle_portio(cpu, &vcpu->exit_ctx.IoPortAccess); in whpx_vcpu_run()
1755 vcpu->ready_for_pic_interrupt = 1; in whpx_vcpu_run()
1756 vcpu->window_registered = 0; in whpx_vcpu_run()
1762 ioapic_eoi_broadcast(vcpu->exit_ctx.ApicEoi.InterruptVector); in whpx_vcpu_run()
1775 uint64_t icr = vcpu->exit_ctx.ApicInitSipi.ApicIcr; in whpx_vcpu_run()
1810 /* no shorthand. Bits 56-63 contain the destination. */ in whpx_vcpu_run()
1813 hr = whp_dispatch.WHvRequestInterrupt(whpx->partition, in whpx_vcpu_run()
1816 error_report("WHPX: Failed to request interrupt hr=%08lx", in whpx_vcpu_run()
1844 if (i == cpu->cpu_index && !include_self) { in whpx_vcpu_run()
1852 * guest to modify the APIC ID. in whpx_vcpu_run()
1855 hr = whp_dispatch.WHvRequestInterrupt(whpx->partition, in whpx_vcpu_run()
1859 "WHPX: Failed to request SIPI for %d, hr=%08lx", in whpx_vcpu_run()
1870 * We are trying to step over a single instruction, and in whpx_vcpu_run()
1871 * likely got a request to stop from another thread. in whpx_vcpu_run()
1877 cpu->exception_index = EXCP_INTERRUPT; in whpx_vcpu_run()
1891 vcpu->exit_ctx.VpContext.Rip + in whpx_vcpu_run()
1892 vcpu->exit_ctx.VpContext.InstructionLength; in whpx_vcpu_run()
1899 reg_count = vcpu->exit_ctx.MsrAccess.AccessInfo.IsWrite ? in whpx_vcpu_run()
1903 whpx->partition, in whpx_vcpu_run()
1904 cpu->cpu_index, in whpx_vcpu_run()
1909 error_report("WHPX: Failed to set MsrAccess state " in whpx_vcpu_run()
1921 CPUX86State *env = &x86_cpu->env; in whpx_vcpu_run()
1925 rip = vcpu->exit_ctx.VpContext.Rip + in whpx_vcpu_run()
1926 vcpu->exit_ctx.VpContext.InstructionLength; in whpx_vcpu_run()
1927 cpuid_fn = vcpu->exit_ctx.CpuidAccess.Rax; in whpx_vcpu_run()
1930 * Ideally, these should be supplied to the hypervisor during VCPU in whpx_vcpu_run()
1931 * initialization and it should be able to satisfy this request. in whpx_vcpu_run()
1935 * QEMU to satisfy these requests, until WHPX adds support for in whpx_vcpu_run()
1936 * being able to set these values in the hypervisor at runtime. in whpx_vcpu_run()
1948 rax = env->tsc_khz; in whpx_vcpu_run()
1949 rbx = env->apic_bus_freq / 1000; /* Hz to KHz */ in whpx_vcpu_run()
1972 whpx->partition, cpu->cpu_index, in whpx_vcpu_run()
1978 error_report("WHPX: Failed to set CpuidAccess state registers," in whpx_vcpu_run()
1987 if ((vcpu->exit_ctx.VpException.ExceptionType == in whpx_vcpu_run()
1989 (vcpu->exit_ctx.VpException.InstructionByteCount >= 1) && in whpx_vcpu_run()
1990 (vcpu->exit_ctx.VpException.InstructionBytes[0] == in whpx_vcpu_run()
1993 cpu->exception_index = EXCP_DEBUG; in whpx_vcpu_run()
1994 } else if ((vcpu->exit_ctx.VpException.ExceptionType == in whpx_vcpu_run()
1996 !cpu->singlestep_enabled) { in whpx_vcpu_run()
1999 * gdb does not expect us to do single-stepping. in whpx_vcpu_run()
2002 cpu->exception_index = EXCP_INTERRUPT; in whpx_vcpu_run()
2004 /* Another exception or debug event. Report it to GDB. */ in whpx_vcpu_run()
2005 cpu->exception_index = EXCP_DEBUG; in whpx_vcpu_run()
2016 vcpu->exit_ctx.ExitReason); in whpx_vcpu_run()
2029 stepped_over_bp->address, in whpx_vcpu_run()
2037 cpu->running = false; in whpx_vcpu_run()
2048 if (--whpx->running_cpus == 0) { in whpx_vcpu_run()
2052 qatomic_set(&cpu->exit_request, false); in whpx_vcpu_run()
2059 if (!cpu->vcpu_dirty) { in do_whpx_cpu_synchronize_state()
2061 cpu->vcpu_dirty = true; in do_whpx_cpu_synchronize_state()
2069 cpu->vcpu_dirty = false; in do_whpx_cpu_synchronize_post_reset()
2076 cpu->vcpu_dirty = false; in do_whpx_cpu_synchronize_post_init()
2082 cpu->vcpu_dirty = true; in do_whpx_cpu_synchronize_pre_loadvm()
2091 if (!cpu->vcpu_dirty) { in whpx_cpu_synchronize_state()
2127 env->tsc_valid = false; in whpx_cpu_update_state()
2138 CPUX86State *env = &x86_cpu->env; in whpx_init_vcpu()
2147 "State blocked due to non-migratable CPUID feature support," in whpx_init_vcpu()
2152 ret = -EINVAL; in whpx_init_vcpu()
2161 &vcpu->emulator); in whpx_init_vcpu()
2163 error_report("WHPX: Failed to setup instruction completion support," in whpx_init_vcpu()
2165 ret = -EINVAL; in whpx_init_vcpu()
2170 whpx->partition, cpu->cpu_index, 0); in whpx_init_vcpu()
2172 error_report("WHPX: Failed to create a virtual processor," in whpx_init_vcpu()
2174 whp_dispatch.WHvEmulatorDestroyEmulator(vcpu->emulator); in whpx_init_vcpu()
2175 ret = -EINVAL; in whpx_init_vcpu()
2181 * provided by Hyper-V if the former is not present. In the latter case, we in whpx_init_vcpu()
2182 * query it from Hyper-V and record in env->tsc_khz, so that vcpu's TSC in whpx_init_vcpu()
2185 if (!env->tsc_khz) { in whpx_init_vcpu()
2191 printf("WHPX: Failed to query tsc frequency, hr=0x%08lx\n", hr); in whpx_init_vcpu()
2193 env->tsc_khz = freq / 1000; /* Hz to KHz */ in whpx_init_vcpu()
2198 env->apic_bus_freq = HYPERV_APIC_BUS_FREQUENCY; in whpx_init_vcpu()
2203 printf("WHPX: Failed to query apic bus frequency hr=0x%08lx\n", hr); in whpx_init_vcpu()
2205 env->apic_bus_freq = freq; in whpx_init_vcpu()
2213 if (x86_cpu->vmware_cpuid_freq && env->tsc_khz) { in whpx_init_vcpu()
2217 whpx->partition, in whpx_init_vcpu()
2223 error_report("WHPX: Failed to set partition CpuidExitList hr=%08lx", in whpx_init_vcpu()
2225 ret = -EINVAL; in whpx_init_vcpu()
2230 vcpu->interruptable = true; in whpx_init_vcpu()
2231 cpu->vcpu_dirty = true; in whpx_init_vcpu()
2232 cpu->accel = vcpu; in whpx_init_vcpu()
2233 max_vcpu_index = max(max_vcpu_index, cpu->cpu_index); in whpx_init_vcpu()
2250 if (cpu->exception_index >= EXCP_INTERRUPT) { in whpx_vcpu_exec()
2251 ret = cpu->exception_index; in whpx_vcpu_exec()
2252 cpu->exception_index = -1; in whpx_vcpu_exec()
2259 error_report("WHPX: Failed to exec a virtual processor"); in whpx_vcpu_exec()
2270 AccelCPUState *vcpu = cpu->accel; in whpx_destroy_vcpu()
2272 whp_dispatch.WHvDeleteVirtualProcessor(whpx->partition, cpu->cpu_index); in whpx_destroy_vcpu()
2273 whp_dispatch.WHvEmulatorDestroyEmulator(vcpu->emulator); in whpx_destroy_vcpu()
2274 g_free(cpu->accel); in whpx_destroy_vcpu()
2281 whpx->partition, cpu->cpu_index, 0); in whpx_vcpu_kick()
2299 (rom ? "ROM" : "RAM"), name); in whpx_update_mapping()
2307 hr = whp_dispatch.WHvMapGpaRange(whpx->partition, in whpx_update_mapping()
2315 hr = whp_dispatch.WHvUnmapGpaRange(whpx->partition, in whpx_update_mapping()
2321 error_report("WHPX: Failed to %s GPA range '%s' PA:%p, Size:%p bytes," in whpx_update_mapping()
2330 MemoryRegion *mr = section->mr; in whpx_process_section()
2331 hwaddr start_pa = section->offset_within_address_space; in whpx_process_section()
2332 ram_addr_t size = int128_get64(section->size); in whpx_process_section()
2340 delta = qemu_real_host_page_size() - (start_pa & ~qemu_real_host_page_mask()); in whpx_process_section()
2346 size -= delta; in whpx_process_section()
2353 + section->offset_within_region + delta; in whpx_process_section()
2356 memory_region_is_rom(mr), mr->name); in whpx_process_section()
2362 memory_region_ref(section->mr); in whpx_region_add()
2370 memory_region_unref(section->mr); in whpx_region_del()
2384 MemoryRegion *mr = section->mr; in whpx_log_sync()
2390 memory_region_set_dirty(mr, 0, int128_get64(section->size)); in whpx_log_sync()
2482 whpx->kernel_irqchip_allowed = true; in whpx_set_kernel_irqchip()
2483 whpx->kernel_irqchip_required = true; in whpx_set_kernel_irqchip()
2487 whpx->kernel_irqchip_allowed = false; in whpx_set_kernel_irqchip()
2488 whpx->kernel_irqchip_required = false; in whpx_set_kernel_irqchip()
2494 "Try without kernel-irqchip or with kernel-irqchip=on|off"); in whpx_set_kernel_irqchip()
2517 acc->cpu_instance_init = whpx_cpu_instance_init; in whpx_cpu_accel_class_init()
2546 ret = -ENOSYS; in whpx_accel_init()
2550 whpx->mem_quota = ms->ram_size; in whpx_accel_init()
2557 ret = -ENOSPC; in whpx_accel_init()
2564 error_report("WHPX: Failed to query capabilities, hr=%08lx", hr); in whpx_accel_init()
2565 ret = -EINVAL; in whpx_accel_init()
2569 hr = whp_dispatch.WHvCreatePartition(&whpx->partition); in whpx_accel_init()
2571 error_report("WHPX: Failed to create partition, hr=%08lx", hr); in whpx_accel_init()
2572 ret = -EINVAL; in whpx_accel_init()
2581 whpx->partition, in whpx_accel_init()
2592 error_report("WHPX: Failed to query XSAVE capability, hr=%08lx", hr); in whpx_accel_init()
2600 prop.ProcessorCount = ms->smp.cpus; in whpx_accel_init()
2602 whpx->partition, in whpx_accel_init()
2608 error_report("WHPX: Failed to set partition processor count to %u," in whpx_accel_init()
2610 ret = -EINVAL; in whpx_accel_init()
2618 if (whpx->kernel_irqchip_required && (!features.LocalApicEmulation || in whpx_accel_init()
2621 "Try without kernel-irqchip or with kernel-irqchip=off"); in whpx_accel_init()
2622 ret = -EINVAL; in whpx_accel_init()
2626 if (whpx->kernel_irqchip_allowed && features.LocalApicEmulation && in whpx_accel_init()
2632 whpx->partition, in whpx_accel_init()
2637 error_report("WHPX: Failed to enable kernel irqchip hr=%08lx", hr); in whpx_accel_init()
2638 if (whpx->kernel_irqchip_required) { in whpx_accel_init()
2640 ret = -EINVAL; in whpx_accel_init()
2644 whpx->apic_in_platform = true; in whpx_accel_init()
2658 whpx->partition, in whpx_accel_init()
2663 error_report("WHPX: Failed to enable MSR & CPUIDexit, hr=%08lx", hr); in whpx_accel_init()
2664 ret = -EINVAL; in whpx_accel_init()
2669 whpx->partition, in whpx_accel_init()
2675 error_report("WHPX: Failed to set partition CpuidExitList hr=%08lx", in whpx_accel_init()
2677 ret = -EINVAL; in whpx_accel_init()
2682 * We do not want to intercept any exceptions from the guest, in whpx_accel_init()
2685 whpx->exception_exit_bitmap = -1; in whpx_accel_init()
2689 error_report("WHPX: Failed to set exception exit bitmap, hr=%08lx", hr); in whpx_accel_init()
2690 ret = -EINVAL; in whpx_accel_init()
2694 hr = whp_dispatch.WHvSetupPartition(whpx->partition); in whpx_accel_init()
2696 error_report("WHPX: Failed to setup partition, hr=%08lx", hr); in whpx_accel_init()
2697 ret = -EINVAL; in whpx_accel_init()
2708 if (NULL != whpx->partition) { in whpx_accel_init()
2709 whp_dispatch.WHvDeletePartition(whpx->partition); in whpx_accel_init()
2710 whpx->partition = NULL; in whpx_accel_init()
2723 ac->name = "WHPX"; in whpx_accel_class_init()
2724 ac->init_machine = whpx_accel_init; in whpx_accel_class_init()
2725 ac->pre_resume_vm = whpx_pre_resume_vm; in whpx_accel_class_init()
2726 ac->allowed = &whpx_allowed; in whpx_accel_class_init()
2728 object_class_property_add(oc, "kernel-irqchip", "on|off|split", in whpx_accel_class_init()
2731 object_class_property_set_description(oc, "kernel-irqchip", in whpx_accel_class_init()
2732 "Configure WHPX in-kernel irqchip"); in whpx_accel_class_init()
2740 /* Turn on kernel-irqchip, by default */ in whpx_accel_instance_init()
2741 whpx->kernel_irqchip_allowed = true; in whpx_accel_instance_init()