/*
 * Userspace interfaces for /dev/mshv* devices and derived fds
 *
 * SPDX-License-Identifier: GPL-2.0-or-later
 */

#ifndef HW_HYPERV_HVGDK_MINI_H
#define HW_HYPERV_HVGDK_MINI_H

#define MSHV_IOCTL  0xB8

typedef enum hv_register_name {
    /* Pending Interruption Register */
    HV_REGISTER_PENDING_INTERRUPTION = 0x00010002,

    /* X64 User-Mode Registers */
    HV_X64_REGISTER_RAX     = 0x00020000,
    HV_X64_REGISTER_RCX     = 0x00020001,
    HV_X64_REGISTER_RDX     = 0x00020002,
    HV_X64_REGISTER_RBX     = 0x00020003,
    HV_X64_REGISTER_RSP     = 0x00020004,
    HV_X64_REGISTER_RBP     = 0x00020005,
    HV_X64_REGISTER_RSI     = 0x00020006,
    HV_X64_REGISTER_RDI     = 0x00020007,
    HV_X64_REGISTER_R8      = 0x00020008,
    HV_X64_REGISTER_R9      = 0x00020009,
    HV_X64_REGISTER_R10     = 0x0002000A,
    HV_X64_REGISTER_R11     = 0x0002000B,
    HV_X64_REGISTER_R12     = 0x0002000C,
    HV_X64_REGISTER_R13     = 0x0002000D,
    HV_X64_REGISTER_R14     = 0x0002000E,
    HV_X64_REGISTER_R15     = 0x0002000F,
    HV_X64_REGISTER_RIP     = 0x00020010,
    HV_X64_REGISTER_RFLAGS  = 0x00020011,

    /* X64 Floating Point and Vector Registers */
    HV_X64_REGISTER_XMM0                = 0x00030000,
    HV_X64_REGISTER_XMM1                = 0x00030001,
    HV_X64_REGISTER_XMM2                = 0x00030002,
    HV_X64_REGISTER_XMM3                = 0x00030003,
    HV_X64_REGISTER_XMM4                = 0x00030004,
    HV_X64_REGISTER_XMM5                = 0x00030005,
    HV_X64_REGISTER_XMM6                = 0x00030006,
    HV_X64_REGISTER_XMM7                = 0x00030007,
    HV_X64_REGISTER_XMM8                = 0x00030008,
    HV_X64_REGISTER_XMM9                = 0x00030009,
    HV_X64_REGISTER_XMM10               = 0x0003000A,
    HV_X64_REGISTER_XMM11               = 0x0003000B,
    HV_X64_REGISTER_XMM12               = 0x0003000C,
    HV_X64_REGISTER_XMM13               = 0x0003000D,
    HV_X64_REGISTER_XMM14               = 0x0003000E,
    HV_X64_REGISTER_XMM15               = 0x0003000F,
    HV_X64_REGISTER_FP_MMX0             = 0x00030010,
    HV_X64_REGISTER_FP_MMX1             = 0x00030011,
    HV_X64_REGISTER_FP_MMX2             = 0x00030012,
    HV_X64_REGISTER_FP_MMX3             = 0x00030013,
    HV_X64_REGISTER_FP_MMX4             = 0x00030014,
    HV_X64_REGISTER_FP_MMX5             = 0x00030015,
    HV_X64_REGISTER_FP_MMX6             = 0x00030016,
    HV_X64_REGISTER_FP_MMX7             = 0x00030017,
    HV_X64_REGISTER_FP_CONTROL_STATUS   = 0x00030018,
    HV_X64_REGISTER_XMM_CONTROL_STATUS  = 0x00030019,

    /* X64 Control Registers */
    HV_X64_REGISTER_CR0     = 0x00040000,
    HV_X64_REGISTER_CR2     = 0x00040001,
    HV_X64_REGISTER_CR3     = 0x00040002,
    HV_X64_REGISTER_CR4     = 0x00040003,
    HV_X64_REGISTER_CR8     = 0x00040004,
    HV_X64_REGISTER_XFEM    = 0x00040005,

    /* X64 Segment Registers */
    HV_X64_REGISTER_ES      = 0x00060000,
    HV_X64_REGISTER_CS      = 0x00060001,
    HV_X64_REGISTER_SS      = 0x00060002,
    HV_X64_REGISTER_DS      = 0x00060003,
    HV_X64_REGISTER_FS      = 0x00060004,
    HV_X64_REGISTER_GS      = 0x00060005,
    HV_X64_REGISTER_LDTR    = 0x00060006,
    HV_X64_REGISTER_TR      = 0x00060007,

    /* X64 Table Registers */
    HV_X64_REGISTER_IDTR    = 0x00070000,
    HV_X64_REGISTER_GDTR    = 0x00070001,

    /* X64 Virtualized MSRs */
    HV_X64_REGISTER_TSC             = 0x00080000,
    HV_X64_REGISTER_EFER            = 0x00080001,
    HV_X64_REGISTER_KERNEL_GS_BASE  = 0x00080002,
    HV_X64_REGISTER_APIC_BASE       = 0x00080003,
    HV_X64_REGISTER_PAT             = 0x00080004,
    HV_X64_REGISTER_SYSENTER_CS     = 0x00080005,
    HV_X64_REGISTER_SYSENTER_EIP    = 0x00080006,
    HV_X64_REGISTER_SYSENTER_ESP    = 0x00080007,
    HV_X64_REGISTER_STAR            = 0x00080008,
    HV_X64_REGISTER_LSTAR           = 0x00080009,
    HV_X64_REGISTER_CSTAR           = 0x0008000A,
    HV_X64_REGISTER_SFMASK          = 0x0008000B,
    HV_X64_REGISTER_INITIAL_APIC_ID = 0x0008000C,

    /* X64 Cache control MSRs */
    HV_X64_REGISTER_MSR_MTRR_CAP            = 0x0008000D,
    HV_X64_REGISTER_MSR_MTRR_DEF_TYPE       = 0x0008000E,
    HV_X64_REGISTER_MSR_MTRR_PHYS_BASE0     = 0x00080010,
    HV_X64_REGISTER_MSR_MTRR_PHYS_BASE1     = 0x00080011,
    HV_X64_REGISTER_MSR_MTRR_PHYS_BASE2     = 0x00080012,
    HV_X64_REGISTER_MSR_MTRR_PHYS_BASE3     = 0x00080013,
    HV_X64_REGISTER_MSR_MTRR_PHYS_BASE4     = 0x00080014,
    HV_X64_REGISTER_MSR_MTRR_PHYS_BASE5     = 0x00080015,
    HV_X64_REGISTER_MSR_MTRR_PHYS_BASE6     = 0x00080016,
    HV_X64_REGISTER_MSR_MTRR_PHYS_BASE7     = 0x00080017,
    HV_X64_REGISTER_MSR_MTRR_PHYS_BASE8     = 0x00080018,
    HV_X64_REGISTER_MSR_MTRR_PHYS_BASE9     = 0x00080019,
    HV_X64_REGISTER_MSR_MTRR_PHYS_BASEA     = 0x0008001A,
    HV_X64_REGISTER_MSR_MTRR_PHYS_BASEB     = 0x0008001B,
    HV_X64_REGISTER_MSR_MTRR_PHYS_BASEC     = 0x0008001C,
    HV_X64_REGISTER_MSR_MTRR_PHYS_BASED     = 0x0008001D,
    HV_X64_REGISTER_MSR_MTRR_PHYS_BASEE     = 0x0008001E,
    HV_X64_REGISTER_MSR_MTRR_PHYS_BASEF     = 0x0008001F,
    HV_X64_REGISTER_MSR_MTRR_PHYS_MASK0     = 0x00080040,
    HV_X64_REGISTER_MSR_MTRR_PHYS_MASK1     = 0x00080041,
    HV_X64_REGISTER_MSR_MTRR_PHYS_MASK2     = 0x00080042,
    HV_X64_REGISTER_MSR_MTRR_PHYS_MASK3     = 0x00080043,
    HV_X64_REGISTER_MSR_MTRR_PHYS_MASK4     = 0x00080044,
    HV_X64_REGISTER_MSR_MTRR_PHYS_MASK5     = 0x00080045,
    HV_X64_REGISTER_MSR_MTRR_PHYS_MASK6     = 0x00080046,
    HV_X64_REGISTER_MSR_MTRR_PHYS_MASK7     = 0x00080047,
    HV_X64_REGISTER_MSR_MTRR_PHYS_MASK8     = 0x00080048,
    HV_X64_REGISTER_MSR_MTRR_PHYS_MASK9     = 0x00080049,
    HV_X64_REGISTER_MSR_MTRR_PHYS_MASKA     = 0x0008004A,
    HV_X64_REGISTER_MSR_MTRR_PHYS_MASKB     = 0x0008004B,
    HV_X64_REGISTER_MSR_MTRR_PHYS_MASKC     = 0x0008004C,
    HV_X64_REGISTER_MSR_MTRR_PHYS_MASKD     = 0x0008004D,
    HV_X64_REGISTER_MSR_MTRR_PHYS_MASKE     = 0x0008004E,
    HV_X64_REGISTER_MSR_MTRR_PHYS_MASKF     = 0x0008004F,
    HV_X64_REGISTER_MSR_MTRR_FIX64K00000    = 0x00080070,
    HV_X64_REGISTER_MSR_MTRR_FIX16K80000    = 0x00080071,
    HV_X64_REGISTER_MSR_MTRR_FIX16KA0000    = 0x00080072,
    HV_X64_REGISTER_MSR_MTRR_FIX4KC0000     = 0x00080073,
    HV_X64_REGISTER_MSR_MTRR_FIX4KC8000     = 0x00080074,
    HV_X64_REGISTER_MSR_MTRR_FIX4KD0000     = 0x00080075,
    HV_X64_REGISTER_MSR_MTRR_FIX4KD8000     = 0x00080076,
    HV_X64_REGISTER_MSR_MTRR_FIX4KE0000     = 0x00080077,
    HV_X64_REGISTER_MSR_MTRR_FIX4KE8000     = 0x00080078,
    HV_X64_REGISTER_MSR_MTRR_FIX4KF0000     = 0x00080079,
    HV_X64_REGISTER_MSR_MTRR_FIX4KF8000     = 0x0008007A,

    HV_X64_REGISTER_TSC_AUX     = 0x0008007B,
    HV_X64_REGISTER_BNDCFGS     = 0x0008007C,
    HV_X64_REGISTER_DEBUG_CTL   = 0x0008007D,

    /* Available */

    HV_X64_REGISTER_SPEC_CTRL       = 0x00080084,
    HV_X64_REGISTER_TSC_ADJUST      = 0x00080096,

    /* Other MSRs */
    HV_X64_REGISTER_MSR_IA32_MISC_ENABLE = 0x000800A0,

    /* Misc */
    HV_REGISTER_GUEST_OS_ID         = 0x00090002,
    HV_REGISTER_REFERENCE_TSC       = 0x00090017,

    /* Hypervisor-defined Registers (Synic) */
    HV_REGISTER_SINT0       = 0x000A0000,
    HV_REGISTER_SINT1       = 0x000A0001,
    HV_REGISTER_SINT2       = 0x000A0002,
    HV_REGISTER_SINT3       = 0x000A0003,
    HV_REGISTER_SINT4       = 0x000A0004,
    HV_REGISTER_SINT5       = 0x000A0005,
    HV_REGISTER_SINT6       = 0x000A0006,
    HV_REGISTER_SINT7       = 0x000A0007,
    HV_REGISTER_SINT8       = 0x000A0008,
    HV_REGISTER_SINT9       = 0x000A0009,
    HV_REGISTER_SINT10      = 0x000A000A,
    HV_REGISTER_SINT11      = 0x000A000B,
    HV_REGISTER_SINT12      = 0x000A000C,
    HV_REGISTER_SINT13      = 0x000A000D,
    HV_REGISTER_SINT14      = 0x000A000E,
    HV_REGISTER_SINT15      = 0x000A000F,
    HV_REGISTER_SCONTROL    = 0x000A0010,
    HV_REGISTER_SVERSION    = 0x000A0011,
    HV_REGISTER_SIEFP       = 0x000A0012,
    HV_REGISTER_SIMP        = 0x000A0013,
    HV_REGISTER_EOM         = 0x000A0014,
    HV_REGISTER_SIRBP       = 0x000A0015,
} hv_register_name;

enum hv_intercept_type {
    HV_INTERCEPT_TYPE_X64_IO_PORT       = 0X00000000,
    HV_INTERCEPT_TYPE_X64_MSR           = 0X00000001,
    HV_INTERCEPT_TYPE_X64_CPUID         = 0X00000002,
    HV_INTERCEPT_TYPE_EXCEPTION         = 0X00000003,

    /* Used to be HV_INTERCEPT_TYPE_REGISTER */
    HV_INTERCEPT_TYPE_RESERVED0         = 0X00000004,
    HV_INTERCEPT_TYPE_MMIO              = 0X00000005,
    HV_INTERCEPT_TYPE_X64_GLOBAL_CPUID  = 0X00000006,
    HV_INTERCEPT_TYPE_X64_APIC_SMI      = 0X00000007,
    HV_INTERCEPT_TYPE_HYPERCALL         = 0X00000008,

    HV_INTERCEPT_TYPE_X64_APIC_INIT_SIPI        = 0X00000009,
    HV_INTERCEPT_MC_UPDATE_PATCH_LEVEL_MSR_READ = 0X0000000A,

    HV_INTERCEPT_TYPE_X64_APIC_WRITE        = 0X0000000B,
    HV_INTERCEPT_TYPE_X64_MSR_INDEX         = 0X0000000C,
    HV_INTERCEPT_TYPE_MAX,
    HV_INTERCEPT_TYPE_INVALID               = 0XFFFFFFFF,
};

struct hv_u128 {
    uint64_t low_part;
    uint64_t high_part;
} QEMU_PACKED;

union hv_x64_xmm_control_status_register {
    struct hv_u128 as_uint128;
    struct {
        union {
            /* long mode */
            uint64_t last_fp_rdp;
            /* 32 bit mode */
            struct {
                uint32_t last_fp_dp;
                uint16_t last_fp_ds;
                uint16_t padding;
            };
        };
        uint32_t xmm_status_control;
        uint32_t xmm_status_control_mask;
    };
};

union hv_x64_fp_register {
    struct hv_u128 as_uint128;
    struct {
        uint64_t mantissa;
        uint64_t biased_exponent:15;
        uint64_t sign:1;
        uint64_t reserved:48;
    };
};

union hv_x64_pending_exception_event {
    uint64_t as_uint64[2];
    struct {
        uint32_t event_pending:1;
        uint32_t event_type:3;
        uint32_t reserved0:4;
        uint32_t deliver_error_code:1;
        uint32_t reserved1:7;
        uint32_t vector:16;
        uint32_t error_code;
        uint64_t exception_parameter;
    };
};

union hv_x64_pending_virtualization_fault_event {
    uint64_t as_uint64[2];
    struct {
        uint32_t event_pending:1;
        uint32_t event_type:3;
        uint32_t reserved0:4;
        uint32_t reserved1:8;
        uint32_t parameter0:16;
        uint32_t code;
        uint64_t parameter1;
    };
};

union hv_x64_pending_interruption_register {
    uint64_t as_uint64;
    struct {
        uint32_t interruption_pending:1;
        uint32_t interruption_type:3;
        uint32_t deliver_error_code:1;
        uint32_t instruction_length:4;
        uint32_t nested_event:1;
        uint32_t reserved:6;
        uint32_t interruption_vector:16;
        uint32_t error_code;
    };
};

union hv_x64_register_sev_control {
    uint64_t as_uint64;
    struct {
        uint64_t enable_encrypted_state:1;
        uint64_t reserved_z:11;
        uint64_t vmsa_gpa_page_number:52;
    };
};

union hv_x64_msr_npiep_config_contents {
    uint64_t as_uint64;
    struct {
        /*
         * These bits enable instruction execution prevention for
         * specific instructions.
         */
        uint64_t prevents_gdt:1;
        uint64_t prevents_idt:1;
        uint64_t prevents_ldt:1;
        uint64_t prevents_tr:1;

        /* The reserved bits must always be 0. */
        uint64_t reserved:60;
    };
};

typedef struct hv_x64_segment_register {
    uint64_t base;
    uint32_t limit;
    uint16_t selector;
    union {
        struct {
            uint16_t segment_type:4;
            uint16_t non_system_segment:1;
            uint16_t descriptor_privilege_level:2;
            uint16_t present:1;
            uint16_t reserved:4;
            uint16_t available:1;
            uint16_t _long:1;
            uint16_t _default:1;
            uint16_t granularity:1;
        };
        uint16_t attributes;
    };
} QEMU_PACKED hv_x64_segment_register;

typedef struct hv_x64_table_register {
    uint16_t pad[3];
    uint16_t limit;
    uint64_t base;
} QEMU_PACKED hv_x64_table_register;

union hv_x64_fp_control_status_register {
    struct hv_u128 as_uint128;
    struct {
        uint16_t fp_control;
        uint16_t fp_status;
        uint8_t fp_tag;
        uint8_t reserved;
        uint16_t last_fp_op;
        union {
            /* long mode */
            uint64_t last_fp_rip;
            /* 32 bit mode */
            struct {
                uint32_t last_fp_eip;
                uint16_t last_fp_cs;
                uint16_t padding;
            };
        };
    };
};

/* General Hypervisor Register Content Definitions */

union hv_explicit_suspend_register {
    uint64_t as_uint64;
    struct {
        uint64_t suspended:1;
        uint64_t reserved:63;
    };
};

union hv_internal_activity_register {
    uint64_t as_uint64;

    struct {
        uint64_t startup_suspend:1;
        uint64_t halt_suspend:1;
        uint64_t idle_suspend:1;
        uint64_t rsvd_z:61;
    };
};

union hv_x64_interrupt_state_register {
    uint64_t as_uint64;
    struct {
        uint64_t interrupt_shadow:1;
        uint64_t nmi_masked:1;
        uint64_t reserved:62;
    };
};

union hv_intercept_suspend_register {
    uint64_t as_uint64;
    struct {
        uint64_t suspended:1;
        uint64_t reserved:63;
    };
};

typedef union hv_register_value {
    struct hv_u128 reg128;
    uint64_t reg64;
    uint32_t reg32;
    uint16_t reg16;
    uint8_t reg8;
    union hv_x64_fp_register fp;
    union hv_x64_fp_control_status_register fp_control_status;
    union hv_x64_xmm_control_status_register xmm_control_status;
    struct hv_x64_segment_register segment;
    struct hv_x64_table_register table;
    union hv_explicit_suspend_register explicit_suspend;
    union hv_intercept_suspend_register intercept_suspend;
    union hv_internal_activity_register internal_activity;
    union hv_x64_interrupt_state_register interrupt_state;
    union hv_x64_pending_interruption_register pending_interruption;
    union hv_x64_msr_npiep_config_contents npiep_config;
    union hv_x64_pending_exception_event pending_exception_event;
    union hv_x64_pending_virtualization_fault_event
        pending_virtualization_fault_event;
    union hv_x64_register_sev_control sev_control;
} hv_register_value;

/*
 * This struct is __packed in the kernel. Since all members are naturally
 * aligned, we can omit QEMU_PACKED to avoid address-of-packed-member warnings.
 */
typedef struct hv_register_assoc {
    uint32_t name;         /* enum hv_register_name */
    uint32_t reserved1;
    uint64_t reserved2;
    union hv_register_value value;
} hv_register_assoc;

union hv_input_vtl {
    uint8_t as_uint8;
    struct {
        uint8_t target_vtl:4;
        uint8_t use_target_vtl:1;
        uint8_t reserved_z:3;
    };
};

typedef struct hv_input_get_vp_registers {
    uint64_t partition_id;
    uint32_t vp_index;
    union hv_input_vtl input_vtl;
    uint8_t  rsvd_z8;
    uint16_t rsvd_z16;
    uint32_t names[];
} QEMU_PACKED hv_input_get_vp_registers;

typedef struct hv_input_set_vp_registers {
    uint64_t partition_id;
    uint32_t vp_index;
    union hv_input_vtl input_vtl;
    uint8_t  rsvd_z8;
    uint16_t rsvd_z16;
    struct hv_register_assoc elements[];
} QEMU_PACKED hv_input_set_vp_registers;

union hv_interrupt_control {
    uint64_t as_uint64;
    struct {
        uint32_t interrupt_type; /* enum hv_interrupt type */
        uint32_t level_triggered:1;
        uint32_t logical_dest_mode:1;
        uint32_t rsvd:30;
    };
};

struct hv_input_assert_virtual_interrupt {
    uint64_t partition_id;
    union hv_interrupt_control control;
    uint64_t dest_addr; /* cpu's apic id */
    uint32_t vector;
    uint8_t target_vtl;
    uint8_t rsvd_z0;
    uint16_t rsvd_z1;
} QEMU_PACKED;

/* /dev/mshv */
#define MSHV_CREATE_PARTITION   _IOW(MSHV_IOCTL, 0x00, struct mshv_create_partition)
#define MSHV_CREATE_VP          _IOW(MSHV_IOCTL, 0x01, struct mshv_create_vp)

/* Partition fds created with MSHV_CREATE_PARTITION */
#define MSHV_INITIALIZE_PARTITION   _IO(MSHV_IOCTL, 0x00)
#define MSHV_SET_GUEST_MEMORY       _IOW(MSHV_IOCTL, 0x02, struct mshv_user_mem_region)
#define MSHV_IRQFD                  _IOW(MSHV_IOCTL, 0x03, struct mshv_user_irqfd)
#define MSHV_IOEVENTFD              _IOW(MSHV_IOCTL, 0x04, struct mshv_user_ioeventfd)
#define MSHV_SET_MSI_ROUTING        _IOW(MSHV_IOCTL, 0x05, struct mshv_user_irq_table)

/*
 ********************************
 * VP APIs for child partitions *
 ********************************
 */

/*
 * This struct is __packed in the kernel, but since all members are naturally
 * aligned, so we can omit QEMU_PACKED to avoid address-of-packed-member
 * warnings.
 */
struct hv_local_interrupt_controller_state {
    /* HV_X64_INTERRUPT_CONTROLLER_STATE */
    uint32_t apic_id;
    uint32_t apic_version;
    uint32_t apic_ldr;
    uint32_t apic_dfr;
    uint32_t apic_spurious;
    uint32_t apic_isr[8];
    uint32_t apic_tmr[8];
    uint32_t apic_irr[8];
    uint32_t apic_esr;
    uint32_t apic_icr_high;
    uint32_t apic_icr_low;
    uint32_t apic_lvt_timer;
    uint32_t apic_lvt_thermal;
    uint32_t apic_lvt_perfmon;
    uint32_t apic_lvt_lint0;
    uint32_t apic_lvt_lint1;
    uint32_t apic_lvt_error;
    uint32_t apic_lvt_cmci;
    uint32_t apic_error_status;
    uint32_t apic_initial_count;
    uint32_t apic_counter_value;
    uint32_t apic_divide_configuration;
    uint32_t apic_remote_read;
};

/* Generic hypercall */
#define MSHV_ROOT_HVCALL        _IOWR(MSHV_IOCTL, 0x07, struct mshv_root_hvcall)

/* From hvgdk_mini.h */

#define HV_X64_MSR_GUEST_OS_ID      0x40000000
#define HV_X64_MSR_SINT0            0x40000090
#define HV_X64_MSR_SINT1            0x40000091
#define HV_X64_MSR_SINT2            0x40000092
#define HV_X64_MSR_SINT3            0x40000093
#define HV_X64_MSR_SINT4            0x40000094
#define HV_X64_MSR_SINT5            0x40000095
#define HV_X64_MSR_SINT6            0x40000096
#define HV_X64_MSR_SINT7            0x40000097
#define HV_X64_MSR_SINT8            0x40000098
#define HV_X64_MSR_SINT9            0x40000099
#define HV_X64_MSR_SINT10           0x4000009A
#define HV_X64_MSR_SINT11           0x4000009B
#define HV_X64_MSR_SINT12           0x4000009C
#define HV_X64_MSR_SINT13           0x4000009D
#define HV_X64_MSR_SINT14           0x4000009E
#define HV_X64_MSR_SINT15           0x4000009F
#define HV_X64_MSR_SCONTROL         0x40000080
#define HV_X64_MSR_SIEFP            0x40000082
#define HV_X64_MSR_SIMP             0x40000083
#define HV_X64_MSR_REFERENCE_TSC    0x40000021
#define HV_X64_MSR_EOM              0x40000084

/* Define port identifier type. */
union hv_port_id {
    uint32_t asuint32_t;
    struct {
        uint32_t id:24;
        uint32_t reserved:8;
    };
};

#define HV_MESSAGE_SIZE                 (256)
#define HV_MESSAGE_PAYLOAD_BYTE_COUNT   (240)
#define HV_MESSAGE_PAYLOAD_QWORD_COUNT  (30)

/* Define hypervisor message types. */
enum hv_message_type {
    HVMSG_NONE                          = 0x00000000,

    /* Memory access messages. */
    HVMSG_UNMAPPED_GPA                  = 0x80000000,
    HVMSG_GPA_INTERCEPT                 = 0x80000001,
    HVMSG_UNACCEPTED_GPA                = 0x80000003,
    HVMSG_GPA_ATTRIBUTE_INTERCEPT       = 0x80000004,

    /* Timer notification messages. */
    HVMSG_TIMER_EXPIRED                 = 0x80000010,

    /* Error messages. */
    HVMSG_INVALID_VP_REGISTER_VALUE     = 0x80000020,
    HVMSG_UNRECOVERABLE_EXCEPTION       = 0x80000021,
    HVMSG_UNSUPPORTED_FEATURE           = 0x80000022,

    /*
     * Opaque intercept message. The original intercept message is only
     * accessible from the mapped intercept message page.
     */
    HVMSG_OPAQUE_INTERCEPT              = 0x8000003F,

    /* Trace buffer complete messages. */
    HVMSG_EVENTLOG_BUFFERCOMPLETE       = 0x80000040,

    /* Hypercall intercept */
    HVMSG_HYPERCALL_INTERCEPT           = 0x80000050,

    /* SynIC intercepts */
    HVMSG_SYNIC_EVENT_INTERCEPT         = 0x80000060,
    HVMSG_SYNIC_SINT_INTERCEPT          = 0x80000061,
    HVMSG_SYNIC_SINT_DELIVERABLE        = 0x80000062,

    /* Async call completion intercept */
    HVMSG_ASYNC_CALL_COMPLETION         = 0x80000070,

    /* Root scheduler messages */
    HVMSG_SCHEDULER_VP_SIGNAL_BITSE     = 0x80000100,
    HVMSG_SCHEDULER_VP_SIGNAL_PAIR      = 0x80000101,

    /* Platform-specific processor intercept messages. */
    HVMSG_X64_IO_PORT_INTERCEPT         = 0x80010000,
    HVMSG_X64_MSR_INTERCEPT             = 0x80010001,
    HVMSG_X64_CPUID_INTERCEPT           = 0x80010002,
    HVMSG_X64_EXCEPTION_INTERCEPT       = 0x80010003,
    HVMSG_X64_APIC_EOI                  = 0x80010004,
    HVMSG_X64_LEGACY_FP_ERROR           = 0x80010005,
    HVMSG_X64_IOMMU_PRQ                 = 0x80010006,
    HVMSG_X64_HALT                      = 0x80010007,
    HVMSG_X64_INTERRUPTION_DELIVERABLE  = 0x80010008,
    HVMSG_X64_SIPI_INTERCEPT            = 0x80010009,
    HVMSG_X64_SEV_VMGEXIT_INTERCEPT     = 0x80010013,
};

union hv_x64_vp_execution_state {
    uint16_t as_uint16;
    struct {
        uint16_t cpl:2;
        uint16_t cr0_pe:1;
        uint16_t cr0_am:1;
        uint16_t efer_lma:1;
        uint16_t debug_active:1;
        uint16_t interruption_pending:1;
        uint16_t vtl:4;
        uint16_t enclave_mode:1;
        uint16_t interrupt_shadow:1;
        uint16_t virtualization_fault_active:1;
        uint16_t reserved:2;
    };
};

/* From openvmm::hvdef */
enum hv_x64_intercept_access_type {
    HV_X64_INTERCEPT_ACCESS_TYPE_READ = 0,
    HV_X64_INTERCEPT_ACCESS_TYPE_WRITE = 1,
    HV_X64_INTERCEPT_ACCESS_TYPE_EXECUTE = 2,
};

struct hv_x64_intercept_message_header {
    uint32_t vp_index;
    uint8_t instruction_length:4;
    uint8_t cr8:4; /* Only set for exo partitions */
    uint8_t intercept_access_type;
    union hv_x64_vp_execution_state execution_state;
    struct hv_x64_segment_register cs_segment;
    uint64_t rip;
    uint64_t rflags;
} QEMU_PACKED;

union hv_x64_io_port_access_info {
    uint8_t as_uint8;
    struct {
        uint8_t access_size:3;
        uint8_t string_op:1;
        uint8_t rep_prefix:1;
        uint8_t reserved:3;
    };
};

typedef struct hv_x64_io_port_intercept_message {
    struct hv_x64_intercept_message_header header;
    uint16_t port_number;
    union hv_x64_io_port_access_info access_info;
    uint8_t instruction_byte_count;
    uint32_t reserved;
    uint64_t rax;
    uint8_t instruction_bytes[16];
    struct hv_x64_segment_register ds_segment;
    struct hv_x64_segment_register es_segment;
    uint64_t rcx;
    uint64_t rsi;
    uint64_t rdi;
} QEMU_PACKED hv_x64_io_port_intercept_message;

union hv_x64_memory_access_info {
    uint8_t as_uint8;
    struct {
        uint8_t gva_valid:1;
        uint8_t gva_gpa_valid:1;
        uint8_t hypercall_output_pending:1;
        uint8_t tlb_locked_no_overlay:1;
        uint8_t reserved:4;
    };
};

struct hv_x64_memory_intercept_message {
    struct hv_x64_intercept_message_header header;
    uint32_t cache_type; /* enum hv_cache_type */
    uint8_t instruction_byte_count;
    union hv_x64_memory_access_info memory_access_info;
    uint8_t tpr_priority;
    uint8_t reserved1;
    uint64_t guest_virtual_address;
    uint64_t guest_physical_address;
    uint8_t instruction_bytes[16];
} QEMU_PACKED;

union hv_message_flags {
    uint8_t asu8;
    struct {
        uint8_t msg_pending:1;
        uint8_t reserved:7;
    };
};

struct hv_message_header {
    uint32_t message_type;
    uint8_t payload_size;
    union hv_message_flags message_flags;
    uint8_t reserved[2];
    union {
        uint64_t sender;
        union hv_port_id port;
    };
} QEMU_PACKED;

struct hv_message {
    struct hv_message_header header;
    union {
        uint64_t payload[HV_MESSAGE_PAYLOAD_QWORD_COUNT];
    } u;
} QEMU_PACKED;

/* From  github.com/rust-vmm/mshv-bindings/src/x86_64/regs.rs */

struct hv_cpuid_entry {
    uint32_t function;
    uint32_t index;
    uint32_t flags;
    uint32_t eax;
    uint32_t ebx;
    uint32_t ecx;
    uint32_t edx;
    uint32_t padding[3];
} QEMU_PACKED;

struct hv_cpuid {
    uint32_t nent;
    uint32_t padding;
    struct hv_cpuid_entry entries[0];
} QEMU_PACKED;

#define IA32_MSR_TSC            0x00000010
#define IA32_MSR_EFER           0xC0000080
#define IA32_MSR_KERNEL_GS_BASE 0xC0000102
#define IA32_MSR_APIC_BASE      0x0000001B
#define IA32_MSR_PAT            0x0277
#define IA32_MSR_SYSENTER_CS    0x00000174
#define IA32_MSR_SYSENTER_ESP   0x00000175
#define IA32_MSR_SYSENTER_EIP   0x00000176
#define IA32_MSR_STAR           0xC0000081
#define IA32_MSR_LSTAR          0xC0000082
#define IA32_MSR_CSTAR          0xC0000083
#define IA32_MSR_SFMASK         0xC0000084

#define IA32_MSR_MTRR_CAP       0x00FE
#define IA32_MSR_MTRR_DEF_TYPE  0x02FF
#define IA32_MSR_MTRR_PHYSBASE0 0x0200
#define IA32_MSR_MTRR_PHYSMASK0 0x0201
#define IA32_MSR_MTRR_PHYSBASE1 0x0202
#define IA32_MSR_MTRR_PHYSMASK1 0x0203
#define IA32_MSR_MTRR_PHYSBASE2 0x0204
#define IA32_MSR_MTRR_PHYSMASK2 0x0205
#define IA32_MSR_MTRR_PHYSBASE3 0x0206
#define IA32_MSR_MTRR_PHYSMASK3 0x0207
#define IA32_MSR_MTRR_PHYSBASE4 0x0208
#define IA32_MSR_MTRR_PHYSMASK4 0x0209
#define IA32_MSR_MTRR_PHYSBASE5 0x020A
#define IA32_MSR_MTRR_PHYSMASK5 0x020B
#define IA32_MSR_MTRR_PHYSBASE6 0x020C
#define IA32_MSR_MTRR_PHYSMASK6 0x020D
#define IA32_MSR_MTRR_PHYSBASE7 0x020E
#define IA32_MSR_MTRR_PHYSMASK7 0x020F

#define IA32_MSR_MTRR_FIX64K_00000 0x0250
#define IA32_MSR_MTRR_FIX16K_80000 0x0258
#define IA32_MSR_MTRR_FIX16K_A0000 0x0259
#define IA32_MSR_MTRR_FIX4K_C0000 0x0268
#define IA32_MSR_MTRR_FIX4K_C8000 0x0269
#define IA32_MSR_MTRR_FIX4K_D0000 0x026A
#define IA32_MSR_MTRR_FIX4K_D8000 0x026B
#define IA32_MSR_MTRR_FIX4K_E0000 0x026C
#define IA32_MSR_MTRR_FIX4K_E8000 0x026D
#define IA32_MSR_MTRR_FIX4K_F0000 0x026E
#define IA32_MSR_MTRR_FIX4K_F8000 0x026F

#define IA32_MSR_TSC_AUX          0xC0000103
#define IA32_MSR_BNDCFGS          0x00000d90
#define IA32_MSR_DEBUG_CTL        0x1D9
#define IA32_MSR_SPEC_CTRL        0x00000048
#define IA32_MSR_TSC_ADJUST       0x0000003b

#define IA32_MSR_MISC_ENABLE 0x000001a0

#define HV_TRANSLATE_GVA_VALIDATE_READ       (0x0001)
#define HV_TRANSLATE_GVA_VALIDATE_WRITE      (0x0002)
#define HV_TRANSLATE_GVA_VALIDATE_EXECUTE    (0x0004)

#define HV_HYP_PAGE_SHIFT       12
#define HV_HYP_PAGE_SIZE        BIT(HV_HYP_PAGE_SHIFT)
#define HV_HYP_PAGE_MASK        (~(HV_HYP_PAGE_SIZE - 1))

#define HVCALL_GET_PARTITION_PROPERTY    0x0044
#define HVCALL_SET_PARTITION_PROPERTY    0x0045
#define HVCALL_GET_VP_REGISTERS          0x0050
#define HVCALL_SET_VP_REGISTERS          0x0051
#define HVCALL_TRANSLATE_VIRTUAL_ADDRESS 0x0052
#define HVCALL_REGISTER_INTERCEPT_RESULT 0x0091
#define HVCALL_ASSERT_VIRTUAL_INTERRUPT  0x0094

#endif /* HW_HYPERV_HVGDK_MINI_H */
