Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions core/libs/prx/libc/include/WindowsMappings.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,9 @@ class WindowsMappings {
split(cursor + done, pageBytes);
void* page = reinterpret_cast<void*>(cursor + done);
if (!map(section, GetCurrentProcess(), page, offset + done, pageBytes, MEM_REPLACE_PLACEHOLDER, PAGE_EXECUTE_READWRITE, nullptr, 0)) fail("map shared guest page");
MEMORY_BASIC_INFORMATION memory{};
if (VirtualQuery(page, &memory, sizeof(memory)) != sizeof(memory)) fail("query shared guest page");
if (memory.State == MEM_RESERVE && !VirtualAlloc(page, pageBytes, MEM_COMMIT, PAGE_EXECUTE_READWRITE)) fail("commit shared guest page");
DWORD previous;
if (!VirtualProtect(page, pageBytes, protection, &previous)) fail("protect shared guest page");
const auto key = std::make_pair(reinterpret_cast<std::uintptr_t>(section), offset + done);
Expand Down
2 changes: 1 addition & 1 deletion core/libs/prx/libkernel/DirectMemory/DirectMemory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ class PhysicalBacking {
#ifdef _WIN32
static_cast<void>(start);
const auto size = static_cast<std::uint64_t>(bytes);
section = CreateFileMappingW(INVALID_HANDLE_VALUE, nullptr, PAGE_EXECUTE_READWRITE, static_cast<DWORD>(size >> 32), static_cast<DWORD>(size), nullptr);
section = CreateFileMappingW(INVALID_HANDLE_VALUE, nullptr, PAGE_EXECUTE_READWRITE | SEC_RESERVE, static_cast<DWORD>(size >> 32), static_cast<DWORD>(size), nullptr);
if (!section) {
const auto error = static_cast<int>(GetLastError());
char message[96];
Expand Down
29 changes: 29 additions & 0 deletions core/libs/tests/GuestMemory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,34 @@ static void CheckDirectMemoryFollowsPhysicalPages() {
Require(sceKernelReleaseDirectMemory(again, page * 2) == 0);
}

static void CheckSparseDirectMemoryBacking() {
constexpr std::size_t page = 0x4000;
constexpr std::size_t size = 256u * 1024u * 1024u;
std::int64_t physical = 0;
Require(sceKernelAllocateDirectMemory(0, 0x7fffffffffll, size, 0, 0, &physical) == 0);
void* first = nullptr;
void* last = nullptr;
Require(sceKernelMapDirectMemory(&first, page, 3, 0, physical, 0) == 0);
Require(sceKernelMapDirectMemory(&last, page, 3, 0, physical + size - page, 0) == 0);
auto* firstBytes = static_cast<unsigned char*>(first);
auto* lastBytes = static_cast<unsigned char*>(last);
Require(firstBytes[0] == 0 && firstBytes[page - 1] == 0 && lastBytes[0] == 0 && lastBytes[page - 1] == 0);
firstBytes[0] = 17;
lastBytes[page - 1] = 29;
void* alias = nullptr;
Require(sceKernelMapDirectMemory(&alias, page, 3, 0, physical + size - page, 0) == 0);
auto* aliasBytes = static_cast<unsigned char*>(alias);
Require(aliasBytes[page - 1] == 29 && aliasBytes[0] == 0);
aliasBytes[page - 1] = 41;
Require(lastBytes[page - 1] == 41 && firstBytes[0] == 17);
Require(sceKernelMunmap(last, page) == 0 && sceKernelMunmap(alias, page) == 0);
last = nullptr;
Require(sceKernelMapDirectMemory(&last, page, 3, 0, physical + size - page, 0) == 0);
Require(static_cast<unsigned char*>(last)[page - 1] == 41);
Require(sceKernelMunmap(first, page) == 0 && sceKernelMunmap(last, page) == 0);
Require(sceKernelReleaseDirectMemory(physical, size) == 0);
}

static void CheckReleaseDirectMemoryClearsMappings() {
constexpr std::size_t page = 0x4000;
std::int64_t phys = 0;
Expand Down Expand Up @@ -1715,6 +1743,7 @@ int main() {
CheckCheckedReleaseDirectMemory();
CheckAudioCoprocessorProtection();
CheckDirectMemoryFollowsPhysicalPages();
CheckSparseDirectMemoryBacking();
CheckReleaseDirectMemoryClearsMappings();
CheckReleaseDirectMemoryRejectsInvalidRanges();
CheckFixedMappingReplacesPartialOverlap();
Expand Down
4 changes: 4 additions & 0 deletions docs/dev/TechnicalDebt.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@
- libwinpthread-1.dll
- winpthreads initializes a statically initialized rwlock on its first lock and fails a concurrent first lock with `EINVAL`, which `std::shared_mutex` and `std::shared_timed_mutex` ignore, so that lock does not exclude. Guest rwlocks ([Pthread.hpp](../../core/libs/prx/libkernel/Pthread/include/Pthread.hpp)) are locked once when created. The host `std::shared_mutex` objects in [Recompiler.cpp](../../core/shader/recompiler/Recompiler.cpp) and [GuestWriteWatch.cpp](../../core/libs/prx/libc/src/GuestWriteWatch.cpp) are not, and can still race on their first contended use.

### Direct memory

- Windows direct-memory backing reserves a paging-file section and commits each mapped guest page before setting its protection. Committed physical contents remain in the section across unmap/remap and are released when the backing and its remaining views are destroyed; commitment is not recovered merely by unmapping a page. Linux retains its existing backing. Peak gameplay memory and Windows versions other than the tested host remain unverified.

### Silent stubs

Throughout the project, every function at every stage either **does exactly what it's supposed to or throws an exception**. Everywhere... except:
Expand Down
Loading