1use std::mem::MaybeUninit;
2
3use anyhow::{anyhow, bail, Result};
4use simics::{get_interface, read_byte, Access, ConfObject, ProcessorInfoV2Interface};
5
6use super::paging::{
7 DIR_TABLE_BASE, PAGE_1GB_SHIFT, PAGE_2MB_SHIFT, PAGE_4KB_SHIFT, PDE, PDPTE, PDPTE_LARGE, PML4E,
8 PTE, VIRTUAL_ADDRESS,
9};
10
11pub fn read_virtual<T>(processor: *mut ConfObject, virtual_address: u64) -> Result<T>
13where
14 T: Sized,
15{
16 let mut processor_info_v2: ProcessorInfoV2Interface = get_interface(processor)?;
17
18 let size = std::mem::size_of::<T>();
19
20 let mut t = MaybeUninit::<T>::uninit();
21
22 let memory = processor_info_v2.get_physical_memory()?;
23
24 let contents = (0..size)
25 .map(|i| {
26 processor_info_v2
27 .logical_to_physical(virtual_address + i as u64, Access::Sim_Access_Read)
28 .and_then(|b| read_byte(memory, b.address))
29 .map_err(|e| anyhow!("Failed to read memory: {}", e))
30 })
31 .collect::<Result<Vec<u8>>>()?;
32
33 unsafe {
34 std::ptr::copy_nonoverlapping(contents.as_ptr(), t.as_mut_ptr() as *mut u8, size);
35 Ok(t.assume_init())
36 }
37}
38
39pub fn read_physical<T>(processor: *mut ConfObject, physical_address: u64) -> Result<T> {
41 let mut processor_info_v2: ProcessorInfoV2Interface = get_interface(processor)?;
42
43 let size = std::mem::size_of::<T>();
44
45 let mut t = MaybeUninit::<T>::uninit();
46
47 let memory = processor_info_v2.get_physical_memory()?;
48
49 let contents = (0..size)
50 .map(|i| {
51 read_byte(memory, physical_address + i as u64)
52 .map_err(|e| anyhow!("Failed to read memory: {}", e))
53 })
54 .collect::<Result<Vec<u8>>>()?;
55
56 unsafe {
57 std::ptr::copy_nonoverlapping(contents.as_ptr(), t.as_mut_ptr() as *mut u8, size);
58 Ok(t.assume_init())
59 }
60}
61
62pub fn read_virtual_dtb<T>(
64 processor: *mut ConfObject,
65 directory_table_base: u64,
66 virtual_address: u64,
67) -> Result<T> {
68 let physical_address = virtual_to_physical(processor, directory_table_base, virtual_address)?;
69 read_physical(processor, physical_address)
70}
71
72pub fn virtual_to_physical(
74 processor: *mut ConfObject,
75 directory_table_base: u64,
76 virtual_address: u64,
77 ) -> Result<u64> {
79 let virtual_address = VIRTUAL_ADDRESS {
80 All: virtual_address,
81 };
82 let dir_table_base = DIR_TABLE_BASE {
83 All: directory_table_base,
84 };
85 let pml4e = read_physical::<PML4E>(
86 processor,
87 (unsafe { dir_table_base.Bits }.PhysicalAddress() << PAGE_4KB_SHIFT as u64)
88 + (unsafe { virtual_address.Bits }.Pml4Index() * 8),
89 )?;
90
91 if unsafe { pml4e.Bits }.Present() == 0 {
92 bail!("PML4E not present");
93 }
94
95 let pdpte = read_physical::<PDPTE>(
96 processor,
97 (unsafe { pml4e.Bits }.PhysicalAddress() << PAGE_4KB_SHIFT)
98 + (unsafe { virtual_address.Bits }.PdptIndex() * 8),
99 )?;
100
101 if unsafe { pdpte.Bits }.Present() == 0 {
102 bail!("PDPTE not present");
103 }
104
105 if (unsafe { pdpte.All } >> 7) & 1 != 0 {
106 let pdpte_large = PDPTE_LARGE {
107 All: unsafe { pdpte.All },
108 };
109 return Ok(
110 ((unsafe { pdpte_large.Bits }.PhysicalAddress()) << PAGE_1GB_SHIFT)
111 + (unsafe { virtual_address.All } & (!(u64::MAX << PAGE_1GB_SHIFT))),
112 );
113 }
114
115 let pde = read_physical::<PDE>(
116 processor,
117 (unsafe { pdpte.Bits }.PhysicalAddress() << PAGE_4KB_SHIFT)
118 + (unsafe { virtual_address.Bits }.PdIndex() * 8),
119 )?;
120
121 if unsafe { pde.Bits }.Present() == 0 {
122 bail!("PDE not present");
123 }
124
125 if (unsafe { pde.All } >> 7) & 1 != 0 {
126 let pde_large = PDPTE_LARGE {
127 All: unsafe { pde.All },
128 };
129 return Ok(
130 ((unsafe { pde_large.Bits }.PhysicalAddress()) << PAGE_2MB_SHIFT)
131 + (unsafe { virtual_address.All } & (!(u64::MAX << PAGE_2MB_SHIFT))),
132 );
133 }
134
135 let pte = read_physical::<PTE>(
136 processor,
137 (unsafe { pde.Bits }.PhysicalAddress() << PAGE_4KB_SHIFT)
138 + (unsafe { virtual_address.Bits }.PtIndex() * 8),
139 )?;
140
141 if unsafe { pte.Bits }.Present() == 0 {
142 bail!("PTE not present");
143 }
144
145 Ok((unsafe { pte.Bits }.PhysicalAddress() << PAGE_4KB_SHIFT)
146 + unsafe { virtual_address.Bits }.PageIndex())
147}
148
149pub fn read_unicode_string(
150 processor: *mut ConfObject,
151 length: usize,
152 buffer: *const u16,
153) -> Result<String> {
154 if length == 0 || buffer.is_null() {
155 return Ok(String::new());
156 }
157
158 let mut string = Vec::new();
159 let mut address = buffer as u64;
160
161 for _ in 0..length {
162 let character = read_virtual::<u16>(processor, address)?;
163
164 if character == 0 {
165 break;
166 }
167
168 string.push(character);
169 address += 2;
170 }
171
172 String::from_utf16(&string).map_err(|e| anyhow!("Failed to convert string: {}", e))
173}
174
175pub fn read_unicode_string_dtb(
176 processor: *mut ConfObject,
177 length: usize,
178 buffer: *const u16,
179 directory_table_base: u64,
180) -> Result<String> {
181 if length == 0 || buffer.is_null() {
182 return Ok(String::new());
183 }
184 let mut string = Vec::new();
185 let mut address = buffer as u64;
186
187 for _ in 0..length {
188 let character = read_virtual_dtb::<u16>(processor, directory_table_base, address)?;
189
190 if character == 0 {
191 break;
192 }
193
194 string.push(character);
195 address += 2;
196 }
197
198 String::from_utf16(&string).map_err(|e| anyhow!("Failed to convert string: {}", e))
199}
200
201pub fn read_nul_terminated_string(processor: *mut ConfObject, address: u64) -> Result<String> {
202 if address == 0 {
203 return Ok(String::new());
204 }
205 let mut string = String::new();
206 let mut address = address;
207
208 loop {
209 let character = read_virtual::<u8>(processor, address)?;
210
211 if character == 0 {
212 break;
213 }
214
215 string.push(character as char);
216 address += 1;
217 }
218
219 Ok(string)
220}
221
222pub fn read_nul_terminated_string_dtb(
223 processor: *mut ConfObject,
224 address: u64,
225 directory_table_base: u64,
226) -> Result<String> {
227 if address == 0 {
228 return Ok(String::new());
229 }
230 let mut string = String::new();
231 let mut address = address;
232
233 loop {
234 let character = read_virtual_dtb::<u8>(processor, directory_table_base, address)?;
235
236 if character == 0 {
237 break;
238 }
239
240 string.push(character as char);
241 address += 1;
242 }
243
244 Ok(string)
245}