Browse Source

[core] initial unaligned mapping support

remotes/1785854429613479800/tmp_refs/heads/variable-page-size
Exverge 2 weeks ago
parent
commit
e74bac2639
No known key found for this signature in database GPG Key ID: DAD399BCC5FB77E4
  1. 78
      src/core/memory.cpp

78
src/core/memory.cpp

@ -67,15 +67,34 @@ struct Memory::Impl {
void MapMemoryRegion(Common::PageTable& page_table, Common::ProcessAddress base, u64 size,
Common::PhysicalAddress target, Common::MemoryPermission perms,
bool separate_heap) {
ASSERT_MSG((size & YUZU_PAGEMASK) == 0, "non-page aligned size: {:016X}", size);
ASSERT_MSG((base & YUZU_PAGEMASK) == 0, "non-page aligned base: {:016X}", GetInteger(base));
ASSERT_MSG(target >= DramMemoryMap::Base, "Out of bounds target: {:016X}",
ASSERT_MSG((size & YUZU_PAGEMASK) == 0, "non-page aligned size: {:#x}", size);
ASSERT_MSG((base & YUZU_PAGEMASK) == 0, "non-page aligned base: {:#x}", GetInteger(base));
ASSERT_MSG((target & YUZU_PAGEMASK) == 0, "non-page aligned target: {:#x}", GetInteger(target));
ASSERT_MSG(target >= DramMemoryMap::Base, "Out of bounds target: {:#x}",
GetInteger(target));
MapPages(page_table, base / YUZU_PAGESIZE, size / YUZU_PAGESIZE, target,
auto out = MapPages(page_table, base / YUZU_PAGESIZE, size / YUZU_PAGESIZE, target,
Common::PageType::Memory);
if (current_page_table->fastmem_arena) {
host_buffer->Map(GetInteger(base), GetInteger(target) - DramMemoryMap::Base, size, perms, separate_heap);
ASSERT_MSG(GetInteger(base) % Common::HostPageSize == GetInteger(target) % Common::HostPageSize,
"base {:#x} and target {:#x} aren't aligned in relation to host page size {}",
GetInteger(base), GetInteger(target), Common::HostPageSize);
LOG_WARNING(HW_Memory, "fastmem called");
auto align = [&](bool b, u64 v) {
return b ? Common::AlignUp(v, Common::HostPageSize) : Common::AlignDown(v, Common::HostPageSize);
};
auto aligned_base = align(out.first, GetInteger(base));
auto aligned_target = align(out.first, GetInteger(target) - DramMemoryMap::Base);
auto aligned_end = align(!out.second, GetInteger(base) + size);
host_buffer->Map(
aligned_base,
aligned_target,
aligned_end - aligned_base,
perms, separate_heap);
}
}
@ -525,7 +544,7 @@ struct Memory::Impl {
* @param target The target address to begin mapping from.
* @param type The page type to map the memory as.
*/
void MapPages(Common::PageTable& page_table, Common::ProcessAddress base_address, u64 size,
/*[[nodiscard]]*/ std::pair<bool, bool> MapPages(Common::PageTable& page_table, Common::ProcessAddress base_address, u64 size,
Common::PhysicalAddress target, Common::PageType type) {
auto base = GetInteger(base_address);
@ -539,17 +558,59 @@ struct Memory::Impl {
ASSERT_MSG(type != Common::PageType::Memory,
"Mapping memory page without a pointer @ {:016x}", base * YUZU_PAGESIZE);
// TODO: remove extra pages
while (base != end) {
page_table.entries[base].ptr.Store(0, type);
page_table.entries[base].addr = 0;
page_table.entries[base].block = 0;
base += 1;
}
return {false, false};
} else {
std::pair out = {false, false};
// keep track of mappings that are unaligned to host page size
if (auto off = base % Common::GuestHostAlignment; off != 0) {
// using `block` here for storage vs. keeping it in another set is a hack to save memory;
// it'll never gets used as a direct value, just as a marker by GetSpan,
// and the value we input here should never be the same so we don't have to worry about GetSpan
// returning the wrong value
auto e = base - off;
for (u64 i = 0; i < off; ++i, ++e) {
if (page_table.entries[e].addr == 0 && page_table.entries[e].block == 0) {
LOG_WARNING(HW_Memory, "marked before");
page_table.entries[e].block = (GetInteger(target) >> YUZU_PAGEBITS) - off + i;
} else {
// Either an irregular mapping or unaligned one; either way we'll just skip this anyway
out.first = true;
}
}
}
if (auto off = end & (Common::GuestHostAlignment - 1); off != 0) {
auto remaining = Common::GuestHostAlignment - off;
auto e = end;
for (u64 i = 0; i < remaining; ++i, ++e) {
if (page_table.entries[e].addr == 0 && page_table.entries[e].block == 0) {
LOG_WARNING(HW_Memory, "marked end");
page_table.entries[e].block = (GetInteger(target) >> YUZU_PAGEBITS) + size + i;
} else {
out.second = true;
}
}
}
auto orig_base = base;
while (base != end) {
auto host_ptr = uintptr_t(system.DeviceMemory().GetPointer<u8>(target)) - (base << YUZU_PAGEBITS);
auto backing = GetInteger(target) - (base << YUZU_PAGEBITS);
auto target_paddr = target;
if (auto real_paddr = page_table.entries[base].block; real_paddr != 0 && page_table.entries[base].addr == 0) {
// Irregular mapping; let's just map its original physical address and continue
LOG_WARNING(HW_Memory, "Mapping irregular address; {:#x} points to {:#x} instead of {:#x}",
base << YUZU_PAGEBITS, real_paddr << YUZU_PAGEBITS, GetInteger(target));
target_paddr = real_paddr << YUZU_PAGEBITS;
}
auto host_ptr = uintptr_t(system.DeviceMemory().GetPointer<u8>(target_paddr)) - (base << YUZU_PAGEBITS);
auto backing = GetInteger(target_paddr) - (base << YUZU_PAGEBITS);
page_table.entries[base].ptr.Store(host_ptr, type);
page_table.entries[base].addr = backing;
page_table.entries[base].block = orig_base << YUZU_PAGEBITS;
@ -560,6 +621,7 @@ struct Memory::Impl {
base += 1;
target += YUZU_PAGESIZE;
}
return out;
}
}

Loading…
Cancel
Save