vmm.h revision 277149
1135446Strhodes/*- 2262706Serwin * Copyright (c) 2011 NetApp, Inc. 3153816Sdougb * All rights reserved. 4204619Sdougb * 5135446Strhodes * Redistribution and use in source and binary forms, with or without 6135446Strhodes * modification, are permitted provided that the following conditions 7153816Sdougb * are met: 8135446Strhodes * 1. Redistributions of source code must retain the above copyright 9135446Strhodes * notice, this list of conditions and the following disclaimer. 10153816Sdougb * 2. Redistributions in binary form must reproduce the above copyright 11135446Strhodes * notice, this list of conditions and the following disclaimer in the 12135446Strhodes * documentation and/or other materials provided with the distribution. 13135446Strhodes * 14135446Strhodes * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND 15135446Strhodes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16234010Sdougb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17153816Sdougb * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE 18153816Sdougb * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19153816Sdougb * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20153816Sdougb * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21170222Sdougb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22153816Sdougb * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23153816Sdougb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24254897Serwin * SUCH DAMAGE. 25153816Sdougb * 26153816Sdougb * $FreeBSD: head/sys/amd64/include/vmm.h 277149 2015-01-13 22:00:47Z neel $ 27153816Sdougb */ 28153816Sdougb 29153816Sdougb#ifndef _VMM_H_ 30153816Sdougb#define _VMM_H_ 31153816Sdougb 32153816Sdougb#include <x86/segments.h> 33153816Sdougb 34262706Serwinenum vm_suspend_how { 35170222Sdougb VM_SUSPEND_NONE, 36170222Sdougb VM_SUSPEND_RESET, 37170222Sdougb VM_SUSPEND_POWEROFF, 38170222Sdougb VM_SUSPEND_HALT, 39170222Sdougb VM_SUSPEND_TRIPLEFAULT, 40170222Sdougb VM_SUSPEND_LAST 41153816Sdougb}; 42153816Sdougb 43170222Sdougb/* 44153816Sdougb * Identifiers for architecturally defined registers. 45153816Sdougb */ 46170222Sdougbenum vm_reg_name { 47153816Sdougb VM_REG_GUEST_RAX, 48153816Sdougb VM_REG_GUEST_RBX, 49170222Sdougb VM_REG_GUEST_RCX, 50153816Sdougb VM_REG_GUEST_RDX, 51153816Sdougb VM_REG_GUEST_RSI, 52153816Sdougb VM_REG_GUEST_RDI, 53262706Serwin VM_REG_GUEST_RBP, 54153816Sdougb VM_REG_GUEST_R8, 55153816Sdougb VM_REG_GUEST_R9, 56135446Strhodes VM_REG_GUEST_R10, 57153816Sdougb VM_REG_GUEST_R11, 58153816Sdougb VM_REG_GUEST_R12, 59153816Sdougb VM_REG_GUEST_R13, 60262706Serwin VM_REG_GUEST_R14, 61153816Sdougb VM_REG_GUEST_R15, 62153816Sdougb VM_REG_GUEST_CR0, 63153816Sdougb VM_REG_GUEST_CR3, 64153816Sdougb VM_REG_GUEST_CR4, 65153816Sdougb VM_REG_GUEST_DR7, 66153816Sdougb VM_REG_GUEST_RSP, 67153816Sdougb VM_REG_GUEST_RIP, 68153816Sdougb VM_REG_GUEST_RFLAGS, 69262706Serwin VM_REG_GUEST_ES, 70153816Sdougb VM_REG_GUEST_CS, 71153816Sdougb VM_REG_GUEST_SS, 72153816Sdougb VM_REG_GUEST_DS, 73153816Sdougb VM_REG_GUEST_FS, 74153816Sdougb VM_REG_GUEST_GS, 75153816Sdougb VM_REG_GUEST_LDTR, 76153816Sdougb VM_REG_GUEST_TR, 77153816Sdougb VM_REG_GUEST_IDTR, 78262706Serwin VM_REG_GUEST_GDTR, 79153816Sdougb VM_REG_GUEST_EFER, 80170222Sdougb VM_REG_GUEST_CR2, 81153816Sdougb VM_REG_GUEST_PDPTE0, 82153816Sdougb VM_REG_GUEST_PDPTE1, 83170222Sdougb VM_REG_GUEST_PDPTE2, 84170222Sdougb VM_REG_GUEST_PDPTE3, 85153816Sdougb VM_REG_GUEST_INTR_SHADOW, 86153816Sdougb VM_REG_LAST 87153816Sdougb}; 88153816Sdougb 89153816Sdougbenum x2apic_state { 90153816Sdougb X2APIC_DISABLED, 91153816Sdougb X2APIC_ENABLED, 92153816Sdougb X2APIC_STATE_LAST 93153816Sdougb}; 94153816Sdougb 95153816Sdougb#define VM_INTINFO_VECTOR(info) ((info) & 0xff) 96153816Sdougb#define VM_INTINFO_DEL_ERRCODE 0x800 97153816Sdougb#define VM_INTINFO_RSVD 0x7ffff000 98153816Sdougb#define VM_INTINFO_VALID 0x80000000 99153816Sdougb#define VM_INTINFO_TYPE 0x700 100262706Serwin#define VM_INTINFO_HWINTR (0 << 8) 101153816Sdougb#define VM_INTINFO_NMI (2 << 8) 102153816Sdougb#define VM_INTINFO_HWEXCEPTION (3 << 8) 103153816Sdougb#define VM_INTINFO_SWINTR (4 << 8) 104153816Sdougb 105153816Sdougb#ifdef _KERNEL 106153816Sdougb 107153816Sdougb#define VM_MAX_NAMELEN 32 108262706Serwin 109153816Sdougbstruct vm; 110224092Sdougbstruct vm_exception; 111224092Sdougbstruct vm_memory_segment; 112224092Sdougbstruct seg_desc; 113224092Sdougbstruct vm_exit; 114224092Sdougbstruct vm_run; 115224092Sdougbstruct vhpet; 116262706Serwinstruct vioapic; 117224092Sdougbstruct vlapic; 118153816Sdougbstruct vmspace; 119153816Sdougbstruct vm_object; 120153816Sdougbstruct vm_guest_paging; 121153816Sdougbstruct pmap; 122153816Sdougb 123153816Sdougbtypedef int (*vmm_init_func_t)(int ipinum); 124153816Sdougbtypedef int (*vmm_cleanup_func_t)(void); 125153816Sdougbtypedef void (*vmm_resume_func_t)(void); 126153816Sdougbtypedef void * (*vmi_init_func_t)(struct vm *vm, struct pmap *pmap); 127153816Sdougbtypedef int (*vmi_run_func_t)(void *vmi, int vcpu, register_t rip, 128262706Serwin struct pmap *pmap, void *rendezvous_cookie, 129153816Sdougb void *suspend_cookie); 130153816Sdougbtypedef void (*vmi_cleanup_func_t)(void *vmi); 131153816Sdougbtypedef int (*vmi_get_register_t)(void *vmi, int vcpu, int num, 132153816Sdougb uint64_t *retval); 133153816Sdougbtypedef int (*vmi_set_register_t)(void *vmi, int vcpu, int num, 134135446Strhodes uint64_t val); 135135446Strhodestypedef int (*vmi_get_desc_t)(void *vmi, int vcpu, int num, 136153816Sdougb struct seg_desc *desc); 137153816Sdougbtypedef int (*vmi_set_desc_t)(void *vmi, int vcpu, int num, 138153816Sdougb struct seg_desc *desc); 139153816Sdougbtypedef int (*vmi_get_cap_t)(void *vmi, int vcpu, int num, int *retval); 140135446Strhodestypedef int (*vmi_set_cap_t)(void *vmi, int vcpu, int num, int val); 141153816Sdougbtypedef struct vmspace * (*vmi_vmspace_alloc)(vm_offset_t min, vm_offset_t max); 142153816Sdougbtypedef void (*vmi_vmspace_free)(struct vmspace *vmspace); 143153816Sdougbtypedef struct vlapic * (*vmi_vlapic_init)(void *vmi, int vcpu); 144153816Sdougbtypedef void (*vmi_vlapic_cleanup)(void *vmi, struct vlapic *vlapic); 145153816Sdougb 146262706Serwinstruct vmm_ops { 147153816Sdougb vmm_init_func_t init; /* module wide initialization */ 148153816Sdougb vmm_cleanup_func_t cleanup; 149153816Sdougb vmm_resume_func_t resume; 150153816Sdougb 151135446Strhodes vmi_init_func_t vminit; /* vm-specific initialization */ 152153816Sdougb vmi_run_func_t vmrun; 153153816Sdougb vmi_cleanup_func_t vmcleanup; 154153816Sdougb vmi_get_register_t vmgetreg; 155153816Sdougb vmi_set_register_t vmsetreg; 156153816Sdougb vmi_get_desc_t vmgetdesc; 157153816Sdougb vmi_set_desc_t vmsetdesc; 158153816Sdougb vmi_get_cap_t vmgetcap; 159262706Serwin vmi_set_cap_t vmsetcap; 160153816Sdougb vmi_vmspace_alloc vmspace_alloc; 161153816Sdougb vmi_vmspace_free vmspace_free; 162153816Sdougb vmi_vlapic_init vlapic_init; 163153816Sdougb vmi_vlapic_cleanup vlapic_cleanup; 164153816Sdougb}; 165153816Sdougb 166153816Sdougbextern struct vmm_ops vmm_ops_intel; 167153816Sdougbextern struct vmm_ops vmm_ops_amd; 168153816Sdougb 169153816Sdougbint vm_create(const char *name, struct vm **retvm); 170153816Sdougbvoid vm_destroy(struct vm *vm); 171153816Sdougbint vm_reinit(struct vm *vm); 172153816Sdougbconst char *vm_name(struct vm *vm); 173153816Sdougbint vm_malloc(struct vm *vm, vm_paddr_t gpa, size_t len); 174153816Sdougbint vm_map_mmio(struct vm *vm, vm_paddr_t gpa, size_t len, vm_paddr_t hpa); 175153816Sdougbint vm_unmap_mmio(struct vm *vm, vm_paddr_t gpa, size_t len); 176153816Sdougbvoid *vm_gpa_hold(struct vm *, vm_paddr_t gpa, size_t len, int prot, 177153816Sdougb void **cookie); 178153816Sdougbvoid vm_gpa_release(void *cookie); 179153816Sdougbint vm_gpabase2memseg(struct vm *vm, vm_paddr_t gpabase, 180153816Sdougb struct vm_memory_segment *seg); 181153816Sdougbint vm_get_memobj(struct vm *vm, vm_paddr_t gpa, size_t len, 182153816Sdougb vm_offset_t *offset, struct vm_object **object); 183186462Sdougbboolean_t vm_mem_allocated(struct vm *vm, vm_paddr_t gpa); 184153816Sdougbint vm_get_register(struct vm *vm, int vcpu, int reg, uint64_t *retval); 185153816Sdougbint vm_set_register(struct vm *vm, int vcpu, int reg, uint64_t val); 186153816Sdougbint vm_get_seg_desc(struct vm *vm, int vcpu, int reg, 187262706Serwin struct seg_desc *ret_desc); 188153816Sdougbint vm_set_seg_desc(struct vm *vm, int vcpu, int reg, 189153816Sdougb struct seg_desc *desc); 190153816Sdougbint vm_run(struct vm *vm, struct vm_run *vmrun); 191153816Sdougbint vm_suspend(struct vm *vm, enum vm_suspend_how how); 192153816Sdougbint vm_inject_nmi(struct vm *vm, int vcpu); 193153816Sdougbint vm_nmi_pending(struct vm *vm, int vcpuid); 194153816Sdougbvoid vm_nmi_clear(struct vm *vm, int vcpuid); 195224092Sdougbint vm_inject_extint(struct vm *vm, int vcpu); 196153816Sdougbint vm_extint_pending(struct vm *vm, int vcpuid); 197153816Sdougbvoid vm_extint_clear(struct vm *vm, int vcpuid); 198153816Sdougbstruct vlapic *vm_lapic(struct vm *vm, int cpu); 199153816Sdougbstruct vioapic *vm_ioapic(struct vm *vm); 200153816Sdougbstruct vhpet *vm_hpet(struct vm *vm); 201153816Sdougbint vm_get_capability(struct vm *vm, int vcpu, int type, int *val); 202153816Sdougbint vm_set_capability(struct vm *vm, int vcpu, int type, int val); 203193149Sdougbint vm_get_x2apic_state(struct vm *vm, int vcpu, enum x2apic_state *state); 204153816Sdougbint vm_set_x2apic_state(struct vm *vm, int vcpu, enum x2apic_state state); 205153816Sdougbint vm_apicid2vcpuid(struct vm *vm, int apicid); 206153816Sdougbint vm_activate_cpu(struct vm *vm, int vcpu); 207153816Sdougbcpuset_t vm_active_cpus(struct vm *vm); 208153816Sdougbcpuset_t vm_suspended_cpus(struct vm *vm); 209153816Sdougbstruct vm_exit *vm_exitinfo(struct vm *vm, int vcpuid); 210153816Sdougbvoid vm_exit_suspended(struct vm *vm, int vcpuid, uint64_t rip); 211153816Sdougbvoid vm_exit_rendezvous(struct vm *vm, int vcpuid, uint64_t rip); 212135446Strhodesvoid vm_exit_astpending(struct vm *vm, int vcpuid, uint64_t rip); 213153816Sdougb 214153816Sdougb/* 215153816Sdougb * Rendezvous all vcpus specified in 'dest' and execute 'func(arg)'. 216153816Sdougb * The rendezvous 'func(arg)' is not allowed to do anything that will 217153816Sdougb * cause the thread to be put to sleep. 218170222Sdougb * 219170222Sdougb * If the rendezvous is being initiated from a vcpu context then the 220193149Sdougb * 'vcpuid' must refer to that vcpu, otherwise it should be set to -1. 221193149Sdougb * 222193149Sdougb * The caller cannot hold any locks when initiating the rendezvous. 223153816Sdougb * 224224092Sdougb * The implementation of this API may cause vcpus other than those specified 225153816Sdougb * by 'dest' to be stalled. The caller should not rely on any vcpus making 226153816Sdougb * forward progress when the rendezvous is in progress. 227153816Sdougb */ 228153816Sdougbtypedef void (*vm_rendezvous_func_t)(struct vm *vm, int vcpuid, void *arg); 229153816Sdougbvoid vm_smp_rendezvous(struct vm *vm, int vcpuid, cpuset_t dest, 230193149Sdougb vm_rendezvous_func_t func, void *arg); 231193149Sdougb 232170222Sdougbstatic __inline int 233170222Sdougbvcpu_rendezvous_pending(void *rendezvous_cookie) 234153816Sdougb{ 235153816Sdougb 236170222Sdougb return (*(uintptr_t *)rendezvous_cookie != 0); 237170222Sdougb} 238170222Sdougb 239170222Sdougbstatic __inline int 240170222Sdougbvcpu_suspended(void *suspend_cookie) 241153816Sdougb{ 242153816Sdougb 243153816Sdougb return (*(int *)suspend_cookie); 244153816Sdougb} 245153816Sdougb 246153816Sdougb/* 247170222Sdougb * Return 1 if device indicated by bus/slot/func is supposed to be a 248153816Sdougb * pci passthrough device. 249170222Sdougb * 250153816Sdougb * Return 0 otherwise. 251153816Sdougb */ 252153816Sdougbint vmm_is_pptdev(int bus, int slot, int func); 253170222Sdougb 254234010Sdougbvoid *vm_iommu_domain(struct vm *vm); 255153816Sdougb 256170222Sdougbenum vcpu_state { 257135446Strhodes VCPU_IDLE, 258224092Sdougb VCPU_FROZEN, 259224092Sdougb VCPU_RUNNING, 260224092Sdougb VCPU_SLEEPING, 261224092Sdougb}; 262224092Sdougb 263224092Sdougbint vcpu_set_state(struct vm *vm, int vcpu, enum vcpu_state state, 264224092Sdougb bool from_idle); 265224092Sdougbenum vcpu_state vcpu_get_state(struct vm *vm, int vcpu, int *hostcpu); 266224092Sdougb 267224092Sdougbstatic int __inline 268224092Sdougbvcpu_is_running(struct vm *vm, int vcpu, int *hostcpu) 269170222Sdougb{ 270170222Sdougb return (vcpu_get_state(vm, vcpu, hostcpu) == VCPU_RUNNING); 271170222Sdougb} 272170222Sdougb 273170222Sdougb#ifdef _SYS_PROC_H_ 274153816Sdougbstatic int __inline 275153816Sdougbvcpu_should_yield(struct vm *vm, int vcpu) 276135446Strhodes{ 277153816Sdougb return (curthread->td_flags & (TDF_ASTPENDING | TDF_NEEDRESCHED)); 278193149Sdougb} 279170222Sdougb#endif 280193149Sdougb 281153816Sdougbvoid *vcpu_stats(struct vm *vm, int vcpu); 282170222Sdougbvoid vcpu_notify_event(struct vm *vm, int vcpuid, bool lapic_intr); 283153816Sdougbstruct vmspace *vm_get_vmspace(struct vm *vm); 284170222Sdougbint vm_assign_pptdev(struct vm *vm, int bus, int slot, int func); 285224092Sdougbint vm_unassign_pptdev(struct vm *vm, int bus, int slot, int func); 286135446Strhodesstruct vatpic *vm_atpic(struct vm *vm); 287174187Sdougbstruct vatpit *vm_atpit(struct vm *vm); 288153816Sdougbstruct vpmtmr *vm_pmtmr(struct vm *vm); 289153816Sdougbstruct vrtc *vm_rtc(struct vm *vm); 290153816Sdougb 291170222Sdougb/* 292193149Sdougb * Inject exception 'vector' into the guest vcpu. This function returns 0 on 293153816Sdougb * success and non-zero on failure. 294254897Serwin * 295254897Serwin * Wrapper functions like 'vm_inject_gp()' should be preferred to calling 296153816Sdougb * this function directly because they enforce the trap-like or fault-like 297135446Strhodes * behavior of an exception. 298153816Sdougb * 299153816Sdougb * This function should only be called in the context of the thread that is 300153816Sdougb * executing this vcpu. 301135446Strhodes */ 302135446Strhodesint vm_inject_exception(struct vm *vm, int vcpuid, int vector, int err_valid, 303153816Sdougb uint32_t errcode, int restart_instruction); 304153816Sdougb 305153816Sdougb/* 306153816Sdougb * This function is called after a VM-exit that occurred during exception or 307153816Sdougb * interrupt delivery through the IDT. The format of 'intinfo' is described 308153816Sdougb * in Figure 15-1, "EXITINTINFO for All Intercepts", APM, Vol 2. 309153816Sdougb * 310153816Sdougb * If a VM-exit handler completes the event delivery successfully then it 311153816Sdougb * should call vm_exit_intinfo() to extinguish the pending event. For e.g., 312153816Sdougb * if the task switch emulation is triggered via a task gate then it should 313193149Sdougb * call this function with 'intinfo=0' to indicate that the external event 314153816Sdougb * is not pending anymore. 315193149Sdougb * 316193149Sdougb * Return value is 0 on success and non-zero on failure. 317193149Sdougb */ 318193149Sdougbint vm_exit_intinfo(struct vm *vm, int vcpuid, uint64_t intinfo); 319135446Strhodes 320153816Sdougb/* 321153816Sdougb * This function is called before every VM-entry to retrieve a pending 322153816Sdougb * event that should be injected into the guest. This function combines 323153816Sdougb * nested events into a double or triple fault. 324135446Strhodes * 325153816Sdougb * Returns 0 if there are no events that need to be injected into the guest 326153816Sdougb * and non-zero otherwise. 327153816Sdougb */ 328153816Sdougbint vm_entry_intinfo(struct vm *vm, int vcpuid, uint64_t *info); 329153816Sdougb 330135446Strhodesint vm_get_intinfo(struct vm *vm, int vcpuid, uint64_t *info1, uint64_t *info2); 331153816Sdougb 332153816Sdougbenum vm_reg_name vm_segment_name(int seg_encoding); 333224092Sdougb 334262706Serwinstruct vm_copyinfo { 335193149Sdougb uint64_t gpa; 336170222Sdougb size_t len; 337170222Sdougb void *hva; 338224092Sdougb void *cookie; 339224092Sdougb}; 340224092Sdougb 341224092Sdougb/* 342224092Sdougb * Set up 'copyinfo[]' to copy to/from guest linear address space starting 343224092Sdougb * at 'gla' and 'len' bytes long. The 'prot' should be set to PROT_READ for 344224092Sdougb * a copyin or PROT_WRITE for a copyout. 345135446Strhodes * 346193149Sdougb * Returns 0 on success. 347193149Sdougb * Returns 1 if an exception was injected into the guest. 348153816Sdougb * Returns -1 otherwise. 349153816Sdougb * 350153816Sdougb * The 'copyinfo[]' can be passed to 'vm_copyin()' or 'vm_copyout()' only if 351153816Sdougb * the return value is 0. The 'copyinfo[]' resources should be freed by calling 352153816Sdougb * 'vm_copy_teardown()' after the copy is done. 353153816Sdougb */ 354153816Sdougbint vm_copy_setup(struct vm *vm, int vcpuid, struct vm_guest_paging *paging, 355153816Sdougb uint64_t gla, size_t len, int prot, struct vm_copyinfo *copyinfo, 356153816Sdougb int num_copyinfo); 357153816Sdougbvoid vm_copy_teardown(struct vm *vm, int vcpuid, struct vm_copyinfo *copyinfo, 358153816Sdougb int num_copyinfo); 359153816Sdougbvoid vm_copyin(struct vm *vm, int vcpuid, struct vm_copyinfo *copyinfo, 360153816Sdougb void *kaddr, size_t len); 361153816Sdougbvoid vm_copyout(struct vm *vm, int vcpuid, const void *kaddr, 362153816Sdougb struct vm_copyinfo *copyinfo, size_t len); 363153816Sdougb 364262706Serwinint vcpu_trace_exceptions(struct vm *vm, int vcpuid); 365153816Sdougb#endif /* KERNEL */ 366153816Sdougb 367153816Sdougb#define VM_MAXCPU 16 /* maximum virtual cpus */ 368153816Sdougb 369153816Sdougb/* 370135446Strhodes * Identifiers for optional vmm capabilities 371153816Sdougb */ 372153816Sdougbenum vm_cap_type { 373153816Sdougb VM_CAP_HALT_EXIT, 374135446Strhodes VM_CAP_MTRAP_EXIT, 375135446Strhodes VM_CAP_PAUSE_EXIT, 376153816Sdougb VM_CAP_UNRESTRICTED_GUEST, 377135446Strhodes VM_CAP_ENABLE_INVPCID, 378135446Strhodes VM_CAP_MAX 379135446Strhodes}; 380170222Sdougb 381135446Strhodesenum vm_intr_trigger { 382135446Strhodes EDGE_TRIGGER, 383135446Strhodes LEVEL_TRIGGER 384153816Sdougb}; 385224092Sdougb 386224092Sdougb/* 387135446Strhodes * The 'access' field has the format specified in Table 21-2 of the Intel 388135446Strhodes * Architecture Manual vol 3b. 389153816Sdougb * 390193149Sdougb * XXX The contents of the 'access' field are architecturally defined except 391153816Sdougb * bit 16 - Segment Unusable. 392153816Sdougb */ 393153816Sdougbstruct seg_desc { 394153816Sdougb uint64_t base; 395153816Sdougb uint32_t limit; 396153816Sdougb uint32_t access; 397153816Sdougb}; 398153816Sdougb#define SEG_DESC_TYPE(access) ((access) & 0x001f) 399135446Strhodes#define SEG_DESC_DPL(access) (((access) >> 5) & 0x3) 400153816Sdougb#define SEG_DESC_PRESENT(access) (((access) & 0x0080) ? 1 : 0) 401153816Sdougb#define SEG_DESC_DEF32(access) (((access) & 0x4000) ? 1 : 0) 402153816Sdougb#define SEG_DESC_GRANULARITY(access) (((access) & 0x8000) ? 1 : 0) 403153816Sdougb#define SEG_DESC_UNUSABLE(access) (((access) & 0x10000) ? 1 : 0) 404153816Sdougb 405170222Sdougbenum vm_cpu_mode { 406170222Sdougb CPU_MODE_REAL, 407193149Sdougb CPU_MODE_PROTECTED, 408193149Sdougb CPU_MODE_COMPATIBILITY, /* IA-32E mode (CS.L = 0) */ 409193149Sdougb CPU_MODE_64BIT, /* IA-32E mode (CS.L = 1) */ 410153816Sdougb}; 411224092Sdougb 412153816Sdougbenum vm_paging_mode { 413153816Sdougb PAGING_MODE_FLAT, 414153816Sdougb PAGING_MODE_32, 415153816Sdougb PAGING_MODE_PAE, 416153816Sdougb PAGING_MODE_64, 417193149Sdougb}; 418193149Sdougb 419170222Sdougbstruct vm_guest_paging { 420170222Sdougb uint64_t cr3; 421153816Sdougb int cpl; 422153816Sdougb enum vm_cpu_mode cpu_mode; 423170222Sdougb enum vm_paging_mode paging_mode; 424170222Sdougb}; 425170222Sdougb 426170222Sdougb/* 427170222Sdougb * The data structures 'vie' and 'vie_op' are meant to be opaque to the 428153816Sdougb * consumers of instruction decoding. The only reason why their contents 429153816Sdougb * need to be exposed is because they are part of the 'vm_exit' structure. 430153816Sdougb */ 431153816Sdougbstruct vie_op { 432153816Sdougb uint8_t op_byte; /* actual opcode byte */ 433153816Sdougb uint8_t op_type; /* type of operation (e.g. MOV) */ 434135446Strhodes uint16_t op_flags; 435153816Sdougb}; 436170222Sdougb 437153816Sdougb#define VIE_INST_SIZE 15 438153816Sdougbstruct vie { 439153816Sdougb uint8_t inst[VIE_INST_SIZE]; /* instruction bytes */ 440170222Sdougb uint8_t num_valid; /* size of the instruction */ 441234010Sdougb uint8_t num_processed; 442170222Sdougb 443170222Sdougb uint8_t addrsize:4, opsize:4; /* address and operand sizes */ 444135446Strhodes uint8_t rex_w:1, /* REX prefix */ 445224092Sdougb rex_r:1, 446224092Sdougb rex_x:1, 447224092Sdougb rex_b:1, 448224092Sdougb rex_present:1, 449224092Sdougb opsize_override:1, /* Operand size override */ 450224092Sdougb addrsize_override:1; /* Address size override */ 451224092Sdougb 452224092Sdougb uint8_t mod:2, /* ModRM byte */ 453224092Sdougb reg:4, 454224092Sdougb rm:4; 455224092Sdougb 456170222Sdougb uint8_t ss:2, /* SIB byte */ 457170222Sdougb index:4, 458170222Sdougb base:4; 459170222Sdougb 460170222Sdougb uint8_t disp_bytes; 461153816Sdougb uint8_t imm_bytes; 462153816Sdougb 463135446Strhodes uint8_t scale; 464153816Sdougb int base_register; /* VM_REG_GUEST_xyz */ 465193149Sdougb int index_register; /* VM_REG_GUEST_xyz */ 466170222Sdougb 467193149Sdougb int64_t displacement; /* optional addr displacement */ 468153816Sdougb int64_t immediate; /* optional immediate operand */ 469170222Sdougb 470153816Sdougb uint8_t decoded; /* set to 1 if successfully decoded */ 471170222Sdougb 472224092Sdougb struct vie_op op; /* opcode description */ 473135446Strhodes}; 474174187Sdougb 475153816Sdougbenum vm_exitcode { 476153816Sdougb VM_EXITCODE_INOUT, 477153816Sdougb VM_EXITCODE_VMX, 478170222Sdougb VM_EXITCODE_BOGUS, 479193149Sdougb VM_EXITCODE_RDMSR, 480153816Sdougb VM_EXITCODE_WRMSR, 481254897Serwin VM_EXITCODE_HLT, 482254897Serwin VM_EXITCODE_MTRAP, 483153816Sdougb VM_EXITCODE_PAUSE, 484135446Strhodes VM_EXITCODE_PAGING, 485153816Sdougb VM_EXITCODE_INST_EMUL, 486153816Sdougb VM_EXITCODE_SPINUP_AP, 487153816Sdougb VM_EXITCODE_DEPRECATED1, /* used to be SPINDOWN_CPU */ 488135446Strhodes VM_EXITCODE_RENDEZVOUS, 489135446Strhodes VM_EXITCODE_IOAPIC_EOI, 490153816Sdougb VM_EXITCODE_SUSPENDED, 491153816Sdougb VM_EXITCODE_INOUT_STR, 492153816Sdougb VM_EXITCODE_TASK_SWITCH, 493153816Sdougb VM_EXITCODE_MONITOR, 494153816Sdougb VM_EXITCODE_MWAIT, 495153816Sdougb VM_EXITCODE_SVM, 496153816Sdougb VM_EXITCODE_MAX 497153816Sdougb}; 498153816Sdougb 499153816Sdougbstruct vm_inout { 500153816Sdougb uint16_t bytes:3; /* 1 or 2 or 4 */ 501135446Strhodes uint16_t in:1; 502153816Sdougb uint16_t string:1; 503153816Sdougb uint16_t rep:1; 504153816Sdougb uint16_t port; 505153816Sdougb uint32_t eax; /* valid for out */ 506135446Strhodes}; 507153816Sdougb 508153816Sdougbstruct vm_inout_str { 509153816Sdougb struct vm_inout inout; /* must be the first element */ 510153816Sdougb struct vm_guest_paging paging; 511153816Sdougb uint64_t rflags; 512135446Strhodes uint64_t cr0; 513153816Sdougb uint64_t index; 514193149Sdougb uint64_t count; /* rep=1 (%rcx), rep=0 (1) */ 515153816Sdougb int addrsize; 516170222Sdougb enum vm_reg_name seg_name; 517170222Sdougb struct seg_desc seg_desc; 518224092Sdougb}; 519135446Strhodes 520153816Sdougbenum task_switch_reason { 521153816Sdougb TSR_CALL, 522153816Sdougb TSR_IRET, 523153816Sdougb TSR_JMP, 524153816Sdougb TSR_IDT_GATE, /* task gate in IDT */ 525153816Sdougb}; 526153816Sdougb 527153816Sdougbstruct vm_task_switch { 528262706Serwin uint16_t tsssel; /* new TSS selector */ 529153816Sdougb int ext; /* task switch due to external event */ 530153816Sdougb uint32_t errcode; 531254897Serwin int errcode_valid; /* push 'errcode' on the new stack */ 532153816Sdougb enum task_switch_reason reason; 533153816Sdougb struct vm_guest_paging paging; 534135446Strhodes}; 535153816Sdougb 536153816Sdougbstruct vm_exit { 537153816Sdougb enum vm_exitcode exitcode; 538153816Sdougb int inst_length; /* 0 means unknown */ 539135446Strhodes uint64_t rip; 540135446Strhodes union { 541153816Sdougb struct vm_inout inout; 542153816Sdougb struct vm_inout_str inout_str; 543153816Sdougb struct { 544170222Sdougb uint64_t gpa; 545170222Sdougb int fault_type; 546170222Sdougb } paging; 547170222Sdougb struct { 548153816Sdougb uint64_t gpa; 549153816Sdougb uint64_t gla; 550170222Sdougb int cs_d; /* CS.D */ 551170222Sdougb struct vm_guest_paging paging; 552224092Sdougb struct vie vie; 553135446Strhodes } inst_emul; 554153816Sdougb /* 555193149Sdougb * VMX specific payload. Used when there is no "better" 556153816Sdougb * exitcode to represent the VM-exit. 557153816Sdougb */ 558153816Sdougb struct { 559224092Sdougb int status; /* vmx inst status */ 560153816Sdougb /* 561193149Sdougb * 'exit_reason' and 'exit_qualification' are valid 562193149Sdougb * only if 'status' is zero. 563224092Sdougb */ 564224092Sdougb uint32_t exit_reason; 565224092Sdougb uint64_t exit_qualification; 566224092Sdougb /* 567170222Sdougb * 'inst_error' and 'inst_type' are valid 568224092Sdougb * only if 'status' is non-zero. 569135446Strhodes */ 570174187Sdougb int inst_type; 571153816Sdougb int inst_error; 572153816Sdougb } vmx; 573153816Sdougb /* 574170222Sdougb * SVM specific payload. 575193149Sdougb */ 576153816Sdougb struct { 577254897Serwin uint64_t exitcode; 578254897Serwin uint64_t exitinfo1; 579153816Sdougb uint64_t exitinfo2; 580135446Strhodes } svm; 581153816Sdougb struct { 582153816Sdougb uint32_t code; /* ecx value */ 583153816Sdougb uint64_t wval; 584135446Strhodes } msr; 585135446Strhodes struct { 586153816Sdougb int vcpu; 587153816Sdougb uint64_t rip; 588153816Sdougb } spinup_ap; 589153816Sdougb struct { 590153816Sdougb uint64_t rflags; 591153816Sdougb } hlt; 592153816Sdougb struct { 593153816Sdougb int vector; 594153816Sdougb } ioapic_eoi; 595153816Sdougb struct { 596254897Serwin enum vm_suspend_how how; 597153816Sdougb } suspended; 598135446Strhodes struct vm_task_switch task_switch; 599153816Sdougb } u; 600153816Sdougb}; 601153816Sdougb 602153816Sdougb/* APIs to inject faults into the guest */ 603135446Strhodesvoid vm_inject_fault(void *vm, int vcpuid, int vector, int errcode_valid, 604153816Sdougb int errcode); 605153816Sdougb 606153816Sdougbstatic __inline void 607153816Sdougbvm_inject_ud(void *vm, int vcpuid) 608153816Sdougb{ 609135446Strhodes vm_inject_fault(vm, vcpuid, IDT_UD, 0, 0); 610153816Sdougb} 611193149Sdougb 612153816Sdougbstatic __inline void 613135446Strhodesvm_inject_gp(void *vm, int vcpuid) 614193149Sdougb{ 615193149Sdougb vm_inject_fault(vm, vcpuid, IDT_GP, 1, 0); 616153816Sdougb} 617153816Sdougb 618153816Sdougbstatic __inline void 619153816Sdougbvm_inject_ac(void *vm, int vcpuid, int errcode) 620153816Sdougb{ 621153816Sdougb vm_inject_fault(vm, vcpuid, IDT_AC, 1, errcode); 622153816Sdougb} 623153816Sdougb 624153816Sdougbstatic __inline void 625262706Serwinvm_inject_ss(void *vm, int vcpuid, int errcode) 626170222Sdougb{ 627170222Sdougb vm_inject_fault(vm, vcpuid, IDT_SS, 1, errcode); 628153816Sdougb} 629153816Sdougb 630262706Serwinvoid vm_inject_pf(void *vm, int vcpuid, int error_code, uint64_t cr2); 631170222Sdougb 632174187Sdougbint vm_restart_instruction(void *vm, int vcpuid); 633170222Sdougb 634174187Sdougb#endif /* _VMM_H_ */ 635170222Sdougb