/*
** Copyright (c) 2011, Intel Corporation
**
** This software is licensed under the terms of the GNU General Public
** License version 2, as published by the Free Software Foundation, and
** may be copied, distributed, and modified under those terms.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.
*/

#ifndef _HAX_INTERFACE_H
#define _HAX_INTERFACE_H

/*
 * Common data structure for HAX interface on both Mac and Windows
 * The IOCTL is defined in hax-darwin.h and hax-windows.h
 */

/* fx_layout according to Intel SDM */
struct fx_layout {
    uint16_t    fcw;
    uint16_t    fsw;
    uint8       ftw;
    uint8       res1;
    uint16_t    fop;
    union {
        struct {
            uint32      fip;
            uint16_t    fcs;
            uint16_t    res2;
        };
        uint64  fpu_ip;
    };
    union {
        struct {
            uint32      fdp;
            uint16_t    fds;
            uint16_t    res3;
        };
        uint64 fpu_dp;
    };
    uint32      mxcsr;
    uint32      mxcsr_mask;
    uint8       st_mm[8][16];
    uint8       mmx_1[8][16];
    uint8       mmx_2[8][16];
    uint8       pad[96];
};

struct vmx_msr {
    uint64 entry;
    uint64 value;
};

/*
 * Use fixed-size array to make Mac OS X support efficient by avoiding
 * use memory map or copy-in routines.
 */
#define HAX_MAX_MSR_ARRAY 0x20
struct hax_msr_data
{
    uint16_t nr_msr;
    uint16_t done;
    uint16_t pad[2];
    struct vmx_msr entries[HAX_MAX_MSR_ARRAY];
};

union interruptibility_state_t {
    uint32 raw;
    struct {
        uint32 sti_blocking   : 1;
        uint32 movss_blocking : 1;
        uint32 smi_blocking   : 1;
        uint32 nmi_blocking   : 1;
        uint32 reserved       : 28;
    };
    uint64_t pad;
};

typedef union interruptibility_state_t interruptibility_state_t;

// Segment descriptor
struct segment_desc_t {
    uint16_t selector;
    uint16_t _dummy;
    uint32 limit;
    uint64 base;
    union {
        struct {
            uint32 type             : 4;
            uint32 desc             : 1;
            uint32 dpl              : 2;
            uint32 present          : 1;
            uint32                  : 4;
            uint32 available        : 1;
            uint32 long_mode        : 1;
            uint32 operand_size     : 1;
            uint32 granularity      : 1;
            uint32 null             : 1;
            uint32                  : 15;
        };
        uint32 ar;
    };
    uint32 ipad;
};

typedef struct segment_desc_t segment_desc_t;

struct vcpu_state_t
{
    union {
        uint64 _regs[16];
        struct {
            union {
                struct {
                    uint8 _al,
                          _ah;
                };
                uint16_t    _ax;
                uint32    _eax;
                uint64    _rax;
            };
            union {
                struct {
                    uint8 _cl,
                          _ch;
                };
                uint16_t    _cx;
                uint32    _ecx;
                uint64    _rcx;
            };
            union {
                struct {
                    uint8 _dl,
                          _dh;
                };
                uint16_t    _dx;
                uint32    _edx;
                uint64    _rdx;
            };
            union {
                struct {
                    uint8 _bl,
                          _bh;
                };
                uint16_t    _bx;
                uint32    _ebx;
                uint64    _rbx;
            };
            union {
                uint16_t    _sp;
                uint32    _esp;
                uint64    _rsp;
            };
            union {
                uint16_t    _bp;
                uint32    _ebp;
                uint64    _rbp;
            };
            union {
                uint16_t    _si;
                uint32    _esi;
                uint64    _rsi;
            };
            union {
                uint16_t    _di;
                uint32    _edi;
                uint64    _rdi;
            };

            uint64 _r8;
            uint64 _r9;
            uint64 _r10;
            uint64 _r11;
            uint64 _r12;
            uint64 _r13;
            uint64 _r14;
            uint64 _r15;
        };
    };

    union {
        uint32 _eip;
        uint64 _rip;
    };

    union {
        uint32 _eflags;
        uint64 _rflags;
    };

    segment_desc_t _cs;
    segment_desc_t _ss;
    segment_desc_t _ds;
    segment_desc_t _es;
    segment_desc_t _fs;
    segment_desc_t _gs;
    segment_desc_t _ldt;
    segment_desc_t _tr;

    segment_desc_t _gdt;
    segment_desc_t _idt;

    uint64 _cr0;
    uint64 _cr2;
    uint64 _cr3;
    uint64 _cr4;

    uint64 _dr0;
    uint64 _dr1;
    uint64 _dr2;
    uint64 _dr3;
    uint64 _dr6;
    uint64 _dr7;
    uint64 _pde;

    uint32 _efer;

    uint32 _sysenter_cs;
    uint64 _sysenter_eip;
    uint64 _sysenter_esp;

    uint32 _activity_state;
    uint32 pad;
    interruptibility_state_t _interruptibility_state;
};

/*
 * HAX tunnel is a per-vCPU shared memory between QEMU and HAX driver
 * It is used to pass information between QEMU and HAX driver, like KVM_RUN
 *
 * In HAX_VCPU_IOCTL_SETUP_TUNNEL ioctl, HAX driver allocats the memory, maps
 * it to QEMU virtual address space and returns the virtual address and size to
 * QEMU through hax_tunnel_info structure
 */
struct hax_tunnel
{
    uint32_t _exit_reason;
    uint32_t _exit_flag;
    uint32_t _exit_status;
    uint32_t user_event_pending;
    int ready_for_interrupt_injection;
    int request_interrupt_window;
    union {
        struct {
            /* 0: read, 1: write */
#define HAX_EXIT_IO_IN  1
#define HAX_EXIT_IO_OUT 0
            uint8_t _direction;
            uint8_t _df;
            uint16_t _size;
            uint16_t _port;
            uint16_t _count;
            uint8_t _flags;
            uint8_t _pad0;
            uint16_t _pad1;
            uint32_t _pad2;
            uint64_t _vaddr;
        } pio;
        struct {
            uint64_t gla;
        } mmio;
        struct {
        } state;
    };
};

struct hax_tunnel_info
{
    uint64_t va;
    uint64_t io_va;
    uint16_t size;
    uint16_t pad[3];
};

/* The exit reason in HAX tunnel for HAX_VCPU_IOCTL_RUN IOCTL */
enum exit_status {
    /* IO port emulation request */
    HAX_EXIT_IO = 1,
    /* MMIO instruction emulation request
     * QEMU emulates MMIO instruction in following step:
     * 1. When guest accesses MMIO address, it is trapped to HAX driver
     * 2. HAX driver return back to QEMU with the instruction pointer address
     * 3. QEMU sync the vcpu state with HAX driver
     * 4. QEMU emulates this instruction
     * 5. QEMU sync the vcpu state to HAX driver
     * 6. HAX driver continuous run the guest through HAX_VCPU_IOCTL_RUN
     */
    HAX_EXIT_MMIO,
    /*
     * QEMU emulation mode request
     * QEMU emulates guest instruction when guest is running in
     * real mode or protected mode
     */
    HAX_EXIT_REAL,
    /*
     * Interrupt window open, qemu can inject an interrupt now.
     * Also used to indicate a signal is pending to QEMU
     */
    HAX_EXIT_INTERRUPT,
    /* Unknown vmexit, mostly trigger reboot */
    HAX_EXIT_UNKNOWN_VMEXIT,
    /*
     * Halt in guest
     * When guest executes HLT instruction with interrupt enabled, HAX
     * return back to QEMU.
     */
    HAX_EXIT_HLT,
    /* Reboot request, like because of tripple fault in guest */
    HAX_EXIT_STATECHANGE,
    /*
     * The VCPU is paused
     * Now the vcpu is only paused when to be destroid, so simply return to hax
     */
    HAX_EXIT_PAUSED,
    /* from API 2.0 */
    /*
     * In API 1.0, HAXM driver utilizes QEMU to decode and emulate MMIO
     * operations.
     * From 2.0, HAXM driver will decode some MMIO instructions to improve
     * MMIO handling performance, especially for GLES hardware acceleration
     */
    HAX_EXIT_FAST_MMIO,
};

/*
 * The API version between QEMU and HAX driver
 * Compat_version defines the oldest API version the HAX driver can support
 */
struct hax_module_version
{
    uint32_t compat_version;
    uint32_t cur_version;
};

/* This interface is support only after API version 2 */
struct hax_qemu_version
{
    /* Current API version in QEMU*/
    uint32_t cur_version;
    /* The least API version supported by QEMU */
    uint32_t least_version;
};

/* See comments for HAX_VM_IOCTL_ALLOC_RAM ioctl */
struct hax_alloc_ram_info
{
    uint32_t size;
    uint32_t pad;
    uint64_t va;
};

/* See comments for HAX_VM_IOCTL_SET_RAM ioctl */
#define HAX_RAM_INFO_ROM 0x1
struct hax_set_ram_info
{
    uint64_t pa_start;
    uint32_t size;
    uint8_t flags;
    uint8_t pad[3];
    uint64_t va;
};

/*
 * We need to load the HAXM (HAX Manager) to tell if the host system has the
 * required capabilities to operate, and we use hax_capabilityinfo to get such
 * info from HAXM.
 *
 * To prevent HAXM from over-consuming RAM, we set the maximum amount of RAM
 * that can be used for guests at HAX installation time. Once the quota is
 * reached, HAXM will no longer attempt to allocate memory for guests.
 * Detect that HAXM is out of quota can take the emulator to non-HAXM model
 */
struct hax_capabilityinfo
{
    /* bit 0: 1 - HAXM is working
     *        0 - HAXM is not working possibly because VT/NX is disabled
                  NX means Non-eXecution, aks. XD (eXecution Disable)
     * bit 1: 1 - HAXM has hard limit on how many RAM can be used as guest RAM
     *        0 - HAXM has no memory limitation
     */
#define HAX_CAP_STATUS_WORKING  0x1
#define HAX_CAP_STATUS_NOTWORKING  0x0
#define HAX_CAP_WORKSTATUS_MASK 0x1
#define HAX_CAP_MEMQUOTA        0x2
    uint16_t wstatus;
    /*
     * valid when HAXM is not working
     * bit 0: HAXM is not working because VT is not enabeld
     * bit 1: HAXM is not working because NX not enabled
     */
#define HAX_CAP_FAILREASON_VT   0x1
#define HAX_CAP_FAILREASON_NX   0x2
    uint16_t winfo;
    uint32_t pad;
    uint64_t mem_quota;
};

/* API 2.0 */

struct hax_fastmmio
{
    uint64_t gpa;
    uint64_t value;
    uint8_t size;
    uint8_t direction;
    uint16_t reg_index;
    uint32_t pad0;
    uint64_t _cr0;
    uint64_t _cr2;
    uint64_t _cr3;
    uint64_t _cr4;
};

#endif