201 if (!physical_space_)
202 return unexpected(remote_page_table_walk_error::invalid_physical_space);
204 return unexpected(remote_page_table_walk_error::invalid_layout);
205 if (root_table_address == 0)
206 return unexpected(remote_page_table_walk_error::invalid_root);
208 uintptr_t table_address = root_table_address;
209 const size_t level_count = layout_.level_count();
211 for (
size_t level = 0; level < level_count; ++level) {
213 if (!layout_.describe_level(level, description) || description.index_bits == 0 || description.index_bits >= 64 ||
214 description.index_shift >=
static_cast<uint8_t
>(
sizeof(uintptr_t) * 8)) {
215 return unexpected(remote_page_table_walk_error::invalid_level);
217 if (description.entry_size != 1 && description.entry_size != 2 && description.entry_size != 4 &&
218 description.entry_size != 8) {
219 return unexpected(remote_page_table_walk_error::unsupported_entry_size);
222 const uint64_t index_mask = (UINT64_C(1) << description.index_bits) - UINT64_C(1);
223 const uint64_t index = (
static_cast<uint64_t
>(virtual_address) >> description.index_shift) & index_mask;
224 if (index > std::numeric_limits<uintptr_t>::max() / description.entry_size) {
225 return unexpected(remote_page_table_walk_error::address_overflow);
227 const uintptr_t entry_offset =
static_cast<uintptr_t
>(index) * description.entry_size;
228 if (table_address > std::numeric_limits<uintptr_t>::max() - entry_offset) {
229 return unexpected(remote_page_table_walk_error::address_overflow);
231 const uintptr_t entry_address = table_address + entry_offset;
233 array<std::byte, 8> entry_bytes{};
234 const auto read_result = physical_space_.read_bytes(entry_address, entry_bytes.data(), description.entry_size);
236 return unexpected(remote_page_table_walk_error::read_failed);
238 uint64_t raw_entry = 0;
239 for (
size_t byte = 0;
byte < description.entry_size; ++byte) {
240 raw_entry |=
static_cast<uint64_t
>(
static_cast<unsigned char>(entry_bytes[byte])) << (
byte * 8);
244 if (!layout_.decode_entry(level, raw_entry, decoded))
245 return unexpected(remote_page_table_walk_error::decode_failed);
249 if (decoded.kind == remote_page_table_entry_kind::invalid)
250 return unexpected(remote_page_table_walk_error::invalid_entry);
252 if (decoded.kind == remote_page_table_entry_kind::next_table) {
253 if (level + 1 == level_count || decoded.output_address == 0)
254 return unexpected(remote_page_table_walk_error::unexpected_next_table);
255 table_address = decoded.output_address;
259 if (decoded.kind != remote_page_table_entry_kind::leaf || decoded.page_size == 0 ||
260 (decoded.page_size & (decoded.page_size - 1)) != 0 ||
261 decoded.output_address >
262 std::numeric_limits<uintptr_t>::max() - (virtual_address & (decoded.page_size - 1))) {
263 return unexpected(remote_page_table_walk_error::invalid_leaf);
266 const uintptr_t physical_address = decoded.output_address + (virtual_address & (decoded.page_size - 1));
268 decoded.readable, decoded.writable, decoded.executable,
269 decoded.user_accessible};
273 return unexpected(remote_page_table_walk_error::invalid_entry);