mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-21 03:16:54 +02:00
memory: honor sparse AMM unmaps and restore failed GPU ranges
This commit is contained in:
+52
-21
@@ -72,6 +72,9 @@ constexpr uint64_t DEFAULT_FLEXIBLE_MEMORY_SIZE = 1ull * 1024ull * 1024ull * 102
|
||||
static uint64_t g_flexible_memory_size = DEFAULT_FLEXIBLE_MEMORY_SIZE;
|
||||
static bool g_flexible_memory_size_frozen = false;
|
||||
static Graphics::RenderContext* g_gpu_resources = nullptr;
|
||||
#if defined(KYTY_VIRTUAL_MEMORY_ALLOCATION_TESTS)
|
||||
static void (*g_test_gpu_range)(bool, uint64_t, size_t) = nullptr;
|
||||
#endif
|
||||
|
||||
static Graphics::RenderContext& GetGpuResources() {
|
||||
EXIT_IF(g_gpu_resources == nullptr);
|
||||
@@ -83,6 +86,9 @@ static bool IsGpuAddressRange(uint64_t vaddr, uint64_t size) {
|
||||
}
|
||||
|
||||
static void MapGpuRange(uint64_t vaddr, uint64_t size) {
|
||||
#if defined(KYTY_VIRTUAL_MEMORY_ALLOCATION_TESTS)
|
||||
if (g_test_gpu_range != nullptr) g_test_gpu_range(true, vaddr, size);
|
||||
#endif
|
||||
if (g_gpu_resources == nullptr || !IsGpuAddressRange(vaddr, size)) {
|
||||
return;
|
||||
}
|
||||
@@ -90,6 +96,9 @@ static void MapGpuRange(uint64_t vaddr, uint64_t size) {
|
||||
}
|
||||
|
||||
static void UnmapGpuRange(uint64_t vaddr, uint64_t size) {
|
||||
#if defined(KYTY_VIRTUAL_MEMORY_ALLOCATION_TESTS)
|
||||
if (g_test_gpu_range != nullptr) g_test_gpu_range(false, vaddr, size);
|
||||
#endif
|
||||
if (g_gpu_resources == nullptr || !IsGpuAddressRange(vaddr, size)) {
|
||||
return;
|
||||
}
|
||||
@@ -2528,20 +2537,7 @@ static bool FreeGuestMemoryOwner(uint64_t vaddr, uint64_t size) {
|
||||
g_virtual_ranges->Remove(vaddr, size);
|
||||
}
|
||||
|
||||
static int UnmapMemoryRange(uint64_t vaddr, size_t len) {
|
||||
if (len == 0 || UINT64_MAX - vaddr < len) {
|
||||
return KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
|
||||
VirtualRanges::Range range {};
|
||||
if (!g_virtual_ranges->Query(vaddr, 0, &range)) {
|
||||
return KERNEL_ERROR_EACCES;
|
||||
}
|
||||
const auto chunk_len = std::min<uint64_t>(len, range.size - (vaddr - range.start));
|
||||
if (chunk_len < len) {
|
||||
const int ret = UnmapMemoryRange(vaddr, chunk_len);
|
||||
return ret == OK ? UnmapMemoryRange(vaddr + chunk_len, len - chunk_len) : ret;
|
||||
}
|
||||
static int UnmapMemoryOwner(const VirtualRanges::Range& range, uint64_t vaddr, size_t len) {
|
||||
if (IsReservedRangeType(range.type)) {
|
||||
if (!g_guest_address_space->ReleaseFree(vaddr, len)) {
|
||||
return KERNEL_ERROR_EACCES;
|
||||
@@ -2605,6 +2601,13 @@ static int UnmapMemoryRange(uint64_t vaddr, size_t len) {
|
||||
return OK;
|
||||
}
|
||||
|
||||
static int UnmapMemoryRange(const VirtualRanges::Range& range, uint64_t vaddr, size_t len) {
|
||||
UnmapGpuRange(vaddr, len);
|
||||
const int result = UnmapMemoryOwner(range, vaddr, len);
|
||||
if (result != OK && IsCommittedRangeType(range.type)) MapGpuRange(vaddr, len);
|
||||
return result;
|
||||
}
|
||||
|
||||
// The ABI entry point and batch operations hold g_memory_operation_mutex.
|
||||
static int UnmapMemory(uint64_t vaddr, size_t len) {
|
||||
LOGF("\t start = 0x%016" PRIx64 "\n"
|
||||
@@ -2618,8 +2621,11 @@ static int UnmapMemory(uint64_t vaddr, size_t len) {
|
||||
if (!g_virtual_ranges->QuerySpan(vaddr, len, &ranges)) {
|
||||
return KERNEL_ERROR_EACCES;
|
||||
}
|
||||
UnmapGpuRange(vaddr, len);
|
||||
return UnmapMemoryRange(vaddr, len);
|
||||
for (const auto& range: ranges) {
|
||||
const int result = UnmapMemoryRange(range, range.start, range.size);
|
||||
if (result != OK) return result;
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
int KYTY_SYSV_ABI KernelMunmap(uint64_t vaddr, size_t len) {
|
||||
@@ -2628,6 +2634,31 @@ int KYTY_SYSV_ABI KernelMunmap(uint64_t vaddr, size_t len) {
|
||||
return UnmapMemory(vaddr, len);
|
||||
}
|
||||
|
||||
static bool IsAmmMemoryRange(uint64_t vaddr, size_t size) {
|
||||
constexpr uint64_t page_size = 0x4000;
|
||||
return size != 0 && ((vaddr | size) & (page_size - 1)) == 0 &&
|
||||
vaddr >= kExtendedMemoryBase && vaddr < kExtendedMemoryBase + kExtendedMemorySize &&
|
||||
size <= kExtendedMemoryBase + kExtendedMemorySize - vaddr;
|
||||
}
|
||||
|
||||
int UnmapAmmMemory(uint64_t vaddr, size_t size) {
|
||||
std::lock_guard<std::recursive_mutex> memory_operation_lock(g_memory_operation_mutex);
|
||||
if (!IsAmmMemoryRange(vaddr, size)) return KERNEL_ERROR_EINVAL;
|
||||
|
||||
const auto end = vaddr + size;
|
||||
while (vaddr < end) {
|
||||
VirtualRanges::Range range {};
|
||||
// AMM unmap accepts holes, including a completely unmapped range.
|
||||
if (!g_virtual_ranges->Query(vaddr, 1, &range) || range.start >= end) break;
|
||||
vaddr = std::max(vaddr, range.start);
|
||||
const auto chunk = std::min(end, range.start + range.size) - vaddr;
|
||||
const int result = UnmapMemoryRange(range, vaddr, chunk);
|
||||
if (result != OK) return result;
|
||||
vaddr += chunk;
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
size_t KYTY_SYSV_ABI KernelGetDirectMemorySize() {
|
||||
PRINT_NAME();
|
||||
|
||||
@@ -3229,11 +3260,7 @@ int KYTY_SYSV_ABI KernelMapDirectMemory2(void** addr, size_t len, int type, int
|
||||
int MapAutomaticMemory(uint64_t vaddr, size_t size, int type, int prot) {
|
||||
std::lock_guard<std::recursive_mutex> memory_operation_lock(g_memory_operation_mutex);
|
||||
constexpr uint64_t page_size = 0x4000;
|
||||
if (size == 0 || (vaddr & (page_size - 1)) != 0 || (size & (page_size - 1)) != 0 ||
|
||||
vaddr < kExtendedMemoryBase || vaddr >= kExtendedMemoryBase + kExtendedMemorySize ||
|
||||
size > kExtendedMemoryBase + kExtendedMemorySize - vaddr) {
|
||||
return KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
if (!IsAmmMemoryRange(vaddr, size)) return KERNEL_ERROR_EINVAL;
|
||||
|
||||
PhysicalMemory::PhysicalRanges ranges;
|
||||
if (!g_physical_memory->ReserveAutomatic(size, &ranges)) {
|
||||
@@ -3571,6 +3598,10 @@ int KYTY_SYSV_ABI KernelReserveVirtualRange(void** addr, size_t len, int flags,
|
||||
}
|
||||
|
||||
#if defined(KYTY_VIRTUAL_MEMORY_ALLOCATION_TESTS)
|
||||
void TestSetGpuRangeCallback(void (*callback)(bool, uint64_t, size_t)) {
|
||||
g_test_gpu_range = callback;
|
||||
}
|
||||
|
||||
void TestBeforeNextBackingMap(callback_func_t callback) {
|
||||
g_test_before_backing_map = callback;
|
||||
}
|
||||
|
||||
@@ -112,6 +112,7 @@ void SetFlexibleMemorySize(uint64_t size);
|
||||
int AllocateDirectMemory(int64_t search_start, int64_t search_end, size_t size, size_t alignment,
|
||||
int memory_type, int64_t* phys_addr_out, bool automatic = false);
|
||||
int MapAutomaticMemory(uint64_t vaddr, size_t size, int type, int prot);
|
||||
int UnmapAmmMemory(uint64_t vaddr, size_t size);
|
||||
bool TryWriteBacking(uint64_t vaddr, const void* data, uint64_t size);
|
||||
bool TryReadBacking(uint64_t vaddr, void* data, uint64_t size);
|
||||
bool TryReadBufferBacking(uint64_t vaddr, void* data, uint64_t size);
|
||||
@@ -192,6 +193,7 @@ bool ProtectGuestHostMemory(uint64_t vaddr, uint64_t size, Common::VirtualMemory
|
||||
bool FreeGuestMemory(uint64_t vaddr, uint64_t size);
|
||||
|
||||
#if defined(KYTY_VIRTUAL_MEMORY_ALLOCATION_TESTS)
|
||||
void TestSetGpuRangeCallback(void (*callback)(bool mapped, uint64_t addr, size_t size));
|
||||
void TestBeforeNextBackingMap(callback_func_t callback);
|
||||
void TestSetBackingReadCallback(callback_func_t callback);
|
||||
void TestFailNextPhysicalMemoryUnmap();
|
||||
|
||||
Reference in New Issue
Block a user