LLVM: Indirect call map

This commit is contained in:
Nekotekina 2016-06-27 19:34:08 +03:00
parent 7a921cbdf9
commit 0ea0c21fed
6 changed files with 49 additions and 56 deletions

View File

@ -25,21 +25,21 @@ namespace memory_helper
return ret;
}
void commit_page_memory(void* pointer, size_t page_size)
void commit_page_memory(void* pointer, size_t size)
{
#ifdef _WIN32
VERIFY(VirtualAlloc((u8*)pointer, page_size, MEM_COMMIT, PAGE_READWRITE) != NULL);
VERIFY(VirtualAlloc(pointer, size, MEM_COMMIT, PAGE_READWRITE) != NULL);
#else
VERIFY(mprotect((u8*)pointer, page_size, PROT_READ | PROT_WRITE) != -1);
VERIFY(mprotect((void*)((u64)pointer & -4096), size, PROT_READ | PROT_WRITE) != -1);
#endif
}
void free_reserved_memory(void* pointer, size_t size)
{
#ifdef _WIN32
VERIFY(VirtualFree(pointer, 0, MEM_RELEASE) != 0);
VERIFY(VirtualFree(pointer, 0, MEM_DECOMMIT) != 0);
#else
VERIFY(munmap(pointer, size) == 0);
VERIFY(mprotect(pointer, size, PROT_NONE) != -1);
#endif
}
}

View File

@ -3,20 +3,20 @@
namespace memory_helper
{
/**
* Reserve size bytes of virtual memory and returns it.
* Reserve `size` bytes of virtual memory and returns it.
* The memory should be commited before usage.
*/
void* reserve_memory(size_t size);
void* reserve_memory(std::size_t size);
/**
* Commit page_size bytes of virtual memory starting at pointer.
* Commit `size` bytes of virtual memory starting at pointer.
* That is, bake reserved memory with physical memory.
* pointer should belong to a range of reserved memory.
*/
void commit_page_memory(void* pointer, size_t page_size);
void commit_page_memory(void* pointer, std::size_t size);
/**
* Free memory alloced via reserve_memory.
* Decommit all memory committed via commit_page_memory.
*/
void free_reserved_memory(void* pointer, size_t size);
}
void free_reserved_memory(void* pointer, std::size_t size);
}

View File

@ -13,6 +13,7 @@
logs::channel cellGcmSys("cellGcmSys", logs::level::notice);
extern s32 cellGcmCallback(vm::ptr<CellGcmContextData> context, u32 count);
extern void ppu_register_function_at(u32 addr, ppu_function_t ptr);
const u32 tiled_pitches[] = {
0x00000000, 0x00000200, 0x00000300, 0x00000400,
@ -384,6 +385,7 @@ s32 _cellGcmInitBody(vm::pptr<CellGcmContextData> context, u32 cmdSize, u32 ioSi
vm::write32(gcm_info.context_addr + 0x44, 0xabadcafe);
vm::write32(gcm_info.context_addr + 0x48, ppu_instructions::HACK(FIND_FUNC(cellGcmCallback)));
vm::write32(gcm_info.context_addr + 0x4c, ppu_instructions::BLR());
ppu_register_function_at(gcm_info.context_addr + 0x48, BIND_FUNC(cellGcmCallback));
vm::_ref<CellGcmContextData>(gcm_info.context_addr) = current_context;
context->set(gcm_info.context_addr);

View File

@ -1,5 +1,6 @@
#include "stdafx.h"
#include "Utilities/Config.h"
#include "Utilities/VirtualMemory.h"
#include "Emu/Memory/Memory.h"
#include "Emu/System.h"
#include "Emu/IdManager.h"
@ -56,17 +57,16 @@ cfg::map_entry<ppu_decoder_type> g_cfg_ppu_decoder(cfg::root.core, "PPU Decoder"
const ppu_decoder<ppu_interpreter_precise> s_ppu_interpreter_precise;
const ppu_decoder<ppu_interpreter_fast> s_ppu_interpreter_fast;
struct ppu_addr_hash
const auto s_ppu_compiled = static_cast<ppu_function_t*>(memory_helper::reserve_memory(0x200000000));
extern void ppu_register_function_at(u32 addr, ppu_function_t ptr)
{
u32 operator()(u32 value) const
if (g_cfg_ppu_decoder.get() == ppu_decoder_type::llvm)
{
return value / sizeof(32);
memory_helper::commit_page_memory(s_ppu_compiled + addr / 4, sizeof(ppu_function_t));
s_ppu_compiled[addr / 4] = ptr;
}
};
static std::unordered_map<u32, ppu_function_t, ppu_addr_hash> s_ppu_compiled; // TODO
}
std::string PPUThread::get_name() const
{
@ -134,12 +134,7 @@ void PPUThread::cpu_task_main()
{
if (g_cfg_ppu_decoder.get() == ppu_decoder_type::llvm)
{
const auto found = s_ppu_compiled.find(pc);
if (found != s_ppu_compiled.end())
{
return found->second(*this);
}
return s_ppu_compiled[pc / 4](*this);
}
g_tls_log_prefix = []
@ -397,27 +392,6 @@ static void ppu_trace(u64 addr)
LOG_NOTICE(PPU, "Trace: 0x%llx", addr);
}
static void ppu_call(PPUThread& ppu, u32 addr)
{
const auto found = s_ppu_compiled.find(addr);
if (found != s_ppu_compiled.end())
{
return found->second(ppu);
}
const auto op = vm::read32(addr).value();
const auto itype = s_ppu_itype.decode(op);
// Allow HLE callbacks without compiling them
if (itype == ppu_itype::HACK && vm::read32(addr + 4) == ppu_instructions::BLR())
{
return ppu_execute_function(ppu, op & 0x3ffffff);
}
ppu_trap(addr);
}
static __m128 sse_rcp_ps(__m128 A)
{
return _mm_rcp_ps(A);
@ -511,7 +485,7 @@ extern void ppu_initialize(const std::string& name, const std::vector<std::pair<
{ "__hlecall", (u64)&ppu_execute_function },
{ "__syscall", (u64)&ppu_execute_syscall },
{ "__get_tbl", (u64)&get_timebased_time },
{ "__call", (u64)&ppu_call },
{ "__call", (u64)s_ppu_compiled },
{ "__lwarx", (u64)&ppu_lwarx },
{ "__ldarx", (u64)&ppu_ldarx },
{ "__stwcx", (u64)&ppu_stwcx },
@ -676,17 +650,19 @@ extern void ppu_initialize(const std::string& name, const std::vector<std::pair<
return;
}
s_ppu_compiled.clear();
memory_helper::free_reserved_memory(s_ppu_compiled, 0x200000000); // TODO
// Get function addresses
// Get and install function addresses
for (const auto& info : funcs)
{
const u32 addr = info.first;
if (info.second)
{
const std::uintptr_t link = jit->get(fmt::format("__sub_%x", info.first));
s_ppu_compiled.emplace(info.first, (ppu_function_t)link);
const std::uintptr_t link = jit->get(fmt::format("__sub_%x", addr));
memory_helper::commit_page_memory(s_ppu_compiled + addr / 4, sizeof(ppu_function_t));
s_ppu_compiled[addr / 4] = (ppu_function_t)link;
LOG_NOTICE(PPU, "** Function __sub_%x -> 0x%llx (addr=0x%x, size=0x%x)", info.first, link, info.first, info.second);
LOG_NOTICE(PPU, "** Function __sub_%x -> 0x%llx (addr=0x%x, size=0x%x)", addr, link, addr, info.second);
}
}

View File

@ -82,6 +82,9 @@ PPUTranslator::PPUTranslator(LLVMContext& context, Module* module, u64 base, u64
thread_struct.insert(thread_struct.end(), 32, GetType<bool>()); // CR[0..31]
m_thread_type = StructType::create(m_context, thread_struct, "context_t");
// Callable
m_call = new GlobalVariable(*module, ArrayType::get(FunctionType::get(GetType<void>(), {m_thread_type->getPointerTo()}, false)->getPointerTo(), 0x40000000), true, GlobalValue::ExternalLinkage, 0, "__call");
}
PPUTranslator::~PPUTranslator()
@ -265,8 +268,7 @@ Function* PPUTranslator::TranslateToIR(u64 start_addr, u64 end_addr, be_t<u32>*
}
m_ir->SetInsertPoint(_default);
Call(GetType<void>(), "__call", m_thread, _ctr);
m_ir->CreateRetVoid();
CallFunction(0, true, _ctr);
}
//for (auto i = inst_begin(*m_function), end = inst_end(*m_function); i != end;)
@ -321,7 +323,17 @@ void PPUTranslator::CallFunction(u64 target, bool tail, Value* indirect)
const auto callee_type = func ? m_func_types[target] : nullptr;
const auto result = func ? m_ir->CreateCall(func, {m_thread}) : Call(GetType<void>(), "__call", m_thread, indirect ? indirect : m_ir->getInt64(target));
if (func)
{
m_ir->CreateCall(func, {m_thread});
}
else
{
const auto addr = indirect ? indirect : (Value*)m_ir->getInt64(target);
const auto pos = m_ir->CreateLShr(addr, 2, "", true);
const auto ptr = m_ir->CreateGEP(m_call, {m_ir->getInt64(0), pos});
m_ir->CreateCall(m_ir->CreateLoad(ptr), {m_thread});
}
if (!tail)
{

View File

@ -157,6 +157,9 @@ class PPUTranslator final //: public CPUTranslator
// Thread context
llvm::Value* m_thread;
// Callable functions
llvm::Value* m_call;
// Thread context struct
llvm::StructType* m_thread_type;