xen/ctrl/altp2m/
view.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
use xen_sys::{
    xc_altp2m_change_gfn, xc_altp2m_create_view, xc_altp2m_destroy_view, xc_altp2m_get_mem_access,
    xc_altp2m_set_mem_access, xc_altp2m_set_mem_access_multi, xc_altp2m_switch_to_view,
};

use crate::{ctrl::XenInterface, xc_check_error, MemoryAccess, XenDomainId, XenError};

pub struct XenAltP2MView {
    interface: XenInterface,
    domain_id: XenDomainId,
    view_id: u16,
}

impl XenAltP2MView {
    pub(crate) fn new(
        interface: XenInterface,
        domain_id: XenDomainId,
        default_access: MemoryAccess,
    ) -> Result<Self, XenError> {
        let mut view_id = 0;
        let rc = unsafe {
            xc_altp2m_create_view(
                interface.handle.0,
                domain_id.0,
                default_access.bits().into(),
                &mut view_id,
            )
        };

        if rc < 0 {
            return Err(XenError::Io(std::io::Error::last_os_error()));
        }

        tracing::trace!(domain_id = domain_id.0, view_id, "created altp2m view");

        Ok(Self {
            interface,
            domain_id,
            view_id,
        })
    }

    pub fn id(&self) -> u16 {
        self.view_id
    }

    pub fn switch(&self) -> Result<(), XenError> {
        let rc = unsafe {
            xc_altp2m_switch_to_view(self.interface.handle.0, self.domain_id.0, self.view_id)
        };
        xc_check_error!(self.interface.handle.0, rc);
        Ok(())
    }

    pub fn get_mem_access(&self, gfn: u64) -> Result<MemoryAccess, XenError> {
        let mut access = 0;
        let rc = unsafe {
            xc_altp2m_get_mem_access(
                self.interface.handle.0,
                self.domain_id.0,
                self.view_id,
                gfn,
                &mut access,
            )
        };
        xc_check_error!(self.interface.handle.0, rc);
        Ok(MemoryAccess::from_bits_truncate(access as _))
    }

    pub fn set_mem_access(&self, gfn: u64, access: MemoryAccess) -> Result<(), XenError> {
        let rc = unsafe {
            xc_altp2m_set_mem_access(
                self.interface.handle.0,
                self.domain_id.0,
                self.view_id,
                gfn,
                access.bits().into(),
            )
        };
        xc_check_error!(self.interface.handle.0, rc);
        Ok(())
    }

    pub fn set_mem_access_multi(
        &self,
        access: &[MemoryAccess],
        gfns: &[u64],
    ) -> Result<(), XenError> {
        let rc = unsafe {
            xc_altp2m_set_mem_access_multi(
                self.interface.handle.0,
                self.domain_id.0,
                self.view_id,
                access.as_ptr() as *mut u8,
                gfns.as_ptr() as *mut u64,
                std::cmp::min(access.len(), gfns.len()) as u32,
            )
        };
        xc_check_error!(self.interface.handle.0, rc);
        Ok(())
    }

    pub fn change_gfn(&self, old_gfn: u64, new_gfn: u64) -> Result<(), XenError> {
        let rc = unsafe {
            xc_altp2m_change_gfn(
                self.interface.handle.0,
                self.domain_id.0,
                self.view_id,
                old_gfn,
                new_gfn,
            )
        };
        xc_check_error!(self.interface.handle.0, rc);
        Ok(())
    }
}

impl Drop for XenAltP2MView {
    fn drop(&mut self) {
        tracing::trace!(
            domain_id = self.domain_id.0,
            view_id = self.view_id,
            "destroying altp2m view"
        );

        unsafe {
            xc_altp2m_destroy_view(self.interface.handle.0, self.domain_id.0, self.view_id);
        }
    }
}