Merge pull request #880 from adriadam10/feat/kernel-mtypeprotect-type
feat(kernel): apply the memory type in sceKernelMtypeprotect
This commit is contained in:
commit
f6f47bf1de
|
|
@ -649,6 +649,33 @@ int DoMprotect(const void* addr, size_t len, int prot) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int DoMtypeprotect(const void* addr, size_t len, int type, int prot) {
|
||||
const int result = DoMprotect(addr, len, prot);
|
||||
const auto address = reinterpret_cast<std::uintptr_t>(addr);
|
||||
constexpr auto pageMask = static_cast<std::uintptr_t>(PS5_PAGE_SIZE - 1);
|
||||
const auto first = address & ~pageMask;
|
||||
const auto end = (address + len + pageMask) & ~pageMask;
|
||||
std::vector<std::pair<std::uint64_t, std::size_t>> physical;
|
||||
{
|
||||
std::lock_guard lock(g_directLock);
|
||||
auto it = g_directMappings.lower_bound(first);
|
||||
if (it != g_directMappings.begin() && std::prev(it)->second.end > first) --it;
|
||||
while (it != g_directMappings.end() && it->first < end) {
|
||||
const auto base = it->first;
|
||||
const auto mapping = it->second;
|
||||
it = g_directMappings.erase(it);
|
||||
if (base < first) g_directMappings.emplace(base, DirectMapping{first, mapping.phys, mapping.memoryType, mapping.backing});
|
||||
const auto low = std::max(base, first);
|
||||
const auto high = std::min(mapping.end, end);
|
||||
g_directMappings.emplace(low, DirectMapping{high, mapping.phys + low - base, type, mapping.backing});
|
||||
physical.emplace_back(mapping.phys + low - base, high - low);
|
||||
if (mapping.end > end) it = g_directMappings.emplace(end, DirectMapping{mapping.end, mapping.phys + end - base, mapping.memoryType, mapping.backing}).first;
|
||||
}
|
||||
}
|
||||
for (const auto& [phys, bytes] : physical) DirectMemoryRetype(static_cast<int64_t>(phys), bytes, type);
|
||||
return result;
|
||||
}
|
||||
|
||||
int DoMunmap(void* addr, size_t len) {
|
||||
Trace("unmap %p+0x%zx", addr, len);
|
||||
if (len == 0 || (len & (PS5_PAGE_SIZE - 1)) != 0 || !addr) return SCE_KERNEL_ERROR_EINVAL;
|
||||
|
|
|
|||
|
|
@ -16,10 +16,12 @@ void CreateDirectMemoryBacking(int64_t start, size_t len, int memoryType);
|
|||
bool QueryDirectMapping(std::uintptr_t address, std::uintptr_t* start, std::uintptr_t* end, std::uint64_t* offset, int* memoryType);
|
||||
void ForgetDirectMemory(int64_t start, size_t len);
|
||||
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);
|
||||
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);
|
||||
int DoMprotect(const void* addr, size_t len, int prot);
|
||||
int DoMtypeprotect(const void* addr, size_t len, int type, int prot);
|
||||
int DoMunmap(void* addr, size_t len);
|
||||
int DoReserveVirtual(void** addr, size_t len, int flags, size_t alignment);
|
||||
bool GuestProtection(uintptr_t addr, int* prot);
|
||||
|
|
|
|||
|
|
@ -316,8 +316,7 @@ int APS5_VABI sceKernelCheckedReleaseDirectMemory(int64_t start, size_t len) {
|
|||
}
|
||||
|
||||
int APS5_VABI sceKernelMtypeprotect(const void* addr, size_t len, int type, int prot) {
|
||||
(void)type;
|
||||
return DoMprotect(addr, len, prot);
|
||||
return DoMtypeprotect(addr, len, type, prot);
|
||||
}
|
||||
|
||||
int APS5_VABI sceKernelQueryMemoryProtection(void* addr, void** start, void** end, int* prot) {
|
||||
|
|
@ -426,9 +425,11 @@ int APS5_VABI sceKernelBatchMap2(KernelBatchMapEntry* entries, int num_entries,
|
|||
result = sceKernelMunmap(reinterpret_cast<uint64_t>(entry.start), entry.length);
|
||||
break;
|
||||
case OpProtect:
|
||||
case OpTypeProtect:
|
||||
result = DoMprotect(entry.start, entry.length, static_cast<uint8_t>(entry.protection));
|
||||
break;
|
||||
case OpTypeProtect:
|
||||
result = DoMtypeprotect(entry.start, entry.length, static_cast<uint8_t>(entry.type), static_cast<uint8_t>(entry.protection));
|
||||
break;
|
||||
case OpMapFlexible:
|
||||
result = _mapFlexible(&entry.start, entry.length, static_cast<uint8_t>(entry.protection), flags);
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#include "prx/libkernel/DirectMemory/MemoryPool.hpp"
|
||||
#include "prx/libkernel/DirectMemory/DirectMemory.hpp"
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
|
||||
|
|
@ -56,6 +57,21 @@ struct PhysicalMemoryPool {
|
|||
return true;
|
||||
}
|
||||
|
||||
void Retype(uint64_t start, size_t len, int memoryType) {
|
||||
std::lock_guard<std::mutex> lock(_mutex);
|
||||
const uint64_t end = start + len;
|
||||
auto it = _blocks.upper_bound(start);
|
||||
if (it != _blocks.begin() && std::prev(it)->second.end > start) --it;
|
||||
while (it != _blocks.end() && it->first < end) {
|
||||
const uint64_t blockStart = it->first;
|
||||
const Block block = it->second;
|
||||
it = _blocks.erase(it);
|
||||
if (blockStart < start) _blocks[blockStart] = {start, block.type};
|
||||
_blocks[std::max(blockStart, start)] = {std::min(block.end, end), memoryType};
|
||||
if (block.end > end) it = _blocks.emplace(end, Block{block.end, block.type}).first;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
|
@ -125,6 +141,10 @@ bool DirectMemoryFind(int64_t offset, bool findNext, int64_t* start, int64_t* en
|
|||
return PhysicalMemoryPool::Instance().Find(static_cast<uint64_t>(offset), findNext, start, end, memoryType);
|
||||
}
|
||||
|
||||
void DirectMemoryRetype(int64_t start, size_t len, int memoryType) {
|
||||
PhysicalMemoryPool::Instance().Retype(static_cast<uint64_t>(start), len, memoryType);
|
||||
}
|
||||
|
||||
size_t DirectMemoryFreeRun(uint64_t offset, uint64_t limit) {
|
||||
return PhysicalMemoryPool::Instance().FreeRun(offset, limit);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,6 +43,8 @@ int APS5_VABI sceKernelMapFlexibleMemory(void**, std::size_t, int, int);
|
|||
int APS5_VABI sceKernelMunmap(void*, std::size_t);
|
||||
int APS5_VABI sceKernelReleaseFlexibleMemory(void*, std::size_t);
|
||||
int APS5_VABI sceKernelMprotect(const void*, std::size_t, int);
|
||||
int APS5_VABI sceKernelMtypeprotect(const void*, std::size_t, int, int);
|
||||
int APS5_VABI sceKernelBatchMap2(KernelBatchMapEntry*, int, int*, int);
|
||||
int APS5_VABI sceKernelVirtualQuery(const void*, int, VirtualQueryInfo*, std::uint64_t);
|
||||
int APS5_VABI sceKernelSetVirtualRangeName(const void*, std::uint64_t, const char*);
|
||||
int APS5_VABI sceKernelClearVirtualRangeName(const void*, std::uint64_t);
|
||||
|
|
@ -293,6 +295,52 @@ static void CheckGetDirectMemoryType() {
|
|||
Require(sceKernelGetDirectMemoryType(second, &type, &start, &end) == SCE_KERNEL_ERROR_ENOENT);
|
||||
}
|
||||
|
||||
static void CheckMtypeprotect() {
|
||||
constexpr std::size_t page = 0x4000;
|
||||
std::int64_t phys = 0;
|
||||
Require(sceKernelAllocateDirectMemory(0, 0x7fffffffffll, page * 3, 0, 0, &phys) == 0);
|
||||
void* mapped = nullptr;
|
||||
Require(sceKernelMapDirectMemory(&mapped, page * 3, 3, 0, phys, 0) == 0);
|
||||
auto* bytes = static_cast<unsigned char*>(mapped);
|
||||
Require(sceKernelMtypeprotect(bytes + page + 1, 1, 3, 1) == 0);
|
||||
const auto check = [&](std::size_t index, int expectedType, int expectedProtection) {
|
||||
VirtualQueryInfo info{};
|
||||
Require(sceKernelVirtualQuery(bytes + page * index, 0, &info, sizeof(info)) == 0);
|
||||
Require(info.is_direct && info.memory_type == expectedType && info.protection == expectedProtection);
|
||||
Require(info.start == reinterpret_cast<std::uintptr_t>(bytes + page * index) && info.end == info.start + page);
|
||||
Require(info.offset == static_cast<std::uint64_t>(phys) + page * index);
|
||||
int type = -1;
|
||||
std::int64_t start = -1;
|
||||
std::int64_t end = -1;
|
||||
Require(sceKernelGetDirectMemoryType(phys + static_cast<std::int64_t>(page * index), &type, &start, &end) == 0);
|
||||
Require(type == expectedType && start == phys + static_cast<std::int64_t>(page * index) && end == start + static_cast<std::int64_t>(page));
|
||||
};
|
||||
check(0, 0, 3);
|
||||
check(1, 3, 1);
|
||||
check(2, 0, 3);
|
||||
KernelBatchMapEntry entry{};
|
||||
entry.start = bytes + page * 2;
|
||||
entry.length = page;
|
||||
entry.protection = 3;
|
||||
entry.type = 5;
|
||||
entry.operation = 4;
|
||||
int processed = -1;
|
||||
Require(sceKernelBatchMap2(&entry, 1, &processed, 0) == 0 && processed == 1);
|
||||
check(0, 0, 3);
|
||||
check(1, 3, 1);
|
||||
check(2, 5, 3);
|
||||
Require(sceKernelMtypeprotect(bytes, page * 3, 2, 3) == 0);
|
||||
VirtualQueryInfo whole{};
|
||||
Require(sceKernelVirtualQuery(bytes, 0, &whole, sizeof(whole)) == 0);
|
||||
Require(whole.memory_type == 2 && whole.protection == 3);
|
||||
int type = -1;
|
||||
std::int64_t start = -1;
|
||||
std::int64_t end = -1;
|
||||
Require(sceKernelGetDirectMemoryType(phys + static_cast<std::int64_t>(page * 2), &type, &start, &end) == 0 && type == 2);
|
||||
Require(sceKernelMunmap(mapped, page * 3) == 0);
|
||||
Require(sceKernelReleaseDirectMemory(phys, page * 3) == 0);
|
||||
}
|
||||
|
||||
static void CheckFixedVirtualReservation() {
|
||||
constexpr std::size_t page = 0x4000;
|
||||
void* probe = nullptr;
|
||||
|
|
@ -860,6 +908,7 @@ int main() {
|
|||
CheckMlock();
|
||||
CheckSharedDirectMemoryLifecycle();
|
||||
CheckGetDirectMemoryType();
|
||||
CheckMtypeprotect();
|
||||
CheckHeapAfterMappingReuse();
|
||||
#ifdef _WIN32
|
||||
CheckNoOverwriteRejectsHostOccupiedMapping();
|
||||
|
|
|
|||
|
|
@ -88,6 +88,7 @@ Throughout the project, every function at every stage either **does exactly what
|
|||
- [sceKernelAioSubmitReadCommandsMultiple / sceKernelAioSubmitWriteCommandsMultiple / sceKernelAioWaitRequests / sceKernelAioCancelRequest / sceKernelAioCancelRequests / sceKernelAioDeleteRequests](../../core/libs/prx/libkernel/Aio/src/Aio.cpp) (libkernel) - behaviour from shadPS4 (one id per request for the Multiple submits, cancel turns any request aborted and id 0 reports processing, wait mode 2 returns once one request completed); the 128 requests or ids per batch limit is from SharpProspero, with an unknown error, so larger batches throw; wait modes other than 1 (and) and 2 (or) throw; null pointers, negative counts and invalid ids return the codes the single-request siblings use, checked before any state is written
|
||||
- [sceKernelGetAvailableCpumask](../../core/libs/prx/libkernel/Pthread/src/Thread.cpp) (libkernel) - returns the default thread affinity, 0x1FFF (CPUs 0 to 12), as KytyPS5 does. Titles pin threads within it (PPSA02664 passes 0x1FFB, Hades II PPSA36082 0x3 and 0x3F); whether CPU 13 is available to a title is not confirmed
|
||||
- [sceKernelMapNamedFlexibleMemoryInternal](../../core/libs/prx/libkernel/DirectMemory/Export.cpp) (libkernel) - flag 0x8000 unknown; only the sceKernelMapNamedFlexibleMemory flags are accepted
|
||||
- [sceKernelMtypeprotect](../../core/libs/prx/libkernel/DirectMemory/DirectMemory.cpp) (libkernel) - sets the memory type of the direct mappings in the page-rounded range and of the direct memory behind them, as shadPS4 and prosper do (KytyPS5 ignores the type); the type is not validated, flexible pages in the range only get the protection, and a later map of the retyped direct memory reports the type it was allocated with. `sceKernelBatchMap2` operation 4 takes the same path with the entry type
|
||||
- [Guest arena](../../core/libs/prx/libc/src/GuestArena.cpp) (libc) - the application map area is assumed to end at 0xFC_0000_0000, as `SCE_KERNEL_APP_MAP_AREA_END_ADDR` does on the PS4. On Windows, host allocations made in the arena before libc loads stay, and a fixed guest mapping over one throws
|
||||
- [sceLibcInternalBacktraceForGame](../../core/libs/prx/libc/src/HeapDiagnostics.cpp) (libSceLibcInternal, implemented in libc) - unknown signature
|
||||
- [sceLibcInternalHeapErrorReportForGame](../../core/libs/prx/libc/src/HeapDiagnostics.cpp) (libSceLibcInternal, implemented in libc) - unknown signature
|
||||
|
|
|
|||
Loading…
Reference in New Issue