root/usr/src/uts/intel/sys/vmm_data.h
/*
 * This file and its contents are supplied under the terms of the
 * Common Development and Distribution License ("CDDL"), version 1.0.
 * You may only use this file in accordance with the terms of version
 * 1.0 of the CDDL.
 *
 * A full copy of the text of the CDDL should have accompanied this
 * source.  A copy of the CDDL is also available via the Internet at
 * http://www.illumos.org/license/CDDL.
 */
/* This file is dual-licensed; see usr/src/contrib/bhyve/LICENSE */

/*
 * Copyright 2025 Oxide Computer Company
 */

#ifndef _VMM_DATA_H_
#define _VMM_DATA_H_

/* VMM Data Classes */
#define VDC_VERSION     1       /* Version information for each data class */

/* Classes bearing per-CPU data */
#define VDC_REGISTER    2       /* Registers (GPR, segment, etc) */
#define VDC_MSR         3       /* Model-specific registers */
#define VDC_FPU         4       /* FPU (and associated SIMD) */
#define VDC_LAPIC       5       /* Local APIC */
#define VDC_VMM_ARCH    6       /* Arch-specific VMM state (VMX/SVM) */
#define VDC_PMU_AMD     14      /* PMU for AMD CPUs */

/* Classes for system-wide devices */
#define VDC_IOAPIC      7       /* bhyve IO-APIC */
#define VDC_ATPIT       8       /* i8254 PIT */
#define VDC_ATPIC       9       /* i8259 PIC */
#define VDC_HPET        10      /* HPET */
#define VDC_PM_TIMER    11      /* ACPI Power Management Timer */
#define VDC_RTC         12      /* IBM PC Real Time Clock */

#define VDC_VMM_TIME    13      /* Time-related VMM data */

/* Indicates top of VMM Data Class range, updated as classes are added */
#define VDC_MAX         (VDC_PMU_AMD + 1)


/* VMM Data Identifiers */

/*
 * Generic field encoding for 64-bit (or smaller) data which are identified by a
 * 32-bit (or smaller) name.
 *
 * Used by the following classes/version:
 * - VDC_REGISTER v1: `vm_reg_name` identifiers
 * - VDC_MSR v1: MSR identifiers
 * - VDC_VMM_ARCH v1: Identifiers described below
 */
struct vdi_field_entry_v1 {
        uint32_t        vfe_ident;
        uint32_t        _pad;
        uint64_t        vfe_value;
};

/* VDC_VERSION */
struct vdi_version_entry_v1 {
        uint16_t        vve_class;
        uint16_t        vve_version;
        uint16_t        vve_len_expect;
        uint16_t        vve_len_per_item;
};

/*
 * VDC_FPU:
 *
 * Unimplemented for now.  Use VM_GET_FPU/VM_SET_FPU ioctls.
 */

/* VDC_LAPIC: */

struct vdi_lapic_page_v1 {
        uint32_t        vlp_id;
        uint32_t        vlp_version;
        uint32_t        vlp_tpr;
        uint32_t        vlp_apr;
        uint32_t        vlp_ldr;
        uint32_t        vlp_dfr;
        uint32_t        vlp_svr;
        uint32_t        vlp_isr[8];
        uint32_t        vlp_tmr[8];
        uint32_t        vlp_irr[8];
        uint32_t        vlp_esr;
        uint32_t        vlp_lvt_cmci;
        uint64_t        vlp_icr;
        uint32_t        vlp_lvt_timer;
        uint32_t        vlp_lvt_thermal;
        uint32_t        vlp_lvt_pcint;
        uint32_t        vlp_lvt_lint0;
        uint32_t        vlp_lvt_lint1;
        uint32_t        vlp_lvt_error;
        uint32_t        vlp_icr_timer;
        uint32_t        vlp_dcr_timer;
};

struct vdi_lapic_v1 {
        struct vdi_lapic_page_v1 vl_lapic;
        uint64_t                vl_msr_apicbase;
        int64_t                 vl_timer_target;
        uint32_t                vl_esr_pending;
};

/*
 * VDC_VMM_ARCH:
 */

/* VDC_PMU_AMD: */

struct vdi_pmu_amd_v1 {
        uint64_t        vpa_evtsel[6];
        uint64_t        vpa_ctr[6];
};

/*
 * Version 1 identifiers:
 */

/*
 * VM-wide:
 */

/* Is the VM currently in the "paused" state? (0 or 1) */
#define VAI_VM_IS_PAUSED        4

/*
 * per-vCPU:
 *
 * Note: While these are currently defined with values disjoint from those in
 * the VM-wide category, it is not required that they be.  The VM-wide and
 * per-vCPU identifiers are distinguished by vm_data_xfer`vdx_vcpuid.
 */

/* NMI pending injection for vCPU (0 or 1) */
#define VAI_PEND_NMI            10
/* extint pending injection for vCPU (0 or 1) */
#define VAI_PEND_EXTINT         11
/* HW exception pending injection for vCPU */
#define VAI_PEND_EXCP           12
/* exception/interrupt pending injection for vCPU */
#define VAI_PEND_INTINFO        13

/* VDC_IOAPIC: */

struct vdi_ioapic_v1 {
        uint64_t        vi_pin_reg[32];
        uint32_t        vi_pin_level[32];
        uint32_t        vi_id;
        uint32_t        vi_reg_sel;
};

/* VDC_ATPIT: */

struct vdi_atpit_channel_v1 {
        uint16_t        vac_initial;
        uint16_t        vac_reg_cr;
        uint16_t        vac_reg_ol;
        uint8_t         vac_reg_status;
        uint8_t         vac_mode;
        /*
         * vac_status bits:
         * - 0b00001 status latched
         * - 0b00010 output latched
         * - 0b00100 control register sel
         * - 0b01000 output latch sel
         * - 0b10000 free-running timer
         */
        uint8_t         vac_status;

        int64_t         vac_time_target;
};

struct vdi_atpit_v1 {
        struct vdi_atpit_channel_v1 va_channel[3];
};

/* VDC_ATPIC: */

struct vdi_atpic_chip_v1 {
        uint8_t         vac_icw_state;
        /*
         * vac_status bits:
         * - 0b00000001 ready
         * - 0b00000010 auto EOI
         * - 0b00000100 poll
         * - 0b00001000 rotate
         * - 0b00010000 special full nested
         * - 0b00100000 read isr next
         * - 0b01000000 intr raised
         * - 0b10000000 special mask mode
         */
        uint8_t         vac_status;
        uint8_t         vac_reg_irr;
        uint8_t         vac_reg_isr;
        uint8_t         vac_reg_imr;
        uint8_t         vac_irq_base;
        uint8_t         vac_lowprio;
        uint8_t         vac_elc;
        uint32_t        vac_level[8];
};

struct vdi_atpic_v1 {
        struct vdi_atpic_chip_v1 va_chip[2];
};

/* VDC_HPET: */

struct vdi_hpet_timer_v1 {
        uint64_t        vht_config;
        uint64_t        vht_msi;
        uint32_t        vht_comp_val;
        uint32_t        vht_comp_rate;
        int64_t         vht_time_target;
};

struct vdi_hpet_v1 {
        uint64_t        vh_config;
        uint64_t        vh_isr;
        uint32_t        vh_count_base;
        int64_t         vh_time_base;

        struct vdi_hpet_timer_v1        vh_timers[8];
};

/* VDC_PM_TIMER: */

struct vdi_pm_timer_v1 {
        int64_t         vpt_time_base;
        /*
         * Since the PM-timer IO port registration can be set by a dedicated
         * ioctl today, it is considered a read-only field in the vmm data
         * interface and its contents will be ignored when writing state data to
         * the timer.
         */
        uint16_t        vpt_ioport;
};

/* VDC_RTC: */

struct vdi_rtc_v2 {
        int64_t         vr_base_clock;
        int64_t         vr_last_period;
        uint8_t         vr_content[128];
        uint8_t         vr_addr;
};

/* VDC_VMM_TIME: */

/*
 * Interface for modifying time-related data of a guest, allowing the guest's
 * TSC and device timers to continue working across inter-machine live
 * migrations.
 *
 * Reads of this data will populate all fields, including:
 * - current guest TSC (a calculated value)
 * - guest TSC frequency
 * - guest boot_time, which tracks the offset of the guest boot based on host
 *   hrtime
 * - current host hrtime and wall clock time (hrestime) at the time of read
 *
 * Callers writing this data may want to make adjustments to the guest TSC based
 * on the time between read and write, such as in the case of a migration.
 * For migrations between machines, the boot_hrtime must also be updated based
 * on the hrtime of the target system. Callers should populate the host time
 * fields for the host the write is performed on. These fields are used by the
 * write interface to make additional adjustments to the guest fields to account
 * for latency between the userspace adjustment and kernel receipt of those
 * values.
 */
struct vdi_time_info_v1 {
        /* guest-related fields */
        uint64_t        vt_guest_freq;  /* guest TSC frequency (hz) */
        uint64_t        vt_guest_tsc;   /* current guest TSC */
        int64_t         vt_boot_hrtime; /* guest boot_hrtime */

        /* host time fields */
        int64_t         vt_hrtime;      /* host hrtime (ns) */
        uint64_t        vt_hres_sec;    /* host hrestime (sec) */
        uint64_t        vt_hres_ns;     /* host hrestime (ns) */
};

#endif /* _VMM_DATA_H_ */