mirror of
https://github.com/hedge-dev/UnleashedRecomp
synced 2026-06-11 21:19:18 -04:00
Initial Commit
This commit is contained in:
@@ -0,0 +1,37 @@
|
||||
#include <stdafx.h>
|
||||
#include "code_cache.h"
|
||||
#include "ppc_context.h"
|
||||
|
||||
CodeCache::CodeCache()
|
||||
{
|
||||
bucket = (char*)VirtualAlloc(nullptr, 0x200000000, MEM_RESERVE, PAGE_READWRITE);
|
||||
assert(bucket);
|
||||
}
|
||||
|
||||
CodeCache::~CodeCache()
|
||||
{
|
||||
VirtualFree(bucket, 0, MEM_RELEASE);
|
||||
}
|
||||
|
||||
void CodeCache::Init()
|
||||
{
|
||||
for (size_t i = 0; PPCFuncMappings[i].guest != 0; i++)
|
||||
{
|
||||
if (PPCFuncMappings[i].host != nullptr)
|
||||
{
|
||||
VirtualAlloc(bucket + PPCFuncMappings[i].guest * 2, sizeof(void*), MEM_COMMIT, PAGE_READWRITE);
|
||||
*(void**)(bucket + PPCFuncMappings[i].guest * 2) = PPCFuncMappings[i].host;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CodeCache::Insert(uint32_t guest, const void* host)
|
||||
{
|
||||
VirtualAlloc(bucket + static_cast<uint64_t>(guest) * 2, sizeof(void*), MEM_COMMIT, PAGE_READWRITE);
|
||||
*reinterpret_cast<const void**>(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);
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
struct CodeCache
|
||||
{
|
||||
char* bucket{};
|
||||
|
||||
CodeCache();
|
||||
~CodeCache();
|
||||
|
||||
void Init();
|
||||
void Insert(uint32_t guest, const void* host);
|
||||
|
||||
void* Find(uint32_t guest) const;
|
||||
};
|
||||
|
||||
extern CodeCache gCodeCache;
|
||||
@@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
#include "ppc_context.h"
|
||||
#include "memory.h"
|
||||
|
||||
struct GuestCode
|
||||
{
|
||||
inline static void Run(void* hostAddress, PPCContext* ctx, void* baseAddress, void* callStack)
|
||||
{
|
||||
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*>(gMemory.base));
|
||||
}
|
||||
|
||||
inline static void Run(void* hostAddress)
|
||||
{
|
||||
Run(hostAddress, GetPPCContext());
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,143 @@
|
||||
#include <stdafx.h>
|
||||
#include "guest_thread.h"
|
||||
#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;
|
||||
constexpr size_t TLS_SIZE = 0x100;
|
||||
constexpr size_t TEB_SIZE = 0x2E0;
|
||||
constexpr size_t STACK_SIZE = 0x40000;
|
||||
constexpr size_t CALL_STACK_SIZE = 0x8000;
|
||||
constexpr size_t TOTAL_SIZE = PCR_SIZE + TLS_SIZE + TEB_SIZE + STACK_SIZE + CALL_STACK_SIZE;
|
||||
|
||||
constexpr size_t TEB_OFFSET = PCR_SIZE + TLS_SIZE;
|
||||
|
||||
DWORD GuestThread::Start(uint32_t function)
|
||||
{
|
||||
const GuestThreadParameter parameter{ function };
|
||||
return Start(parameter);
|
||||
}
|
||||
|
||||
DWORD GuestThread::Start(const GuestThreadParameter& parameter)
|
||||
{
|
||||
auto* thread = (uint8_t*)gUserHeap.Alloc(TOTAL_SIZE);
|
||||
|
||||
const auto procMask = (uint8_t)(parameter.flags >> 24);
|
||||
const auto cpuNumber = procMask == 0 ? 0 : 7 - std::countl_zero(procMask);
|
||||
|
||||
memset(thread, 0, TOTAL_SIZE);
|
||||
|
||||
*(uint32_t*)thread = std::byteswap(gMemory.MapVirtual(thread + PCR_SIZE)); // tls pointer
|
||||
*(uint32_t*)(thread + 0x100) = std::byteswap(gMemory.MapVirtual(thread + PCR_SIZE + TLS_SIZE)); // teb pointer
|
||||
*(thread + 0x10C) = cpuNumber;
|
||||
|
||||
*(uint32_t*)(thread + PCR_SIZE + 0x10) = 0xFFFFFFFF; // that one TLS entry that felt quirky
|
||||
*(uint32_t*)(thread + PCR_SIZE + TLS_SIZE + 0x14C) = std::byteswap(GetCurrentThreadId()); // thread id
|
||||
|
||||
PPCContext ppcContext{};
|
||||
ppcContext.fn = (uint8_t*)gCodeCache.bucket;
|
||||
ppcContext.r1.u64 = gMemory.MapVirtual(thread + PCR_SIZE + TLS_SIZE + TEB_SIZE + STACK_SIZE); // stack pointer
|
||||
ppcContext.r3.u64 = parameter.value;
|
||||
ppcContext.r13.u64 = gMemory.MapVirtual(thread);
|
||||
|
||||
SetPPCContext(ppcContext);
|
||||
|
||||
GuestCode::Run(gCodeCache.Find(parameter.function), &ppcContext, gMemory.Translate(0), gMemory.Translate(ppcContext.r1.u32));
|
||||
gUserHeap.Free(thread);
|
||||
|
||||
return (DWORD)ppcContext.r3.u64;
|
||||
}
|
||||
|
||||
DWORD HostThreadStart(void* pParameter)
|
||||
{
|
||||
auto* parameter = static_cast<GuestThreadParameter*>(pParameter);
|
||||
const auto result = GuestThread::Start(*parameter);
|
||||
|
||||
delete parameter;
|
||||
return result;
|
||||
}
|
||||
|
||||
HANDLE GuestThread::Start(uint32_t function, uint32_t parameter, uint32_t flags, LPDWORD threadId)
|
||||
{
|
||||
const auto hostCreationFlags = (flags & 1) != 0 ? CREATE_SUSPENDED : 0;
|
||||
//return CreateThread(nullptr, 0, Start, (void*)((uint64_t(parameter) << 32) | function), suspended ? CREATE_SUSPENDED : 0, threadId);
|
||||
return CreateThread(nullptr, 0, HostThreadStart, new GuestThreadParameter{ function, parameter, flags }, hostCreationFlags, threadId);
|
||||
}
|
||||
|
||||
void GuestThread::SetThreadName(uint32_t id, const char* name)
|
||||
{
|
||||
#pragma pack(push,8)
|
||||
const DWORD MS_VC_EXCEPTION = 0x406D1388;
|
||||
|
||||
typedef struct tagTHREADNAME_INFO
|
||||
{
|
||||
DWORD dwType; // Must be 0x1000.
|
||||
LPCSTR szName; // Pointer to name (in user addr space).
|
||||
DWORD dwThreadID; // Thread ID (-1=caller thread).
|
||||
DWORD dwFlags; // Reserved for future use, must be zero.
|
||||
} THREADNAME_INFO;
|
||||
#pragma pack(pop)
|
||||
|
||||
THREADNAME_INFO info;
|
||||
info.dwType = 0x1000;
|
||||
info.szName = name;
|
||||
info.dwThreadID = id;
|
||||
info.dwFlags = 0;
|
||||
|
||||
__try
|
||||
{
|
||||
RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR*)&info);
|
||||
}
|
||||
__except (EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
void GuestThread::SetLastError(DWORD error)
|
||||
{
|
||||
auto* thread = (char*)gMemory.Translate(GetPPCContext()->r13.u32);
|
||||
if (*(DWORD*)(thread + 0x150))
|
||||
{
|
||||
// Program doesn't want errors
|
||||
return;
|
||||
}
|
||||
|
||||
// TEB + 0x160 : Win32LastError
|
||||
*(DWORD*)(thread + TEB_OFFSET + 0x160) = std::byteswap(error);
|
||||
}
|
||||
|
||||
PPCContext* GuestThread::Invoke(uint32_t address)
|
||||
{
|
||||
auto* ctx = GetPPCContext();
|
||||
GuestCode::Run(gCodeCache.Find(address), ctx);
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
void SetThreadNameImpl(uint32_t a1, uint32_t threadId, uint32_t* name)
|
||||
{
|
||||
GuestThread::SetThreadName(threadId, (const char*)gMemory.Translate(std::byteswap(*name)));
|
||||
}
|
||||
|
||||
int GetThreadPriorityImpl(uint32_t hThread)
|
||||
{
|
||||
return GetThreadPriority((HANDLE)hThread);
|
||||
}
|
||||
|
||||
DWORD SetThreadIdealProcessorImpl(uint32_t hThread, DWORD dwIdealProcessor)
|
||||
{
|
||||
return SetThreadIdealProcessor((HANDLE)hThread, dwIdealProcessor);
|
||||
}
|
||||
|
||||
GUEST_FUNCTION_HOOK(sub_82DFA2E8, SetThreadNameImpl);
|
||||
GUEST_FUNCTION_HOOK(sub_82BD57A8, GetThreadPriorityImpl);
|
||||
GUEST_FUNCTION_HOOK(sub_82BD5910, SetThreadIdealProcessorImpl);
|
||||
|
||||
void GuestThread::InitHooks()
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
struct PPCContext;
|
||||
struct GuestThreadParameter
|
||||
{
|
||||
uint32_t function;
|
||||
uint32_t value;
|
||||
uint32_t flags;
|
||||
};
|
||||
|
||||
struct GuestThread
|
||||
{
|
||||
static DWORD Start(uint32_t function);
|
||||
static DWORD Start(const GuestThreadParameter& parameter);
|
||||
static HANDLE Start(uint32_t function, uint32_t parameter, uint32_t flags, LPDWORD threadId);
|
||||
|
||||
static void SetThreadName(uint32_t id, const char* name);
|
||||
static void SetLastError(DWORD error);
|
||||
static PPCContext* Invoke(uint32_t address);
|
||||
static void InitHooks();
|
||||
};
|
||||
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
#include "ppc/ppc_context.h"
|
||||
#include "ppc/ppc_recomp_shared.h"
|
||||
|
||||
inline thread_local PPCContext* gPPCContext;
|
||||
|
||||
inline PPCContext* GetPPCContext()
|
||||
{
|
||||
return gPPCContext;
|
||||
}
|
||||
|
||||
inline void SetPPCContext(PPCContext& ctx)
|
||||
{
|
||||
gPPCContext = &ctx;
|
||||
}
|
||||
Reference in New Issue
Block a user