swage_core/memory/
virt_to_phys.rs1use std::fmt::{Debug, Formatter};
2use std::ops::{Add, Sub};
3
4use crate::util::PAGE_SHIFT;
5use itertools::Itertools;
6use log::warn;
7use pagemap2::{MapsEntry, PageMapEntry, PageMapError, VirtualMemoryArea};
8use serde::Serialize;
9use thiserror::Error;
10
11#[repr(transparent)]
12#[derive(Clone, Copy, Default, Serialize, PartialEq, Eq)]
13pub struct PhysAddr(usize);
17
18impl Debug for PhysAddr {
19 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
20 f.write_fmt(format_args!("PhysAddr(0x{:02x})", self.0))
21 }
22}
23
24impl PhysAddr {
25 pub fn new(addr: usize) -> Self {
27 PhysAddr(addr)
28 }
29
30 pub fn as_usize(&self) -> usize {
32 self.0
33 }
34}
35
36pub trait VirtToPhysResolver {
41 type Error;
43 fn get_phys(&mut self, virt: u64) -> Result<PhysAddr, Self::Error>;
49
50 fn get_phys_range(&mut self, region: VirtualMemoryArea) -> Result<Vec<PhysAddr>, Self::Error>;
56}
57
58#[derive(Debug, Error)]
60#[error(transparent)]
61pub struct LinuxPageMapError(#[from] PageMapError);
62
63pub struct LinuxPageMap {
68 pagemap_wrapper: pagemap2::PageMap,
69}
70
71impl LinuxPageMap {
72 pub fn new() -> Result<LinuxPageMap, LinuxPageMapError> {
78 Self::for_process(std::process::id())
79 }
80
81 pub fn for_process(pid: u32) -> Result<LinuxPageMap, LinuxPageMapError> {
91 let res = LinuxPageMap {
92 pagemap_wrapper: pagemap2::PageMap::new(pid as u64)?,
93 };
94 Ok(res)
95 }
96}
97
98pub struct PageMap(pub Vec<(MapsEntry, Vec<PageMapEntry>)>);
99
100impl LinuxPageMap {
101 pub fn pagemap(&mut self) -> Result<PageMap, LinuxPageMapError> {
103 self.pagemap_wrapper
104 .pagemap()
105 .map(PageMap)
106 .map_err(|e| e.into())
107 }
108}
109
110impl VirtToPhysResolver for LinuxPageMap {
111 type Error = LinuxPageMapError;
112 fn get_phys(&mut self, virt: u64) -> Result<PhysAddr, Self::Error> {
113 let vaddr_start_page = virt & !0xFFF;
115 let vaddr_end_page = vaddr_start_page + 4095;
116
117 let memory_region = VirtualMemoryArea::from((vaddr_start_page, vaddr_end_page));
119 let entry = self.pagemap_wrapper.pagemap_vma(&memory_region)?;
120 assert_eq!(
121 entry.len(),
122 1,
123 "Got {} pagemap entries for virtual address 0x{:x}, expected exactly one",
124 entry.len(),
125 virt
126 );
127 let pfn = entry[0].pfn()?;
128 if pfn == 0 {
129 warn!(
130 "Got invalid PFN 0 for virtual address 0x{:x}. Are we root?",
131 virt
132 );
133 }
134
135 let phys_addr = ((pfn << PAGE_SHIFT) | (virt & 0xFFF)) as usize;
136
137 Ok(PhysAddr(phys_addr))
138 }
139 fn get_phys_range(
140 &mut self,
141 memory_region: VirtualMemoryArea,
142 ) -> Result<Vec<PhysAddr>, Self::Error> {
143 let entry = self.pagemap_wrapper.pagemap_vma(&memory_region)?;
144 Ok(entry
145 .into_iter()
146 .map(|e| e.pfn().map(|p| p << PAGE_SHIFT).map_err(|e| e.into()))
147 .collect::<Result<Vec<u64>, Self::Error>>()?
148 .iter()
149 .map(|p| PhysAddr(*p as usize))
150 .collect_vec())
151 }
152}
153
154impl From<PhysAddr> for usize {
155 fn from(addr: PhysAddr) -> usize {
156 addr.0
157 }
158}
159
160impl From<PhysAddr> for *const u8 {
161 fn from(addr: PhysAddr) -> *const u8 {
162 addr.0 as *const u8
163 }
164}
165
166impl std::fmt::Pointer for PhysAddr {
167 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
168 write!(f, "{:p}", self.0 as *const u8)
169 }
170}
171
172impl Add<PhysAddr> for PhysAddr {
173 type Output = PhysAddr;
174
175 fn add(self, rhs: PhysAddr) -> Self::Output {
176 PhysAddr(self.0 + rhs.0)
177 }
178}
179
180impl Sub<PhysAddr> for PhysAddr {
181 type Output = PhysAddr;
182
183 fn sub(self, rhs: PhysAddr) -> Self::Output {
184 assert!(self.0 >= rhs.0);
185 PhysAddr(self.0 - rhs.0)
186 }
187}
188
189impl Add<usize> for PhysAddr {
190 type Output = PhysAddr;
191
192 fn add(self, rhs: usize) -> Self::Output {
193 PhysAddr(self.0 + rhs)
194 }
195}
196
197impl Sub<usize> for PhysAddr {
198 type Output = PhysAddr;
199
200 fn sub(self, rhs: usize) -> Self::Output {
201 assert!(self.0 >= rhs);
202 PhysAddr(self.0 - rhs)
203 }
204}