diff --git a/src/kernel/memory.cpp b/src/kernel/memory.cpp index 38e8722d..66d116b0 100644 --- a/src/kernel/memory.cpp +++ b/src/kernel/memory.cpp @@ -78,8 +78,7 @@ static Graphics::RenderContext& GetGpuResources() { } static bool IsGpuAddressRange(uint64_t vaddr, uint64_t size) { - constexpr uint64_t GPU_ADDRESS_LIMIT = 1ull << 40u; - return vaddr != 0 && size != 0 && vaddr < GPU_ADDRESS_LIMIT && size < GPU_ADDRESS_LIMIT - vaddr; + return Graphics::GuestRange {vaddr, size}.Valid(); } static void MapGpuRange(uint64_t vaddr, uint64_t size) { diff --git a/src/kernel/memory.h b/src/kernel/memory.h index 9f87b09a..94da9790 100644 --- a/src/kernel/memory.h +++ b/src/kernel/memory.h @@ -24,6 +24,8 @@ struct Lifecycle { using callback_func_t = void (*)(uintptr_t addr, size_t size); constexpr uint32_t KERNEL_MAXIMUM_NAME_LENGTH = 32; +constexpr uint64_t kExtendedMemoryBase = 0x080000000000ull; +constexpr uint64_t kExtendedMemorySize = 512ull * 1024 * 1024 * 1024; struct VirtualQueryInfo { uintptr_t start; diff --git a/src/kernel/memoryAddressSpace.inc b/src/kernel/memoryAddressSpace.inc index 868d8ba3..f4a4ea37 100644 --- a/src/kernel/memoryAddressSpace.inc +++ b/src/kernel/memoryAddressSpace.inc @@ -3,7 +3,6 @@ static constexpr uint64_t HOST_SYSTEM_MANAGED_MIN = 0x0000040000ull; static constexpr uint64_t HOST_SYSTEM_MANAGED_MAX = 0x07ffffbfffull; -static constexpr uint64_t HOST_SYSTEM_RESERVED_MIN = HOST_SYSTEM_MANAGED_MAX + 1u; #if defined(__APPLE__) && (defined(__x86_64__) || defined(_M_X64)) static constexpr uint64_t HOST_SYSTEM_RESERVED_MAX = 0x0fbfffffffull; static constexpr uint64_t HOST_USER_MIN = 0x7000000000ull; @@ -1077,51 +1076,51 @@ private: #endif void ReserveGuestRegions() { + const std::array, 3> regions {{ + {HOST_SYSTEM_MANAGED_MIN, HOST_SYSTEM_RESERVED_MAX + 1u}, + {HOST_USER_MIN, HOST_USER_MAX + 1u}, + {kExtendedMemoryBase, kExtendedMemoryBase + kExtendedMemorySize}, + }}; + #if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS constexpr uint64_t MinimumRegionSize = 0x1000000; const auto process = GetCurrentProcess(); - const auto guest_end = HOST_USER_MAX + 1u; - auto next_addr = HOST_SYSTEM_MANAGED_MIN; - - while (next_addr < guest_end) { - MEMORY_BASIC_INFORMATION info {}; - if (VirtualQuery(reinterpret_cast(next_addr), &info, sizeof(info)) == 0) { - EXIT("failed to inspect guest address space at 0x%016" PRIx64 "\n", next_addr); - } - - const auto region_base = reinterpret_cast(info.BaseAddress); - const auto region_end = - std::min(guest_end, region_base + static_cast(info.RegionSize)); - const auto reserve_start = - AlignUp(std::max(region_base, HOST_SYSTEM_MANAGED_MIN), m_granularity); - const auto reserve_end = AlignDown(region_end, m_granularity); - - if (info.State == MEM_FREE && reserve_end > reserve_start && - reserve_end - reserve_start > MinimumRegionSize) { - auto* ptr = VirtualAlloc2( - process, reinterpret_cast(reserve_start), reserve_end - reserve_start, - MEM_RESERVE | MEM_RESERVE_PLACEHOLDER, PAGE_NOACCESS, nullptr, 0); - if (reinterpret_cast(ptr) != reserve_start) { - EXIT("failed to reserve guest address space at 0x%016" PRIx64 - ", size 0x%016" PRIx64 "\n", - reserve_start, reserve_end - reserve_start); + for (const auto& [guest_start, guest_end]: regions) { + auto next_addr = guest_start; + while (next_addr < guest_end) { + MEMORY_BASIC_INFORMATION info {}; + if (VirtualQuery(reinterpret_cast(next_addr), &info, sizeof(info)) == 0) { + EXIT("failed to inspect guest address space at 0x%016" PRIx64 "\n", next_addr); } - AddFreeUnlocked(reserve_start, reserve_end - reserve_start); - m_owned.emplace_back(reserve_start, reserve_end - reserve_start); - } - if (region_end <= next_addr) { - EXIT("guest address-space scan did not advance at 0x%016" PRIx64 "\n", next_addr); + const auto region_base = reinterpret_cast(info.BaseAddress); + const auto region_end = std::min( + guest_end, region_base + static_cast(info.RegionSize)); + const auto reserve_start = + AlignUp(std::max(region_base, guest_start), m_granularity); + const auto reserve_end = AlignDown(region_end, m_granularity); + + if (info.State == MEM_FREE && reserve_end > reserve_start && + reserve_end - reserve_start > MinimumRegionSize) { + auto* ptr = VirtualAlloc2( + process, reinterpret_cast(reserve_start), reserve_end - reserve_start, + MEM_RESERVE | MEM_RESERVE_PLACEHOLDER, PAGE_NOACCESS, nullptr, 0); + if (reinterpret_cast(ptr) != reserve_start) { + EXIT("failed to reserve guest address space at 0x%016" PRIx64 + ", size 0x%016" PRIx64 "\n", + reserve_start, reserve_end - reserve_start); + } + AddFreeUnlocked(reserve_start, reserve_end - reserve_start); + m_owned.emplace_back(reserve_start, reserve_end - reserve_start); + } + + if (region_end <= next_addr) { + EXIT("guest address-space scan did not advance at 0x%016" PRIx64 "\n", next_addr); + } + next_addr = region_end; } - next_addr = region_end; } #else - const std::array, 3> regions {{ - {HOST_SYSTEM_MANAGED_MIN, HOST_SYSTEM_MANAGED_MAX + 1u}, - {HOST_SYSTEM_RESERVED_MIN, HOST_SYSTEM_RESERVED_MAX + 1u}, - {HOST_USER_MIN, HOST_USER_MAX + 1u}, - }}; - #if KYTY_PLATFORM == KYTY_PLATFORM_LINUX && !defined(__APPLE__) std::vector> occupied; FILE* maps = fopen("/proc/self/maps", "r"); diff --git a/src/libs/libAmpr.cpp b/src/libs/libAmpr.cpp index 741ecc5f..d7eadab5 100644 --- a/src/libs/libAmpr.cpp +++ b/src/libs/libAmpr.cpp @@ -685,8 +685,6 @@ constexpr int PROT_AMPR_READ = 0x40; constexpr int PROT_AMPR_WRITE = 0x80; constexpr int PROT_ACP_READ = 0x100; constexpr int PROT_ACP_WRITE = 0x200; -constexpr uint64_t AMM_VA_START = 0x0000001000000000ull; -constexpr uint64_t AMM_VA_SIZE = 0x0000001000000000ull; constexpr uint64_t APR_MAX_READ_LENGTH = 0x0000000100000000ull; constexpr uint64_t APR_MAX_FILE_OFFSET = 0x0000010000000000ull; constexpr uint64_t APR_MAX_APP_ADDRESS = 0x0000f00000000000ull; @@ -750,13 +748,6 @@ struct AmmAutoPoolRange { uint64_t used = 0; }; -struct AmmVirtualAddressRanges { - uint64_t va_start = 0; - uint64_t va_end = 0; - uint64_t multimap_va_start = 0; - uint64_t multimap_va_end = 0; -}; - struct AmmUsageStatsData { uint64_t size_in_bytes = 0; uint16_t num_page_table_pool_entries = 0; @@ -2386,19 +2377,18 @@ static void KYTY_SYSV_ABI AmmGetVirtualAddressRanges(uint64_t* va_start, uint64_ uint64_t* multimap_va_end) { PRINT_NAME(); + constexpr auto end = LibKernel::Memory::kExtendedMemoryBase + LibKernel::Memory::kExtendedMemorySize; if (va_start != nullptr) { - AprShared::WriteGuest(reinterpret_cast(va_start), AMM_VA_START); + AprShared::WriteGuest(reinterpret_cast(va_start), LibKernel::Memory::kExtendedMemoryBase); } if (va_end != nullptr) { - AprShared::WriteGuest(reinterpret_cast(va_end), AMM_VA_START + AMM_VA_SIZE); + AprShared::WriteGuest(reinterpret_cast(va_end), end); } if (multimap_va_start != nullptr) { - AprShared::WriteGuest(reinterpret_cast(multimap_va_start), - AMM_VA_START + AMM_VA_SIZE / 2u); + AprShared::WriteGuest(reinterpret_cast(multimap_va_start), end); } if (multimap_va_end != nullptr) { - AprShared::WriteGuest(reinterpret_cast(multimap_va_end), - AMM_VA_START + AMM_VA_SIZE); + AprShared::WriteGuest(reinterpret_cast(multimap_va_end), end); } } diff --git a/tests/VirtualMemoryAllocationTests.cpp b/tests/VirtualMemoryAllocationTests.cpp index bd1791b9..cb5639ee 100644 --- a/tests/VirtualMemoryAllocationTests.cpp +++ b/tests/VirtualMemoryAllocationTests.cpp @@ -2163,6 +2163,50 @@ void TestFixedReserveRangeAddRollbackKeepsPlaceholder() { std::printf("[host] %-48s ok\n", test); } +void TestExtendedAndUserMappingsDoNotAlias() { + const char* test = "ExtendedAndUserMappingsDoNotAlias"; + constexpr uint64_t user_address = 0x1000000000ull; + const uint64_t addresses[] { + user_address, + Libs::LibKernel::Memory::kExtendedMemoryBase + user_address, + Libs::LibKernel::Memory::kExtendedMemoryBase + Libs::LibKernel::Memory::kExtendedMemorySize - + SceKernelPageSize, + }; + int64_t physical = 0; + CheckOk(test, + Libs::LibKernel::Memory::KernelAllocateDirectMemory( + 0, Libs::LibKernel::Memory::KernelGetDirectMemorySize(), + SceKernelPageSize * std::size(addresses), SceKernelPageSize, SceKernelMtypeC, + &physical), + "KernelAllocateDirectMemory"); + for (size_t i = 0; i < std::size(addresses); ++i) { + void* mapped = reinterpret_cast(addresses[i]); + CheckOk(test, + Libs::LibKernel::Memory::KernelMapDirectMemory( + &mapped, SceKernelPageSize, SceKernelProtCpuRw, + SceKernelMapFixed | SceKernelMapNoOverwrite, + physical + i * SceKernelPageSize, SceKernelPageSize), + "KernelMapDirectMemory"); + Check(test, mapped == reinterpret_cast(addresses[i]), "fixed mapping moved"); + *static_cast(mapped) = 0x0123456700000000ull + i; + } + for (size_t i = 0; i < std::size(addresses); ++i) { + uint64_t value = 0; + Check(test, + Libs::LibKernel::Memory::TryReadBacking(addresses[i], &value, sizeof(value)) && + value == 0x0123456700000000ull + i && + *reinterpret_cast(addresses[i]) == value, + "Extended and user mappings overlap or lost their backing"); + CheckOk(test, Libs::LibKernel::Memory::KernelMunmap(addresses[i], SceKernelPageSize), + "KernelMunmap"); + } + CheckOk(test, + Libs::LibKernel::Memory::KernelReleaseDirectMemory( + physical, SceKernelPageSize * std::size(addresses)), + "KernelReleaseDirectMemory"); + std::printf("[host] %-48s ok\n", test); +} + void TestLargeHintedReserveHostsSmallDirectMap() { const char* test = "LargeHintedReserveHostsSmallDirectMap"; @@ -3155,6 +3199,7 @@ int main(int argc, char** argv) { RunTest(TestFixedReserveRollbackSkipsUntouchedChunks); RunTest(TestFixedReserveRangeAddRollbackKeepsPlaceholder); RunTest(TestLargeHintedReserveHostsSmallDirectMap); + RunTest(TestExtendedAndUserMappingsDoNotAlias); RunTest(TestMemoryPoolAlignmentContracts); RunTest(TestProsperoSampleMemoryPoolExpandCommit); RunTest(TestFragmentedMemoryPoolBacking);