1#[cfg(mshv2)]
18extern crate mshv_bindings2 as mshv_bindings;
19#[cfg(mshv2)]
20extern crate mshv_ioctls2 as mshv_ioctls;
21
22#[cfg(mshv3)]
23extern crate mshv_bindings3 as mshv_bindings;
24#[cfg(mshv3)]
25extern crate mshv_ioctls3 as mshv_ioctls;
26
27use std::fmt::{Debug, Formatter};
28
29use log::error;
30#[cfg(mshv2)]
31use mshv_bindings::hv_message;
32#[cfg(gdb)]
33use mshv_bindings::{
34 hv_intercept_parameters, hv_intercept_type_HV_INTERCEPT_TYPE_EXCEPTION,
35 hv_message_type_HVMSG_X64_EXCEPTION_INTERCEPT, mshv_install_intercept,
36 HV_INTERCEPT_ACCESS_MASK_EXECUTE,
37};
38use mshv_bindings::{
39 hv_message_type, hv_message_type_HVMSG_GPA_INTERCEPT, hv_message_type_HVMSG_UNMAPPED_GPA,
40 hv_message_type_HVMSG_X64_HALT, hv_message_type_HVMSG_X64_IO_PORT_INTERCEPT, hv_register_assoc,
41 hv_register_name_HV_X64_REGISTER_RIP, hv_register_value, mshv_user_mem_region,
42 FloatingPointUnit, SegmentRegister, SpecialRegisters, StandardRegisters,
43};
44#[cfg(mshv3)]
45use mshv_bindings::{
46 hv_partition_property_code_HV_PARTITION_PROPERTY_SYNTHETIC_PROC_FEATURES,
47 hv_partition_synthetic_processor_features,
48};
49use mshv_ioctls::{Mshv, VcpuFd, VmFd};
50use tracing::{instrument, Span};
51
52use super::fpu::{FP_CONTROL_WORD_DEFAULT, FP_TAG_WORD_DEFAULT, MXCSR_DEFAULT};
53#[cfg(gdb)]
54use super::gdb::{DebugCommChannel, DebugMsg, DebugResponse, GuestDebug, MshvDebug};
55#[cfg(gdb)]
56use super::handlers::DbgMemAccessHandlerWrapper;
57use super::handlers::{MemAccessHandlerWrapper, OutBHandlerWrapper};
58use super::{
59 Hypervisor, VirtualCPU, CR0_AM, CR0_ET, CR0_MP, CR0_NE, CR0_PE, CR0_PG, CR0_WP, CR4_OSFXSR,
60 CR4_OSXMMEXCPT, CR4_PAE, EFER_LMA, EFER_LME, EFER_NX, EFER_SCE,
61};
62use crate::hypervisor::hypervisor_handler::HypervisorHandler;
63use crate::hypervisor::HyperlightExit;
64use crate::mem::memory_region::{MemoryRegion, MemoryRegionFlags};
65use crate::mem::ptr::{GuestPtr, RawPtr};
66#[cfg(gdb)]
67use crate::HyperlightError;
68use crate::{log_then_return, new_error, Result};
69
70#[cfg(gdb)]
71mod debug {
72 use std::sync::{Arc, Mutex};
73
74 use super::{HypervLinuxDriver, *};
75 use crate::hypervisor::gdb::{DebugMsg, DebugResponse, VcpuStopReason, X86_64Regs};
76 use crate::hypervisor::handlers::DbgMemAccessHandlerCaller;
77 use crate::{new_error, Result};
78
79 impl HypervLinuxDriver {
80 fn disable_debug(&mut self) -> Result<()> {
82 let mut debug = MshvDebug::default();
83
84 debug.set_single_step(&self.vcpu_fd, false)?;
85
86 self.debug = Some(debug);
87
88 Ok(())
89 }
90
91 pub(crate) fn get_stop_reason(&mut self) -> Result<VcpuStopReason> {
93 let debug = self
94 .debug
95 .as_mut()
96 .ok_or_else(|| new_error!("Debug is not enabled"))?;
97
98 debug.get_stop_reason(&self.vcpu_fd, self.entrypoint)
99 }
100
101 pub(crate) fn process_dbg_request(
102 &mut self,
103 req: DebugMsg,
104 dbg_mem_access_fn: Arc<Mutex<dyn DbgMemAccessHandlerCaller>>,
105 ) -> Result<DebugResponse> {
106 if let Some(debug) = self.debug.as_mut() {
107 match req {
108 DebugMsg::AddHwBreakpoint(addr) => Ok(DebugResponse::AddHwBreakpoint(
109 debug
110 .add_hw_breakpoint(&self.vcpu_fd, addr)
111 .map_err(|e| {
112 log::error!("Failed to add hw breakpoint: {:?}", e);
113
114 e
115 })
116 .is_ok(),
117 )),
118 DebugMsg::AddSwBreakpoint(addr) => Ok(DebugResponse::AddSwBreakpoint(
119 debug
120 .add_sw_breakpoint(&self.vcpu_fd, addr, dbg_mem_access_fn)
121 .map_err(|e| {
122 log::error!("Failed to add sw breakpoint: {:?}", e);
123
124 e
125 })
126 .is_ok(),
127 )),
128 DebugMsg::Continue => {
129 debug.set_single_step(&self.vcpu_fd, false).map_err(|e| {
130 log::error!("Failed to continue execution: {:?}", e);
131
132 e
133 })?;
134
135 Ok(DebugResponse::Continue)
136 }
137 DebugMsg::DisableDebug => {
138 self.disable_debug().map_err(|e| {
139 log::error!("Failed to disable debugging: {:?}", e);
140
141 e
142 })?;
143
144 Ok(DebugResponse::DisableDebug)
145 }
146 DebugMsg::GetCodeSectionOffset => {
147 let offset = dbg_mem_access_fn
148 .try_lock()
149 .map_err(|e| {
150 new_error!("Error locking at {}:{}: {}", file!(), line!(), e)
151 })?
152 .get_code_offset()
153 .map_err(|e| {
154 log::error!("Failed to get code offset: {:?}", e);
155
156 e
157 })?;
158
159 Ok(DebugResponse::GetCodeSectionOffset(offset as u64))
160 }
161 DebugMsg::ReadAddr(addr, len) => {
162 let mut data = vec![0u8; len];
163
164 debug
165 .read_addrs(&self.vcpu_fd, addr, &mut data, dbg_mem_access_fn)
166 .map_err(|e| {
167 log::error!("Failed to read from address: {:?}", e);
168
169 e
170 })?;
171
172 Ok(DebugResponse::ReadAddr(data))
173 }
174 DebugMsg::ReadRegisters => {
175 let mut regs = X86_64Regs::default();
176
177 debug
178 .read_regs(&self.vcpu_fd, &mut regs)
179 .map_err(|e| {
180 log::error!("Failed to read registers: {:?}", e);
181
182 e
183 })
184 .map(|_| DebugResponse::ReadRegisters(regs))
185 }
186 DebugMsg::RemoveHwBreakpoint(addr) => Ok(DebugResponse::RemoveHwBreakpoint(
187 debug
188 .remove_hw_breakpoint(&self.vcpu_fd, addr)
189 .map_err(|e| {
190 log::error!("Failed to remove hw breakpoint: {:?}", e);
191
192 e
193 })
194 .is_ok(),
195 )),
196 DebugMsg::RemoveSwBreakpoint(addr) => Ok(DebugResponse::RemoveSwBreakpoint(
197 debug
198 .remove_sw_breakpoint(&self.vcpu_fd, addr, dbg_mem_access_fn)
199 .map_err(|e| {
200 log::error!("Failed to remove sw breakpoint: {:?}", e);
201
202 e
203 })
204 .is_ok(),
205 )),
206 DebugMsg::Step => {
207 debug.set_single_step(&self.vcpu_fd, true).map_err(|e| {
208 log::error!("Failed to enable step instruction: {:?}", e);
209
210 e
211 })?;
212
213 Ok(DebugResponse::Step)
214 }
215 DebugMsg::WriteAddr(addr, data) => {
216 debug
217 .write_addrs(&self.vcpu_fd, addr, &data, dbg_mem_access_fn)
218 .map_err(|e| {
219 log::error!("Failed to write to address: {:?}", e);
220
221 e
222 })?;
223
224 Ok(DebugResponse::WriteAddr)
225 }
226 DebugMsg::WriteRegisters(regs) => debug
227 .write_regs(&self.vcpu_fd, ®s)
228 .map_err(|e| {
229 log::error!("Failed to write registers: {:?}", e);
230
231 e
232 })
233 .map(|_| DebugResponse::WriteRegisters),
234 }
235 } else {
236 Err(new_error!("Debugging is not enabled"))
237 }
238 }
239
240 pub(crate) fn recv_dbg_msg(&mut self) -> Result<DebugMsg> {
241 let gdb_conn = self
242 .gdb_conn
243 .as_mut()
244 .ok_or_else(|| new_error!("Debug is not enabled"))?;
245
246 gdb_conn.recv().map_err(|e| {
247 new_error!(
248 "Got an error while waiting to receive a
249 message: {:?}",
250 e
251 )
252 })
253 }
254
255 pub(crate) fn send_dbg_msg(&mut self, cmd: DebugResponse) -> Result<()> {
256 log::debug!("Sending {:?}", cmd);
257
258 let gdb_conn = self
259 .gdb_conn
260 .as_mut()
261 .ok_or_else(|| new_error!("Debug is not enabled"))?;
262
263 gdb_conn
264 .send(cmd)
265 .map_err(|e| new_error!("Got an error while sending a response message {:?}", e))
266 }
267 }
268}
269
270#[instrument(skip_all, parent = Span::current(), level = "Trace")]
273pub(crate) fn is_hypervisor_present() -> bool {
274 match Mshv::open_with_cloexec(true) {
275 Ok(fd) => {
276 unsafe {
277 libc::close(fd);
278 } true
280 }
281 Err(e) => {
282 log::info!("Error creating MSHV object: {:?}", e);
283 false
284 }
285 }
286}
287
288pub(super) struct HypervLinuxDriver {
291 _mshv: Mshv,
292 vm_fd: VmFd,
293 vcpu_fd: VcpuFd,
294 entrypoint: u64,
295 mem_regions: Vec<MemoryRegion>,
296 orig_rsp: GuestPtr,
297
298 #[cfg(gdb)]
299 debug: Option<MshvDebug>,
300 #[cfg(gdb)]
301 gdb_conn: Option<DebugCommChannel<DebugResponse, DebugMsg>>,
302}
303
304impl HypervLinuxDriver {
305 #[instrument(skip_all, parent = Span::current(), level = "Trace")]
314 pub(super) fn new(
315 mem_regions: Vec<MemoryRegion>,
316 entrypoint_ptr: GuestPtr,
317 rsp_ptr: GuestPtr,
318 pml4_ptr: GuestPtr,
319 #[cfg(gdb)] gdb_conn: Option<DebugCommChannel<DebugResponse, DebugMsg>>,
320 ) -> Result<Self> {
321 let mshv = Mshv::new()?;
322 let pr = Default::default();
323 #[cfg(mshv2)]
324 let vm_fd = mshv.create_vm_with_config(&pr)?;
325 #[cfg(mshv3)]
326 let vm_fd = {
327 let vm_fd = mshv.create_vm_with_args(&pr)?;
332 let features: hv_partition_synthetic_processor_features = Default::default();
333 vm_fd.hvcall_set_partition_property(
334 hv_partition_property_code_HV_PARTITION_PROPERTY_SYNTHETIC_PROC_FEATURES,
335 unsafe { features.as_uint64[0] },
336 )?;
337 vm_fd.initialize()?;
338 vm_fd
339 };
340
341 let mut vcpu_fd = vm_fd.create_vcpu(0)?;
342
343 #[cfg(gdb)]
344 let (debug, gdb_conn) = if let Some(gdb_conn) = gdb_conn {
345 let mut debug = MshvDebug::new();
346 debug.add_hw_breakpoint(&vcpu_fd, entrypoint_ptr.absolute()?)?;
347
348 vm_fd
353 .install_intercept(mshv_install_intercept {
354 access_type_mask: HV_INTERCEPT_ACCESS_MASK_EXECUTE,
355 intercept_type: hv_intercept_type_HV_INTERCEPT_TYPE_EXCEPTION,
356 intercept_parameter: hv_intercept_parameters {
358 exception_vector: 0x1,
359 },
360 })
361 .map_err(|e| new_error!("Cannot install debug exception intercept: {}", e))?;
362
363 vm_fd
365 .install_intercept(mshv_install_intercept {
366 access_type_mask: HV_INTERCEPT_ACCESS_MASK_EXECUTE,
367 intercept_type: hv_intercept_type_HV_INTERCEPT_TYPE_EXCEPTION,
368 intercept_parameter: hv_intercept_parameters {
370 exception_vector: 0x3,
371 },
372 })
373 .map_err(|e| new_error!("Cannot install breakpoint exception intercept: {}", e))?;
374
375 (Some(debug), Some(gdb_conn))
376 } else {
377 (None, None)
378 };
379
380 mem_regions.iter().try_for_each(|region| {
381 let mshv_region = region.to_owned().into();
382 vm_fd.map_user_memory(mshv_region)
383 })?;
384
385 Self::setup_initial_sregs(&mut vcpu_fd, pml4_ptr.absolute()?)?;
386
387 Ok(Self {
388 _mshv: mshv,
389 vm_fd,
390 vcpu_fd,
391 mem_regions,
392 entrypoint: entrypoint_ptr.absolute()?,
393 orig_rsp: rsp_ptr,
394
395 #[cfg(gdb)]
396 debug,
397 #[cfg(gdb)]
398 gdb_conn,
399 })
400 }
401
402 #[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")]
403 fn setup_initial_sregs(vcpu: &mut VcpuFd, pml4_addr: u64) -> Result<()> {
404 let sregs = SpecialRegisters {
405 cr0: CR0_PE | CR0_MP | CR0_ET | CR0_NE | CR0_AM | CR0_PG | CR0_WP,
406 cr4: CR4_PAE | CR4_OSFXSR | CR4_OSXMMEXCPT,
407 cr3: pml4_addr,
408 efer: EFER_LME | EFER_LMA | EFER_SCE | EFER_NX,
409 cs: SegmentRegister {
410 type_: 11,
411 present: 1,
412 s: 1,
413 l: 1,
414 ..Default::default()
415 },
416 tr: SegmentRegister {
417 limit: 65535,
418 type_: 11,
419 present: 1,
420 ..Default::default()
421 },
422 ..Default::default()
423 };
424 vcpu.set_sregs(&sregs)?;
425 Ok(())
426 }
427}
428
429impl Debug for HypervLinuxDriver {
430 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
431 let mut f = f.debug_struct("Hyperv Linux Driver");
432
433 f.field("Entrypoint", &self.entrypoint)
434 .field("Original RSP", &self.orig_rsp);
435
436 for region in &self.mem_regions {
437 f.field("Memory Region", ®ion);
438 }
439
440 let regs = self.vcpu_fd.get_regs();
441
442 if let Ok(regs) = regs {
443 f.field("Registers", ®s);
444 }
445
446 let sregs = self.vcpu_fd.get_sregs();
447
448 if let Ok(sregs) = sregs {
449 f.field("Special Registers", &sregs);
450 }
451
452 f.finish()
453 }
454}
455
456impl Hypervisor for HypervLinuxDriver {
457 #[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")]
458 fn initialise(
459 &mut self,
460 peb_addr: RawPtr,
461 seed: u64,
462 page_size: u32,
463 outb_hdl: OutBHandlerWrapper,
464 mem_access_hdl: MemAccessHandlerWrapper,
465 hv_handler: Option<HypervisorHandler>,
466 #[cfg(gdb)] dbg_mem_access_fn: DbgMemAccessHandlerWrapper,
467 ) -> Result<()> {
468 let regs = StandardRegisters {
469 rip: self.entrypoint,
470 rsp: self.orig_rsp.absolute()?,
471 rflags: 2, rcx: peb_addr.into(),
475 rdx: seed,
476 r8: page_size.into(),
477 r9: self.get_max_log_level().into(),
478
479 ..Default::default()
480 };
481 self.vcpu_fd.set_regs(®s)?;
482
483 VirtualCPU::run(
484 self.as_mut_hypervisor(),
485 hv_handler,
486 outb_hdl,
487 mem_access_hdl,
488 #[cfg(gdb)]
489 dbg_mem_access_fn,
490 )?;
491
492 Ok(())
493 }
494
495 #[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")]
496 fn dispatch_call_from_host(
497 &mut self,
498 dispatch_func_addr: RawPtr,
499 outb_handle_fn: OutBHandlerWrapper,
500 mem_access_fn: MemAccessHandlerWrapper,
501 hv_handler: Option<HypervisorHandler>,
502 #[cfg(gdb)] dbg_mem_access_fn: DbgMemAccessHandlerWrapper,
503 ) -> Result<()> {
504 let regs = StandardRegisters {
506 rip: dispatch_func_addr.into(),
507 rsp: self.orig_rsp.absolute()?,
508 rflags: 2, ..Default::default()
510 };
511 self.vcpu_fd.set_regs(®s)?;
512
513 let fpu = FloatingPointUnit {
515 fcw: FP_CONTROL_WORD_DEFAULT,
516 ftwx: FP_TAG_WORD_DEFAULT,
517 mxcsr: MXCSR_DEFAULT,
518 ..Default::default() };
520 self.vcpu_fd.set_fpu(&fpu)?;
521
522 VirtualCPU::run(
524 self.as_mut_hypervisor(),
525 hv_handler,
526 outb_handle_fn,
527 mem_access_fn,
528 #[cfg(gdb)]
529 dbg_mem_access_fn,
530 )?;
531
532 Ok(())
533 }
534
535 #[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")]
536 fn handle_io(
537 &mut self,
538 port: u16,
539 data: Vec<u8>,
540 rip: u64,
541 instruction_length: u64,
542 outb_handle_fn: OutBHandlerWrapper,
543 ) -> Result<()> {
544 let payload = data[..8].try_into()?;
545 outb_handle_fn
546 .try_lock()
547 .map_err(|e| new_error!("Error locking at {}:{}: {}", file!(), line!(), e))?
548 .call(port, u64::from_le_bytes(payload))?;
549
550 self.vcpu_fd.set_reg(&[hv_register_assoc {
552 name: hv_register_name_HV_X64_REGISTER_RIP,
553 value: hv_register_value {
554 reg64: rip + instruction_length,
555 },
556 ..Default::default()
557 }])?;
558 Ok(())
559 }
560
561 #[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")]
562 fn run(&mut self) -> Result<super::HyperlightExit> {
563 const HALT_MESSAGE: hv_message_type = hv_message_type_HVMSG_X64_HALT;
564 const IO_PORT_INTERCEPT_MESSAGE: hv_message_type =
565 hv_message_type_HVMSG_X64_IO_PORT_INTERCEPT;
566 const UNMAPPED_GPA_MESSAGE: hv_message_type = hv_message_type_HVMSG_UNMAPPED_GPA;
567 const INVALID_GPA_ACCESS_MESSAGE: hv_message_type = hv_message_type_HVMSG_GPA_INTERCEPT;
568 #[cfg(gdb)]
569 const EXCEPTION_INTERCEPT: hv_message_type = hv_message_type_HVMSG_X64_EXCEPTION_INTERCEPT;
570
571 #[cfg(mshv2)]
572 let run_result = {
573 let hv_message: hv_message = Default::default();
574 &self.vcpu_fd.run(hv_message)
575 };
576 #[cfg(mshv3)]
577 let run_result = &self.vcpu_fd.run();
578
579 let result = match run_result {
580 Ok(m) => match m.header.message_type {
581 HALT_MESSAGE => {
582 crate::debug!("mshv - Halt Details : {:#?}", &self);
583 HyperlightExit::Halt()
584 }
585 IO_PORT_INTERCEPT_MESSAGE => {
586 let io_message = m.to_ioport_info()?;
587 let port_number = io_message.port_number;
588 let rip = io_message.header.rip;
589 let rax = io_message.rax;
590 let instruction_length = io_message.header.instruction_length() as u64;
591 crate::debug!("mshv IO Details : \nPort : {}\n{:#?}", port_number, &self);
592 HyperlightExit::IoOut(
593 port_number,
594 rax.to_le_bytes().to_vec(),
595 rip,
596 instruction_length,
597 )
598 }
599 UNMAPPED_GPA_MESSAGE => {
600 let mimo_message = m.to_memory_info()?;
601 let addr = mimo_message.guest_physical_address;
602 crate::debug!(
603 "mshv MMIO unmapped GPA -Details: Address: {} \n {:#?}",
604 addr,
605 &self
606 );
607 HyperlightExit::Mmio(addr)
608 }
609 INVALID_GPA_ACCESS_MESSAGE => {
610 let mimo_message = m.to_memory_info()?;
611 let gpa = mimo_message.guest_physical_address;
612 let access_info = MemoryRegionFlags::try_from(mimo_message)?;
613 crate::debug!(
614 "mshv MMIO invalid GPA access -Details: Address: {} \n {:#?}",
615 gpa,
616 &self
617 );
618 match self.get_memory_access_violation(
619 gpa as usize,
620 &self.mem_regions,
621 access_info,
622 ) {
623 Some(access_info_violation) => access_info_violation,
624 None => HyperlightExit::Mmio(gpa),
625 }
626 }
627 #[cfg(gdb)]
630 EXCEPTION_INTERCEPT => match self.get_stop_reason() {
631 Ok(reason) => HyperlightExit::Debug(reason),
632 Err(e) => {
633 log_then_return!("Error getting stop reason: {:?}", e);
634 }
635 },
636 other => {
637 crate::debug!("mshv Other Exit: Exit: {:#?} \n {:#?}", other, &self);
638 log_then_return!("unknown Hyper-V run message type {:?}", other);
639 }
640 },
641 Err(e) => match e.errno() {
642 libc::EINTR => HyperlightExit::Cancelled(),
644 libc::EAGAIN => HyperlightExit::Retry(),
645 _ => {
646 crate::debug!("mshv Error - Details: Error: {} \n {:#?}", e, &self);
647 log_then_return!("Error running VCPU {:?}", e);
648 }
649 },
650 };
651 Ok(result)
652 }
653
654 #[instrument(skip_all, parent = Span::current(), level = "Trace")]
655 fn as_mut_hypervisor(&mut self) -> &mut dyn Hypervisor {
656 self as &mut dyn Hypervisor
657 }
658
659 #[cfg(crashdump)]
660 fn get_memory_regions(&self) -> &[MemoryRegion] {
661 &self.mem_regions
662 }
663
664 #[cfg(gdb)]
665 fn handle_debug(
666 &mut self,
667 dbg_mem_access_fn: std::sync::Arc<
668 std::sync::Mutex<dyn super::handlers::DbgMemAccessHandlerCaller>,
669 >,
670 stop_reason: super::gdb::VcpuStopReason,
671 ) -> Result<()> {
672 self.send_dbg_msg(DebugResponse::VcpuStopped(stop_reason))
673 .map_err(|e| new_error!("Couldn't signal vCPU stopped event to GDB thread: {:?}", e))?;
674
675 loop {
676 log::debug!("Debug wait for event to resume vCPU");
677
678 let req = self.recv_dbg_msg()?;
680
681 let result = self.process_dbg_request(req, dbg_mem_access_fn.clone());
682
683 let response = match result {
684 Ok(response) => response,
685 Err(HyperlightError::TranslateGuestAddress(_)) => DebugResponse::ErrorOccurred,
687 Err(e) => {
688 return Err(e);
689 }
690 };
691
692 let cont = matches!(
694 response,
695 DebugResponse::Step | DebugResponse::Continue | DebugResponse::DisableDebug
696 );
697
698 self.send_dbg_msg(response)
699 .map_err(|e| new_error!("Couldn't send response to gdb: {:?}", e))?;
700
701 if cont {
702 break;
703 }
704 }
705
706 Ok(())
707 }
708}
709
710impl Drop for HypervLinuxDriver {
711 #[instrument(skip_all, parent = Span::current(), level = "Trace")]
712 fn drop(&mut self) {
713 for region in &self.mem_regions {
714 let mshv_region: mshv_user_mem_region = region.to_owned().into();
715 match self.vm_fd.unmap_user_memory(mshv_region) {
716 Ok(_) => (),
717 Err(e) => error!("Failed to unmap user memory in HyperVOnLinux ({:?})", e),
718 }
719 }
720 }
721}
722
723#[cfg(test)]
724mod tests {
725 use super::*;
726 use crate::mem::memory_region::MemoryRegionVecBuilder;
727 use crate::mem::shared_mem::{ExclusiveSharedMemory, SharedMemory};
728
729 #[rustfmt::skip]
730 const CODE: [u8; 12] = [
731 0xba, 0xf8, 0x03, 0x00, 0xd8, 0x04, b'0', 0xee, 0xb0, b'\0', 0xee, 0xf4, ];
740
741 fn shared_mem_with_code(
742 code: &[u8],
743 mem_size: usize,
744 load_offset: usize,
745 ) -> Result<Box<ExclusiveSharedMemory>> {
746 if load_offset > mem_size {
747 log_then_return!(
748 "code load offset ({}) > memory size ({})",
749 load_offset,
750 mem_size
751 );
752 }
753 let mut shared_mem = ExclusiveSharedMemory::new(mem_size)?;
754 shared_mem.copy_from_slice(code, load_offset)?;
755 Ok(Box::new(shared_mem))
756 }
757
758 #[test]
759 fn create_driver() {
760 if !super::is_hypervisor_present() {
761 return;
762 }
763 const MEM_SIZE: usize = 0x3000;
764 let gm = shared_mem_with_code(CODE.as_slice(), MEM_SIZE, 0).unwrap();
765 let rsp_ptr = GuestPtr::try_from(0).unwrap();
766 let pml4_ptr = GuestPtr::try_from(0).unwrap();
767 let entrypoint_ptr = GuestPtr::try_from(0).unwrap();
768 let mut regions = MemoryRegionVecBuilder::new(0, gm.base_addr());
769 regions.push_page_aligned(
770 MEM_SIZE,
771 MemoryRegionFlags::READ | MemoryRegionFlags::WRITE | MemoryRegionFlags::EXECUTE,
772 crate::mem::memory_region::MemoryRegionType::Code,
773 );
774 super::HypervLinuxDriver::new(
775 regions.build(),
776 entrypoint_ptr,
777 rsp_ptr,
778 pml4_ptr,
779 #[cfg(gdb)]
780 None,
781 )
782 .unwrap();
783 }
784}