Combine guest memory and function table into one virtual allocation.

This commit is contained in:
Skyth 2025-01-02 14:45:42 +03:00
parent 038edfdebd
commit 967a0ce17f
27 changed files with 46 additions and 199 deletions

View file

@ -112,7 +112,6 @@ endif()
set(SWA_CPU_CXX_SOURCES
"cpu/guest_thread.cpp"
"cpu/code_cache.cpp"
)
set(SWA_GPU_CXX_SOURCES

View file

@ -1,6 +1,5 @@
#pragma once
#include <cpu/guest_code.h>
#include <cpu/guest_stack_var.h>
#include <kernel/function.h>

View file

@ -3,7 +3,7 @@
#include <bit>
#include "audio.h"
#include "cpu/code_cache.h"
#include <kernel/memory.h>
#define AUDIO_DRIVER_KEY (uint32_t)('DAUD')
@ -21,7 +21,7 @@ uint32_t XAudioRegisterRenderDriverClient(be<uint32_t>* callback, be<uint32_t>*
#endif
*driver = AUDIO_DRIVER_KEY;
XAudioRegisterClient(KeFindHostFunction(*callback), callback[1]);
XAudioRegisterClient(g_memory.FindFunction(*callback), callback[1]);
return 0;
}

View file

@ -1,7 +1,5 @@
#include "sdl2_driver.h"
#include <cpu/code_cache.h>
#include <cpu/guest_thread.h>
#include <cpu/guest_code.h>
#include <kernel/heap.h>
static PPCFunc* g_clientCallback{};
@ -50,7 +48,7 @@ static void AudioThread()
if ((queuedAudioSize / callbackAudioSize) <= MAX_LATENCY)
{
ctx.ppcContext.r3.u32 = g_clientCallbackParam;
g_clientCallback(ctx.ppcContext, reinterpret_cast<uint8_t*>(g_memory.base));
g_clientCallback(ctx.ppcContext, g_memory.base);
}
auto now = std::chrono::steady_clock::now();

View file

@ -1,9 +1,7 @@
#include <stdafx.h>
#include "xaudio_driver.h"
#include <xaudio2.h>
#include <cpu/code_cache.h>
#include <cpu/guest_thread.h>
#include <cpu/guest_code.h>
#include <cpu/ppc_context.h>
#include <kernel/heap.h>
@ -55,7 +53,7 @@ PPC_FUNC(DriverLoop)
WaitForSingleObject(g_audioSemaphore, INFINITE);
ctx.r3.u64 = g_clientCallbackParam;
GuestCode::Run((void*)g_clientCallback, &ctx);
g_clientCallback(ctx, g_memory.base);
}
}

View file

@ -1,60 +0,0 @@
#include <stdafx.h>
#include "code_cache.h"
#include "ppc_context.h"
CodeCache::CodeCache()
{
#ifdef _WIN32
bucket = (char*)VirtualAlloc(nullptr, 0x200000000, MEM_RESERVE, PAGE_READWRITE);
assert(bucket != nullptr);
#else
bucket = (char*)mmap(NULL, 0x200000000, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
assert(bucket != (char*)MAP_FAILED);
#endif
}
CodeCache::~CodeCache()
{
#ifdef _WIN32
VirtualFree(bucket, 0, MEM_RELEASE);
#else
munmap(bucket, 0x200000000);
#endif
}
void CodeCache::Init()
{
for (size_t i = 0; PPCFuncMappings[i].guest != 0; i++)
{
if (PPCFuncMappings[i].host != nullptr)
{
#ifdef _WIN32
VirtualAlloc(bucket + PPCFuncMappings[i].guest * 2, sizeof(void*), MEM_COMMIT, PAGE_READWRITE);
#endif
*(void**)(bucket + PPCFuncMappings[i].guest * 2) = (void*)PPCFuncMappings[i].host;
}
}
}
void CodeCache::Insert(uint32_t guest, PPCFunc* host)
{
#ifdef _WIN32
VirtualAlloc(bucket + static_cast<uint64_t>(guest) * 2, sizeof(void*), MEM_COMMIT, PAGE_READWRITE);
#endif
*reinterpret_cast<PPCFunc**>(bucket + static_cast<uint64_t>(guest) * 2) = host;
}
void* CodeCache::Find(uint32_t guest) const
{
return *reinterpret_cast<void**>(bucket + static_cast<uint64_t>(guest) * 2);
}
SWA_API PPCFunc* KeFindHostFunction(uint32_t guest)
{
return reinterpret_cast<PPCFunc*>(g_codeCache.Find(guest));
}
SWA_API void KeInsertHostFunction(uint32_t guest, PPCFunc* function)
{
g_codeCache.Insert(guest, function);
}

View file

@ -1,19 +0,0 @@
#pragma once
struct CodeCache
{
char* bucket{};
CodeCache();
~CodeCache();
void Init();
void Insert(uint32_t guest, PPCFunc* host);
void* Find(uint32_t guest) const;
};
SWA_API PPCFunc* KeFindHostFunction(uint32_t guest);
SWA_API void KeInsertHostFunction(uint32_t guest, PPCFunc* function);
extern CodeCache g_codeCache;

View file

@ -1,23 +0,0 @@
#pragma once
#include "ppc_context.h"
#include <kernel/memory.h>
struct GuestCode
{
inline static void Run(void* hostAddress, PPCContext* ctx, void* baseAddress)
{
ctx->fpscr.loadFromHost();
reinterpret_cast<PPCFunc*>(hostAddress)(*ctx, reinterpret_cast<uint8_t*>(baseAddress));
}
inline static void Run(void* hostAddress, PPCContext* ctx)
{
ctx->fpscr.loadFromHost();
reinterpret_cast<PPCFunc*>(hostAddress)(*ctx, reinterpret_cast<uint8_t*>(g_memory.base));
}
inline static void Run(void* hostAddress)
{
Run(hostAddress, GetPPCContext());
}
};

View file

@ -3,8 +3,6 @@
#include <kernel/memory.h>
#include <kernel/heap.h>
#include <kernel/function.h>
#include "code_cache.h"
#include "guest_code.h"
#include "ppc_context.h"
constexpr size_t PCR_SIZE = 0xAB0;
@ -29,7 +27,6 @@ GuestThreadContext::GuestThreadContext(uint32_t cpuNumber)
*(uint32_t*)(thread + PCR_SIZE + 0x10) = 0xFFFFFFFF; // that one TLS entry that felt quirky
*(uint32_t*)(thread + PCR_SIZE + TLS_SIZE + 0x14C) = ByteSwap(GuestThread::GetCurrentThreadId()); // thread id
ppcContext.fn = (uint8_t*)g_codeCache.bucket;
ppcContext.r1.u64 = g_memory.MapVirtual(thread + PCR_SIZE + TLS_SIZE + TEB_SIZE + STACK_SIZE); // stack pointer
ppcContext.r13.u64 = g_memory.MapVirtual(thread);
ppcContext.fpscr.loadFromHost();
@ -78,7 +75,7 @@ uint32_t GuestThread::Start(const GuestThreadParams& params)
GuestThreadContext ctx(cpuNumber);
ctx.ppcContext.r3.u64 = params.value;
reinterpret_cast<PPCFunc*>(g_codeCache.Find(params.function))(ctx.ppcContext, reinterpret_cast<uint8_t*>(g_memory.base));
g_memory.FindFunction(params.function)(ctx.ppcContext, g_memory.base);
return ctx.ppcContext.r3.u32;
}

View file

@ -6,8 +6,6 @@
#include <app.h>
#include <bc_diff.h>
#include <cpu/code_cache.h>
#include <cpu/guest_code.h>
#include <cpu/guest_thread.h>
#include <decompressor.h>
#include <kernel/function.h>
@ -1682,7 +1680,7 @@ static uint32_t CreateDevice(uint32_t a1, uint32_t a2, uint32_t a3, uint32_t a4,
memset(device, 0, sizeof(*device));
uint32_t functionOffset = 0x443344; // D3D
g_codeCache.Insert(functionOffset, HostToGuestFunction<SetRenderStateUnimplemented>);
g_memory.InsertFunction(functionOffset, HostToGuestFunction<SetRenderStateUnimplemented>);
for (size_t i = 0; i < std::size(device->setRenderStateFunctions); i++)
device->setRenderStateFunctions[i] = functionOffset;
@ -1690,7 +1688,7 @@ static uint32_t CreateDevice(uint32_t a1, uint32_t a2, uint32_t a3, uint32_t a4,
for (auto& [state, function] : g_setRenderStateFunctions)
{
functionOffset += 4;
g_codeCache.Insert(functionOffset, function);
g_memory.InsertFunction(functionOffset, function);
device->setRenderStateFunctions[state / 4] = functionOffset;
}

View file

@ -314,19 +314,18 @@ T GuestToHostFunction(const TFunction& func, TArgs&&... argv)
auto& currentCtx = *GetPPCContext();
PPCContext newCtx; // NOTE: No need for zero initialization, has lots of unnecessary code generation.
newCtx.fn = currentCtx.fn;
newCtx.r1 = currentCtx.r1;
newCtx.r13 = currentCtx.r13;
newCtx.fpscr = currentCtx.fpscr;
_translate_args_to_guest(newCtx, (uint8_t*)g_memory.base, args);
_translate_args_to_guest(newCtx, g_memory.base, args);
SetPPCContext(newCtx);
if constexpr (std::is_function_v<TFunction>)
func(newCtx, (uint8_t*)g_memory.base);
func(newCtx, g_memory.base);
else
(*(PPCFunc**)(newCtx.fn + uint64_t(func) * 2))(newCtx, (uint8_t*)g_memory.base);
g_memory.FindFunction(func)(newCtx, g_memory.base);
currentCtx.fpscr = newCtx.fpscr;
SetPPCContext(currentCtx);

View file

@ -8,10 +8,7 @@ constexpr size_t RESERVED_END = 0xA0000000;
void Heap::Init()
{
g_memory.Alloc(0x20000, RESERVED_BEGIN - 0x20000, MEM_COMMIT);
heap = o1heapInit(g_memory.Translate(0x20000), RESERVED_BEGIN - 0x20000);
g_memory.Alloc(RESERVED_END, 0x100000000 - RESERVED_END, MEM_COMMIT);
physicalHeap = o1heapInit(g_memory.Translate(RESERVED_END), 0x100000000 - RESERVED_END);
}

View file

@ -1,48 +1,30 @@
#include <stdafx.h>
#include "memory.h"
Memory::Memory(void* address, size_t size) : size(size)
Memory::Memory()
{
#ifdef _WIN32
base = (char*)VirtualAlloc(address, size, MEM_RESERVE, PAGE_READWRITE);
base = (uint8_t*)VirtualAlloc((void*)0x100000000ull, PPC_MEMORY_SIZE + PPC_FUNC_TABLE_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
if (base == nullptr)
base = (char*)VirtualAlloc(nullptr, size, MEM_RESERVE, PAGE_READWRITE);
#else
base = (char*)mmap(address, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
base = (uint8_t*)VirtualAlloc(nullptr, PPC_MEMORY_SIZE + PPC_FUNC_TABLE_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
if (base == (char*)MAP_FAILED)
base = (char*)mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
DWORD oldProtect;
VirtualProtect(base, 4096, PAGE_NOACCESS, &oldProtect);
#else
base = (uint8_t*)mmap((void*)0x100000000ull, PPC_MEMORY_SIZE + PPC_FUNC_TABLE_SIZE, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
if (base == (uint8_t*)MAP_FAILED)
base = (uint8_t*)mmap(NULL, PPC_MEMORY_SIZE + PPC_FUNC_TABLE_SIZE, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
mprotect(base, 4096, PROT_NONE);
#endif
}
void* Memory::Alloc(size_t offset, size_t size, uint32_t type)
{
#ifdef _WIN32
return VirtualAlloc(base + offset, size, type, PAGE_READWRITE);
#else
return base + offset;
#endif
}
void* Memory::Commit(size_t offset, size_t size)
{
#ifdef _WIN32
return Alloc(offset, size, MEM_COMMIT);
#else
return base + offset;
#endif
}
void* Memory::Reserve(size_t offset, size_t size)
{
#ifdef _WIN32
return Alloc(offset, size, MEM_RESERVE);
#else
return base + offset;
#endif
for (size_t i = 0; PPCFuncMappings[i].guest != 0; i++)
{
if (PPCFuncMappings[i].host != nullptr)
InsertFunction(PPCFuncMappings[i].guest, PPCFuncMappings[i].host);
}
}
void* MmGetHostAddress(uint32_t ptr)

View file

@ -5,29 +5,21 @@
#define MEM_RESERVE 0x00002000
#endif
class Memory
struct Memory
{
public:
char* base{};
size_t size{};
size_t guestBase{};
uint8_t* base{};
Memory(void* address, size_t size);
void* Alloc(size_t offset, size_t size, uint32_t type);
void* Commit(size_t offset, size_t size);
void* Reserve(size_t offset, size_t size);
Memory();
bool IsInMemoryRange(const void* host) const noexcept
{
return host >= base && host < (base + size);
return host >= base && host < (base + PPC_MEMORY_SIZE);
}
void* Translate(size_t offset) const noexcept
{
if (offset)
assert(offset < 0x100000000ull);
assert(offset < PPC_MEMORY_SIZE);
return base + offset;
}
@ -37,7 +29,17 @@ public:
if (host)
assert(IsInMemoryRange(host));
return static_cast<uint32_t>(static_cast<const char*>(host) - base);
return static_cast<uint32_t>(static_cast<const uint8_t*>(host) - base);
}
PPCFunc* FindFunction(uint32_t guest) const noexcept
{
return *reinterpret_cast<PPCFunc**>(base + PPC_FUNC_TABLE_OFFSET + (uint64_t(guest) * 2));
}
void InsertFunction(uint32_t guest, PPCFunc* host)
{
*reinterpret_cast<PPCFunc**>(base + PPC_FUNC_TABLE_OFFSET + (uint64_t(guest) * 2)) = host;
}
};

View file

@ -1,5 +1,4 @@
#include <stdafx.h>
#include <cpu/code_cache.h>
#include <cpu/guest_thread.h>
#include <gpu/video.h>
#include <kernel/function.h>
@ -25,9 +24,8 @@
const size_t XMAIOBegin = 0x7FEA0000;
const size_t XMAIOEnd = XMAIOBegin + 0x0000FFFF;
Memory g_memory{ reinterpret_cast<void*>(0x100000000), 0x100000000 };
Memory g_memory;
Heap g_userHeap;
CodeCache g_codeCache;
XDBFWrapper g_xdbfWrapper;
std::unordered_map<uint16_t, GuestTexture*> g_xdbfTextureCache;
@ -37,11 +35,7 @@ void HostStartup()
CoInitializeEx(nullptr, COINIT_MULTITHREADED);
#endif
g_memory.Alloc(0x10000, 0x1000, MEM_COMMIT);
g_userHeap.Init();
g_codeCache.Init();
g_memory.Alloc(XMAIOBegin, 0xFFFF, MEM_COMMIT);
hid::Init();
}
@ -109,8 +103,6 @@ uint32_t LdrLoadModule(const std::filesystem::path &path)
auto* xex = reinterpret_cast<XEX_HEADER*>(loadResult.data());
auto security = reinterpret_cast<XEX2_SECURITY_INFO*>((char*)xex + xex->AddressOfSecurityInfo);
g_memory.Alloc(security->ImageBase, security->SizeOfImage, MEM_COMMIT);
auto format = Xex2FindOptionalHeader<XEX_FILE_FORMAT_INFO>(xex, XEX_HEADER_FILE_FORMAT_INFO);
auto entry = *Xex2FindOptionalHeader<uint32_t>(xex, XEX_HEADER_ENTRY_POINT);
ByteSwapInplace(entry);

View file

@ -1,4 +1,3 @@
#include <cpu/guest_code.h>
#include <user/config.h>
#include <kernel/function.h>
#include <os/media.h>

View file

@ -1,4 +1,3 @@
#include <cpu/guest_code.h>
#include <api/SWA.h>
#include <ui/game_window.h>
#include <user/config.h>

View file

@ -1,5 +1,4 @@
#include <cpu/code_cache.h>
#include <cpu/guest_code.h>
#include <kernel/memory.h>
#include <api/SWA.h>
#include <ui/game_window.h>
#include <user/config.h>
@ -87,13 +86,13 @@ bool LoadingUpdateMidAsmHook(PPCRegister& r31)
double deltaTime = std::min(std::chrono::duration<double>(now - g_prev).count(), 1.0 / 15.0);
g_prev = now;
uint8_t* base = reinterpret_cast<uint8_t*>(g_memory.base);
uint8_t* base = g_memory.base;
uint32_t application = PPC_LOAD_U32(PPC_LOAD_U32(r31.u32 + 4));
uint32_t update = PPC_LOAD_U32(PPC_LOAD_U32(application) + 20);
g_ppcContext->r3.u32 = application;
g_ppcContext->f1.f64 = deltaTime;
reinterpret_cast<PPCFunc*>(g_codeCache.Find(update))(*g_ppcContext, base);
g_memory.FindFunction(update)(*g_ppcContext, base);
bool loading = PPC_LOAD_U8(0x83367A4C);
if (loading)

View file

@ -1,4 +1,3 @@
#include <cpu/guest_code.h>
#include <api/SWA.h>
#include <ui/game_window.h>
#include <user/achievement_data.h>

View file

@ -1,5 +1,3 @@
#include <cpu/guest_code.h>
// CObjFlame::CObjFlame
// A field is not zero initialized,
// causing collisions to constantly get created

View file

@ -1,4 +1,3 @@
#include <cpu/guest_code.h>
#include <api/SWA.h>
#include <ui/game_window.h>
#include <ui/window_events.h>

View file

@ -1,4 +1,3 @@
#include <cpu/guest_code.h>
#include <user/achievement_data.h>
#include <user/config.h>
#include <api/SWA.h>

View file

@ -1,4 +1,3 @@
#include <cpu/guest_code.h>
#include <kernel/function.h>
#include <api/SWA.h>
#include <ui/achievement_menu.h>

View file

@ -1,4 +1,3 @@
#include <cpu/guest_code.h>
#include <api/SWA.h>
#include <locale/locale.h>
#include <ui/fader.h>

View file

@ -1,4 +1,3 @@
#include <cpu/guest_code.h>
#include <api/SWA.h>
#include <locale/locale.h>
#include <ui/button_guide.h>

View file

@ -1,4 +1,3 @@
#include <cpu/guest_code.h>
#include <user/config.h>
#include <api/SWA.h>
#include <ui/game_window.h>

@ -1 +1 @@
Subproject commit 4650dc69fb40d0e5857fe28c40e85eec7c97edf7
Subproject commit de2840970ffc3161a4cb8743b10ddd4da93bdc9f