xhypervisor/x86_64/
mod.rs

1pub mod consts;
2pub mod ffi;
3
4use self::consts::*;
5use self::ffi::*;
6use crate::x86_64::vmcs::*;
7use crate::{match_MemPerm, match_error_code, Error, MemPerm};
8use core::fmt;
9use libc::*;
10
11/// Creates a VM instance for the current Mach task
12pub fn create_vm() -> Result<(), Error> {
13	match_error_code(unsafe { hv_vm_create(HV_VM_DEFAULT) })
14}
15
16/// Maps a region in the virtual address space of the current task into the guest physical
17/// address space of the viurtal machine
18pub fn map_mem(mem: &[u8], gpa: u64, mem_perm: MemPerm) -> Result<(), Error> {
19	match_error_code(unsafe {
20		hv_vm_map(
21			mem.as_ptr() as *const c_void,
22			gpa as hv_gpaddr_t,
23			mem.len() as size_t,
24			match_MemPerm(mem_perm),
25		)
26	})
27}
28
29/// Modifies the permissions of a region in the guest physical address space of the virtual
30/// machine
31pub fn protect_mem(gpa: u64, size: usize, mem_perm: MemPerm) -> Result<(), Error> {
32	match_error_code(unsafe {
33		hv_vm_protect(gpa as hv_gpaddr_t, size as size_t, match_MemPerm(mem_perm))
34	})
35}
36
37/// Unmaps a region in the guest physical address space of the virutal machine
38pub fn unmap_mem(gpa: u64, size: usize) -> Result<(), Error> {
39	match_error_code(unsafe { hv_vm_unmap(gpa as hv_gpaddr_t, size as size_t) })
40}
41
42/// Synchronizes the guest Timestamp-Counters (TSC) across all VirtualCpus
43///
44/// * `tsc` Guest TSC value
45pub fn sync_tsc(tsc: u64) -> Result<(), Error> {
46	match_error_code(unsafe { hv_vm_sync_tsc(tsc) })
47}
48
49/// Forces an immediate VMEXIT of a set of VirtualCpus
50///
51/// * `VirtualCpu_ids` Array of VirtualCpu IDs
52pub fn interrupt_vcpus(vcpu_ids: &[u32]) -> Result<(), Error> {
53	match_error_code(unsafe { hv_vcpu_interrupt(vcpu_ids.as_ptr(), vcpu_ids.len() as c_uint) })
54}
55
56/// Virtual CPU
57pub struct VirtualCpu {
58	/// Virtual CPU Id
59	id: u32,
60	/// Virtual CPU handle
61	vcpu_handle: hv_vcpuid_t,
62}
63
64/// x86 architectural register
65#[derive(Clone)]
66#[repr(C)]
67pub enum Register {
68	RIP,
69	RFLAGS,
70	RAX,
71	RCX,
72	RDX,
73	RBX,
74	RSI,
75	RDI,
76	RSP,
77	RBP,
78	R8,
79	R9,
80	R10,
81	R11,
82	R12,
83	R13,
84	R14,
85	R15,
86	CS,
87	SS,
88	DS,
89	ES,
90	FS,
91	GS,
92	IDT_BASE,
93	IDT_LIMIT,
94	GDT_BASE,
95	GDT_LIMIT,
96	LDTR,
97	LDT_BASE,
98	LDT_LIMIT,
99	LDT_AR,
100	TR,
101	TSS_BASE,
102	TSS_LIMIT,
103	TSS_AR,
104	CR0,
105	CR1,
106	CR2,
107	CR3,
108	CR4,
109	DR0,
110	DR1,
111	DR2,
112	DR3,
113	DR4,
114	DR5,
115	DR6,
116	DR7,
117	TPR,
118	XCR0,
119	REGISTERS_MAX,
120}
121
122impl VirtualCpu {
123	/// Creates a VirtualCpu instance for the current thread
124	///
125	/// `id` represents the internal numbering of the processor.
126	pub fn new(id: u32) -> Result<VirtualCpu, Error> {
127		let mut vcpu_handle: hv_vcpuid_t = 0;
128
129		match_error_code(unsafe { hv_vcpu_create(&mut vcpu_handle, HV_VCPU_DEFAULT) })?;
130
131		Ok(VirtualCpu { id, vcpu_handle })
132	}
133
134	pub fn get_id(&self) -> u32 {
135		self.id
136	}
137
138	pub fn get_handle(&self) -> hv_vcpuid_t {
139		self.vcpu_handle
140	}
141
142	/// Forces an immediate VMEXIT of the VirtualCpu
143	pub fn interrupt(&self) -> Result<(), Error> {
144		match_error_code(unsafe { hv_vcpu_interrupt(&(self.vcpu_handle), 1 as c_uint) })
145	}
146
147	/// Returns the cumulative execution time of the VirtualCpu in nanoseconds
148	pub fn exec_time(&self) -> Result<u64, Error> {
149		let mut exec_time: u64 = 0;
150
151		let _error =
152			match_error_code(unsafe { hv_vcpu_get_exec_time(self.vcpu_handle, &mut exec_time) })?;
153
154		Ok(exec_time)
155	}
156
157	/// Forces flushing of cached VirtualCpu state
158	pub fn flush(&self) -> Result<(), Error> {
159		match_error_code(unsafe { hv_vcpu_flush(self.vcpu_handle) })
160	}
161
162	/// Invalidates the translation lookaside buffer (TLB) of the VirtualCpu
163	pub fn invalidate_tlb(&self) -> Result<(), Error> {
164		match_error_code(unsafe { hv_vcpu_invalidate_tlb(self.vcpu_handle) })
165	}
166
167	/// Enables an MSR to be used natively by the VM
168	pub fn enable_native_msr(&self, msr: u32, enable: bool) -> Result<(), Error> {
169		match_error_code(unsafe { hv_vcpu_enable_native_msr(self.vcpu_handle, msr, enable) })
170	}
171
172	/// Returns the current value of an MSR of the VirtualCpu
173	pub fn read_msr(&self, msr: u32) -> Result<u64, Error> {
174		let mut value: u64 = 0;
175
176		let _error =
177			match_error_code(unsafe { hv_vcpu_read_msr(self.vcpu_handle, msr, &mut value) })?;
178
179		Ok(value)
180	}
181
182	/// Set the value of an MSR of the VirtualCpu
183	pub fn write_msr(&self, msr: u32, value: u64) -> Result<(), Error> {
184		match_error_code(unsafe { hv_vcpu_write_msr(self.vcpu_handle, msr, &(value)) })
185	}
186
187	/// Returns the current value of an architectural x86 register
188	/// of the VirtualCpu
189	pub fn read_register(&self, reg: &Register) -> Result<u64, Error> {
190		let mut value: u64 = 0;
191
192		match_error_code(unsafe {
193			hv_vcpu_read_register(self.vcpu_handle, (*reg).clone(), &mut value)
194		})?;
195
196		Ok(value)
197	}
198
199	/// Sets the value of an architectural x86 register of the VirtualCpu
200	pub fn write_register(&self, reg: &Register, value: u64) -> Result<(), Error> {
201		match_error_code(unsafe { hv_vcpu_write_register(self.vcpu_handle, (*reg).clone(), value) })
202	}
203
204	/// Returns the current value of a VMCS field of the VirtualCpu
205	pub fn read_vmcs(&self, field: u32) -> Result<u64, Error> {
206		let mut value: u64 = 0;
207
208		match_error_code(unsafe { hv_vmx_vcpu_read_vmcs(self.vcpu_handle, field, &mut value) })?;
209
210		Ok(value)
211	}
212
213	/// Sets the value of a VMCS field of the VirtualCpu
214	pub fn write_vmcs(&self, field: u32, value: u64) -> Result<(), Error> {
215		match_error_code(unsafe { hv_vmx_vcpu_write_vmcs(self.vcpu_handle, field, value) })
216	}
217
218	/// Sets the address of the guest APIC for the VirtualCpu in the
219	/// guest physical address space of the VM
220	pub fn set_apic_addr(&self, gpa: u64) -> Result<(), Error> {
221		match_error_code(unsafe { hv_vmx_vcpu_set_apic_address(self.vcpu_handle, gpa) })
222	}
223
224	/// Reads the current architectural x86 floating point and SIMD state of the VirtualCpu
225	pub fn read_fpstate(&self, buffer: &mut [u8]) -> Result<(), Error> {
226		match_error_code(unsafe {
227			hv_vcpu_read_fpstate(
228				self.vcpu_handle,
229				buffer.as_mut_ptr() as *mut c_void,
230				buffer.len() as size_t,
231			)
232		})
233	}
234
235	/// Sets the architectural x86 floating point and SIMD state of the VirtualCpu
236	pub fn write_fpstate(&self, buffer: &[u8]) -> Result<(), Error> {
237		match_error_code(unsafe {
238			hv_vcpu_write_fpstate(
239				self.vcpu_handle,
240				buffer.as_ptr() as *const c_void,
241				buffer.len() as size_t,
242			)
243		})
244	}
245}
246
247impl fmt::Debug for VirtualCpu {
248	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
249		write!(f, "\nDump state of CPU {}", self.id)?;
250		write!(f, "VMCS:")?;
251		write!(f, "-----")?;
252		write!(
253			f,
254			"CR0: mask {:016x}  shadow {:016x}",
255			self.read_vmcs(VMCS_CTRL_CR0_MASK).unwrap(),
256			self.read_vmcs(VMCS_CTRL_CR0_SHADOW).unwrap()
257		)?;
258		write!(
259			f,
260			"CR4: mask {:016x}  shadow {:016x}",
261			self.read_vmcs(VMCS_CTRL_CR4_MASK).unwrap(),
262			self.read_vmcs(VMCS_CTRL_CR4_SHADOW).unwrap()
263		)?;
264		write!(
265			f,
266			"Pinbased: {:016x}\n1st:      {:016x}\n2nd:      {:016x}",
267			self.read_vmcs(VMCS_CTRL_PIN_BASED).unwrap(),
268			self.read_vmcs(VMCS_CTRL_CPU_BASED).unwrap(),
269			self.read_vmcs(VMCS_CTRL_CPU_BASED2).unwrap()
270		)?;
271		write!(
272			f,
273			"Entry:    {:016x}\nExit:     {:016x}",
274			self.read_vmcs(VMCS_CTRL_VMENTRY_CONTROLS).unwrap(),
275			self.read_vmcs(VMCS_CTRL_VMEXIT_CONTROLS).unwrap()
276		)?;
277
278		write!(f, "\nRegisters:")?;
279		write!(f, "----------")?;
280
281		let rip = self.read_register(&Register::RIP).unwrap();
282		let rflags = self.read_register(&Register::RFLAGS).unwrap();
283		let rsp = self.read_register(&Register::RSP).unwrap();
284		let rbp = self.read_register(&Register::RBP).unwrap();
285		let rax = self.read_register(&Register::RAX).unwrap();
286		let rbx = self.read_register(&Register::RBX).unwrap();
287		let rcx = self.read_register(&Register::RCX).unwrap();
288		let rdx = self.read_register(&Register::RDX).unwrap();
289		let rsi = self.read_register(&Register::RSI).unwrap();
290		let rdi = self.read_register(&Register::RDI).unwrap();
291		let r8 = self.read_register(&Register::R8).unwrap();
292		let r9 = self.read_register(&Register::R9).unwrap();
293		let r10 = self.read_register(&Register::R10).unwrap();
294		let r11 = self.read_register(&Register::R11).unwrap();
295		let r12 = self.read_register(&Register::R12).unwrap();
296		let r13 = self.read_register(&Register::R13).unwrap();
297		let r14 = self.read_register(&Register::R14).unwrap();
298		let r15 = self.read_register(&Register::R15).unwrap();
299
300		write!(
301			f,
302			"rip: {rip:016x}   rsp: {rsp:016x} flags: {rflags:016x}\n\
303			rax: {rax:016x}   rbx: {rbx:016x}   rcx: {rcx:016x}\n\
304			rdx: {rdx:016x}   rsi: {rsi:016x}   rdi: {rdi:016x}\n\
305			rbp: {rbp:016x}    r8: {r8:016x}    r9: {r9:016x}\n\
306			r10: {r10:016x}   r11: {r11:016x}   r12: {r12:016x}\n\
307			r13: {r13:016x}   r14: {r14:016x}   r15: {r15:016x}\n"
308		)?;
309
310		let cr0 = self.read_register(&Register::CR0).unwrap();
311		let cr2 = self.read_register(&Register::CR2).unwrap();
312		let cr3 = self.read_register(&Register::CR3).unwrap();
313		let cr4 = self.read_register(&Register::CR4).unwrap();
314		let efer = self.read_vmcs(VMCS_GUEST_IA32_EFER).unwrap();
315
316		write!(f,
317			"cr0: {cr0:016x}   cr2: {cr2:016x}   cr3: {cr3:016x}\ncr4: {cr4:016x}  efer: {efer:016x}"
318		)?;
319
320		write!(f, "\nSegment registers:")?;
321		write!(f, "------------------")?;
322		write!(
323			f,
324			"register  selector  base              limit     type  p dpl db s l g avl"
325		)?;
326
327		let cs = self.read_register(&Register::CS).unwrap();
328		let ds = self.read_register(&Register::DS).unwrap();
329		let es = self.read_register(&Register::ES).unwrap();
330		let ss = self.read_register(&Register::SS).unwrap();
331		let fs = self.read_register(&Register::FS).unwrap();
332		let gs = self.read_register(&Register::GS).unwrap();
333		let tr = self.read_register(&Register::TR).unwrap();
334		let ldtr = self.read_register(&Register::LDTR).unwrap();
335
336		let cs_limit = self.read_vmcs(VMCS_GUEST_CS_LIMIT).unwrap();
337		let cs_base = self.read_vmcs(VMCS_GUEST_CS_BASE).unwrap();
338		let cs_ar = self.read_vmcs(VMCS_GUEST_CS_AR).unwrap();
339		let ss_limit = self.read_vmcs(VMCS_GUEST_SS_LIMIT).unwrap();
340		let ss_base = self.read_vmcs(VMCS_GUEST_SS_BASE).unwrap();
341		let ss_ar = self.read_vmcs(VMCS_GUEST_SS_AR).unwrap();
342		let ds_limit = self.read_vmcs(VMCS_GUEST_DS_LIMIT).unwrap();
343		let ds_base = self.read_vmcs(VMCS_GUEST_DS_BASE).unwrap();
344		let ds_ar = self.read_vmcs(VMCS_GUEST_DS_AR).unwrap();
345		let es_limit = self.read_vmcs(VMCS_GUEST_ES_LIMIT).unwrap();
346		let es_base = self.read_vmcs(VMCS_GUEST_ES_BASE).unwrap();
347		let es_ar = self.read_vmcs(VMCS_GUEST_ES_AR).unwrap();
348		let fs_limit = self.read_vmcs(VMCS_GUEST_FS_LIMIT).unwrap();
349		let fs_base = self.read_vmcs(VMCS_GUEST_FS_BASE).unwrap();
350		let fs_ar = self.read_vmcs(VMCS_GUEST_FS_AR).unwrap();
351		let gs_limit = self.read_vmcs(VMCS_GUEST_GS_LIMIT).unwrap();
352		let gs_base = self.read_vmcs(VMCS_GUEST_GS_BASE).unwrap();
353		let gs_ar = self.read_vmcs(VMCS_GUEST_GS_AR).unwrap();
354		let tr_limit = self.read_vmcs(VMCS_GUEST_TR_LIMIT).unwrap();
355		let tr_base = self.read_vmcs(VMCS_GUEST_TR_BASE).unwrap();
356		let tr_ar = self.read_vmcs(VMCS_GUEST_TR_AR).unwrap();
357		let ldtr_limit = self.read_vmcs(VMCS_GUEST_LDTR_LIMIT).unwrap();
358		let ldtr_base = self.read_vmcs(VMCS_GUEST_LDTR_BASE).unwrap();
359		let ldtr_ar = self.read_vmcs(VMCS_GUEST_LDTR_AR).unwrap();
360
361		/*
362		 * Format of Access Rights
363		 * -----------------------
364		 * 3-0 : Segment type
365		 * 4   : S — Descriptor type (0 = system; 1 = code or data)
366		 * 6-5 : DPL — Descriptor privilege level
367		 * 7   : P — Segment present
368		 * 11-8: Reserved
369		 * 12  : AVL — Available for use by system software
370		 * 13  : L — 64-bit mode active (for CS only)
371		 * 14  : D/B — Default operation size (0 = 16-bit segment; 1 = 32-bit segment)
372		 * 15  : G — Granularity
373		 * 16  : Segment unusable (0 = usable; 1 = unusable)
374		 *
375		 * Output sequence: type p dpl db s l g avl
376		 */
377		write!(f, "cs        {:04x}      {:016x}  {:08x}  {:02x}    {:x} {:x}   {:x}  {:x} {:x} {:x} {:x}",
378			cs, cs_base, cs_limit, (cs_ar) & 0xf, (cs_ar >> 7) & 0x1, (cs_ar >> 5) & 0x3, (cs_ar >> 14) & 0x1,
379			(cs_ar >> 4) & 0x1, (cs_ar >> 13) & 0x1, (cs_ar >> 15) & 0x1, (cs_ar >> 12) & 1)?;
380		write!(f, "ss        {:04x}      {:016x}  {:08x}  {:02x}    {:x} {:x}   {:x}  {:x} {:x} {:x} {:x}",
381			ss, ss_base, ss_limit, (ss_ar) & 0xf, (ss_ar >> 7) & 0x1, (ss_ar >> 5) & 0x3, (ss_ar >> 14) & 0x1,
382			(ss_ar >> 4) & 0x1, (ss_ar >> 13) & 0x1, (ss_ar >> 15) & 0x1, (ss_ar >> 12) & 1)?;
383		write!(f, "ds        {:04x}      {:016x}  {:08x}  {:02x}    {:x} {:x}   {:x}  {:x} {:x} {:x} {:x}",
384			ds, ds_base, ds_limit, (ds_ar) & 0xf, (ds_ar >> 7) & 0x1, (ds_ar >> 5) & 0x3, (ds_ar >> 14) & 0x1,
385			(ds_ar >> 4) & 0x1, (ds_ar >> 13) & 0x1, (ds_ar >> 15) & 0x1, (ds_ar >> 12) & 1)?;
386		write!(f, "es        {:04x}      {:016x}  {:08x}  {:02x}    {:x} {:x}   {:x}  {:x} {:x} {:x} {:x}",
387			es, es_base, es_limit, (es_ar) & 0xf, (es_ar >> 7) & 0x1, (es_ar >> 5) & 0x3, (es_ar >> 14) & 0x1,
388			(es_ar >> 4) & 0x1, (es_ar >> 13) & 0x1, (es_ar >> 15) & 0x1, (es_ar >> 12) & 1)?;
389		write!(f, "fs        {:04x}      {:016x}  {:08x}  {:02x}    {:x} {:x}   {:x}  {:x} {:x} {:x} {:x}",
390			fs, fs_base, fs_limit, (fs_ar) & 0xf, (fs_ar >> 7) & 0x1, (fs_ar >> 5) & 0x3, (fs_ar >> 14) & 0x1,
391			(fs_ar >> 4) & 0x1, (fs_ar >> 13) & 0x1, (fs_ar >> 15) & 0x1, (fs_ar >> 12) & 1)?;
392		write!(f, "gs        {:04x}      {:016x}  {:08x}  {:02x}    {:x} {:x}   {:x}  {:x} {:x} {:x} {:x}",
393			gs, gs_base, gs_limit, (gs_ar) & 0xf, (gs_ar >> 7) & 0x1, (gs_ar >> 5) & 0x3, (gs_ar >> 14) & 0x1,
394			(gs_ar >> 4) & 0x1, (gs_ar >> 13) & 0x1, (gs_ar >> 15) & 0x1, (gs_ar >> 12) & 1)?;
395		write!(f, "tr        {:04x}      {:016x}  {:08x}  {:02x}    {:x} {:x}   {:x}  {:x} {:x} {:x} {:x}",
396			tr, tr_base, tr_limit, (tr_ar) & 0xf, (tr_ar >> 7) & 0x1, (tr_ar >> 5) & 0x3, (tr_ar >> 14) & 0x1,
397			(tr_ar >> 4) & 0x1, (tr_ar >> 13) & 0x1, (tr_ar >> 15) & 0x1, (tr_ar >> 12) & 1)?;
398		write!(f, "ldt       {:04x}      {:016x}  {:08x}  {:02x}    {:x} {:x}   {:x}  {:x} {:x} {:x} {:x}",
399			ldtr, ldtr_base, ldtr_limit, (ldtr_ar) & 0xf, (ldtr_ar >> 7) & 0x1, (ldtr_ar >> 5) & 0x3, (ldtr_ar >> 14) & 0x1,
400			(ldtr_ar >> 4) & 0x1, (ldtr_ar >> 13) & 0x1, (ldtr_ar >> 15) & 0x1, (ldtr_ar >> 12) & 1)?;
401
402		let gdt_base = self.read_vmcs(VMCS_GUEST_GDTR_BASE).unwrap();
403		let gdt_limit = self.read_vmcs(VMCS_GUEST_GDTR_LIMIT).unwrap();
404		write!(f, "gdt                 {gdt_base:016x}  {gdt_limit:08x}")?;
405		let idt_base = self.read_vmcs(VMCS_GUEST_IDTR_BASE).unwrap();
406		let idt_limit = self.read_vmcs(VMCS_GUEST_IDTR_LIMIT).unwrap();
407		write!(f, "idt                 {idt_base:016x}  {idt_limit:08x}")?;
408		write!(
409			f,
410			"VMCS link pointer   {:016x}",
411			self.read_vmcs(VMCS_GUEST_LINK_POINTER).unwrap()
412		)
413	}
414}
415
416/// VMX cabability
417#[allow(non_camel_case_types)]
418#[derive(Clone, Debug)]
419#[repr(C)]
420pub enum VMXCap {
421	/// Pin-based VMX capabilities
422	PINBASED = 0,
423	/// Primary proc-based VMX capabilities
424	PROCBASED = 1,
425	/// Secondary proc-based VMX capabilities
426	PROCBASED2 = 2,
427	/// VM-entry VMX capabilities
428	ENTRY = 3,
429	/// VM-exit VMX capabilities
430	EXIT = 4,
431	/// VMX preemption timer frequency
432	PREEMPTION_TIMER = 32,
433}
434
435/// Reads a VMX capability of the host processor
436pub fn read_vmx_cap(vmx_cap: &VMXCap) -> Result<u64, Error> {
437	let mut value: u64 = 0;
438
439	match_error_code(unsafe { hv_vmx_read_capability((*vmx_cap).clone(), &mut value) })?;
440
441	Ok(value)
442}
443
444impl fmt::Display for VMXCap {
445	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
446		match *self {
447			VMXCap::PINBASED => write!(f, "Pin-based VMX capabilities"),
448			VMXCap::PROCBASED => write!(f, "Primary proc-based VMX capabilities"),
449			VMXCap::PROCBASED2 => write!(f, "Secondary proc-based VMX capabilities"),
450			VMXCap::ENTRY => write!(f, "VM-entry VMX capabilities"),
451			VMXCap::EXIT => write!(f, "VM-exit VMX capabilities"),
452			VMXCap::PREEMPTION_TIMER => write!(f, "VMX preemption timer frequency"),
453		}
454	}
455}