/** ****************************************************************************** * Xenia : Xbox 360 Emulator Research Project * ****************************************************************************** * Copyright 2013 Ben Vanik. All rights reserved. * * Released under the BSD license - see LICENSE in the root for more details. * ****************************************************************************** */ #include #include #include #include #include #include #include #include #include #include "cpu/codegen/emit.h" using namespace llvm; using namespace xe; using namespace xe::cpu; using namespace xe::kernel; namespace { void InitializeIfNeeded(); void CleanupOnShutdown(); void InitializeIfNeeded() { static bool has_initialized = false; if (has_initialized) { return; } has_initialized = true; // TODO(benvanik): only do this once LLVMLinkInInterpreter(); LLVMLinkInJIT(); InitializeNativeTarget(); // TODO(benvanik): only do this once codegen::RegisterEmitCategoryALU(); codegen::RegisterEmitCategoryControl(); codegen::RegisterEmitCategoryFPU(); codegen::RegisterEmitCategoryMemory(); atexit(CleanupOnShutdown); } void CleanupOnShutdown() { llvm_shutdown(); } } Processor::Processor(xe_pal_ref pal, xe_memory_ref memory) { pal_ = xe_pal_retain(pal); memory_ = xe_memory_retain(memory); InitializeIfNeeded(); } Processor::~Processor() { // Cleanup all modules. for (std::vector::iterator it = modules_.begin(); it != modules_.end(); ++it) { delete *it; } engine_.reset(); xe_memory_release(memory_); xe_pal_release(pal_); } xe_pal_ref Processor::pal() { return xe_pal_retain(pal_); } xe_memory_ref Processor::memory() { return xe_memory_retain(memory_); } int Processor::Setup() { XEASSERTNULL(engine_); if (!llvm_start_multithreaded()) { return 1; } dummy_context_ = auto_ptr(new LLVMContext()); Module* dummy_module = new Module("dummy", *dummy_context_.get()); std::string error_message; engine_ = shared_ptr( ExecutionEngine::create(dummy_module, false, &error_message, CodeGenOpt::Aggressive, false)); if (!engine_) { return 1; } return 0; } int Processor::PrepareModule( const char* module_name, const char* module_path, uint32_t start_address, uint32_t end_address, shared_ptr export_resolver) { ExecModule* exec_module = new ExecModule( memory_, export_resolver, module_name, module_path, engine_); if (exec_module->PrepareRawBinary(start_address, end_address)) { delete exec_module; return 1; } exec_module->AddFunctionsToMap(all_fns_); modules_.push_back(exec_module); exec_module->Dump(); return 0; } int Processor::PrepareModule(UserModule* user_module, shared_ptr export_resolver) { ExecModule* exec_module = new ExecModule( memory_, export_resolver, user_module->name(), user_module->path(), engine_); if (exec_module->PrepareUserModule(user_module)) { delete exec_module; return 1; } exec_module->AddFunctionsToMap(all_fns_); modules_.push_back(exec_module); //user_module->Dump(export_resolver.get()); exec_module->Dump(); return 0; } uint32_t Processor::CreateCallback(void (*callback)(void* data), void* data) { // TODO(benvanik): implement callback creation. return 0; } ThreadState* Processor::AllocThread(uint32_t stack_address, uint32_t stack_size) { ThreadState* thread_state = new ThreadState( this, stack_address, stack_size); return thread_state; } void Processor::DeallocThread(ThreadState* thread_state) { delete thread_state; } int Processor::Execute(ThreadState* thread_state, uint32_t address) { // Find the function to execute. Function* f = GetFunction(address); if (!f) { XELOGCPU("Failed to find function %.8X to execute.\n", address); return 1; } xe_ppc_state_t* ppc_state = thread_state->ppc_state(); // This could be set to anything to give us a unique identifier to track // re-entrancy/etc. uint32_t lr = 0xBEBEBEBE; // Setup registers. ppc_state->lr = 0xBEBEBEBE; // Args: // - i8* state // - i64 lr std::vector args; args.push_back(PTOGV(ppc_state)); GenericValue lr_arg; lr_arg.IntVal = APInt(64, lr); args.push_back(lr_arg); GenericValue ret = engine_->runFunction(f, args); //return (uint32_t)ret.IntVal.getSExtValue(); return 0; } Function* Processor::GetFunction(uint32_t address) { FunctionMap::iterator it = all_fns_.find(address); if (it != all_fns_.end()) { return it->second; } return NULL; }