/** ****************************************************************************** * 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 using namespace xe; using namespace xe::cpu; using namespace xe::cpu::sdb; using namespace xe::cpu::x64; using namespace AsmJit; X64JIT::X64JIT(xe_memory_ref memory, SymbolTable* sym_table) : JIT(memory, sym_table), emitter_(NULL) { } X64JIT::~X64JIT() { delete emitter_; } int X64JIT::Setup() { int result_code = 1; XELOGCPU("Initializing x64 JIT backend..."); // Check processor for support. result_code = CheckProcessor(); if (result_code) { XELOGE("Processor check failed, aborting..."); } XEEXPECTZERO(result_code); // Create the emitter used to generate functions. emitter_ = new X64Emitter(memory_); result_code = 0; XECLEANUP: return result_code; } namespace { struct BitDescription { uint32_t mask; const char* description; }; static const BitDescription x86Features[] = { { kX86FeatureRdtsc , "RDTSC" }, { kX86FeatureRdtscP , "RDTSCP" }, { kX86FeatureCMov , "CMOV" }, { kX86FeatureCmpXchg8B , "CMPXCHG8B" }, { kX86FeatureCmpXchg16B , "CMPXCHG16B" }, { kX86FeatureClFlush , "CLFLUSH" }, { kX86FeaturePrefetch , "PREFETCH" }, { kX86FeatureLahfSahf , "LAHF/SAHF" }, { kX86FeatureFXSR , "FXSAVE/FXRSTOR" }, { kX86FeatureFFXSR , "FXSAVE/FXRSTOR Optimizations" }, { kX86FeatureMmx , "MMX" }, { kX86FeatureMmxExt , "MMX Extensions" }, { kX86Feature3dNow , "3dNow!" }, { kX86Feature3dNowExt , "3dNow! Extensions" }, { kX86FeatureSse , "SSE" }, { kX86FeatureSse2 , "SSE2" }, { kX86FeatureSse3 , "SSE3" }, { kX86FeatureSsse3 , "SSSE3" }, { kX86FeatureSse4A , "SSE4A" }, { kX86FeatureSse41 , "SSE4.1" }, { kX86FeatureSse42 , "SSE4.2" }, { kX86FeatureAvx , "AVX" }, { kX86FeatureMSse , "Misaligned SSE" }, { kX86FeatureMonitorMWait , "MONITOR/MWAIT" }, { kX86FeatureMovBE , "MOVBE" }, { kX86FeaturePopCnt , "POPCNT" }, { kX86FeatureLzCnt , "LZCNT" }, { kX86FeaturePclMulDQ , "PCLMULDQ" }, { kX86FeatureMultiThreading , "Multi-Threading" }, { kX86FeatureExecuteDisableBit , "Execute-Disable Bit" }, { kX86Feature64Bit , "64-Bit Processor" }, { 0, NULL }, }; } int X64JIT::CheckProcessor() { const CpuInfo* cpu = CpuInfo::getGlobal(); const X86CpuInfo* x86Cpu = static_cast(cpu); XELOGCPU("Processor Info:"); XELOGCPU(" Vendor string : %s", cpu->getVendorString()); XELOGCPU(" Brand string : %s", cpu->getBrandString()); XELOGCPU(" Family : %u", cpu->getFamily()); XELOGCPU(" Model : %u", cpu->getModel()); XELOGCPU(" Stepping : %u", cpu->getStepping()); XELOGCPU(" Number of Processors : %u", cpu->getNumberOfProcessors()); XELOGCPU(" Features : 0x%08X", cpu->getFeatures()); XELOGCPU(" Bugs : 0x%08X", cpu->getBugs()); XELOGCPU(" Processor Type : %u", x86Cpu->getProcessorType()); XELOGCPU(" Brand Index : %u", x86Cpu->getBrandIndex()); XELOGCPU(" CL Flush Cache Line : %u", x86Cpu->getFlushCacheLineSize()); XELOGCPU(" Max logical Processors: %u", x86Cpu->getMaxLogicalProcessors()); XELOGCPU(" APIC Physical ID : %u", x86Cpu->getApicPhysicalId()); XELOGCPU(" Features:"); uint32_t mask = cpu->getFeatures(); for (const BitDescription* d = x86Features; d->mask; d++) { if (mask & d->mask) { XELOGCPU(" %s", d->description); } } // TODO(benvanik): ensure features we want are supported. return 0; } int X64JIT::InitModule(ExecModule* module) { // TODO(benvanik): precompile interesting functions (kernel calls, etc). // TODO(benvanik): warn on unimplemented instructions. // TODO(benvanik): dump instruction use report. // TODO(benvanik): dump kernel use report. // TODO(benvanik): check for cached code/patches/etc. return 0; } int X64JIT::UninitModule(ExecModule* module) { return 0; } int X64JIT::Execute(xe_ppc_state_t* ppc_state, FunctionSymbol* fn_symbol) { XELOGCPU("Execute(%.8X): %s...", fn_symbol->start_address, fn_symbol->name()); // Check function. x64_function_t fn_ptr = (x64_function_t)fn_symbol->impl_value; if (!fn_ptr) { // Function hasn't been prepped yet - make it now inline. // The emitter will lock and do other fancy things, if required. if (emitter_->PrepareFunction(fn_symbol)) { XELOGCPU("Execute(%.8X): unable to make function %s", fn_symbol->start_address, fn_symbol->name()); return 1; } fn_ptr = (x64_function_t)fn_symbol->impl_value; XEASSERTNOTNULL(fn_ptr); } // Call into the function. This will compile it if needed. fn_ptr(ppc_state, ppc_state->lr); return 0; }