├── .gitignore ├── Cargo.toml ├── LICENSE.md ├── README.md ├── build.rs └── src ├── consts ├── irq.rs ├── mod.rs ├── vmcs.rs ├── vmx_cap.rs └── vmx_exit.rs ├── ffi.rs └── lib.rs /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "hypervisor" 3 | version = "0.0.8" 4 | authors = ["Saurav Sachidanand "] 5 | 6 | license = "MIT" 7 | repository = "https://www.github.com/saurvs/hypervisor-rs" 8 | documentation = "https://saurvs.github.io/hypervisor-rs" 9 | 10 | description = " Hardware-accelerated virtualization on OS X" 11 | keywords = ["hypervisor", "virtualization", "osx", "x86", "VT-x"] 12 | 13 | build = "build.rs" 14 | 15 | [dependencies] 16 | libc = "0.2.11" 17 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016 Saurav Sachidanand 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # hypervisor-rs [![](http://meritbadge.herokuapp.com/hypervisor)](https://crates.io/crates/hypervisor) [![](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/saurvs/hypervisor-rs/blob/master/LICENSE.md) 2 | 3 | `hypervisor` is a Rust library that taps into functionality that enables hardware-accelerated execution of 4 | virtual machines on OS X. 5 | 6 | It binds to the [Hypervisor](https://developer.apple.com/library/mac/documentation/Hypervisor/Reference/Hypervisor_Reference/index.html#//apple_ref/doc/uid/TP40016756) framework on OS X, and exposes a safe Rust 7 | interface through the `hypervisor` module, and an unsafe foreign function 8 | interface through the `hypervisor::ffi` module. 9 | 10 | [Documentation](https://saurvs.github.io/hypervisor-rs/) 11 | 12 | ## Prerequisites 13 | 14 | To use this library, you need 15 | 16 | * OS X Yosemite (10.10), or newer 17 | 18 | * an Intel processor with the VT-x feature set that includes Extended Page 19 | Tables (EPT) and the Unrestricted Mode. To verify this, run and expect the 20 | following in your Terminal: 21 | ```shell 22 | $ sysctl kern.hv_support 23 | kern.hv_support: 1 24 | ``` 25 | 26 | ## Status 27 | - [x] Accessing x86 registers 28 | - [x] Accessing model-specific registers (MSRs) 29 | - [x] Mapping guest physical memory segments into guest physical address space 30 | - [x] Virtual CPUs 31 | - [x] Executing and interrupting 32 | - [x] Force flushing cached state 33 | - [x] Invalidating translation lookaside buffer (TLB) 34 | - [x] Accessing floating point (FP) and SIMD state 35 | - [x] Obtaining cumulative execution time 36 | - [x] Synchronizing guest timestamp-counters (TSC) 37 | - [x] Accessing fields of Virtual Machine Control Structures (VMCS) 38 | -------------------------------------------------------------------------------- /build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | println!("cargo:rustc-link-lib=framework=Hypervisor"); 3 | } 4 | -------------------------------------------------------------------------------- /src/consts/irq.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2016 Saurav Sachidanand 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | //! Interrupt Request (IRQ) Codes 24 | 25 | use libc::*; 26 | 27 | pub const IRQ_INFO_EXT_IRQ : uint32_t = 0 << 8; 28 | pub const IRQ_INFO_NMI : uint32_t = 2 << 8; 29 | pub const IRQ_INFO_HARD_EXC : uint32_t = 3 << 8; 30 | pub const IRQ_INFO_SOFT_IRQ : uint32_t = 4 << 8; 31 | pub const IRQ_INFO_PRIV_SOFT_EXC : uint32_t = 5 << 8; 32 | pub const IRQ_INFO_SOFT_EXC : uint32_t = 6 << 8; 33 | pub const IRQ_INFO_ERROR_VALID : uint32_t = 1 << 11; 34 | pub const IRQ_INFO_VALID : uint32_t = 1 << 31; 35 | -------------------------------------------------------------------------------- /src/consts/mod.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2016 Saurav Sachidanand 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | //! Some useful constants 24 | 25 | pub mod vmcs; 26 | pub mod vmx_cap; 27 | pub mod vmx_exit; 28 | pub mod irq; 29 | 30 | use libc::*; 31 | 32 | pub const VMX_BASIC_TRUE_CTLS: uint64_t = 1 << 55; 33 | -------------------------------------------------------------------------------- /src/consts/vmcs.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2016 Saurav Sachidanand 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | //! Virtual Machine Control Structure (VMCS) field IDs 24 | 25 | use libc::*; 26 | 27 | pub const VMCS_VPID : uint32_t = 0x00000000; 28 | pub const VMCS_CTRL_POSTED_INT_N_VECTOR : uint32_t = 0x00000002; 29 | pub const VMCS_CTRL_EPTP_INDEX : uint32_t = 0x00000004; 30 | pub const VMCS_GUEST_ES : uint32_t = 0x00000800; 31 | pub const VMCS_GUEST_CS : uint32_t = 0x00000802; 32 | pub const VMCS_GUEST_SS : uint32_t = 0x00000804; 33 | pub const VMCS_GUEST_DS : uint32_t = 0x00000806; 34 | pub const VMCS_GUEST_FS : uint32_t = 0x00000808; 35 | pub const VMCS_GUEST_GS : uint32_t = 0x0000080a; 36 | pub const VMCS_GUEST_LDTR : uint32_t = 0x0000080c; 37 | pub const VMCS_GUEST_TR : uint32_t = 0x0000080e; 38 | pub const VMCS_GUEST_INT_STATUS : uint32_t = 0x00000810; 39 | pub const VMCS_HOST_ES : uint32_t = 0x00000c00; 40 | pub const VMCS_HOST_CS : uint32_t = 0x00000c02; 41 | pub const VMCS_HOST_SS : uint32_t = 0x00000c04; 42 | pub const VMCS_HOST_DS : uint32_t = 0x00000c06; 43 | pub const VMCS_HOST_FS : uint32_t = 0x00000c08; 44 | pub const VMCS_HOST_GS : uint32_t = 0x00000c0a; 45 | pub const VMCS_HOST_TR : uint32_t = 0x00000c0c; 46 | pub const VMCS_CTRL_IO_BITMAP_A : uint32_t = 0x00002000; 47 | pub const VMCS_CTRL_IO_BITMAP_B : uint32_t = 0x00002002; 48 | pub const VMCS_CTRL_MSR_BITMAPS : uint32_t = 0x00002004; 49 | pub const VMCS_CTRL_VMEXIT_MSR_STORE_ADDR : uint32_t = 0x00002006; 50 | pub const VMCS_CTRL_VMEXIT_MSR_LOAD_ADDR : uint32_t = 0x00002008; 51 | pub const VMCS_CTRL_VMENTRY_MSR_LOAD_ADDR : uint32_t = 0x0000200a; 52 | pub const VMCS_CTRL_EXECUTIVE_VMCS_PTR : uint32_t = 0x0000200c; 53 | pub const VMCS_CTRL_TSC_OFFSET : uint32_t = 0x00002010; 54 | pub const VMCS_CTRL_VIRTUAL_APIC : uint32_t = 0x00002012; 55 | pub const VMCS_CTRL_APIC_ACCESS : uint32_t = 0x00002014; 56 | pub const VMCS_CTRL_POSTED_INT_DESC_ADDR : uint32_t = 0x00002016; 57 | pub const VMCS_CTRL_VMFUNC_CTRL : uint32_t = 0x00002018; 58 | pub const VMCS_CTRL_EPTP : uint32_t = 0x0000201a; 59 | pub const VMCS_CTRL_EOI_EXIT_BITMAP_0 : uint32_t = 0x0000201c; 60 | pub const VMCS_CTRL_EOI_EXIT_BITMAP_1 : uint32_t = 0x0000201e; 61 | pub const VMCS_CTRL_EOI_EXIT_BITMAP_2 : uint32_t = 0x00002020; 62 | pub const VMCS_CTRL_EOI_EXIT_BITMAP_3 : uint32_t = 0x00002022; 63 | pub const VMCS_CTRL_EPTP_LIST_ADDR : uint32_t = 0x00002024; 64 | pub const VMCS_CTRL_VMREAD_BITMAP_ADDR : uint32_t = 0x00002026; 65 | pub const VMCS_CTRL_VMWRITE_BITMAP_ADDR : uint32_t = 0x00002028; 66 | pub const VMCS_CTRL_VIRT_EXC_INFO_ADDR : uint32_t = 0x0000202a; 67 | pub const VMCS_CTRL_XSS_EXITING_BITMAP : uint32_t = 0x0000202c; 68 | pub const VMCS_GUEST_PHYSICAL_ADDRESS : uint32_t = 0x00002400; 69 | pub const VMCS_GUEST_LINK_POINTER : uint32_t = 0x00002800; 70 | pub const VMCS_GUEST_IA32_DEBUGCTL : uint32_t = 0x00002802; 71 | pub const VMCS_GUEST_IA32_PAT : uint32_t = 0x00002804; 72 | pub const VMCS_GUEST_IA32_EFER : uint32_t = 0x00002806; 73 | pub const VMCS_GUEST_IA32_PERF_GLOBAL_CTRL : uint32_t = 0x00002808; 74 | pub const VMCS_GUEST_PDPTE0 : uint32_t = 0x0000280a; 75 | pub const VMCS_GUEST_PDPTE1 : uint32_t = 0x0000280c; 76 | pub const VMCS_GUEST_PDPTE2 : uint32_t = 0x0000280e; 77 | pub const VMCS_GUEST_PDPTE3 : uint32_t = 0x00002810; 78 | pub const VMCS_HOST_IA32_PAT : uint32_t = 0x00002c00; 79 | pub const VMCS_HOST_IA32_EFER : uint32_t = 0x00002c02; 80 | pub const VMCS_HOST_IA32_PERF_GLOBAL_CTRL : uint32_t = 0x00002c04; 81 | pub const VMCS_CTRL_PIN_BASED : uint32_t = 0x00004000; 82 | pub const VMCS_CTRL_CPU_BASED : uint32_t = 0x00004002; 83 | pub const VMCS_CTRL_EXC_BITMAP : uint32_t = 0x00004004; 84 | pub const VMCS_CTRL_PF_ERROR_MASK : uint32_t = 0x00004006; 85 | pub const VMCS_CTRL_PF_ERROR_MATCH : uint32_t = 0x00004008; 86 | pub const VMCS_CTRL_CR3_COUNT : uint32_t = 0x0000400a; 87 | pub const VMCS_CTRL_VMEXIT_CONTROLS : uint32_t = 0x0000400c; 88 | pub const VMCS_CTRL_VMEXIT_MSR_STORE_COUNT : uint32_t = 0x0000400e; 89 | pub const VMCS_CTRL_VMEXIT_MSR_LOAD_COUNT : uint32_t = 0x00004010; 90 | pub const VMCS_CTRL_VMENTRY_CONTROLS : uint32_t = 0x00004012; 91 | pub const VMCS_CTRL_VMENTRY_MSR_LOAD_COUNT : uint32_t = 0x00004014; 92 | pub const VMCS_CTRL_VMENTRY_IRQ_INFO : uint32_t = 0x00004016; 93 | pub const VMCS_CTRL_VMENTRY_EXC_ERROR : uint32_t = 0x00004018; 94 | pub const VMCS_CTRL_VMENTRY_INSTR_LEN : uint32_t = 0x0000401a; 95 | pub const VMCS_CTRL_TPR_THRESHOLD : uint32_t = 0x0000401c; 96 | pub const VMCS_CTRL_CPU_BASED2 : uint32_t = 0x0000401e; 97 | pub const VMCS_CTRL_PLE_GAP : uint32_t = 0x00004020; 98 | pub const VMCS_CTRL_PLE_WINDOW : uint32_t = 0x00004022; 99 | pub const VMCS_RO_INSTR_ERROR : uint32_t = 0x00004400; 100 | pub const VMCS_RO_EXIT_REASON : uint32_t = 0x00004402; 101 | pub const VMCS_RO_VMEXIT_IRQ_INFO : uint32_t = 0x00004404; 102 | pub const VMCS_RO_VMEXIT_IRQ_ERROR : uint32_t = 0x00004406; 103 | pub const VMCS_RO_IDT_VECTOR_INFO : uint32_t = 0x00004408; 104 | pub const VMCS_RO_IDT_VECTOR_ERROR : uint32_t = 0x0000440a; 105 | pub const VMCS_RO_VMEXIT_INSTR_LEN : uint32_t = 0x0000440c; 106 | pub const VMCS_RO_VMX_INSTR_INFO : uint32_t = 0x0000440e; 107 | pub const VMCS_GUEST_ES_LIMIT : uint32_t = 0x00004800; 108 | pub const VMCS_GUEST_CS_LIMIT : uint32_t = 0x00004802; 109 | pub const VMCS_GUEST_SS_LIMIT : uint32_t = 0x00004804; 110 | pub const VMCS_GUEST_DS_LIMIT : uint32_t = 0x00004806; 111 | pub const VMCS_GUEST_FS_LIMIT : uint32_t = 0x00004808; 112 | pub const VMCS_GUEST_GS_LIMIT : uint32_t = 0x0000480a; 113 | pub const VMCS_GUEST_LDTR_LIMIT : uint32_t = 0x0000480c; 114 | pub const VMCS_GUEST_TR_LIMIT : uint32_t = 0x0000480e; 115 | pub const VMCS_GUEST_GDTR_LIMIT : uint32_t = 0x00004810; 116 | pub const VMCS_GUEST_IDTR_LIMIT : uint32_t = 0x00004812; 117 | pub const VMCS_GUEST_ES_AR : uint32_t = 0x00004814; 118 | pub const VMCS_GUEST_CS_AR : uint32_t = 0x00004816; 119 | pub const VMCS_GUEST_SS_AR : uint32_t = 0x00004818; 120 | pub const VMCS_GUEST_DS_AR : uint32_t = 0x0000481a; 121 | pub const VMCS_GUEST_FS_AR : uint32_t = 0x0000481c; 122 | pub const VMCS_GUEST_GS_AR : uint32_t = 0x0000481e; 123 | pub const VMCS_GUEST_LDTR_AR : uint32_t = 0x00004820; 124 | pub const VMCS_GUEST_TR_AR : uint32_t = 0x00004822; 125 | pub const VMCS_GUEST_IGNORE_IRQ : uint32_t = 0x00004824; 126 | pub const VMCS_GUEST_ACTIVITY_STATE : uint32_t = 0x00004826; 127 | pub const VMCS_GUEST_SMBASE : uint32_t = 0x00004828; 128 | pub const VMCS_GUEST_IA32_SYSENTER_CS : uint32_t = 0x0000482a; 129 | pub const VMCS_GUEST_VMX_TIMER_VALUE : uint32_t = 0x0000482e; 130 | pub const VMCS_HOST_IA32_SYSENTER_CS : uint32_t = 0x00004c00; 131 | pub const VMCS_CTRL_CR0_MASK : uint32_t = 0x00006000; 132 | pub const VMCS_CTRL_CR4_MASK : uint32_t = 0x00006002; 133 | pub const VMCS_CTRL_CR0_SHADOW : uint32_t = 0x00006004; 134 | pub const VMCS_CTRL_CR4_SHADOW : uint32_t = 0x00006006; 135 | pub const VMCS_CTRL_CR3_VALUE0 : uint32_t = 0x00006008; 136 | pub const VMCS_CTRL_CR3_VALUE1 : uint32_t = 0x0000600a; 137 | pub const VMCS_CTRL_CR3_VALUE2 : uint32_t = 0x0000600c; 138 | pub const VMCS_CTRL_CR3_VALUE3 : uint32_t = 0x0000600e; 139 | pub const VMCS_RO_EXIT_QUALIFIC : uint32_t = 0x00006400; 140 | pub const VMCS_RO_IO_RCX : uint32_t = 0x00006402; 141 | pub const VMCS_RO_IO_RSI : uint32_t = 0x00006404; 142 | pub const VMCS_RO_IO_RDI : uint32_t = 0x00006406; 143 | pub const VMCS_RO_IO_RIP : uint32_t = 0x00006408; 144 | pub const VMCS_RO_GUEST_LIN_ADDR : uint32_t = 0x0000640a; 145 | pub const VMCS_GUEST_CR0 : uint32_t = 0x00006800; 146 | pub const VMCS_GUEST_CR3 : uint32_t = 0x00006802; 147 | pub const VMCS_GUEST_CR4 : uint32_t = 0x00006804; 148 | pub const VMCS_GUEST_ES_BASE : uint32_t = 0x00006806; 149 | pub const VMCS_GUEST_CS_BASE : uint32_t = 0x00006808; 150 | pub const VMCS_GUEST_SS_BASE : uint32_t = 0x0000680a; 151 | pub const VMCS_GUEST_DS_BASE : uint32_t = 0x0000680c; 152 | pub const VMCS_GUEST_FS_BASE : uint32_t = 0x0000680e; 153 | pub const VMCS_GUEST_GS_BASE : uint32_t = 0x00006810; 154 | pub const VMCS_GUEST_LDTR_BASE : uint32_t = 0x00006812; 155 | pub const VMCS_GUEST_TR_BASE : uint32_t = 0x00006814; 156 | pub const VMCS_GUEST_GDTR_BASE : uint32_t = 0x00006816; 157 | pub const VMCS_GUEST_IDTR_BASE : uint32_t = 0x00006818; 158 | pub const VMCS_GUEST_DR7 : uint32_t = 0x0000681a; 159 | pub const VMCS_GUEST_RSP : uint32_t = 0x0000681c; 160 | pub const VMCS_GUEST_RIP : uint32_t = 0x0000681e; 161 | pub const VMCS_GUEST_RFLAGS : uint32_t = 0x00006820; 162 | pub const VMCS_GUEST_DEBUG_EXC : uint32_t = 0x00006822; 163 | pub const VMCS_GUEST_SYSENTER_ESP : uint32_t = 0x00006824; 164 | pub const VMCS_GUEST_SYSENTER_EIP : uint32_t = 0x00006826; 165 | pub const VMCS_HOST_CR0 : uint32_t = 0x00006c00; 166 | pub const VMCS_HOST_CR3 : uint32_t = 0x00006c02; 167 | pub const VMCS_HOST_CR4 : uint32_t = 0x00006c04; 168 | pub const VMCS_HOST_FS_BASE : uint32_t = 0x00006c06; 169 | pub const VMCS_HOST_GS_BASE : uint32_t = 0x00006c08; 170 | pub const VMCS_HOST_TR_BASE : uint32_t = 0x00006c0a; 171 | pub const VMCS_HOST_GDTR_BASE : uint32_t = 0x00006c0c; 172 | pub const VMCS_HOST_IDTR_BASE : uint32_t = 0x00006c0e; 173 | pub const VMCS_HOST_IA32_SYSENTER_ESP : uint32_t = 0x00006c10; 174 | pub const VMCS_HOST_IA32_SYSENTER_EIP : uint32_t = 0x00006c12; 175 | pub const VMCS_HOST_RSP : uint32_t = 0x00006c14; 176 | pub const VMCS_HOST_RIP : uint32_t = 0x00006c16; 177 | pub const VMCS_MAX : uint32_t = 0x00006c18; 178 | -------------------------------------------------------------------------------- /src/consts/vmx_cap.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2016 Saurav Sachidanand 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | //! VMX capability field values 24 | 25 | use libc::*; 26 | 27 | pub const PIN_BASED_INTR : uint64_t = 1 << 0; 28 | pub const PIN_BASED_NMI : uint64_t = 1 << 3; 29 | pub const PIN_BASED_VIRTUAL_NMI : uint64_t = 1 << 5; 30 | pub const PIN_BASED_PREEMPTION_TIMER : uint64_t = 1 << 6; 31 | pub const PIN_BASED_POSTED_INTR : uint64_t = 1 << 7; 32 | 33 | pub const CPU_BASED_IRQ_WND : uint64_t = 1 << 2; 34 | pub const CPU_BASED_TSC_OFFSET : uint64_t = 1 << 3; 35 | pub const CPU_BASED_HLT : uint64_t = 1 << 7; 36 | pub const CPU_BASED_INVLPG : uint64_t = 1 << 9; 37 | pub const CPU_BASED_MWAIT : uint64_t = 1 << 10; 38 | pub const CPU_BASED_RDPMC : uint64_t = 1 << 11; 39 | pub const CPU_BASED_RDTSC : uint64_t = 1 << 12; 40 | pub const CPU_BASED_CR3_LOAD : uint64_t = 1 << 15; 41 | pub const CPU_BASED_CR3_STORE : uint64_t = 1 << 16; 42 | pub const CPU_BASED_CR8_LOAD : uint64_t = 1 << 19; 43 | pub const CPU_BASED_CR8_STORE : uint64_t = 1 << 20; 44 | pub const CPU_BASED_TPR_SHADOW : uint64_t = 1 << 21; 45 | pub const CPU_BASED_VIRTUAL_NMI_WND : uint64_t = 1 << 22; 46 | pub const CPU_BASED_MOV_DR : uint64_t = 1 << 23; 47 | pub const CPU_BASED_UNCOND_IO : uint64_t = 1 << 24; 48 | pub const CPU_BASED_IO_BITMAPS : uint64_t = 1 << 25; 49 | pub const CPU_BASED_MTF : uint64_t = 1 << 27; 50 | pub const CPU_BASED_MSR_BITMAPS : uint64_t = 1 << 28; 51 | pub const CPU_BASED_MONITOR : uint64_t = 1 << 29; 52 | pub const CPU_BASED_PAUSE : uint64_t = 1 << 30; 53 | pub const CPU_BASED_SECONDARY_CTLS : uint64_t = 1 << 31; 54 | 55 | pub const CPU_BASED2_VIRTUAL_APIC : uint64_t = 1 << 0; 56 | pub const CPU_BASED2_EPT : uint64_t = 1 << 1; 57 | pub const CPU_BASED2_DESC_TABLE : uint64_t = 1 << 2; 58 | pub const CPU_BASED2_RDTSCP : uint64_t = 1 << 3; 59 | pub const CPU_BASED2_X2APIC : uint64_t = 1 << 4; 60 | pub const CPU_BASED2_VPID : uint64_t = 1 << 5; 61 | pub const CPU_BASED2_WBINVD : uint64_t = 1 << 6; 62 | pub const CPU_BASED2_UNRESTRICTED : uint64_t = 1 << 7; 63 | pub const CPU_BASED2_APIC_REG_VIRT : uint64_t = 1 << 8; 64 | pub const CPU_BASED2_VIRT_INTR_DELIVERY : uint64_t = 1 << 9; 65 | pub const CPU_BASED2_PAUSE_LOOP : uint64_t = 1 << 10; 66 | pub const CPU_BASED2_RDRAND : uint64_t = 1 << 11; 67 | pub const CPU_BASED2_INVPCID : uint64_t = 1 << 12; 68 | pub const CPU_BASED2_VMFUNC : uint64_t = 1 << 13; 69 | pub const CPU_BASED2_VMCS_SHADOW : uint64_t = 1 << 14; 70 | pub const CPU_BASED2_RDSEED : uint64_t = 1 << 16; 71 | pub const CPU_BASED2_EPT_VE : uint64_t = 1 << 18; 72 | pub const CPU_BASED2_XSAVES_XRSTORS : uint64_t = 1 << 20; 73 | 74 | pub const VMX_EPT_VPID_SUPPORT_AD : uint64_t = 1 << 21; 75 | pub const VMX_EPT_VPID_SUPPORT_EXONLY : uint64_t = 1 << 0; 76 | 77 | pub const VMEXIT_SAVE_DBG_CONTROLS : uint64_t = 1 << 2; 78 | pub const VMEXIT_HOST_IA32E : uint64_t = 1 << 9; 79 | pub const VMEXIT_LOAD_IA32_PERF_GLOBAL_CTRL : uint64_t = 1 << 12; 80 | pub const VMEXIT_ACK_INTR : uint64_t = 1 << 15; 81 | pub const VMEXIT_SAVE_IA32_PAT : uint64_t = 1 << 18; 82 | pub const VMEXIT_LOAD_IA32_PAT : uint64_t = 1 << 19; 83 | pub const VMEXIT_SAVE_EFER : uint64_t = 1 << 20; 84 | pub const VMEXIT_LOAD_EFER : uint64_t = 1 << 21; 85 | pub const VMEXIT_SAVE_VMX_TIMER : uint64_t = 1 << 22; 86 | 87 | pub const VMENTRY_LOAD_DBG_CONTROLS : uint64_t = 1 << 2; 88 | pub const VMENTRY_GUEST_IA32E : uint64_t = 1 << 9; 89 | pub const VMENTRY_SMM : uint64_t = 1 << 10; 90 | pub const VMENTRY_DEACTIVATE_DUAL_MONITOR : uint64_t = 1 << 11; 91 | pub const VMENTRY_LOAD_IA32_PERF_GLOBAL_CTRL : uint64_t = 1 << 13; 92 | pub const VMENTRY_LOAD_IA32_PAT : uint64_t = 1 << 14; 93 | pub const VMENTRY_LOAD_EFER : uint64_t = 1 << 15; 94 | -------------------------------------------------------------------------------- /src/consts/vmx_exit.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2016 Saurav Sachidanand 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | //! VMX exit reasons 24 | 25 | use libc::*; 26 | 27 | pub const VMX_REASON_EXC_NMI : uint64_t = 0; 28 | pub const VMX_REASON_IRQ : uint64_t = 1; 29 | pub const VMX_REASON_TRIPLE_FAULT : uint64_t = 2; 30 | pub const VMX_REASON_INIT : uint64_t = 3; 31 | pub const VMX_REASON_SIPI : uint64_t = 4; 32 | pub const VMX_REASON_IO_SMI : uint64_t = 5; 33 | pub const VMX_REASON_OTHER_SMI : uint64_t = 6; 34 | pub const VMX_REASON_IRQ_WND : uint64_t = 7; 35 | pub const VMX_REASON_VIRTUAL_NMI_WND : uint64_t = 8; 36 | pub const VMX_REASON_TASK : uint64_t = 9; 37 | pub const VMX_REASON_CPUID : uint64_t = 10; 38 | pub const VMX_REASON_GETSEC : uint64_t = 11; 39 | pub const VMX_REASON_HLT : uint64_t = 12; 40 | pub const VMX_REASON_INVD : uint64_t = 13; 41 | pub const VMX_REASON_INVLPG : uint64_t = 14; 42 | pub const VMX_REASON_RDPMC : uint64_t = 15; 43 | pub const VMX_REASON_RDTSC : uint64_t = 16; 44 | pub const VMX_REASON_RSM : uint64_t = 17; 45 | pub const VMX_REASON_VMCALL : uint64_t = 18; 46 | pub const VMX_REASON_VMCLEAR : uint64_t = 19; 47 | pub const VMX_REASON_VMLAUNCH : uint64_t = 20; 48 | pub const VMX_REASON_VMPTRLD : uint64_t = 21; 49 | pub const VMX_REASON_VMPTRST : uint64_t = 22; 50 | pub const VMX_REASON_VMREAD : uint64_t = 23; 51 | pub const VMX_REASON_VMRESUME : uint64_t = 24; 52 | pub const VMX_REASON_VMWRITE : uint64_t = 25; 53 | pub const VMX_REASON_VMOFF : uint64_t = 26; 54 | pub const VMX_REASON_VMON : uint64_t = 27; 55 | pub const VMX_REASON_MOV_CR : uint64_t = 28; 56 | pub const VMX_REASON_MOV_DR : uint64_t = 29; 57 | pub const VMX_REASON_IO : uint64_t = 30; 58 | pub const VMX_REASON_RDMSR : uint64_t = 31; 59 | pub const VMX_REASON_WRMSR : uint64_t = 32; 60 | pub const VMX_REASON_VMENTRY_GUEST : uint64_t = 33; 61 | pub const VMX_REASON_VMENTRY_MSR : uint64_t = 34; 62 | pub const VMX_REASON_MWAIT : uint64_t = 36; 63 | pub const VMX_REASON_MTF : uint64_t = 37; 64 | pub const VMX_REASON_MONITOR : uint64_t = 39; 65 | pub const VMX_REASON_PAUSE : uint64_t = 40; 66 | pub const VMX_REASON_VMENTRY_MC : uint64_t = 41; 67 | pub const VMX_REASON_TPR_THRESHOLD : uint64_t = 43; 68 | pub const VMX_REASON_APIC_ACCESS : uint64_t = 44; 69 | pub const VMX_REASON_VIRTUALIZED_EOI : uint64_t = 45; 70 | pub const VMX_REASON_GDTR_IDTR : uint64_t = 46; 71 | pub const VMX_REASON_LDTR_TR : uint64_t = 47; 72 | pub const VMX_REASON_EPT_VIOLATION : uint64_t = 48; 73 | pub const VMX_REASON_EPT_MISCONFIG : uint64_t = 49; 74 | pub const VMX_REASON_EPT_INVEPT : uint64_t = 50; 75 | pub const VMX_REASON_RDTSCP : uint64_t = 51; 76 | pub const VMX_REASON_VMX_TIMER_EXPIRED : uint64_t = 52; 77 | pub const VMX_REASON_INVVPID : uint64_t = 53; 78 | pub const VMX_REASON_WBINVD : uint64_t = 54; 79 | pub const VMX_REASON_XSETBV : uint64_t = 55; 80 | pub const VMX_REASON_APIC_WRITE : uint64_t = 56; 81 | pub const VMX_REASON_RDRAND : uint64_t = 57; 82 | pub const VMX_REASON_INVPCID : uint64_t = 58; 83 | pub const VMX_REASON_VMFUNC : uint64_t = 59; 84 | pub const VMX_REASON_RDSEED : uint64_t = 61; 85 | pub const VMX_REASON_XSAVES : uint64_t = 63; 86 | pub const VMX_REASON_XRSTORS : uint64_t = 64; 87 | -------------------------------------------------------------------------------- /src/ffi.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2016 Saurav Sachidanand 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | //! Bindings to the Hypervisor Framework 24 | 25 | use libc::*; 26 | 27 | /// Hypervisor Framework return code 28 | pub type hv_return_t = uint32_t; 29 | 30 | // Hypervisor Framework return codes 31 | pub const HV_SUCCESS : hv_return_t = 0; 32 | pub const HV_ERROR : hv_return_t = 0xfae94001; 33 | pub const HV_BUSY : hv_return_t = 0xfae94002; 34 | pub const HV_BAD_ARGUMENT : hv_return_t = 0xfae94003; 35 | pub const HV_NO_RESOURCES : hv_return_t = 0xfae94005; 36 | pub const HV_NO_DEVICE : hv_return_t = 0xfae94006; 37 | pub const HV_UNSUPPORTED : hv_return_t = 0xfae9400f; 38 | 39 | /// Options for hv_vcpu_create() 40 | pub type hv_vm_options_t = uint64_t; 41 | pub const HV_VM_DEFAULT: hv_vm_options_t = 0 << 0; 42 | 43 | // Creating and Destroying VM Instances 44 | extern { 45 | /// Creates a VM instance for the current Mach task 46 | pub fn hv_vm_create(flags: hv_vm_options_t) -> hv_return_t; 47 | 48 | /// Destroys the VM instance associated with the current Mach task 49 | pub fn hv_vm_destroy() -> hv_return_t; 50 | } 51 | 52 | /// Type of a vCPU ID 53 | pub type hv_vcpuid_t = c_uint; 54 | 55 | // Option for hv_vcpu_create() 56 | pub const HV_VCPU_DEFAULT: uint64_t = 0; 57 | 58 | // Creating and Managing vCPU Instances 59 | extern { 60 | /// Creates a vCPU instance for the current thread 61 | pub fn hv_vcpu_create(vcpu: *mut hv_vcpuid_t, flags: hv_vm_options_t) -> hv_return_t; 62 | 63 | /// Executes a vCPU 64 | pub fn hv_vcpu_run(vcpu: hv_vcpuid_t) -> hv_return_t; 65 | 66 | /// Forces an immediate VMEXIT of a set of vCPUs of the VM 67 | pub fn hv_vcpu_interrupt(vcpu: *const hv_vcpuid_t, vcpu_count: c_uint) -> hv_return_t; 68 | 69 | /// Returns the cumulative execution time of a vCPU in nanoseconds 70 | pub fn hv_vcpu_get_exec_time(vcpu: hv_vcpuid_t, time: *mut uint64_t) -> hv_return_t; 71 | 72 | /// Forces flushing of cached vCPU state 73 | pub fn hv_vcpu_flush(vcpu: hv_vcpuid_t) -> hv_return_t; 74 | 75 | /// Invalidates the TLB of a vCPU 76 | pub fn hv_vcpu_invalidate_tlb(vcpu: hv_vcpuid_t) -> hv_return_t; 77 | 78 | /// Destroys the vCPU instance associated with the current thread 79 | pub fn hv_vcpu_destroy(vcpu: hv_vcpuid_t) -> hv_return_t; 80 | } 81 | 82 | // Accessing Registers 83 | extern { 84 | /// Returns the current value of an architectural x86 register 85 | /// of a vCPU 86 | pub fn hv_vcpu_read_register(vcpu: hv_vcpuid_t, reg: super::x86Reg, value: *mut uint64_t) -> hv_return_t; 87 | 88 | /// Sets the value of an architectural x86 register of a vCPU 89 | pub fn hv_vcpu_write_register(vcpu: hv_vcpuid_t, reg: super::x86Reg, value: uint64_t) -> hv_return_t; 90 | } 91 | 92 | // Accessing Floating Point (FP) State 93 | extern { 94 | /// Returns the current architectural x86 floating point and 95 | /// SIMD state of a vCPU 96 | pub fn hv_vcpu_read_fpstate(vcpu: hv_vcpuid_t, buffer: *mut c_void, size: size_t) -> hv_return_t; 97 | 98 | /// Sets the architectural x86 floating point and SIMD state of 99 | /// a vCPU 100 | pub fn hv_vcpu_write_fpstate(vcpu: hv_vcpuid_t, buffer: *const c_void, size: size_t) -> hv_return_t; 101 | } 102 | 103 | // Accessing Machine Specific Registers (MSRs) 104 | extern { 105 | /// Enables an MSR to be used natively by the VM 106 | pub fn hv_vcpu_enable_native_msr(vcpu: hv_vcpuid_t, msr: uint32_t, enable: bool) -> hv_return_t; 107 | 108 | /// Returns the current value of an MSR of a vCPU 109 | pub fn hv_vcpu_read_msr(vcpu: hv_vcpuid_t, msr: uint32_t, value: *mut uint64_t) -> hv_return_t; 110 | 111 | /// Set the value of an MSR of a vCPU 112 | pub fn hv_vcpu_write_msr(vcpu: hv_vcpuid_t, msr: uint32_t, value: *const uint64_t) -> hv_return_t; 113 | } 114 | 115 | // Managing Timestamp-Counters (TSC) 116 | extern { 117 | /// Synchronizes guest Timestamp-Counters (TSC) across all vCPUs 118 | pub fn hv_vm_sync_tsc(tsc: uint64_t) -> hv_return_t; 119 | } 120 | 121 | /// Type of a user virtual address 122 | pub type hv_uvaddr_t = *const c_void; 123 | 124 | /// Guest physical memory region permissions for hv_vm_map() 125 | /// and hv_vm_protect() 126 | pub type hv_memory_flags_t = uint64_t; 127 | 128 | /// Type of a guest physical address 129 | pub type hv_gpaddr_t = uint64_t; 130 | 131 | // Guest physical memory region permissions for hv_vm_map() and hv_vm_protect() 132 | pub const HV_MEMORY_READ : hv_memory_flags_t = 1 << 0; 133 | pub const HV_MEMORY_WRITE: hv_memory_flags_t = 1 << 1; 134 | pub const HV_MEMORY_EXEC : hv_memory_flags_t = 1 << 2; 135 | 136 | // Managing Memory Regions 137 | extern { 138 | /// Maps a region in the virtual address space of the current 139 | /// task into the guest physical address space of the VM 140 | pub fn hv_vm_map(uva: hv_uvaddr_t, gpa: hv_gpaddr_t, size: size_t, flags: hv_memory_flags_t) -> hv_return_t; 141 | 142 | /// Unmaps a region in the guest physical address space of the VM 143 | pub fn hv_vm_unmap(gpa: hv_gpaddr_t, size: size_t) -> hv_return_t; 144 | 145 | /// Modifies the permissions of a region in the guest physical 146 | /// address space of the VM 147 | pub fn hv_vm_protect(gpa: hv_gpaddr_t, size: size_t, flags: hv_memory_flags_t) -> hv_return_t; 148 | } 149 | 150 | // Managing Virtual Machine Control Structure (VMCS) 151 | extern { 152 | /// Returns the current value of a VMCS field of a vCPU 153 | pub fn hv_vmx_vcpu_read_vmcs(vcpu: hv_vcpuid_t, field: uint32_t, value: *mut uint64_t) -> hv_return_t; 154 | 155 | /// Sets the value of a VMCS field of a vCPU 156 | pub fn hv_vmx_vcpu_write_vmcs(vcpu: hv_vcpuid_t, field: uint32_t, value: uint64_t) -> hv_return_t; 157 | 158 | /// Returns the VMX capabilities of the host processor 159 | pub fn hv_vmx_read_capability(field: super::VMXCap, value: *mut uint64_t) -> hv_return_t; 160 | 161 | /// Sets the address of the guest APIC for a vCPU in the 162 | /// guest physical address space of the VM 163 | pub fn hv_vmx_vcpu_set_apic_address(vcpu: hv_vcpuid_t, gpa: hv_gpaddr_t) -> hv_return_t; 164 | } 165 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2016 Saurav Sachidanand 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | /*! 24 | This is a Rust library that taps into functionality that enables 25 | hardware-accelerated execution of virtual machines on OS X. 26 | 27 | It binds to the `Hypervisor` framework on OS X, and exposes a safe Rust 28 | interface through the `hypervisor` module, and an unsafe foreign function 29 | interface through the `hypervisor::ffi` module. 30 | 31 | To use this library, you need 32 | 33 | * OS X Yosemite (10.10), or newer 34 | 35 | * an Intel processor with the VT-x feature set that includes Extended Page 36 | Tables (EPT) and Unrestricted Mode. To verify this, run and expect the following 37 | in your Terminal: 38 | 39 | ```shell 40 | $ sysctl kern.hv_support 41 | kern.hv_support: 1 42 | ``` 43 | !*/ 44 | 45 | extern crate libc; 46 | extern crate core; 47 | 48 | #[allow(non_camel_case_types)] 49 | pub mod ffi; 50 | pub mod consts; 51 | 52 | use self::core::fmt; 53 | use libc::*; 54 | 55 | use self::ffi::*; 56 | 57 | /// Error returned after every call 58 | pub enum Error { 59 | /// Success 60 | Success, 61 | /// Error 62 | Error, 63 | /// Busy 64 | Busy, 65 | /// Bad argument 66 | BadArg, 67 | /// No resources 68 | NoRes, 69 | /// No device 70 | NoDev, 71 | /// Unsupported 72 | Unsupp 73 | } 74 | 75 | impl fmt::Debug for Error { 76 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 77 | match *self { 78 | Error::Success => write!(f, "Success"), 79 | Error::Error => write!(f, "Error"), 80 | Error::Busy => write!(f, "Busy"), 81 | Error::BadArg => write!(f, "Bad argument"), 82 | Error::NoRes => write!(f, "No resources"), 83 | Error::NoDev => write!(f, "No device"), 84 | Error::Unsupp => write!(f, "Unsupported"), 85 | } 86 | } 87 | } 88 | 89 | // Returns an Error for a hv_return_t 90 | fn match_error_code(code: hv_return_t) -> Error { 91 | match code { 92 | HV_SUCCESS => Error::Success, 93 | HV_BUSY => Error::Busy, 94 | HV_BAD_ARGUMENT => Error::BadArg, 95 | HV_NO_RESOURCES => Error::NoRes, 96 | HV_NO_DEVICE => Error::NoDev, 97 | HV_UNSUPPORTED => Error::Unsupp, 98 | _ => Error::Error 99 | } 100 | } 101 | 102 | /// Creates a VM instance for the current Mach task 103 | pub fn create_vm() -> Error { 104 | match_error_code(unsafe { 105 | hv_vm_create(HV_VM_DEFAULT) 106 | }) 107 | } 108 | 109 | /// Destroys the VM instance associated with the current Mach task 110 | pub fn destroy_vm() -> Error { 111 | match_error_code(unsafe { 112 | hv_vm_destroy() 113 | }) 114 | } 115 | 116 | /// Guest physical memory region permissions 117 | pub enum MemPerm { 118 | /// Read 119 | Read, 120 | /// Write (implies read) 121 | Write, 122 | /// Execute 123 | Exec, 124 | /// Execute and write (implies read) 125 | ExecAndWrite, 126 | /// Execute and read 127 | ExecAndRead 128 | } 129 | 130 | #[allow(non_snake_case)] 131 | #[inline(always)] 132 | fn match_MemPerm(mem_perm: &MemPerm) -> uint64_t { 133 | match mem_perm { 134 | &MemPerm::Read => HV_MEMORY_READ, 135 | &MemPerm::Write => HV_MEMORY_WRITE | HV_MEMORY_READ, 136 | &MemPerm::Exec => HV_MEMORY_EXEC, 137 | &MemPerm::ExecAndWrite => HV_MEMORY_EXEC | HV_MEMORY_WRITE | HV_MEMORY_READ, 138 | &MemPerm::ExecAndRead => HV_MEMORY_EXEC | HV_MEMORY_READ, 139 | } 140 | } 141 | 142 | /// Maps a region in the virtual address space of the current Mach task into the guest physical 143 | /// address space of the virutal machine 144 | pub fn map_mem(mem: &[u8], gpa: u64, mem_perm: &MemPerm) -> Error { 145 | match_error_code(unsafe { 146 | hv_vm_map( 147 | mem.as_ptr() as *const c_void, gpa as hv_gpaddr_t, mem.len() as size_t, 148 | match_MemPerm(mem_perm) 149 | ) 150 | }) 151 | } 152 | 153 | /// Unmaps a region in the guest physical address space of the virutal machine 154 | pub fn unmap_mem(gpa: u64, size: usize) -> Error { 155 | match_error_code(unsafe { 156 | hv_vm_unmap(gpa as hv_gpaddr_t, size as size_t) 157 | }) 158 | } 159 | 160 | /// Modifies the permissions of a region in the guest physical address space of the virtual 161 | /// machine 162 | pub fn protect_mem(gpa: u64, size: usize, mem_perm: &MemPerm) -> Error { 163 | match_error_code(unsafe { 164 | hv_vm_protect(gpa as hv_gpaddr_t, size as size_t, match_MemPerm(mem_perm)) 165 | }) 166 | } 167 | 168 | /// Synchronizes the guest Timestamp-Counters (TSC) across all vCPUs 169 | /// 170 | /// * `tsc` Guest TSC value 171 | pub fn sync_tsc(tsc: u64) -> Error { 172 | match_error_code(unsafe { 173 | hv_vm_sync_tsc(tsc as uint64_t) 174 | }) 175 | } 176 | 177 | /// Forces an immediate VMEXIT of a set of vCPUs 178 | /// 179 | /// * `vcpu_ids` Array of vCPU IDs 180 | pub fn interrupt_vcpus(vcpu_ids: &[u32]) -> Error { 181 | match_error_code(unsafe { 182 | hv_vcpu_interrupt(vcpu_ids.as_ptr(), vcpu_ids.len() as c_uint) 183 | }) 184 | } 185 | 186 | /// Virtual CPU 187 | #[allow(non_camel_case_types)] 188 | pub struct vCPU { 189 | /// Virtual CPU ID 190 | pub id: u32 191 | } 192 | 193 | /// x86 architectural register 194 | #[allow(non_camel_case_types)] 195 | #[derive(Clone)] 196 | #[repr(C)] 197 | pub enum x86Reg { 198 | RIP, 199 | RFLAGS, 200 | RAX, 201 | RCX, 202 | RDX, 203 | RBX, 204 | RSI, 205 | RDI, 206 | RSP, 207 | RBP, 208 | R8, 209 | R9, 210 | R10, 211 | R11, 212 | R12, 213 | R13, 214 | R14, 215 | R15, 216 | CS, 217 | SS, 218 | DS, 219 | ES, 220 | FS, 221 | GS, 222 | IDT_BASE, 223 | IDT_LIMIT, 224 | GDT_BASE, 225 | GDT_LIMIT, 226 | LDTR, 227 | LDT_BASE, 228 | LDT_LIMIT, 229 | LDT_AR, 230 | TR, 231 | TSS_BASE, 232 | TSS_LIMIT, 233 | TSS_AR, 234 | CR0, 235 | CR1, 236 | CR2, 237 | CR3, 238 | CR4, 239 | DR0, 240 | DR1, 241 | DR2, 242 | DR3, 243 | DR4, 244 | DR5, 245 | DR6, 246 | DR7, 247 | TPR, 248 | XCR0, 249 | REGISTERS_MAX, 250 | } 251 | 252 | impl vCPU { 253 | 254 | /// Creates a vCPU instance for the current thread 255 | pub fn new() -> Result { 256 | let mut vcpuid: hv_vcpuid_t = 0; 257 | 258 | let error = match_error_code(unsafe { 259 | hv_vcpu_create(&mut vcpuid, HV_VCPU_DEFAULT) 260 | }); 261 | 262 | match error { 263 | Error::Success => Ok(vCPU { 264 | id: vcpuid as u32 265 | }), 266 | _ => Err(error) 267 | } 268 | } 269 | 270 | /// Destroys the vCPU instance associated with the current thread 271 | pub fn destroy(&self) -> Error { 272 | match_error_code(unsafe { 273 | hv_vcpu_destroy(self.id as hv_vcpuid_t) 274 | }) 275 | } 276 | 277 | /// Executes the vCPU 278 | pub fn run(&self) -> Error { 279 | match_error_code(unsafe { 280 | hv_vcpu_run(self.id as hv_vcpuid_t) 281 | }) 282 | } 283 | 284 | /// Forces an immediate VMEXIT of the vCPU 285 | pub fn interrupt(&self) -> Error { 286 | match_error_code(unsafe { 287 | hv_vcpu_interrupt(&(self.id), 1 as c_uint) 288 | }) 289 | } 290 | 291 | /// Returns the cumulative execution time of the vCPU in nanoseconds 292 | pub fn exec_time(&self) -> Result { 293 | let mut exec_time: uint64_t = 0; 294 | 295 | let error = match_error_code(unsafe { 296 | hv_vcpu_get_exec_time(self.id, &mut exec_time) 297 | }); 298 | 299 | match error { 300 | Error::Success => Ok(exec_time as u64), 301 | _ => Err(error) 302 | } 303 | } 304 | 305 | /// Forces flushing of cached vCPU state 306 | pub fn flush(&self) -> Error { 307 | match_error_code(unsafe { 308 | hv_vcpu_flush(self.id as hv_vcpuid_t) 309 | }) 310 | } 311 | 312 | /// Invalidates the translation lookaside buffer (TLB) of the vCPU 313 | pub fn invalidate_tlb(&self) -> Error { 314 | match_error_code(unsafe { 315 | hv_vcpu_invalidate_tlb(self.id as hv_vcpuid_t) 316 | }) 317 | } 318 | 319 | /// Enables an MSR to be used natively by the VM 320 | pub fn enable_native_msr(&self, msr: u32, enable: bool) -> Error { 321 | match_error_code(unsafe { 322 | hv_vcpu_enable_native_msr(self.id as hv_vcpuid_t, msr as uint32_t, enable) 323 | }) 324 | } 325 | 326 | /// Returns the current value of an MSR of the vCPU 327 | pub fn read_msr(&self, msr: u32) -> Result { 328 | let mut value: uint64_t = 0; 329 | 330 | let error = match_error_code(unsafe { 331 | hv_vcpu_read_msr(self.id as hv_vcpuid_t, msr as uint32_t, &mut value) 332 | }); 333 | 334 | match error { 335 | Error::Success => Ok(value as u64), 336 | _ => Err(error) 337 | } 338 | } 339 | 340 | /// Set the value of an MSR of the vCPU 341 | pub fn write_msr(&self, msr: u32, value: u64) -> Error { 342 | match_error_code(unsafe { 343 | hv_vcpu_write_msr(self.id as hv_vcpuid_t, msr as uint32_t, &(value as uint64_t)) 344 | }) 345 | } 346 | 347 | /// Returns the current value of an architectural x86 register 348 | /// of the vCPU 349 | pub fn read_register(&self, reg: &x86Reg) -> Result { 350 | let mut value: uint64_t = 0; 351 | 352 | let error = match_error_code(unsafe { 353 | hv_vcpu_read_register(self.id as hv_vcpuid_t, (*reg).clone(), &mut value) 354 | }); 355 | 356 | match error { 357 | Error::Success => Ok(value as u64), 358 | _ => Err(error) 359 | } 360 | } 361 | 362 | /// Sets the value of an architectural x86 register of the vCPU 363 | pub fn write_register(&self, reg: &x86Reg, value: u64) -> Error { 364 | match_error_code(unsafe { 365 | hv_vcpu_write_register(self.id as hv_vcpuid_t, (*reg).clone(), value as uint64_t) 366 | }) 367 | } 368 | 369 | /// Returns the current value of a VMCS field of the vCPU 370 | pub fn read_vmcs(&self, field: u32) -> Result { 371 | let mut value: uint64_t = 0; 372 | 373 | let error = match_error_code(unsafe { 374 | hv_vmx_vcpu_read_vmcs(self.id as hv_vcpuid_t, field as uint32_t, &mut value) 375 | }); 376 | 377 | match error { 378 | Error::Success => Ok(value as u64), 379 | _ => Err(error) 380 | } 381 | } 382 | 383 | /// Sets the value of a VMCS field of the vCPU 384 | pub fn write_vmcs(&self, field: u32, value: u64) -> Error { 385 | match_error_code(unsafe { 386 | hv_vmx_vcpu_write_vmcs(self.id as hv_vcpuid_t, field as uint32_t, value as uint64_t) 387 | }) 388 | } 389 | 390 | /// Sets the address of the guest APIC for the vCPU in the 391 | /// guest physical address space of the VM 392 | pub fn set_apic_addr(&self, gpa: u64) -> Error { 393 | match_error_code(unsafe { 394 | hv_vmx_vcpu_set_apic_address(self.id as hv_vcpuid_t, gpa as uint64_t) 395 | }) 396 | } 397 | 398 | /// Reads the current architectural x86 floating point and SIMD state of the vCPU 399 | pub fn read_fpstate(&self, buffer: &mut [u8]) -> Error { 400 | match_error_code(unsafe { 401 | hv_vcpu_read_fpstate(self.id as hv_vcpuid_t, buffer.as_mut_ptr() as *mut c_void, 402 | buffer.len() as size_t) 403 | }) 404 | } 405 | 406 | /// Sets the architectural x86 floating point and SIMD state of the vCPU 407 | pub fn write_fpstate(&self, buffer: &[u8]) -> Error { 408 | match_error_code(unsafe { 409 | hv_vcpu_write_fpstate(self.id as hv_vcpuid_t, buffer.as_ptr() as *const c_void, 410 | buffer.len() as size_t) 411 | }) 412 | } 413 | 414 | } 415 | 416 | impl fmt::Debug for vCPU { 417 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 418 | write!(f, "vCPU ID: {}", (*self).id) 419 | } 420 | } 421 | 422 | /// VMX cabability 423 | #[allow(non_camel_case_types)] 424 | #[derive(Clone)] 425 | #[repr(C)] 426 | pub enum VMXCap { 427 | /// Pin-based VMX capabilities 428 | PINBASED = 0, 429 | /// Primary proc-based VMX capabilities 430 | PROCBASED = 1, 431 | /// Secondary proc-based VMX capabilities 432 | PROCBASED2 = 2, 433 | /// VM-entry VMX capabilities 434 | ENTRY = 3, 435 | /// VM-exit VMX capabilities 436 | EXIT = 4, 437 | /// VMX preemption timer frequency 438 | PREEMPTION_TIMER = 32, 439 | } 440 | 441 | /// Reads a VMX capability of the host processor 442 | pub fn read_vmx_cap(vmx_cap: &VMXCap) -> Result { 443 | let mut value: uint64_t = 0; 444 | 445 | let error = match_error_code(unsafe { 446 | hv_vmx_read_capability((*vmx_cap).clone(), &mut value) 447 | }); 448 | 449 | match error { 450 | Error::Success => Ok(value as u64), 451 | _ => Err(error) 452 | } 453 | } 454 | --------------------------------------------------------------------------------