#ifndef _VMM_KERNEL_H_
#define _VMM_KERNEL_H_
#include <sys/sdt.h>
#include <x86/segments.h>
#include <sys/vmm.h>
#include <sys/vmm_data.h>
#include <sys/linker_set.h>
SDT_PROVIDER_DECLARE(vmm);
struct vm;
struct vm_exception;
struct seg_desc;
struct vm_exit;
struct vie;
struct vm_run;
struct vhpet;
struct vioapic;
struct vlapic;
struct vmspace;
struct vm_client;
struct vm_object;
struct vm_guest_paging;
struct vmm_data_req;
typedef enum {
FR_VALID,
FR_SCALING_NOT_NEEDED,
FR_SCALING_NOT_SUPPORTED,
FR_OUT_OF_RANGE,
} freqratio_res_t;
typedef int (*vmm_init_func_t)(void);
typedef void (*vmm_resume_func_t)(void);
typedef void * (*vmi_init_func_t)(struct vm *vm);
typedef int (*vmi_run_func_t)(void *vmi, int vcpu, uint64_t rip);
typedef void (*vmi_cleanup_func_t)(void *vmi);
typedef int (*vmi_get_register_t)(void *vmi, int vcpu, int num,
uint64_t *retval);
typedef int (*vmi_set_register_t)(void *vmi, int vcpu, int num,
uint64_t val);
typedef int (*vmi_get_desc_t)(void *vmi, int vcpu, int num,
struct seg_desc *desc);
typedef int (*vmi_set_desc_t)(void *vmi, int vcpu, int num,
const struct seg_desc *desc);
typedef int (*vmi_get_cap_t)(void *vmi, int vcpu, int num, int *retval);
typedef int (*vmi_set_cap_t)(void *vmi, int vcpu, int num, int val);
typedef struct vlapic *(*vmi_vlapic_init)(void *vmi, int vcpu);
typedef void (*vmi_vlapic_cleanup)(void *vmi, struct vlapic *vlapic);
typedef void (*vmi_savectx)(void *vmi, int vcpu);
typedef void (*vmi_restorectx)(void *vmi, int vcpu);
typedef void (*vmi_pause_t)(void *vmi, int vcpu);
typedef int (*vmi_get_msr_t)(void *vmi, int vcpu, uint32_t msr,
uint64_t *valp);
typedef int (*vmi_set_msr_t)(void *vmi, int vcpu, uint32_t msr,
uint64_t val);
typedef freqratio_res_t (*vmi_freqratio_t)(uint64_t guest_hz,
uint64_t host_hz, uint64_t *mult);
struct vmm_ops {
vmm_init_func_t init;
vmm_resume_func_t resume;
vmi_init_func_t vminit;
vmi_run_func_t vmrun;
vmi_cleanup_func_t vmcleanup;
vmi_get_register_t vmgetreg;
vmi_set_register_t vmsetreg;
vmi_get_desc_t vmgetdesc;
vmi_set_desc_t vmsetdesc;
vmi_get_cap_t vmgetcap;
vmi_set_cap_t vmsetcap;
vmi_vlapic_init vlapic_init;
vmi_vlapic_cleanup vlapic_cleanup;
vmi_pause_t vmpause;
vmi_savectx vmsavectx;
vmi_restorectx vmrestorectx;
vmi_get_msr_t vmgetmsr;
vmi_set_msr_t vmsetmsr;
vmi_freqratio_t vmfreqratio;
uint32_t fr_intsize;
uint32_t fr_fracsize;
};
extern struct vmm_ops vmm_ops_intel;
extern struct vmm_ops vmm_ops_amd;
int vm_create(uint64_t flags, struct vm **retvm);
void vm_destroy(struct vm *vm);
int vm_reinit(struct vm *vm, uint64_t);
uint16_t vm_get_maxcpus(struct vm *vm);
void vm_get_topology(struct vm *vm, uint16_t *sockets, uint16_t *cores,
uint16_t *threads, uint16_t *maxcpus);
int vm_set_topology(struct vm *vm, uint16_t sockets, uint16_t cores,
uint16_t threads, uint16_t maxcpus);
int vm_pause_instance(struct vm *);
int vm_resume_instance(struct vm *);
bool vm_is_paused(struct vm *);
int vm_track_dirty_pages(struct vm *, uint64_t, size_t, uint8_t *);
int vm_npt_do_operation(struct vm *, uint64_t, size_t, uint32_t, uint8_t *,
int *);
int vm_mmap_memseg(struct vm *, vm_paddr_t, int, uintptr_t, size_t, int, int);
int vm_munmap_memseg(struct vm *, vm_paddr_t, size_t);
int vm_alloc_memseg(struct vm *vm, int ident, size_t len, bool sysmem);
void vm_free_memseg(struct vm *vm, int ident);
int vm_map_mmio(struct vm *vm, vm_paddr_t gpa, size_t len, vm_paddr_t hpa);
int vm_unmap_mmio(struct vm *vm, vm_paddr_t gpa, size_t len);
int vm_assign_pptdev(struct vm *vm, int pptfd);
int vm_unassign_pptdev(struct vm *vm, int pptfd);
int vm_mmap_getnext(struct vm *, vm_paddr_t *, int *, uintptr_t *, size_t *,
int *, int *);
int vm_get_memseg(struct vm *vm, int ident, size_t *len, bool *sysmem,
struct vm_object **objptr);
vm_paddr_t vmm_sysmem_maxaddr(struct vm *vm);
bool vm_mem_allocated(struct vm *vm, int vcpuid, vm_paddr_t gpa);
int vm_get_register(struct vm *vm, int vcpu, int reg, uint64_t *retval);
int vm_set_register(struct vm *vm, int vcpu, int reg, uint64_t val);
int vm_get_seg_desc(struct vm *vm, int vcpu, int reg,
struct seg_desc *ret_desc);
int vm_set_seg_desc(struct vm *vm, int vcpu, int reg,
const struct seg_desc *desc);
int vm_get_run_state(struct vm *vm, int vcpuid, uint32_t *state,
uint8_t *sipi_vec);
int vm_set_run_state(struct vm *vm, int vcpuid, uint32_t state,
uint8_t sipi_vec);
int vm_get_fpu(struct vm *vm, int vcpuid, void *buf, size_t len);
int vm_set_fpu(struct vm *vm, int vcpuid, void *buf, size_t len);
int vm_run(struct vm *vm, int vcpuid, const struct vm_entry *);
int vm_suspend(struct vm *, enum vm_suspend_how, int);
int vm_inject_nmi(struct vm *vm, int vcpu);
bool vm_nmi_pending(struct vm *vm, int vcpuid);
void vm_nmi_clear(struct vm *vm, int vcpuid);
int vm_inject_extint(struct vm *vm, int vcpu);
bool vm_extint_pending(struct vm *vm, int vcpuid);
void vm_extint_clear(struct vm *vm, int vcpuid);
int vm_inject_init(struct vm *vm, int vcpuid);
int vm_inject_sipi(struct vm *vm, int vcpuid, uint8_t vec);
struct vlapic *vm_lapic(struct vm *vm, int cpu);
struct vioapic *vm_ioapic(struct vm *vm);
struct vhpet *vm_hpet(struct vm *vm);
int vm_get_capability(struct vm *vm, int vcpu, int type, int *val);
int vm_set_capability(struct vm *vm, int vcpu, int type, int val);
int vm_get_x2apic_state(struct vm *vm, int vcpu, enum x2apic_state *state);
int vm_set_x2apic_state(struct vm *vm, int vcpu, enum x2apic_state state);
int vm_apicid2vcpuid(struct vm *vm, int apicid);
int vm_activate_cpu(struct vm *vm, int vcpu);
int vm_suspend_cpu(struct vm *vm, int vcpu);
int vm_resume_cpu(struct vm *vm, int vcpu);
struct vm_exit *vm_exitinfo(struct vm *vm, int vcpuid);
struct vie *vm_vie_ctx(struct vm *vm, int vcpuid);
void vm_exit_suspended(struct vm *vm, int vcpuid, uint64_t rip);
void vm_exit_debug(struct vm *vm, int vcpuid, uint64_t rip);
void vm_exit_astpending(struct vm *vm, int vcpuid, uint64_t rip);
void vm_exit_reqidle(struct vm *vm, int vcpuid, uint64_t rip);
void vm_exit_run_state(struct vm *vm, int vcpuid, uint64_t rip);
int vm_service_mmio_read(struct vm *vm, int cpuid, uint64_t gpa, uint64_t *rval,
int rsize);
int vm_service_mmio_write(struct vm *vm, int cpuid, uint64_t gpa, uint64_t wval,
int wsize);
#ifdef _SYS__CPUSET_H_
cpuset_t vm_active_cpus(struct vm *vm);
cpuset_t vm_debug_cpus(struct vm *vm);
#endif
bool vcpu_entry_bailout_checks(struct vm *vm, int vcpuid, uint64_t rip);
bool vcpu_run_state_pending(struct vm *vm, int vcpuid);
int vcpu_arch_reset(struct vm *vm, int vcpuid, bool init_only);
int vm_vcpu_barrier(struct vm *, int);
bool vmm_is_pptdev(int bus, int slot, int func);
void *vm_iommu_domain(struct vm *vm);
enum vcpu_state {
VCPU_IDLE,
VCPU_FROZEN,
VCPU_RUNNING,
VCPU_SLEEPING,
};
int vcpu_set_state(struct vm *vm, int vcpu, enum vcpu_state state,
bool from_idle);
enum vcpu_state vcpu_get_state(struct vm *vm, int vcpu, int *hostcpu);
void vcpu_block_run(struct vm *, int);
void vcpu_unblock_run(struct vm *, int);
uint64_t vcpu_tsc_offset(struct vm *vm, int vcpuid, bool phys_adj);
hrtime_t vm_normalize_hrtime(struct vm *, hrtime_t);
hrtime_t vm_denormalize_hrtime(struct vm *, hrtime_t);
uint64_t vm_get_freq_multiplier(struct vm *);
static __inline bool
vcpu_is_running(struct vm *vm, int vcpu, int *hostcpu)
{
return (vcpu_get_state(vm, vcpu, hostcpu) == VCPU_RUNNING);
}
#ifdef _SYS_THREAD_H
static __inline int
vcpu_should_yield(struct vm *vm, int vcpu)
{
if (curthread->t_astflag)
return (1);
else if (CPU->cpu_runrun)
return (1);
else
return (0);
}
#endif
typedef enum vcpu_notify {
VCPU_NOTIFY_NONE,
VCPU_NOTIFY_APIC,
VCPU_NOTIFY_EXIT,
} vcpu_notify_t;
void *vcpu_stats(struct vm *vm, int vcpu);
void vcpu_notify_event(struct vm *vm, int vcpuid);
void vcpu_notify_event_type(struct vm *vm, int vcpuid, vcpu_notify_t);
void *vm_get_cookie(struct vm *);
struct vmspace *vm_get_vmspace(struct vm *vm);
struct vm_client *vm_get_vmclient(struct vm *vm, int vcpuid);
struct vatpic *vm_atpic(struct vm *vm);
struct vatpit *vm_atpit(struct vm *vm);
struct vpmtmr *vm_pmtmr(struct vm *vm);
struct vrtc *vm_rtc(struct vm *vm);
int vm_inject_exception(struct vm *vm, int vcpuid, uint8_t vector,
bool err_valid, uint32_t errcode, bool restart_instruction);
int vm_exit_intinfo(struct vm *vm, int vcpuid, uint64_t intinfo);
bool vm_entry_intinfo(struct vm *vm, int vcpuid, uint64_t *info);
int vm_get_intinfo(struct vm *vm, int vcpuid, uint64_t *info1, uint64_t *info2);
enum vm_reg_name vm_segment_name(int seg_encoding);
struct vm_copyinfo {
uint64_t gpa;
size_t len;
int prot;
void *hva;
void *cookie;
};
int vm_copy_setup(struct vm *vm, int vcpuid, struct vm_guest_paging *paging,
uint64_t gla, size_t len, int prot, struct vm_copyinfo *copyinfo,
uint_t num_copyinfo, int *is_fault);
void vm_copy_teardown(struct vm *vm, int vcpuid, struct vm_copyinfo *copyinfo,
uint_t num_copyinfo);
void vm_copyin(struct vm *vm, int vcpuid, struct vm_copyinfo *copyinfo,
void *kaddr, size_t len);
void vm_copyout(struct vm *vm, int vcpuid, const void *kaddr,
struct vm_copyinfo *copyinfo, size_t len);
int vcpu_trace_exceptions(struct vm *vm, int vcpuid);
int vcpu_trap_wbinvd(struct vm *vm, int vcpuid);
void vm_inject_ud(struct vm *vm, int vcpuid);
void vm_inject_gp(struct vm *vm, int vcpuid);
void vm_inject_ac(struct vm *vm, int vcpuid, uint32_t errcode);
void vm_inject_ss(struct vm *vm, int vcpuid, uint32_t errcode);
void vm_inject_pf(struct vm *vm, int vcpuid, uint32_t errcode, uint64_t cr2);
enum event_inject_state {
EIS_CAN_INJECT = 0,
EIS_EV_EXISTING = 1,
EIS_EV_INJECTED = 2,
EIS_GI_BLOCK = 3,
EIS_REQ_EXIT = (1 << 15),
};
typedef enum vm_msr_result {
VMR_OK = 0,
VMR_GP = 1,
VMR_UNHANLDED = 2,
} vm_msr_result_t;
enum vm_cpuid_capability {
VCC_NONE,
VCC_NO_EXECUTE,
VCC_FFXSR,
VCC_TCE,
VCC_LAST
};
typedef struct vcpu_cpuid_config {
uint32_t vcc_flags;
uint32_t vcc_nent;
struct vcpu_cpuid_entry *vcc_entries;
} vcpu_cpuid_config_t;
vcpu_cpuid_config_t *vm_cpuid_config(struct vm *, int);
int vm_get_cpuid(struct vm *, int, vcpu_cpuid_config_t *);
int vm_set_cpuid(struct vm *, int, const vcpu_cpuid_config_t *);
void vcpu_emulate_cpuid(struct vm *, int, uint64_t *, uint64_t *, uint64_t *,
uint64_t *);
void legacy_emulate_cpuid(struct vm *, int, uint32_t *, uint32_t *, uint32_t *,
uint32_t *);
void vcpu_cpuid_init(vcpu_cpuid_config_t *);
void vcpu_cpuid_cleanup(vcpu_cpuid_config_t *);
bool vm_cpuid_capability(struct vm *, int, enum vm_cpuid_capability);
bool validate_guest_xcr0(uint64_t, uint64_t);
void vmm_sol_glue_init(void);
void vmm_sol_glue_cleanup(void);
void *vmm_contig_alloc(size_t);
void vmm_contig_free(void *, size_t);
int vmm_mod_load(void);
void vmm_mod_unload(void);
bool vmm_check_iommu(void);
void vmm_call_trap(uint64_t);
uint64_t vmm_host_tsc_delta(void);
typedef int (*ioport_handler_t)(void *, bool, uint16_t, uint8_t, uint32_t *);
typedef int (*mmio_handler_t)(void *, bool, uint64_t, int, uint64_t *);
int vm_ioport_access(struct vm *vm, int vcpuid, bool in, uint16_t port,
uint8_t bytes, uint32_t *val);
int vm_ioport_attach(struct vm *vm, uint16_t port, ioport_handler_t func,
void *arg, void **cookie);
int vm_ioport_detach(struct vm *vm, void **cookie, ioport_handler_t *old_func,
void **old_arg);
int vm_ioport_hook(struct vm *, uint16_t, ioport_handler_t, void *, void **);
void vm_ioport_unhook(struct vm *, void **);
int vm_mmio_hook(struct vm *, uint64_t, uint32_t, mmio_handler_t, void *,
void **);
int vm_mmio_unhook(struct vm *, void **);
enum vcpu_ustate {
VU_INIT = 0,
VU_RUN,
VU_IDLE,
VU_EMU_KERN,
VU_EMU_USER,
VU_SCHED,
VU_MAX
};
void vcpu_ustate_change(struct vm *, int, enum vcpu_ustate);
typedef struct vmm_kstats {
kstat_named_t vk_name;
} vmm_kstats_t;
typedef struct vmm_vcpu_kstats {
kstat_named_t vvk_vcpu;
kstat_named_t vvk_time_init;
kstat_named_t vvk_time_run;
kstat_named_t vvk_time_idle;
kstat_named_t vvk_time_emu_kern;
kstat_named_t vvk_time_emu_user;
kstat_named_t vvk_time_sched;
} vmm_vcpu_kstats_t;
#define VMM_KSTAT_CLASS "misc"
int vmm_kstat_update_vcpu(struct kstat *, int);
typedef struct vmm_data_req {
uint16_t vdr_class;
uint16_t vdr_version;
uint32_t vdr_flags;
uint32_t vdr_len;
void *vdr_data;
uint32_t *vdr_result_len;
int vdr_vcpuid;
} vmm_data_req_t;
typedef int (*vmm_data_writef_t)(void *, const vmm_data_req_t *);
typedef int (*vmm_data_readf_t)(void *, const vmm_data_req_t *);
typedef int (*vmm_data_vcpu_writef_t)(struct vm *, int, const vmm_data_req_t *);
typedef int (*vmm_data_vcpu_readf_t)(struct vm *, int, const vmm_data_req_t *);
typedef struct vmm_data_version_entry {
uint16_t vdve_class;
uint16_t vdve_version;
uint16_t vdve_len_expect;
uint16_t vdve_len_per_item;
vmm_data_readf_t vdve_readf;
vmm_data_writef_t vdve_writef;
vmm_data_vcpu_readf_t vdve_vcpu_readf;
vmm_data_vcpu_writef_t vdve_vcpu_writef;
bool vdve_vcpu_wildcard;
} vmm_data_version_entry_t;
#define VMM_DATA_VERSION(sym) SET_ENTRY(vmm_data_version_entries, sym)
int vmm_data_read(struct vm *, const vmm_data_req_t *);
int vmm_data_write(struct vm *, const vmm_data_req_t *);
uint64_t vmm_calc_freq_multiplier(uint64_t guest_hz, uint64_t host_hz,
uint32_t frac);
#define VM_TSCM_NOSCALE 0
#endif