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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
use {
    super::MFN_LIST,
    crate::{
        platform::consts::{
            L1_PAGETABLE_ENTRIES, L1_PAGETABLE_SHIFT, L2_PAGETABLE_ENTRIES, L2_PAGETABLE_SHIFT,
            L3_PAGETABLE_ENTRIES, L3_PAGETABLE_SHIFT, L4_PAGETABLE_ENTRIES, L4_PAGETABLE_SHIFT,
            PADDR_MASK, PAGE_MASK, PAGE_SHIFT,
        },
        sections::text_start,
        xen_sys::__HYPERVISOR_VIRT_START,
    },
    core::convert::TryInto,
};

/// Page Entry
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct PageEntry(pub usize);

/// Number for page frame
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct PageFrameNumber(pub usize);

// mfn_to_pfn
impl From<MachineFrameNumber> for PageFrameNumber {
    fn from(mfn: MachineFrameNumber) -> Self {
        Self(unsafe {
            *(__HYPERVISOR_VIRT_START as *const usize).offset(
                mfn.0
                    .try_into()
                    .expect("MachineFrameNumber could not be converted to an isize"),
            )
        })
    }
}

// virt_to_pfn
impl From<VirtualAddress> for PageFrameNumber {
    fn from(virt: VirtualAddress) -> Self {
        // convert to physical then shift down to the previous page frame boundary
        Self(PhysicalAddress::from(virt).0 >> L1_PAGETABLE_SHIFT)
    }
}

/// Number of a page in the machine's address space
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct MachineFrameNumber(pub usize);

// pfn_to_mfn
impl From<PageFrameNumber> for MachineFrameNumber {
    fn from(pfn: PageFrameNumber) -> Self {
        Self(unsafe {
            *MFN_LIST.offset(
                pfn.0
                    .try_into()
                    .expect("PageFrameNumber could not be converted to an isize"),
            )
        })
    }
}

// virt_to_mfn
impl From<VirtualAddress> for MachineFrameNumber {
    fn from(virt: VirtualAddress) -> Self {
        Self::from(PageFrameNumber::from(virt))
    }
}

// pte_to_mfn
impl From<PageEntry> for MachineFrameNumber {
    fn from(pte: PageEntry) -> Self {
        Self(((pte.0) & (PADDR_MASK & PAGE_MASK)) >> L1_PAGETABLE_SHIFT)
    }
}

/// Virtual address
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct VirtualAddress(pub usize);

impl VirtualAddress {
    /// Given a virtual address get an entry offset into an L1 page table
    pub fn l1_table_offset(&self) -> isize {
        ((self.0 >> L1_PAGETABLE_SHIFT) & (L1_PAGETABLE_ENTRIES - 1))
            .try_into()
            .expect("Could not convert page table offset to isize")
    }

    /// Given a virtual address get an entry offset into an L2 page table
    pub fn l2_table_offset(&self) -> isize {
        ((self.0 >> L2_PAGETABLE_SHIFT) & (L2_PAGETABLE_ENTRIES - 1))
            .try_into()
            .expect("Could not convert page table offset to isize")
    }

    /// Given a virtual address get an entry offset into an L3 page table
    pub fn l3_table_offset(&self) -> isize {
        ((self.0 >> L3_PAGETABLE_SHIFT) & (L3_PAGETABLE_ENTRIES - 1))
            .try_into()
            .expect("Could not convert page table offset to isize")
    }

    /// Given a virtual address get an entry offset into an L4 page table
    pub fn l4_table_offset(&self) -> isize {
        ((self.0 >> L4_PAGETABLE_SHIFT) & (L4_PAGETABLE_ENTRIES - 1))
            .try_into()
            .expect("Could not convert page table offset to isize")
    }
}

// to_virt
impl From<PhysicalAddress> for VirtualAddress {
    fn from(phys: PhysicalAddress) -> Self {
        // no pointer arithmetic necessary here
        Self(phys.0 + text_start())
    }
}

// mach_to_virt
impl From<MachineAddress> for VirtualAddress {
    fn from(mach: MachineAddress) -> Self {
        Self::from(PhysicalAddress::from(mach))
    }
}

// mfn_to_virt
impl From<MachineFrameNumber> for VirtualAddress {
    fn from(mfn: MachineFrameNumber) -> Self {
        Self::from(PhysicalAddress(PageFrameNumber::from(mfn).0 << PAGE_SHIFT))
    }
}

// pfn_to_virt
impl From<PageFrameNumber> for VirtualAddress {
    fn from(pfn: PageFrameNumber) -> Self {
        Self::from(PhysicalAddress(pfn.0 << PAGE_SHIFT))
    }
}

// pte_to_virt
impl From<PageEntry> for VirtualAddress {
    fn from(pte: PageEntry) -> Self {
        Self::from(PhysicalAddress(
            PageFrameNumber::from(MachineFrameNumber::from(pte)).0 << PAGE_SHIFT,
        ))
    }
}

/// Pseudo-Physical address
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct PhysicalAddress(pub usize);

// to_phys
impl From<VirtualAddress> for PhysicalAddress {
    fn from(virt: VirtualAddress) -> Self {
        // no pointer arithmetic necessary here
        Self(virt.0 - text_start())
    }
}

// machine_to_phys
impl From<MachineAddress> for PhysicalAddress {
    fn from(mach: MachineAddress) -> Self {
        let pfn = PageFrameNumber::from(MachineFrameNumber(mach.0 >> PAGE_SHIFT));
        Self((pfn.0 << PAGE_SHIFT) | (mach.0 & !PAGE_MASK))
    }
}

/// Machine address
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct MachineAddress(pub usize);

// phys_to_machine
impl From<PhysicalAddress> for MachineAddress {
    fn from(phys: PhysicalAddress) -> Self {
        let mfn = MachineFrameNumber::from(PageFrameNumber(phys.0 >> PAGE_SHIFT));
        Self((mfn.0 << PAGE_SHIFT) | (phys.0 & !PAGE_MASK))
    }
}

// virt_to_mach
impl From<VirtualAddress> for MachineAddress {
    fn from(virt: VirtualAddress) -> Self {
        Self::from(PhysicalAddress::from(virt))
    }
}