xen/arch/
domain.rs

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        // Get the context size.
66        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        // Allocate a buffer to hold the context.
81        let mut buffer = vec![0u8; size as usize];
82
83        // Get the context.
84        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        // Locate the CPU context.
95        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        // Set the context.
117        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}