mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-29 08:41:20 +00:00
memory: separate extended allocations from ordinary guest mappings
This commit is contained in:
1 parent
ab2c1c4c03
commit
c91fe80d64
5 files changed
+90
-55
No files matched your search
@@ -78,8 +78,7 @@ static Graphics::RenderContext& GetGpuResources() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool IsGpuAddressRange(uint64_t vaddr, uint64_t size) {
|
static bool IsGpuAddressRange(uint64_t vaddr, uint64_t size) {
|
||||||
constexpr uint64_t GPU_ADDRESS_LIMIT = 1ull << 40u;
|
return Graphics::GuestRange {vaddr, size}.Valid();
|
||||||
return vaddr != 0 && size != 0 && vaddr < GPU_ADDRESS_LIMIT && size < GPU_ADDRESS_LIMIT - vaddr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void MapGpuRange(uint64_t vaddr, uint64_t size) {
|
static void MapGpuRange(uint64_t vaddr, uint64_t size) {
|
||||||
|
|||||||
@@ -24,6 +24,8 @@ struct Lifecycle {
|
|||||||
using callback_func_t = void (*)(uintptr_t addr, size_t size);
|
using callback_func_t = void (*)(uintptr_t addr, size_t size);
|
||||||
|
|
||||||
constexpr uint32_t KERNEL_MAXIMUM_NAME_LENGTH = 32;
|
constexpr uint32_t KERNEL_MAXIMUM_NAME_LENGTH = 32;
|
||||||
|
constexpr uint64_t kExtendedMemoryBase = 0x080000000000ull;
|
||||||
|
constexpr uint64_t kExtendedMemorySize = 512ull * 1024 * 1024 * 1024;
|
||||||
|
|
||||||
struct VirtualQueryInfo {
|
struct VirtualQueryInfo {
|
||||||
uintptr_t start;
|
uintptr_t start;
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
static constexpr uint64_t HOST_SYSTEM_MANAGED_MIN = 0x0000040000ull;
|
static constexpr uint64_t HOST_SYSTEM_MANAGED_MIN = 0x0000040000ull;
|
||||||
static constexpr uint64_t HOST_SYSTEM_MANAGED_MAX = 0x07ffffbfffull;
|
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))
|
#if defined(__APPLE__) && (defined(__x86_64__) || defined(_M_X64))
|
||||||
static constexpr uint64_t HOST_SYSTEM_RESERVED_MAX = 0x0fbfffffffull;
|
static constexpr uint64_t HOST_SYSTEM_RESERVED_MAX = 0x0fbfffffffull;
|
||||||
static constexpr uint64_t HOST_USER_MIN = 0x7000000000ull;
|
static constexpr uint64_t HOST_USER_MIN = 0x7000000000ull;
|
||||||
@@ -1077,51 +1076,51 @@ private:
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
void ReserveGuestRegions() {
|
void ReserveGuestRegions() {
|
||||||
|
const std::array<std::pair<uint64_t, uint64_t>, 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
|
#if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS
|
||||||
constexpr uint64_t MinimumRegionSize = 0x1000000;
|
constexpr uint64_t MinimumRegionSize = 0x1000000;
|
||||||
const auto process = GetCurrentProcess();
|
const auto process = GetCurrentProcess();
|
||||||
const auto guest_end = HOST_USER_MAX + 1u;
|
for (const auto& [guest_start, guest_end]: regions) {
|
||||||
auto next_addr = HOST_SYSTEM_MANAGED_MIN;
|
auto next_addr = guest_start;
|
||||||
|
while (next_addr < guest_end) {
|
||||||
while (next_addr < guest_end) {
|
MEMORY_BASIC_INFORMATION info {};
|
||||||
MEMORY_BASIC_INFORMATION info {};
|
if (VirtualQuery(reinterpret_cast<const void*>(next_addr), &info, sizeof(info)) == 0) {
|
||||||
if (VirtualQuery(reinterpret_cast<const void*>(next_addr), &info, sizeof(info)) == 0) {
|
EXIT("failed to inspect guest address space at 0x%016" PRIx64 "\n", next_addr);
|
||||||
EXIT("failed to inspect guest address space at 0x%016" PRIx64 "\n", next_addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto region_base = reinterpret_cast<uint64_t>(info.BaseAddress);
|
|
||||||
const auto region_end =
|
|
||||||
std::min<uint64_t>(guest_end, region_base + static_cast<uint64_t>(info.RegionSize));
|
|
||||||
const auto reserve_start =
|
|
||||||
AlignUp(std::max<uint64_t>(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<void*>(reserve_start), reserve_end - reserve_start,
|
|
||||||
MEM_RESERVE | MEM_RESERVE_PLACEHOLDER, PAGE_NOACCESS, nullptr, 0);
|
|
||||||
if (reinterpret_cast<uint64_t>(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) {
|
const auto region_base = reinterpret_cast<uint64_t>(info.BaseAddress);
|
||||||
EXIT("guest address-space scan did not advance at 0x%016" PRIx64 "\n", next_addr);
|
const auto region_end = std::min<uint64_t>(
|
||||||
|
guest_end, region_base + static_cast<uint64_t>(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<void*>(reserve_start), reserve_end - reserve_start,
|
||||||
|
MEM_RESERVE | MEM_RESERVE_PLACEHOLDER, PAGE_NOACCESS, nullptr, 0);
|
||||||
|
if (reinterpret_cast<uint64_t>(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
|
#else
|
||||||
const std::array<std::pair<uint64_t, uint64_t>, 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__)
|
#if KYTY_PLATFORM == KYTY_PLATFORM_LINUX && !defined(__APPLE__)
|
||||||
std::vector<std::pair<uint64_t, uint64_t>> occupied;
|
std::vector<std::pair<uint64_t, uint64_t>> occupied;
|
||||||
FILE* maps = fopen("/proc/self/maps", "r");
|
FILE* maps = fopen("/proc/self/maps", "r");
|
||||||
|
|||||||
+5
-15
@@ -685,8 +685,6 @@ constexpr int PROT_AMPR_READ = 0x40;
|
|||||||
constexpr int PROT_AMPR_WRITE = 0x80;
|
constexpr int PROT_AMPR_WRITE = 0x80;
|
||||||
constexpr int PROT_ACP_READ = 0x100;
|
constexpr int PROT_ACP_READ = 0x100;
|
||||||
constexpr int PROT_ACP_WRITE = 0x200;
|
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_READ_LENGTH = 0x0000000100000000ull;
|
||||||
constexpr uint64_t APR_MAX_FILE_OFFSET = 0x0000010000000000ull;
|
constexpr uint64_t APR_MAX_FILE_OFFSET = 0x0000010000000000ull;
|
||||||
constexpr uint64_t APR_MAX_APP_ADDRESS = 0x0000f00000000000ull;
|
constexpr uint64_t APR_MAX_APP_ADDRESS = 0x0000f00000000000ull;
|
||||||
@@ -750,13 +748,6 @@ struct AmmAutoPoolRange {
|
|||||||
uint64_t used = 0;
|
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 {
|
struct AmmUsageStatsData {
|
||||||
uint64_t size_in_bytes = 0;
|
uint64_t size_in_bytes = 0;
|
||||||
uint16_t num_page_table_pool_entries = 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) {
|
uint64_t* multimap_va_end) {
|
||||||
PRINT_NAME();
|
PRINT_NAME();
|
||||||
|
|
||||||
|
constexpr auto end = LibKernel::Memory::kExtendedMemoryBase + LibKernel::Memory::kExtendedMemorySize;
|
||||||
if (va_start != nullptr) {
|
if (va_start != nullptr) {
|
||||||
AprShared::WriteGuest(reinterpret_cast<uint64_t>(va_start), AMM_VA_START);
|
AprShared::WriteGuest(reinterpret_cast<uint64_t>(va_start), LibKernel::Memory::kExtendedMemoryBase);
|
||||||
}
|
}
|
||||||
if (va_end != nullptr) {
|
if (va_end != nullptr) {
|
||||||
AprShared::WriteGuest(reinterpret_cast<uint64_t>(va_end), AMM_VA_START + AMM_VA_SIZE);
|
AprShared::WriteGuest(reinterpret_cast<uint64_t>(va_end), end);
|
||||||
}
|
}
|
||||||
if (multimap_va_start != nullptr) {
|
if (multimap_va_start != nullptr) {
|
||||||
AprShared::WriteGuest(reinterpret_cast<uint64_t>(multimap_va_start),
|
AprShared::WriteGuest(reinterpret_cast<uint64_t>(multimap_va_start), end);
|
||||||
AMM_VA_START + AMM_VA_SIZE / 2u);
|
|
||||||
}
|
}
|
||||||
if (multimap_va_end != nullptr) {
|
if (multimap_va_end != nullptr) {
|
||||||
AprShared::WriteGuest(reinterpret_cast<uint64_t>(multimap_va_end),
|
AprShared::WriteGuest(reinterpret_cast<uint64_t>(multimap_va_end), end);
|
||||||
AMM_VA_START + AMM_VA_SIZE);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2163,6 +2163,50 @@ void TestFixedReserveRangeAddRollbackKeepsPlaceholder() {
|
|||||||
std::printf("[host] %-48s ok\n", test);
|
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<void*>(addresses[i]);
|
||||||
|
CheckOk(test,
|
||||||
|
Libs::LibKernel::Memory::KernelMapDirectMemory(
|
||||||
|
&mapped, SceKernelPageSize, SceKernelProtCpuRw,
|
||||||
|
SceKernelMapFixed | SceKernelMapNoOverwrite,
|
||||||
|
physical + i * SceKernelPageSize, SceKernelPageSize),
|
||||||
|
"KernelMapDirectMemory");
|
||||||
|
Check(test, mapped == reinterpret_cast<void*>(addresses[i]), "fixed mapping moved");
|
||||||
|
*static_cast<uint64_t*>(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<uint64_t*>(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() {
|
void TestLargeHintedReserveHostsSmallDirectMap() {
|
||||||
const char* test = "LargeHintedReserveHostsSmallDirectMap";
|
const char* test = "LargeHintedReserveHostsSmallDirectMap";
|
||||||
|
|
||||||
@@ -3155,6 +3199,7 @@ int main(int argc, char** argv) {
|
|||||||
RunTest(TestFixedReserveRollbackSkipsUntouchedChunks);
|
RunTest(TestFixedReserveRollbackSkipsUntouchedChunks);
|
||||||
RunTest(TestFixedReserveRangeAddRollbackKeepsPlaceholder);
|
RunTest(TestFixedReserveRangeAddRollbackKeepsPlaceholder);
|
||||||
RunTest(TestLargeHintedReserveHostsSmallDirectMap);
|
RunTest(TestLargeHintedReserveHostsSmallDirectMap);
|
||||||
|
RunTest(TestExtendedAndUserMappingsDoNotAlias);
|
||||||
RunTest(TestMemoryPoolAlignmentContracts);
|
RunTest(TestMemoryPoolAlignmentContracts);
|
||||||
RunTest(TestProsperoSampleMemoryPoolExpandCommit);
|
RunTest(TestProsperoSampleMemoryPoolExpandCommit);
|
||||||
RunTest(TestFragmentedMemoryPoolBacking);
|
RunTest(TestFragmentedMemoryPoolBacking);
|
||||||
|
|||||||
Reference in new issue
Block a user