vmm.h revision 283657
1221828Sgrehan/*- 2221828Sgrehan * Copyright (c) 2011 NetApp, Inc. 3221828Sgrehan * All rights reserved. 4221828Sgrehan * 5221828Sgrehan * Redistribution and use in source and binary forms, with or without 6221828Sgrehan * modification, are permitted provided that the following conditions 7221828Sgrehan * are met: 8221828Sgrehan * 1. Redistributions of source code must retain the above copyright 9221828Sgrehan * notice, this list of conditions and the following disclaimer. 10221828Sgrehan * 2. Redistributions in binary form must reproduce the above copyright 11221828Sgrehan * notice, this list of conditions and the following disclaimer in the 12221828Sgrehan * documentation and/or other materials provided with the distribution. 13221828Sgrehan * 14221828Sgrehan * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND 15221828Sgrehan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16221828Sgrehan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17221828Sgrehan * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE 18221828Sgrehan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19221828Sgrehan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20221828Sgrehan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21221828Sgrehan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22221828Sgrehan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23221828Sgrehan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24221828Sgrehan * SUCH DAMAGE. 25221828Sgrehan * 26245678Sneel * $FreeBSD: head/sys/amd64/include/vmm.h 283657 2015-05-28 17:37:01Z neel $ 27221828Sgrehan */ 28221828Sgrehan 29221828Sgrehan#ifndef _VMM_H_ 30221828Sgrehan#define _VMM_H_ 31221828Sgrehan 32269042Sneel#include <x86/segments.h> 33269042Sneel 34265062Sneelenum vm_suspend_how { 35265062Sneel VM_SUSPEND_NONE, 36265062Sneel VM_SUSPEND_RESET, 37265062Sneel VM_SUSPEND_POWEROFF, 38265203Sneel VM_SUSPEND_HALT, 39268889Sneel VM_SUSPEND_TRIPLEFAULT, 40265062Sneel VM_SUSPEND_LAST 41265062Sneel}; 42265062Sneel 43267338Stychon/* 44267338Stychon * Identifiers for architecturally defined registers. 45267338Stychon */ 46267338Stychonenum vm_reg_name { 47267338Stychon VM_REG_GUEST_RAX, 48267338Stychon VM_REG_GUEST_RBX, 49267338Stychon VM_REG_GUEST_RCX, 50267338Stychon VM_REG_GUEST_RDX, 51267338Stychon VM_REG_GUEST_RSI, 52267338Stychon VM_REG_GUEST_RDI, 53267338Stychon VM_REG_GUEST_RBP, 54267338Stychon VM_REG_GUEST_R8, 55267338Stychon VM_REG_GUEST_R9, 56267338Stychon VM_REG_GUEST_R10, 57267338Stychon VM_REG_GUEST_R11, 58267338Stychon VM_REG_GUEST_R12, 59267338Stychon VM_REG_GUEST_R13, 60267338Stychon VM_REG_GUEST_R14, 61267338Stychon VM_REG_GUEST_R15, 62267338Stychon VM_REG_GUEST_CR0, 63267338Stychon VM_REG_GUEST_CR3, 64267338Stychon VM_REG_GUEST_CR4, 65267338Stychon VM_REG_GUEST_DR7, 66267338Stychon VM_REG_GUEST_RSP, 67267338Stychon VM_REG_GUEST_RIP, 68267338Stychon VM_REG_GUEST_RFLAGS, 69267338Stychon VM_REG_GUEST_ES, 70267338Stychon VM_REG_GUEST_CS, 71267338Stychon VM_REG_GUEST_SS, 72267338Stychon VM_REG_GUEST_DS, 73267338Stychon VM_REG_GUEST_FS, 74267338Stychon VM_REG_GUEST_GS, 75267338Stychon VM_REG_GUEST_LDTR, 76267338Stychon VM_REG_GUEST_TR, 77267338Stychon VM_REG_GUEST_IDTR, 78267338Stychon VM_REG_GUEST_GDTR, 79267338Stychon VM_REG_GUEST_EFER, 80267338Stychon VM_REG_GUEST_CR2, 81268777Sneel VM_REG_GUEST_PDPTE0, 82268777Sneel VM_REG_GUEST_PDPTE1, 83268777Sneel VM_REG_GUEST_PDPTE2, 84268777Sneel VM_REG_GUEST_PDPTE3, 85271451Sneel VM_REG_GUEST_INTR_SHADOW, 86267338Stychon VM_REG_LAST 87267338Stychon}; 88267338Stychon 89267338Stychonenum x2apic_state { 90267338Stychon X2APIC_DISABLED, 91267338Stychon X2APIC_ENABLED, 92267338Stychon X2APIC_STATE_LAST 93267338Stychon}; 94267338Stychon 95268889Sneel#define VM_INTINFO_VECTOR(info) ((info) & 0xff) 96268889Sneel#define VM_INTINFO_DEL_ERRCODE 0x800 97268889Sneel#define VM_INTINFO_RSVD 0x7ffff000 98268889Sneel#define VM_INTINFO_VALID 0x80000000 99268889Sneel#define VM_INTINFO_TYPE 0x700 100268889Sneel#define VM_INTINFO_HWINTR (0 << 8) 101268889Sneel#define VM_INTINFO_NMI (2 << 8) 102268889Sneel#define VM_INTINFO_HWEXCEPTION (3 << 8) 103268889Sneel#define VM_INTINFO_SWINTR (4 << 8) 104268889Sneel 105221828Sgrehan#ifdef _KERNEL 106221828Sgrehan 107221828Sgrehan#define VM_MAX_NAMELEN 32 108221828Sgrehan 109221828Sgrehanstruct vm; 110262506Sneelstruct vm_exception; 111221828Sgrehanstruct vm_memory_segment; 112221828Sgrehanstruct seg_desc; 113221828Sgrehanstruct vm_exit; 114221828Sgrehanstruct vm_run; 115258579Sneelstruct vhpet; 116258075Sneelstruct vioapic; 117221828Sgrehanstruct vlapic; 118256072Sneelstruct vmspace; 119256072Sneelstruct vm_object; 120269008Sneelstruct vm_guest_paging; 121256072Sneelstruct pmap; 122221828Sgrehan 123283657Sneelstruct vm_eventinfo { 124283657Sneel void *rptr; /* rendezvous cookie */ 125283657Sneel int *sptr; /* suspend cookie */ 126283657Sneel int *iptr; /* reqidle cookie */ 127283657Sneel}; 128283657Sneel 129260466Sneeltypedef int (*vmm_init_func_t)(int ipinum); 130221828Sgrehantypedef int (*vmm_cleanup_func_t)(void); 131259782Sjhbtypedef void (*vmm_resume_func_t)(void); 132256072Sneeltypedef void * (*vmi_init_func_t)(struct vm *vm, struct pmap *pmap); 133256072Sneeltypedef int (*vmi_run_func_t)(void *vmi, int vcpu, register_t rip, 134283657Sneel struct pmap *pmap, struct vm_eventinfo *info); 135221828Sgrehantypedef void (*vmi_cleanup_func_t)(void *vmi); 136221828Sgrehantypedef int (*vmi_get_register_t)(void *vmi, int vcpu, int num, 137221828Sgrehan uint64_t *retval); 138221828Sgrehantypedef int (*vmi_set_register_t)(void *vmi, int vcpu, int num, 139221828Sgrehan uint64_t val); 140221828Sgrehantypedef int (*vmi_get_desc_t)(void *vmi, int vcpu, int num, 141221828Sgrehan struct seg_desc *desc); 142221828Sgrehantypedef int (*vmi_set_desc_t)(void *vmi, int vcpu, int num, 143221828Sgrehan struct seg_desc *desc); 144221828Sgrehantypedef int (*vmi_get_cap_t)(void *vmi, int vcpu, int num, int *retval); 145221828Sgrehantypedef int (*vmi_set_cap_t)(void *vmi, int vcpu, int num, int val); 146256072Sneeltypedef struct vmspace * (*vmi_vmspace_alloc)(vm_offset_t min, vm_offset_t max); 147256072Sneeltypedef void (*vmi_vmspace_free)(struct vmspace *vmspace); 148259863Sneeltypedef struct vlapic * (*vmi_vlapic_init)(void *vmi, int vcpu); 149259863Sneeltypedef void (*vmi_vlapic_cleanup)(void *vmi, struct vlapic *vlapic); 150221828Sgrehan 151221828Sgrehanstruct vmm_ops { 152221828Sgrehan vmm_init_func_t init; /* module wide initialization */ 153221828Sgrehan vmm_cleanup_func_t cleanup; 154259782Sjhb vmm_resume_func_t resume; 155221828Sgrehan 156221828Sgrehan vmi_init_func_t vminit; /* vm-specific initialization */ 157221828Sgrehan vmi_run_func_t vmrun; 158221828Sgrehan vmi_cleanup_func_t vmcleanup; 159221828Sgrehan vmi_get_register_t vmgetreg; 160221828Sgrehan vmi_set_register_t vmsetreg; 161221828Sgrehan vmi_get_desc_t vmgetdesc; 162221828Sgrehan vmi_set_desc_t vmsetdesc; 163221828Sgrehan vmi_get_cap_t vmgetcap; 164221828Sgrehan vmi_set_cap_t vmsetcap; 165256072Sneel vmi_vmspace_alloc vmspace_alloc; 166256072Sneel vmi_vmspace_free vmspace_free; 167259863Sneel vmi_vlapic_init vlapic_init; 168259863Sneel vmi_vlapic_cleanup vlapic_cleanup; 169221828Sgrehan}; 170221828Sgrehan 171221828Sgrehanextern struct vmm_ops vmm_ops_intel; 172221828Sgrehanextern struct vmm_ops vmm_ops_amd; 173221828Sgrehan 174249396Sneelint vm_create(const char *name, struct vm **retvm); 175221828Sgrehanvoid vm_destroy(struct vm *vm); 176267216Sneelint vm_reinit(struct vm *vm); 177221828Sgrehanconst char *vm_name(struct vm *vm); 178241041Sneelint vm_malloc(struct vm *vm, vm_paddr_t gpa, size_t len); 179221828Sgrehanint vm_map_mmio(struct vm *vm, vm_paddr_t gpa, size_t len, vm_paddr_t hpa); 180221828Sgrehanint vm_unmap_mmio(struct vm *vm, vm_paddr_t gpa, size_t len); 181256072Sneelvoid *vm_gpa_hold(struct vm *, vm_paddr_t gpa, size_t len, int prot, 182256072Sneel void **cookie); 183256072Sneelvoid vm_gpa_release(void *cookie); 184221828Sgrehanint vm_gpabase2memseg(struct vm *vm, vm_paddr_t gpabase, 185221828Sgrehan struct vm_memory_segment *seg); 186256072Sneelint vm_get_memobj(struct vm *vm, vm_paddr_t gpa, size_t len, 187256072Sneel vm_offset_t *offset, struct vm_object **object); 188256072Sneelboolean_t vm_mem_allocated(struct vm *vm, vm_paddr_t gpa); 189221828Sgrehanint vm_get_register(struct vm *vm, int vcpu, int reg, uint64_t *retval); 190221828Sgrehanint vm_set_register(struct vm *vm, int vcpu, int reg, uint64_t val); 191221828Sgrehanint vm_get_seg_desc(struct vm *vm, int vcpu, int reg, 192221828Sgrehan struct seg_desc *ret_desc); 193221828Sgrehanint vm_set_seg_desc(struct vm *vm, int vcpu, int reg, 194221828Sgrehan struct seg_desc *desc); 195221828Sgrehanint vm_run(struct vm *vm, struct vm_run *vmrun); 196265062Sneelint vm_suspend(struct vm *vm, enum vm_suspend_how how); 197221828Sgrehanint vm_inject_nmi(struct vm *vm, int vcpu); 198241982Sneelint vm_nmi_pending(struct vm *vm, int vcpuid); 199241982Sneelvoid vm_nmi_clear(struct vm *vm, int vcpuid); 200263211Stychonint vm_inject_extint(struct vm *vm, int vcpu); 201263211Stychonint vm_extint_pending(struct vm *vm, int vcpuid); 202263211Stychonvoid vm_extint_clear(struct vm *vm, int vcpuid); 203221828Sgrehanstruct vlapic *vm_lapic(struct vm *vm, int cpu); 204258075Sneelstruct vioapic *vm_ioapic(struct vm *vm); 205258579Sneelstruct vhpet *vm_hpet(struct vm *vm); 206221828Sgrehanint vm_get_capability(struct vm *vm, int vcpu, int type, int *val); 207221828Sgrehanint vm_set_capability(struct vm *vm, int vcpu, int type, int val); 208240922Sneelint vm_get_x2apic_state(struct vm *vm, int vcpu, enum x2apic_state *state); 209240922Sneelint vm_set_x2apic_state(struct vm *vm, int vcpu, enum x2apic_state state); 210258075Sneelint vm_apicid2vcpuid(struct vm *vm, int apicid); 211266933Sneelint vm_activate_cpu(struct vm *vm, int vcpu); 212240894Sneelstruct vm_exit *vm_exitinfo(struct vm *vm, int vcpuid); 213265062Sneelvoid vm_exit_suspended(struct vm *vm, int vcpuid, uint64_t rip); 214267330Sneelvoid vm_exit_rendezvous(struct vm *vm, int vcpuid, uint64_t rip); 215267330Sneelvoid vm_exit_astpending(struct vm *vm, int vcpuid, uint64_t rip); 216283657Sneelvoid vm_exit_reqidle(struct vm *vm, int vcpuid, uint64_t rip); 217221828Sgrehan 218282287Sneel#ifdef _SYS__CPUSET_H_ 219221828Sgrehan/* 220260619Sneel * Rendezvous all vcpus specified in 'dest' and execute 'func(arg)'. 221260619Sneel * The rendezvous 'func(arg)' is not allowed to do anything that will 222260619Sneel * cause the thread to be put to sleep. 223260619Sneel * 224260619Sneel * If the rendezvous is being initiated from a vcpu context then the 225260619Sneel * 'vcpuid' must refer to that vcpu, otherwise it should be set to -1. 226260619Sneel * 227260619Sneel * The caller cannot hold any locks when initiating the rendezvous. 228260619Sneel * 229260619Sneel * The implementation of this API may cause vcpus other than those specified 230260619Sneel * by 'dest' to be stalled. The caller should not rely on any vcpus making 231260619Sneel * forward progress when the rendezvous is in progress. 232260619Sneel */ 233260619Sneeltypedef void (*vm_rendezvous_func_t)(struct vm *vm, int vcpuid, void *arg); 234260619Sneelvoid vm_smp_rendezvous(struct vm *vm, int vcpuid, cpuset_t dest, 235260619Sneel vm_rendezvous_func_t func, void *arg); 236282287Sneelcpuset_t vm_active_cpus(struct vm *vm); 237282287Sneelcpuset_t vm_suspended_cpus(struct vm *vm); 238282287Sneel#endif /* _SYS__CPUSET_H_ */ 239260619Sneel 240260619Sneelstatic __inline int 241283657Sneelvcpu_rendezvous_pending(struct vm_eventinfo *info) 242260619Sneel{ 243260619Sneel 244283657Sneel return (*((uintptr_t *)(info->rptr)) != 0); 245260619Sneel} 246260619Sneel 247263780Sneelstatic __inline int 248283657Sneelvcpu_suspended(struct vm_eventinfo *info) 249263780Sneel{ 250263780Sneel 251283657Sneel return (*info->sptr); 252263780Sneel} 253263780Sneel 254283657Sneelstatic __inline int 255283657Sneelvcpu_reqidle(struct vm_eventinfo *info) 256283657Sneel{ 257283657Sneel 258283657Sneel return (*info->iptr); 259283657Sneel} 260283657Sneel 261260619Sneel/* 262221828Sgrehan * Return 1 if device indicated by bus/slot/func is supposed to be a 263221828Sgrehan * pci passthrough device. 264221828Sgrehan * 265221828Sgrehan * Return 0 otherwise. 266221828Sgrehan */ 267221828Sgrehanint vmm_is_pptdev(int bus, int slot, int func); 268221828Sgrehan 269221828Sgrehanvoid *vm_iommu_domain(struct vm *vm); 270221828Sgrehan 271241489Sneelenum vcpu_state { 272241489Sneel VCPU_IDLE, 273256072Sneel VCPU_FROZEN, 274241489Sneel VCPU_RUNNING, 275256072Sneel VCPU_SLEEPING, 276241489Sneel}; 277221828Sgrehan 278259737Sneelint vcpu_set_state(struct vm *vm, int vcpu, enum vcpu_state state, 279259737Sneel bool from_idle); 280249879Sgrehanenum vcpu_state vcpu_get_state(struct vm *vm, int vcpu, int *hostcpu); 281221828Sgrehan 282221828Sgrehanstatic int __inline 283249879Sgrehanvcpu_is_running(struct vm *vm, int vcpu, int *hostcpu) 284221828Sgrehan{ 285249879Sgrehan return (vcpu_get_state(vm, vcpu, hostcpu) == VCPU_RUNNING); 286221828Sgrehan} 287221828Sgrehan 288269109Sneel#ifdef _SYS_PROC_H_ 289269109Sneelstatic int __inline 290269109Sneelvcpu_should_yield(struct vm *vm, int vcpu) 291269109Sneel{ 292282571Sneel 293282571Sneel if (curthread->td_flags & (TDF_ASTPENDING | TDF_NEEDRESCHED)) 294282571Sneel return (1); 295282571Sneel else if (curthread->td_owepreempt) 296282571Sneel return (1); 297282571Sneel else 298282571Sneel return (0); 299269109Sneel} 300269109Sneel#endif 301269109Sneel 302241489Sneelvoid *vcpu_stats(struct vm *vm, int vcpu); 303259863Sneelvoid vcpu_notify_event(struct vm *vm, int vcpuid, bool lapic_intr); 304256072Sneelstruct vmspace *vm_get_vmspace(struct vm *vm); 305256072Sneelint vm_assign_pptdev(struct vm *vm, int bus, int slot, int func); 306256072Sneelint vm_unassign_pptdev(struct vm *vm, int bus, int slot, int func); 307263035Stychonstruct vatpic *vm_atpic(struct vm *vm); 308263744Stychonstruct vatpit *vm_atpit(struct vm *vm); 309273683Sneelstruct vpmtmr *vm_pmtmr(struct vm *vm); 310276428Sneelstruct vrtc *vm_rtc(struct vm *vm); 311262506Sneel 312262506Sneel/* 313277149Sneel * Inject exception 'vector' into the guest vcpu. This function returns 0 on 314262506Sneel * success and non-zero on failure. 315262506Sneel * 316262506Sneel * Wrapper functions like 'vm_inject_gp()' should be preferred to calling 317262506Sneel * this function directly because they enforce the trap-like or fault-like 318262506Sneel * behavior of an exception. 319262506Sneel * 320262506Sneel * This function should only be called in the context of the thread that is 321262506Sneel * executing this vcpu. 322262506Sneel */ 323277149Sneelint vm_inject_exception(struct vm *vm, int vcpuid, int vector, int err_valid, 324277149Sneel uint32_t errcode, int restart_instruction); 325262506Sneel 326262506Sneel/* 327268889Sneel * This function is called after a VM-exit that occurred during exception or 328268889Sneel * interrupt delivery through the IDT. The format of 'intinfo' is described 329268889Sneel * in Figure 15-1, "EXITINTINFO for All Intercepts", APM, Vol 2. 330262506Sneel * 331268889Sneel * If a VM-exit handler completes the event delivery successfully then it 332268889Sneel * should call vm_exit_intinfo() to extinguish the pending event. For e.g., 333268889Sneel * if the task switch emulation is triggered via a task gate then it should 334268889Sneel * call this function with 'intinfo=0' to indicate that the external event 335268889Sneel * is not pending anymore. 336268889Sneel * 337268889Sneel * Return value is 0 on success and non-zero on failure. 338262506Sneel */ 339268889Sneelint vm_exit_intinfo(struct vm *vm, int vcpuid, uint64_t intinfo); 340262506Sneel 341268889Sneel/* 342268889Sneel * This function is called before every VM-entry to retrieve a pending 343268889Sneel * event that should be injected into the guest. This function combines 344268889Sneel * nested events into a double or triple fault. 345268889Sneel * 346268889Sneel * Returns 0 if there are no events that need to be injected into the guest 347268889Sneel * and non-zero otherwise. 348268889Sneel */ 349268889Sneelint vm_entry_intinfo(struct vm *vm, int vcpuid, uint64_t *info); 350268889Sneel 351268889Sneelint vm_get_intinfo(struct vm *vm, int vcpuid, uint64_t *info1, uint64_t *info2); 352268889Sneel 353266573Sneelenum vm_reg_name vm_segment_name(int seg_encoding); 354266573Sneel 355269008Sneelstruct vm_copyinfo { 356269008Sneel uint64_t gpa; 357269008Sneel size_t len; 358269008Sneel void *hva; 359269008Sneel void *cookie; 360269008Sneel}; 361269008Sneel 362269008Sneel/* 363269008Sneel * Set up 'copyinfo[]' to copy to/from guest linear address space starting 364269008Sneel * at 'gla' and 'len' bytes long. The 'prot' should be set to PROT_READ for 365269008Sneel * a copyin or PROT_WRITE for a copyout. 366269008Sneel * 367282558Sneel * retval is_fault Intepretation 368282558Sneel * 0 0 Success 369282558Sneel * 0 1 An exception was injected into the guest 370282558Sneel * EFAULT N/A Unrecoverable error 371269008Sneel * 372269008Sneel * The 'copyinfo[]' can be passed to 'vm_copyin()' or 'vm_copyout()' only if 373269008Sneel * the return value is 0. The 'copyinfo[]' resources should be freed by calling 374269008Sneel * 'vm_copy_teardown()' after the copy is done. 375269008Sneel */ 376269008Sneelint vm_copy_setup(struct vm *vm, int vcpuid, struct vm_guest_paging *paging, 377269008Sneel uint64_t gla, size_t len, int prot, struct vm_copyinfo *copyinfo, 378282558Sneel int num_copyinfo, int *is_fault); 379269008Sneelvoid vm_copy_teardown(struct vm *vm, int vcpuid, struct vm_copyinfo *copyinfo, 380269008Sneel int num_copyinfo); 381269008Sneelvoid vm_copyin(struct vm *vm, int vcpuid, struct vm_copyinfo *copyinfo, 382269008Sneel void *kaddr, size_t len); 383269008Sneelvoid vm_copyout(struct vm *vm, int vcpuid, const void *kaddr, 384269008Sneel struct vm_copyinfo *copyinfo, size_t len); 385276098Sneel 386276098Sneelint vcpu_trace_exceptions(struct vm *vm, int vcpuid); 387221828Sgrehan#endif /* KERNEL */ 388221828Sgrehan 389255438Sgrehan#define VM_MAXCPU 16 /* maximum virtual cpus */ 390221828Sgrehan 391221828Sgrehan/* 392221828Sgrehan * Identifiers for optional vmm capabilities 393221828Sgrehan */ 394221828Sgrehanenum vm_cap_type { 395221828Sgrehan VM_CAP_HALT_EXIT, 396221828Sgrehan VM_CAP_MTRAP_EXIT, 397221828Sgrehan VM_CAP_PAUSE_EXIT, 398221828Sgrehan VM_CAP_UNRESTRICTED_GUEST, 399256645Sneel VM_CAP_ENABLE_INVPCID, 400221828Sgrehan VM_CAP_MAX 401221828Sgrehan}; 402221828Sgrehan 403266125Sjhbenum vm_intr_trigger { 404266125Sjhb EDGE_TRIGGER, 405266125Sjhb LEVEL_TRIGGER 406266125Sjhb}; 407266125Sjhb 408221828Sgrehan/* 409221828Sgrehan * The 'access' field has the format specified in Table 21-2 of the Intel 410221828Sgrehan * Architecture Manual vol 3b. 411221828Sgrehan * 412221828Sgrehan * XXX The contents of the 'access' field are architecturally defined except 413221828Sgrehan * bit 16 - Segment Unusable. 414221828Sgrehan */ 415221828Sgrehanstruct seg_desc { 416221828Sgrehan uint64_t base; 417221828Sgrehan uint32_t limit; 418221828Sgrehan uint32_t access; 419221828Sgrehan}; 420268701Sneel#define SEG_DESC_TYPE(access) ((access) & 0x001f) 421268777Sneel#define SEG_DESC_DPL(access) (((access) >> 5) & 0x3) 422268701Sneel#define SEG_DESC_PRESENT(access) (((access) & 0x0080) ? 1 : 0) 423268701Sneel#define SEG_DESC_DEF32(access) (((access) & 0x4000) ? 1 : 0) 424268701Sneel#define SEG_DESC_GRANULARITY(access) (((access) & 0x8000) ? 1 : 0) 425268701Sneel#define SEG_DESC_UNUSABLE(access) (((access) & 0x10000) ? 1 : 0) 426221828Sgrehan 427266627Sneelenum vm_cpu_mode { 428268428Sneel CPU_MODE_REAL, 429268428Sneel CPU_MODE_PROTECTED, 430266627Sneel CPU_MODE_COMPATIBILITY, /* IA-32E mode (CS.L = 0) */ 431266627Sneel CPU_MODE_64BIT, /* IA-32E mode (CS.L = 1) */ 432266627Sneel}; 433266627Sneel 434266627Sneelenum vm_paging_mode { 435266627Sneel PAGING_MODE_FLAT, 436266627Sneel PAGING_MODE_32, 437266627Sneel PAGING_MODE_PAE, 438266627Sneel PAGING_MODE_64, 439266627Sneel}; 440266627Sneel 441266627Sneelstruct vm_guest_paging { 442266627Sneel uint64_t cr3; 443266627Sneel int cpl; 444266627Sneel enum vm_cpu_mode cpu_mode; 445266627Sneel enum vm_paging_mode paging_mode; 446266627Sneel}; 447266627Sneel 448266627Sneel/* 449266627Sneel * The data structures 'vie' and 'vie_op' are meant to be opaque to the 450266627Sneel * consumers of instruction decoding. The only reason why their contents 451266627Sneel * need to be exposed is because they are part of the 'vm_exit' structure. 452266627Sneel */ 453266627Sneelstruct vie_op { 454266627Sneel uint8_t op_byte; /* actual opcode byte */ 455266627Sneel uint8_t op_type; /* type of operation (e.g. MOV) */ 456266627Sneel uint16_t op_flags; 457266627Sneel}; 458266627Sneel 459266627Sneel#define VIE_INST_SIZE 15 460266627Sneelstruct vie { 461266627Sneel uint8_t inst[VIE_INST_SIZE]; /* instruction bytes */ 462266627Sneel uint8_t num_valid; /* size of the instruction */ 463266627Sneel uint8_t num_processed; 464266627Sneel 465268701Sneel uint8_t addrsize:4, opsize:4; /* address and operand sizes */ 466266627Sneel uint8_t rex_w:1, /* REX prefix */ 467266627Sneel rex_r:1, 468266627Sneel rex_x:1, 469266627Sneel rex_b:1, 470268701Sneel rex_present:1, 471277360Sneel repz_present:1, /* REP/REPE/REPZ prefix */ 472277360Sneel repnz_present:1, /* REPNE/REPNZ prefix */ 473268701Sneel opsize_override:1, /* Operand size override */ 474277360Sneel addrsize_override:1, /* Address size override */ 475277360Sneel segment_override:1; /* Segment override */ 476266627Sneel 477266627Sneel uint8_t mod:2, /* ModRM byte */ 478266627Sneel reg:4, 479266627Sneel rm:4; 480266627Sneel 481266627Sneel uint8_t ss:2, /* SIB byte */ 482266627Sneel index:4, 483266627Sneel base:4; 484266627Sneel 485266627Sneel uint8_t disp_bytes; 486266627Sneel uint8_t imm_bytes; 487266627Sneel 488266627Sneel uint8_t scale; 489266627Sneel int base_register; /* VM_REG_GUEST_xyz */ 490266627Sneel int index_register; /* VM_REG_GUEST_xyz */ 491277360Sneel int segment_register; /* VM_REG_GUEST_xyz */ 492266627Sneel 493266627Sneel int64_t displacement; /* optional addr displacement */ 494266627Sneel int64_t immediate; /* optional immediate operand */ 495266627Sneel 496266627Sneel uint8_t decoded; /* set to 1 if successfully decoded */ 497266627Sneel 498266627Sneel struct vie_op op; /* opcode description */ 499266627Sneel}; 500266627Sneel 501221828Sgrehanenum vm_exitcode { 502221828Sgrehan VM_EXITCODE_INOUT, 503221828Sgrehan VM_EXITCODE_VMX, 504221828Sgrehan VM_EXITCODE_BOGUS, 505221828Sgrehan VM_EXITCODE_RDMSR, 506221828Sgrehan VM_EXITCODE_WRMSR, 507221828Sgrehan VM_EXITCODE_HLT, 508221828Sgrehan VM_EXITCODE_MTRAP, 509221828Sgrehan VM_EXITCODE_PAUSE, 510234761Sgrehan VM_EXITCODE_PAGING, 511256072Sneel VM_EXITCODE_INST_EMUL, 512240912Sneel VM_EXITCODE_SPINUP_AP, 513265101Sneel VM_EXITCODE_DEPRECATED1, /* used to be SPINDOWN_CPU */ 514260619Sneel VM_EXITCODE_RENDEZVOUS, 515261170Sneel VM_EXITCODE_IOAPIC_EOI, 516263780Sneel VM_EXITCODE_SUSPENDED, 517266573Sneel VM_EXITCODE_INOUT_STR, 518268777Sneel VM_EXITCODE_TASK_SWITCH, 519272670Sneel VM_EXITCODE_MONITOR, 520272670Sneel VM_EXITCODE_MWAIT, 521273375Sneel VM_EXITCODE_SVM, 522283657Sneel VM_EXITCODE_REQIDLE, 523234761Sgrehan VM_EXITCODE_MAX 524221828Sgrehan}; 525221828Sgrehan 526266573Sneelstruct vm_inout { 527266573Sneel uint16_t bytes:3; /* 1 or 2 or 4 */ 528266573Sneel uint16_t in:1; 529266573Sneel uint16_t string:1; 530266573Sneel uint16_t rep:1; 531266573Sneel uint16_t port; 532266573Sneel uint32_t eax; /* valid for out */ 533266573Sneel}; 534266573Sneel 535266573Sneelstruct vm_inout_str { 536266573Sneel struct vm_inout inout; /* must be the first element */ 537266627Sneel struct vm_guest_paging paging; 538266573Sneel uint64_t rflags; 539266573Sneel uint64_t cr0; 540266573Sneel uint64_t index; 541266573Sneel uint64_t count; /* rep=1 (%rcx), rep=0 (1) */ 542266573Sneel int addrsize; 543266573Sneel enum vm_reg_name seg_name; 544266573Sneel struct seg_desc seg_desc; 545266573Sneel}; 546266573Sneel 547268777Sneelenum task_switch_reason { 548268777Sneel TSR_CALL, 549268777Sneel TSR_IRET, 550268777Sneel TSR_JMP, 551268777Sneel TSR_IDT_GATE, /* task gate in IDT */ 552268777Sneel}; 553268777Sneel 554268777Sneelstruct vm_task_switch { 555268777Sneel uint16_t tsssel; /* new TSS selector */ 556268777Sneel int ext; /* task switch due to external event */ 557268777Sneel uint32_t errcode; 558268777Sneel int errcode_valid; /* push 'errcode' on the new stack */ 559268777Sneel enum task_switch_reason reason; 560268777Sneel struct vm_guest_paging paging; 561268777Sneel}; 562268777Sneel 563221828Sgrehanstruct vm_exit { 564221828Sgrehan enum vm_exitcode exitcode; 565221828Sgrehan int inst_length; /* 0 means unknown */ 566221828Sgrehan uint64_t rip; 567221828Sgrehan union { 568266573Sneel struct vm_inout inout; 569266573Sneel struct vm_inout_str inout_str; 570221828Sgrehan struct { 571241497Sgrehan uint64_t gpa; 572256072Sneel int fault_type; 573256072Sneel } paging; 574256072Sneel struct { 575256072Sneel uint64_t gpa; 576256072Sneel uint64_t gla; 577280447Stychon uint64_t cs_base; 578268701Sneel int cs_d; /* CS.D */ 579266627Sneel struct vm_guest_paging paging; 580243640Sneel struct vie vie; 581256072Sneel } inst_emul; 582221828Sgrehan /* 583221828Sgrehan * VMX specific payload. Used when there is no "better" 584221828Sgrehan * exitcode to represent the VM-exit. 585221828Sgrehan */ 586221828Sgrehan struct { 587260167Sneel int status; /* vmx inst status */ 588260167Sneel /* 589260167Sneel * 'exit_reason' and 'exit_qualification' are valid 590260167Sneel * only if 'status' is zero. 591260167Sneel */ 592221828Sgrehan uint32_t exit_reason; 593221828Sgrehan uint64_t exit_qualification; 594260167Sneel /* 595260167Sneel * 'inst_error' and 'inst_type' are valid 596260167Sneel * only if 'status' is non-zero. 597260167Sneel */ 598260167Sneel int inst_type; 599260167Sneel int inst_error; 600221828Sgrehan } vmx; 601273375Sneel /* 602273375Sneel * SVM specific payload. 603273375Sneel */ 604221828Sgrehan struct { 605273375Sneel uint64_t exitcode; 606273375Sneel uint64_t exitinfo1; 607273375Sneel uint64_t exitinfo2; 608273375Sneel } svm; 609273375Sneel struct { 610221828Sgrehan uint32_t code; /* ecx value */ 611221828Sgrehan uint64_t wval; 612221828Sgrehan } msr; 613240912Sneel struct { 614240912Sneel int vcpu; 615240912Sneel uint64_t rip; 616240912Sneel } spinup_ap; 617259081Sneel struct { 618259081Sneel uint64_t rflags; 619259081Sneel } hlt; 620261170Sneel struct { 621261170Sneel int vector; 622261170Sneel } ioapic_eoi; 623265062Sneel struct { 624265062Sneel enum vm_suspend_how how; 625265062Sneel } suspended; 626268777Sneel struct vm_task_switch task_switch; 627221828Sgrehan } u; 628221828Sgrehan}; 629221828Sgrehan 630269042Sneel/* APIs to inject faults into the guest */ 631269042Sneelvoid vm_inject_fault(void *vm, int vcpuid, int vector, int errcode_valid, 632269042Sneel int errcode); 633269042Sneel 634270438Sgrehanstatic __inline void 635269042Sneelvm_inject_ud(void *vm, int vcpuid) 636269042Sneel{ 637269042Sneel vm_inject_fault(vm, vcpuid, IDT_UD, 0, 0); 638269042Sneel} 639269042Sneel 640270438Sgrehanstatic __inline void 641269042Sneelvm_inject_gp(void *vm, int vcpuid) 642269042Sneel{ 643269042Sneel vm_inject_fault(vm, vcpuid, IDT_GP, 1, 0); 644269042Sneel} 645269042Sneel 646270438Sgrehanstatic __inline void 647269042Sneelvm_inject_ac(void *vm, int vcpuid, int errcode) 648269042Sneel{ 649269042Sneel vm_inject_fault(vm, vcpuid, IDT_AC, 1, errcode); 650269042Sneel} 651269042Sneel 652270438Sgrehanstatic __inline void 653269042Sneelvm_inject_ss(void *vm, int vcpuid, int errcode) 654269042Sneel{ 655269042Sneel vm_inject_fault(vm, vcpuid, IDT_SS, 1, errcode); 656269042Sneel} 657269042Sneel 658269042Sneelvoid vm_inject_pf(void *vm, int vcpuid, int error_code, uint64_t cr2); 659269042Sneel 660277149Sneelint vm_restart_instruction(void *vm, int vcpuid); 661277149Sneel 662221828Sgrehan#endif /* _VMM_H_ */ 663