fix(libkernel): report the largest free direct memory block from sceKernelAvailableDirectMemorySize
The call returned the first free gap in the range instead of the largest free block. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
91b1341319
commit
aace6a3f38
|
|
@ -26,6 +26,7 @@ std::vector<DirectMemoryView> DirectMemoryViews(int64_t start, size_t len);
|
|||
void UnmapDirectMemoryViews(const std::vector<DirectMemoryView>& views);
|
||||
bool DirectMemoryFind(int64_t offset, bool findNext, int64_t* start, int64_t* end, int* memoryType);
|
||||
void DirectMemoryRetype(int64_t start, size_t len, int memoryType);
|
||||
bool DirectMemoryLargestFree(int64_t searchStart, int64_t searchEnd, size_t alignment, int64_t* startOut, size_t* sizeOut);
|
||||
size_t DirectMemoryFreeRun(uint64_t offset, uint64_t limit);
|
||||
int DoMapDirect(void** addr, size_t len, int prot, int flags, int64_t physStart, size_t alignment);
|
||||
int DoMapAnon(void** addr, size_t len, int prot, int flags, size_t alignment = PS5_PAGE_SIZE);
|
||||
|
|
|
|||
|
|
@ -133,12 +133,11 @@ int APS5_VABI sceKernelAllocateMainDirectMemory(size_t len, size_t alignment, in
|
|||
|
||||
int APS5_VABI sceKernelAvailableDirectMemorySize(int64_t search_start, int64_t search_end, size_t alignment, int64_t* phys_addr_out, size_t* size_out) {
|
||||
if (!phys_addr_out || !size_out) return SCE_KERNEL_ERROR_EINVAL;
|
||||
int64_t tmpPhys = 0;
|
||||
int ret = DirectMemoryAlloc(search_start, search_end, PS5_PAGE_SIZE, alignment, -1, &tmpPhys);
|
||||
if (ret != 0) { *phys_addr_out = 0; *size_out = 0; return ret; }
|
||||
DirectMemoryFree(tmpPhys, PS5_PAGE_SIZE);
|
||||
*phys_addr_out = tmpPhys;
|
||||
*size_out = DirectMemoryFreeRun(static_cast<uint64_t>(tmpPhys), static_cast<uint64_t>(search_end));
|
||||
int64_t start = 0;
|
||||
size_t size = 0;
|
||||
if (!DirectMemoryLargestFree(search_start, search_end, alignment, &start, &size)) { *phys_addr_out = 0; *size_out = 0; return SCE_KERNEL_ERROR_EAGAIN; }
|
||||
*phys_addr_out = start;
|
||||
*size_out = size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -72,6 +72,34 @@ struct PhysicalMemoryPool {
|
|||
}
|
||||
}
|
||||
|
||||
bool LargestFree(int64_t searchStart, int64_t searchEnd, size_t alignment, int64_t* startOut, size_t* sizeOut) {
|
||||
std::lock_guard<std::mutex> lock(_mutex);
|
||||
if (searchStart < 0 || searchEnd <= searchStart) return false;
|
||||
const uint64_t align = (alignment == 0) ? PS5_PAGE_SIZE : alignment;
|
||||
const uint64_t limit = std::min<uint64_t>(static_cast<uint64_t>(searchEnd), DIRECT_MEMORY_SIZE);
|
||||
uint64_t bestStart = 0;
|
||||
uint64_t bestSize = 0;
|
||||
uint64_t cur = (static_cast<uint64_t>(searchStart) + PS5_PAGE_SIZE - 1) & ~static_cast<uint64_t>(PS5_PAGE_SIZE - 1);
|
||||
while (cur + PS5_PAGE_SIZE <= limit) {
|
||||
if (!_isFree(cur, PS5_PAGE_SIZE)) {
|
||||
cur += PS5_PAGE_SIZE;
|
||||
continue;
|
||||
}
|
||||
uint64_t runEnd = cur;
|
||||
while (runEnd + PS5_PAGE_SIZE <= limit && _isFree(runEnd, PS5_PAGE_SIZE)) runEnd += PS5_PAGE_SIZE;
|
||||
const uint64_t alignedStart = (cur + align - 1) & ~(align - 1);
|
||||
if (alignedStart < runEnd && runEnd - alignedStart > bestSize) {
|
||||
bestStart = alignedStart;
|
||||
bestSize = runEnd - alignedStart;
|
||||
}
|
||||
cur = runEnd;
|
||||
}
|
||||
if (bestSize == 0) return false;
|
||||
*startOut = static_cast<int64_t>(bestStart);
|
||||
*sizeOut = static_cast<size_t>(bestSize);
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t FreeRun(uint64_t offset, uint64_t limit) {
|
||||
std::lock_guard<std::mutex> lock(_mutex);
|
||||
uint64_t cur = offset & ~static_cast<uint64_t>(PS5_PAGE_SIZE - 1);
|
||||
|
|
@ -145,6 +173,10 @@ void DirectMemoryRetype(int64_t start, size_t len, int memoryType) {
|
|||
PhysicalMemoryPool::Instance().Retype(static_cast<uint64_t>(start), len, memoryType);
|
||||
}
|
||||
|
||||
bool DirectMemoryLargestFree(int64_t searchStart, int64_t searchEnd, size_t alignment, int64_t* startOut, size_t* sizeOut) {
|
||||
return PhysicalMemoryPool::Instance().LargestFree(searchStart, searchEnd, alignment, startOut, sizeOut);
|
||||
}
|
||||
|
||||
size_t DirectMemoryFreeRun(uint64_t offset, uint64_t limit) {
|
||||
return PhysicalMemoryPool::Instance().FreeRun(offset, limit);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@ int APS5_VABI sceKernelClearVirtualRangeName(const void*, std::uint64_t);
|
|||
int APS5_VABI sceKernelAllocateDirectMemory(std::int64_t, std::int64_t, std::size_t, std::size_t, int, std::int64_t*);
|
||||
int APS5_VABI sceKernelMapDirectMemory(void**, std::size_t, int, int, std::int64_t, std::size_t);
|
||||
int APS5_VABI sceKernelReleaseDirectMemory(std::int64_t, std::size_t);
|
||||
int APS5_VABI sceKernelAvailableDirectMemorySize(std::int64_t, std::int64_t, std::size_t, std::int64_t*, std::size_t*);
|
||||
int APS5_VABI sceKernelCheckedReleaseDirectMemory(std::int64_t, std::size_t);
|
||||
int APS5_VABI sceKernelReserveVirtualRange(void**, std::size_t, int, std::size_t);
|
||||
int APS5_VABI sceKernelMemoryPoolReserve(void*, std::size_t, std::size_t, int, void**);
|
||||
|
|
@ -1621,10 +1622,41 @@ static void CheckVirtualQueryPartialMunmap() {
|
|||
Require(munmap_nid_postfix(memory + page * 2, page) == 0);
|
||||
}
|
||||
|
||||
|
||||
static void CheckAvailableDirectMemoryIsLargestFreeBlock() {
|
||||
constexpr std::int64_t window = 0x4000000;
|
||||
const std::int64_t top = static_cast<std::int64_t>(DIRECT_MEMORY_SIZE) - window;
|
||||
std::int64_t first = -1;
|
||||
std::int64_t gap = -1;
|
||||
std::int64_t last = -1;
|
||||
Require(sceKernelAllocateDirectMemory(top, top + window, 0x200000, 0x200000, 0, &first) == 0 && first == top);
|
||||
Require(sceKernelAllocateDirectMemory(top, top + window, 0x400000, 0x200000, 0, &gap) == 0 && gap == top + 0x200000);
|
||||
Require(sceKernelAllocateDirectMemory(top, top + window, 0x200000, 0x200000, 0, &last) == 0 && last == top + 0x600000);
|
||||
Require(sceKernelReleaseDirectMemory(gap, 0x400000) == 0);
|
||||
|
||||
std::int64_t start = -1;
|
||||
std::size_t size = 0;
|
||||
Require(sceKernelAvailableDirectMemorySize(top, top + window, 0, &start, &size) == 0);
|
||||
Require(start == top + 0x800000 && size == static_cast<std::size_t>(window - 0x800000));
|
||||
Require(sceKernelAvailableDirectMemorySize(top, top + 0x800000, 0, &start, &size) == 0);
|
||||
Require(start == top + 0x200000 && size == 0x400000);
|
||||
Require(sceKernelAvailableDirectMemorySize(top, top + window, 0x1000000, &start, &size) == 0);
|
||||
Require(start == top + 0x1000000 && size == static_cast<std::size_t>(window - 0x1000000));
|
||||
Require(sceKernelAvailableDirectMemorySize(top, top + 0x200000, 0, &start, &size) == SCE_KERNEL_ERROR_EAGAIN);
|
||||
Require(start == 0 && size == 0);
|
||||
Require(sceKernelAvailableDirectMemorySize(top, top + window, 0, nullptr, &size) == SCE_KERNEL_ERROR_EINVAL);
|
||||
|
||||
Require(sceKernelReleaseDirectMemory(first, 0x200000) == 0);
|
||||
Require(sceKernelReleaseDirectMemory(last, 0x200000) == 0);
|
||||
Require(sceKernelAvailableDirectMemorySize(top, top + window, 0, &start, &size) == 0);
|
||||
Require(start == top && size == static_cast<std::size_t>(window));
|
||||
}
|
||||
|
||||
int main() {
|
||||
#ifdef _WIN32
|
||||
_putenv_s("APS5_PIN_WAIT_MS", "1000");
|
||||
#endif
|
||||
CheckAvailableDirectMemoryIsLargestFreeBlock();
|
||||
CheckVirtualQuerySplitFlexibleRanges();
|
||||
CheckVirtualQueryForNonReadableGuestRange();
|
||||
CheckReleaseFlexibleMemory();
|
||||
|
|
|
|||
Loading…
Reference in New Issue