| /* | |
| * QEMU MSHV support | |
| * | |
| * Copyright Microsoft, Corp. 2025 | |
| * | |
| * Authors: Ziqiao Zhou <ziqiaozhou@microsoft.com> | |
| * Magnus Kulke <magnuskulke@microsoft.com> | |
| * Jinank Jain <jinankjain@microsoft.com> | |
| * | |
| * SPDX-License-Identifier: GPL-2.0-or-later | |
| * | |
| */ | |
| #ifndef QEMU_MSHV_INT_H | |
| #define QEMU_MSHV_INT_H | |
| #include "hw/hyperv/hvhdk.h" | |
| #include "exec/vaddr.h" | |
| #define MSHV_MSR_ENTRIES_COUNT 64 | |
| /* | |
| * Interruption-type encoding, used by the hypervisor in | |
| * hv_x64_pending_interruption_register.interruption_type | |
| * See TLFS 6.0 section 7.9.2, p55 | |
| * https://learn.microsoft.com/en-us/virtualization/hyper-v-on-windows/tlfs/tlfs | |
| */ | |
| #define MSHV_HV_INTERRUPTION_TYPE_EXT_INT 0 | |
| #define MSHV_HV_INTERRUPTION_TYPE_NMI 2 | |
| #define MSHV_HV_INTERRUPTION_TYPE_HW_EXC 3 | |
| #define MSHV_HV_INTERRUPTION_TYPE_SW_INT 4 | |
| #define MSHV_HV_INTERRUPTION_TYPE_PRIV_SW_EXC 5 | |
| #define MSHV_HV_INTERRUPTION_TYPE_SW_EXC 6 | |
| #define MSHV_DIRTY_PAGES_BATCH_SIZE 0x10000 | |
| typedef struct hyperv_message hv_message; | |
| typedef struct MshvHvCallArgs { | |
| void *base; | |
| void *input_page; | |
| void *output_page; | |
| } MshvHvCallArgs; | |
| struct AccelCPUState { | |
| int cpufd; | |
| MshvHvCallArgs hvcall_args; | |
| }; | |
| typedef struct MshvMemoryListener { | |
| MemoryListener listener; | |
| int as_id; | |
| } MshvMemoryListener; | |
| typedef struct MshvAddressSpace { | |
| MshvMemoryListener *ml; | |
| AddressSpace *as; | |
| } MshvAddressSpace; | |
| struct MshvSwBreakpoint { | |
| vaddr pc; | |
| vaddr saved_insn; | |
| int use_count; | |
| QTAILQ_ENTRY(MshvSwBreakpoint) entry; | |
| }; | |
| struct MshvState { | |
| AccelState parent_obj; | |
| int vm; | |
| MshvMemoryListener memory_listener; | |
| /* number of listeners */ | |
| int nr_as; | |
| MshvAddressSpace *as; | |
| int fd; | |
| /* irqchip routing */ | |
| struct mshv_user_irq_table *irq_routes; | |
| int nr_allocated_irq_routes; | |
| unsigned long *used_gsi_bitmap; | |
| unsigned int gsi_count; | |
| union hv_partition_processor_features processor_features; | |
| QTAILQ_HEAD(, MshvSwBreakpoint) sw_breakpoints; | |
| bool exception_intercepts_installed; | |
| }; | |
| typedef struct MshvMsiControl { | |
| bool updated; | |
| GHashTable *gsi_routes; | |
| } MshvMsiControl; | |
| #define mshv_vcpufd(cpu) (cpu->accel->cpufd) | |
| /* cpu */ | |
| typedef enum MshvVmExit { | |
| MshvVmExitIgnore = 0, | |
| MshvVmExitShutdown = 1, | |
| MshvVmExitSpecial = 2, | |
| MshvVmExitDebug = 3, | |
| } MshvVmExit; | |
| void mshv_init_mmio_emu(void); | |
| int mshv_create_vcpu(int vm_fd, uint8_t vp_index, int *cpu_fd); | |
| void mshv_remove_vcpu(int vm_fd, int cpu_fd); | |
| int mshv_configure_vcpu(const CPUState *cpu); | |
| int mshv_run_vcpu(int vm_fd, CPUState *cpu, hv_message *msg, MshvVmExit *exit); | |
| int mshv_set_generic_regs(const CPUState *cpu, const hv_register_assoc *assocs, | |
| size_t n_regs); | |
| int mshv_get_generic_regs(CPUState *cpu, hv_register_assoc *assocs, | |
| size_t n_regs); | |
| int mshv_arch_store_vcpu_state(const CPUState *cpu); | |
| int mshv_arch_load_vcpu_state(CPUState *cpu); | |
| int mshv_arch_set_partition_msrs(const CPUState *cpu); | |
| int mshv_arch_set_mp_state(const CPUState *cpu); | |
| int mshv_arch_insert_sw_breakpoint(CPUState *cpu, struct MshvSwBreakpoint *bp); | |
| int mshv_arch_remove_sw_breakpoint(CPUState *cpu, struct MshvSwBreakpoint *bp); | |
| struct MshvSwBreakpoint *mshv_find_sw_breakpoint(CPUState *cpu, vaddr pc); | |
| void mshv_arch_init_vcpu(CPUState *cpu); | |
| void mshv_arch_destroy_vcpu(CPUState *cpu); | |
| void mshv_arch_amend_proc_features( | |
| union hv_partition_synthetic_processor_features *features); | |
| void mshv_arch_disable_partition_proc_features( | |
| union hv_partition_processor_features *disabled_features); | |
| int mshv_arch_post_init_vm(int vm_fd); | |
| int mshv_get_vp_state(int cpu_fd, struct mshv_get_set_vp_state *state); | |
| int mshv_set_vp_state(int cpu_fd, const struct mshv_get_set_vp_state *state); | |
| typedef struct mshv_root_hvcall mshv_root_hvcall; | |
| int mshv_hvcall(int fd, const mshv_root_hvcall *args); | |
| /* apic */ | |
| int mshv_init_lint(CPUState *cpu); | |
| int mshv_set_lapic(const CPUState *cpu); | |
| int mshv_get_lapic(CPUState *cpu); | |
| /* memory */ | |
| typedef struct MshvMemoryRegion { | |
| uint64_t guest_phys_addr; | |
| uint64_t memory_size; | |
| uint64_t userspace_addr; | |
| bool readonly; | |
| } MshvMemoryRegion; | |
| int mshv_guest_mem_read(uint64_t gpa, uint8_t *data, uintptr_t size, | |
| bool is_secure_mode, bool instruction_fetch); | |
| int mshv_guest_mem_write(uint64_t gpa, const uint8_t *data, uintptr_t size, | |
| bool is_secure_mode); | |
| void mshv_set_phys_mem(MshvMemoryListener *mml, MemoryRegionSection *section, | |
| bool add); | |
| void mshv_log_sync(MemoryListener *listener, MemoryRegionSection *section); | |
| bool mshv_log_global_start(MemoryListener *listener, Error **errp); | |
| void mshv_log_global_stop(MemoryListener *listener); | |
| /* msr */ | |
| int mshv_init_msrs(const CPUState *cpu); | |
| int mshv_get_msrs(CPUState *cpu); | |
| int mshv_set_msrs(const CPUState *cpu); | |
| /* synic */ | |
| int mshv_get_simp(int cpu_fd, uint8_t *page); | |
| int mshv_set_simp(int cpu_fd, const uint8_t *page); | |
| int mshv_get_siefp(int cpu_fd, uint8_t *page); | |
| int mshv_set_siefp(int cpu_fd, const uint8_t *page); | |
| bool mshv_synic_enabled(const CPUState *cpu); | |
| int mshv_get_synthetic_timers(int cpu_fd, uint8_t *state); | |
| int mshv_set_synthetic_timers(int cpu_fd, const uint8_t *state); | |
| #endif |