1use xen_sys::{
2 __HVM_SAVE_TYPE_CPU, __HVM_SAVE_TYPE_LAPIC, __HVM_SAVE_TYPE_LAPIC_REGS, hvm_hw_cpu,
3 hvm_hw_lapic, hvm_hw_lapic_regs, hvm_save_descriptor, xc_domain_hvm_getcontext,
4 xc_domain_hvm_getcontext_partial, xc_domain_hvm_setcontext,
5};
6
7use super::x86::{Amd64, LocalApic, LocalApicRegisters, Registers};
8use crate::{VcpuId, XenDomain, XenError, xc_check_error};
9
10impl XenDomain<Amd64> {
11 pub fn get_context_cpu(&self, vcpu: VcpuId) -> Result<Registers, XenError> {
12 let result = unsafe { std::mem::zeroed::<hvm_hw_cpu>() };
13
14 let rc = unsafe {
15 xc_domain_hvm_getcontext_partial(
16 self.interface.handle.0,
17 self.domain_id.0,
18 size_of_val(&__HVM_SAVE_TYPE_CPU::default().c) as u16,
19 vcpu.0,
20 &result as *const _ as *mut _,
21 size_of_val(&result) as u32,
22 )
23 };
24 xc_check_error!(self.interface.handle.0, rc);
25 Ok(result.into())
26 }
27
28 pub fn get_context_lapic(&self, vcpu: VcpuId) -> Result<LocalApic, XenError> {
29 let result = unsafe { std::mem::zeroed::<hvm_hw_lapic>() };
30
31 let rc = unsafe {
32 xc_domain_hvm_getcontext_partial(
33 self.interface.handle.0,
34 self.domain_id.0,
35 size_of_val(&__HVM_SAVE_TYPE_LAPIC::default().c) as u16,
36 vcpu.0,
37 &result as *const _ as *mut _,
38 size_of_val(&result) as u32,
39 )
40 };
41 xc_check_error!(self.interface.handle.0, rc);
42 Ok(result.into())
43 }
44
45 pub fn get_context_lapic_regs(&self, vcpu: VcpuId) -> Result<LocalApicRegisters, XenError> {
46 let result = unsafe { std::mem::zeroed::<hvm_hw_lapic_regs>() };
47
48 let rc = unsafe {
49 xc_domain_hvm_getcontext_partial(
50 self.interface.handle.0,
51 self.domain_id.0,
52 size_of_val(&__HVM_SAVE_TYPE_LAPIC_REGS::default().c) as u16,
53 vcpu.0,
54 &result as *const _ as *mut _,
55 size_of_val(&result) as u32,
56 )
57 };
58 xc_check_error!(self.interface.handle.0, rc);
59 Ok(result.into())
60 }
61
62 pub fn set_context_cpu(&self, vcpu: VcpuId, registers: Registers) -> Result<(), XenError> {
63 self.pause()?;
64
65 let size = unsafe {
67 xc_domain_hvm_getcontext(
68 self.interface.handle.0,
69 self.domain_id.0,
70 std::ptr::null_mut(),
71 0,
72 )
73 };
74
75 if size <= 0 {
76 self.unpause()?;
77 return Err(XenError::Other("Failed to get context size"));
78 }
79
80 let mut buffer = vec![0u8; size as usize];
82
83 let rc = unsafe {
85 xc_domain_hvm_getcontext(
86 self.interface.handle.0,
87 self.domain_id.0,
88 buffer.as_mut_ptr(),
89 size as u32,
90 )
91 };
92 xc_check_error!(self.interface.handle.0, rc);
93
94 let mut offset: u32 = 0;
96 let size = size as u32;
97 let hvm_save_code_cpu = size_of_val(&__HVM_SAVE_TYPE_CPU::default().c) as u16;
98
99 unsafe {
100 while offset < size {
101 let descriptor =
102 buffer.as_ptr().offset(offset as isize) as *const hvm_save_descriptor;
103
104 offset += size_of::<hvm_save_descriptor>() as u32;
105
106 if (*descriptor).typecode == hvm_save_code_cpu && (*descriptor).instance == vcpu.0 {
107 let vcpu_context = buffer.as_ptr().offset(offset as isize) as *mut hvm_hw_cpu;
108 registers.copy_into(&mut *vcpu_context);
109 break;
110 }
111
112 offset += (*descriptor).length;
113 }
114 }
115
116 let rc = unsafe {
118 xc_domain_hvm_setcontext(
119 self.interface.handle.0,
120 self.domain_id.0,
121 buffer.as_mut_ptr(),
122 size,
123 )
124 };
125 xc_check_error!(self.interface.handle.0, rc);
126
127 self.unpause()?;
128
129 Ok(())
130 }
131}