Memory Cards: mmap on Linux and MacOS

This commit is contained in:
Ty Lamontagne 2025-01-12 22:49:39 -05:00
parent 909b6d8eb6
commit 4d600dc1d4
No known key found for this signature in database
GPG Key ID: 41C90AE46958A892
5 changed files with 66 additions and 17 deletions

View File

@ -291,6 +291,24 @@ void* HostSys::CreateSharedMemory(const char* name, size_t size)
return reinterpret_cast<void*>(static_cast<uintptr_t>(port));
}
void* HostSys::CreateMappingFromFile(FILE* file)
{
return reinterpret_cast<void*>(static_cast<uintptr_t>(fileno(file)));
}
void* HostSys::MapMapping(void* handle, const PageProtectionMode& mode)
{
const u32 mmap_prot = (mode.CanWrite() ? (PROT_READ | PROT_WRITE) : (PROT_READ)) | (mode.CanExecute() ? PROT_EXEC : 0);
return mmap(nullptr, 0, mmap_prot, MAP_PRIVATE | MAP_ANON, static_cast<int>(reinterpret_cast<intptr_t>(handle)), 0);
}
void HostSys::DestroyMapping(void* handle)
{
// The handle mmap requires is the same as the file descriptor.
return;
}
void HostSys::DestroySharedMemory(void* ptr)
{
mach_port_deallocate(mach_task_self(), static_cast<mach_port_t>(reinterpret_cast<uintptr_t>(ptr)));

View File

@ -101,6 +101,11 @@ namespace HostSys
extern std::string GetFileMappingName(const char* prefix);
extern void* CreateSharedMemory(const char* name, size_t size);
extern void* CreateMappingFromFile(FILE* file);
extern void* MapMapping(void* handle, const PageProtectionMode& mode);
extern void DestroyMapping(void* handle);
extern void DestroySharedMemory(void* ptr);
extern void* MapSharedMemory(void* handle, size_t offset, void* baseaddr, size_t size, const PageProtectionMode& mode);
extern void UnmapSharedMemory(void* baseaddr, size_t size);

View File

@ -115,6 +115,22 @@ void* HostSys::CreateSharedMemory(const char* name, size_t size)
return reinterpret_cast<void*>(static_cast<intptr_t>(fd));
}
void* HostSys::CreateMappingFromFile(FILE* file)
{
return reinterpret_cast<void*>(static_cast<intptr_t>(fileno(file)));
}
void* HostSys::MapMapping(void* handle, const PageProtectionMode& mode)
{
return HostSys::MapSharedMemory(handle, 0, nullptr, 0, mode);
}
void HostSys::DestroyMapping(void* handle)
{
// The handle mmap requires is the same as the file descriptor.
return;
}
void HostSys::DestroySharedMemory(void* ptr)
{
close(static_cast<int>(reinterpret_cast<intptr_t>(ptr)));

View File

@ -13,6 +13,7 @@
#include "fmt/core.h"
#include "fmt/format.h"
#include <io.h>
#include <mutex>
static DWORD ConvertToWinApi(const PageProtectionMode& mode)
@ -72,6 +73,22 @@ void* HostSys::CreateSharedMemory(const char* name, size_t size)
static_cast<DWORD>(size >> 32), static_cast<DWORD>(size), StringUtil::UTF8StringToWideString(name).c_str()));
}
void* HostSys::CreateMappingFromFile(FILE* fd)
{
return static_cast<void*>(CreateFileMappingW(reinterpret_cast<HANDLE>(_get_osfhandle(_fileno(fd))), NULL, PAGE_READWRITE,
0, 0, nullptr));
}
void* HostSys::MapMapping(void* handle, const PageProtectionMode& mode)
{
return MapViewOfFile(static_cast<HANDLE>(handle), FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0);
}
void HostSys::DestroyMapping(void* handle)
{
CloseHandle(static_cast<HANDLE>(handle));
}
void HostSys::DestroySharedMemory(void* ptr)
{
CloseHandle(static_cast<HANDLE>(ptr));

View File

@ -10,6 +10,7 @@
#include "common/Console.h"
#include "common/Error.h"
#include "common/FileSystem.h"
#include "common/HostSys.h"
#include "common/Path.h"
#include "common/StringUtil.h"
@ -24,11 +25,6 @@
#include <map>
#ifdef _WIN32
#include <windows.h>
#include <io.h>
#endif
static constexpr int MCD_SIZE = 1024 * 8 * 16; // Legacy PSX card default size
static constexpr int MC2_MBSIZE = 1024 * 528 * 2; // Size of a single megabyte of card data
@ -163,6 +159,7 @@ class FileMemoryCard
protected:
std::FILE* m_file[8] = {};
u8* m_mappings[8] = {};
void* m_mapping_handles[8] = {};
s64 m_fileSize[8] = {};
std::string m_filenames[8] = {};
@ -345,20 +342,16 @@ void FileMemoryCard::Open()
Host::ReportErrorAsync("Memory Card Read Failed", "Error reading memory card.");
}
#ifdef _WIN32
const int fd = _fileno(m_file[slot]);
// Doesn't leak, refcounted based on views
const HANDLE hMapping = CreateFileMapping(reinterpret_cast<HANDLE>(_get_osfhandle(fd)), nullptr, PAGE_READWRITE, 0, 0, nullptr);
if (!hMapping)
m_mapping_handles[slot] = HostSys::CreateMappingFromFile(m_file[slot]);
if (!m_mapping_handles[slot])
{
Console.Warning("CreateFileMapping failed: %d", GetLastError());
Console.Warning("CreateMappingFromFile failed!");
}
m_mappings[slot] = reinterpret_cast<u8*>(MapViewOfFile(hMapping, FILE_MAP_ALL_ACCESS, 0, 0, 0));
m_mappings[slot] = static_cast<u8*>(HostSys::MapMapping(m_mapping_handles[slot], PageAccess_ReadWrite()));
if (!m_mappings[slot])
{
Console.Warning("MapViewOfFile failed: %d", GetLastError());
Console.Warning("MapSharedMemory failed!");
}
#endif
}
}
}
@ -386,13 +379,13 @@ void FileMemoryCard::Close()
m_filenames[slot] = {};
m_fileSize[slot] = -1;
#ifdef _WIN32
if (m_mappings[slot])
{
UnmapViewOfFile(m_mappings[slot]);
HostSys::UnmapSharedMemory(m_mappings[slot], 0);
HostSys::DestroyMapping(m_mapping_handles[slot]);
m_mappings[slot] = nullptr;
}
#endif
}
}