From 07cb56e1ea26d9e5957e78e73a9be89e75c87155 Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Mon, 23 Feb 2015 21:54:17 +0300 Subject: [PATCH 1/9] Flags for HLE functions --- rpcs3/Emu/ARMv7/PSVFuncList.cpp | 17 +----- rpcs3/Emu/ARMv7/PSVFuncList.h | 41 +++++++------ rpcs3/Emu/SysCalls/ModuleManager.cpp | 1 - rpcs3/Emu/SysCalls/Modules.cpp | 29 +++------- rpcs3/Emu/SysCalls/Modules.h | 19 +++++- rpcs3/Emu/SysCalls/Modules/cellSync.cpp | 8 +-- rpcs3/Emu/SysCalls/Modules/sys_net.cpp | 2 +- rpcs3/Emu/SysCalls/SC_FUNC.h | 77 +++++++++++++++---------- rpcs3/Loader/ELF32.cpp | 9 +-- rpcs3/Loader/ELF64.cpp | 35 ++++++++++- 10 files changed, 134 insertions(+), 104 deletions(-) diff --git a/rpcs3/Emu/ARMv7/PSVFuncList.cpp b/rpcs3/Emu/ARMv7/PSVFuncList.cpp index 79fc5efdbe..220ca2c21d 100644 --- a/rpcs3/Emu/ARMv7/PSVFuncList.cpp +++ b/rpcs3/Emu/ARMv7/PSVFuncList.cpp @@ -9,22 +9,7 @@ u32 add_psv_func(psv_func data) { for (auto& f : g_psv_func_list) { - if (f.nid == data.nid) - { - const u32 index = (u32)(&f - g_psv_func_list.data()); - - if (index < SFI_MAX) - { - continue; - } - - if (data.func) - { - f.func = data.func; - } - - return index; - } + assert(f.nid != data.nid || (&f - g_psv_func_list.data()) < SFI_MAX); } g_psv_func_list.push_back(data); diff --git a/rpcs3/Emu/ARMv7/PSVFuncList.h b/rpcs3/Emu/ARMv7/PSVFuncList.h index 2780e33a7b..811f33675a 100644 --- a/rpcs3/Emu/ARMv7/PSVFuncList.h +++ b/rpcs3/Emu/ARMv7/PSVFuncList.h @@ -38,7 +38,7 @@ typedef void(*psv_func_caller)(ARMv7Context&); // Utilities for binding ARMv7Context to C++ function arguments received by HLE functions or sent to callbacks namespace psv_func_detail { - enum bind_arg_type + enum arg_class { ARG_GENERAL, ARG_FLOAT, @@ -48,7 +48,7 @@ namespace psv_func_detail static const auto FIXED_STACK_FRAME_SIZE = 0x100; // described in CB_FUNC.h - template + template struct bind_arg; template @@ -191,7 +191,7 @@ namespace psv_func_detail } }; - template + template struct bind_result { static_assert(type != ARG_FLOAT, "TODO: Unsupported funcion result type (float)"); @@ -265,7 +265,7 @@ namespace psv_func_detail static_assert(!std::is_reference::value, "Invalid function result type (reference)"); static const bool is_float = std::is_floating_point::value; static const bool is_vector = std::is_same::value; - static const bind_arg_type value = is_float ? ARG_FLOAT : (is_vector ? ARG_VECTOR : ARG_GENERAL); + static const arg_class value = is_float ? ARG_FLOAT : (is_vector ? ARG_VECTOR : ARG_GENERAL); }; template @@ -281,7 +281,7 @@ namespace psv_func_detail static const int g_next = g_pos + g_align - 1; static const int f_value = !is_float ? f_count : f_count + 1; static const int v_value = !is_vector ? v_count : v_count + 1; - static const bind_arg_type value = is_float + static const arg_class value = is_float ? ((f_value > 9000) ? ARG_STACK : ARG_FLOAT) : (is_vector ? ((v_value > 9000) ? ARG_STACK : ARG_VECTOR) : ((g_pos > 4) ? ARG_STACK : ARG_GENERAL)); }; @@ -322,7 +322,7 @@ namespace psv_func_detail __forceinline std::tuple get_func_args(ARMv7Context& context) { typedef arg_type type; - const bind_arg_type t = type::value; + const arg_class t = type::value; const int g0 = type::g_pos; const int g1 = type::g_next; const int f = type::f_value; @@ -342,7 +342,7 @@ namespace psv_func_detail __forceinline static bool put_func_args(ARMv7Context& context, T1 arg, T... args) { typedef arg_type type; - const bind_arg_type t = type::value; + const arg_class t = type::value; const int g0 = type::g_pos; const int g1 = type::g_next; const int f = type::f_value; @@ -435,9 +435,23 @@ namespace psv_func_detail struct psv_func { u32 nid; // Unique function ID (should be generated individually for each elf loaded) + u32 flags; const char* name; // Function name for information psv_func_caller func; // Function caller psv_log_base* module; // Module for information + + psv_func() + { + } + + psv_func(u32 nid, u32 flags, psv_log_base* module, const char* name, psv_func_caller func) + : nid(nid) + , flags(flags) + , name(name) + , func(func) + , module(module) + { + } }; enum psv_special_function_index : u16 @@ -450,23 +464,12 @@ enum psv_special_function_index : u16 // Do not call directly u32 add_psv_func(psv_func data); // Do not call directly -__forceinline static u32 add_psv_func(u32 nid, psv_log_base* module, const char* name, psv_func_caller func) -{ - psv_func f; - f.nid = nid; - f.name = name; - f.func = func; - f.module = module; - - return add_psv_func(f); -} -// Do not call directly template __forceinline void call_psv_func(ARMv7Context& context, RT(*func)(T...)) { psv_func_detail::func_binder::do_call(context, func); } -#define reg_psv_func(nid, module, name, func) add_psv_func(nid, module, name, [](ARMv7Context& context){ call_psv_func(context, func); }) +#define reg_psv_func(nid, module, name, func) add_psv_func(psv_func(nid, 0, module, name, [](ARMv7Context& context){ call_psv_func(context, func); })) // Find registered HLE function by NID psv_func* get_psv_func_by_nid(u32 nid, u32* out_index = nullptr); diff --git a/rpcs3/Emu/SysCalls/ModuleManager.cpp b/rpcs3/Emu/SysCalls/ModuleManager.cpp index 1639eceeed..64ae948afd 100644 --- a/rpcs3/Emu/SysCalls/ModuleManager.cpp +++ b/rpcs3/Emu/SysCalls/ModuleManager.cpp @@ -163,7 +163,6 @@ static const g_module_list[] = { 0xf053, "cellAdecAt3multi", nullptr }, { 0xf054, "cellLibatrac3multi", nullptr }, - { -1, "cellSync", &cellSync }, { -1, "cellSysmodule", &cellSysmodule }, { -1, "libmixer", &libmixer }, { -1, "sysPrxForUser", &sysPrxForUser }, diff --git a/rpcs3/Emu/SysCalls/Modules.cpp b/rpcs3/Emu/SysCalls/Modules.cpp index 5939cf47b4..e5b38d103b 100644 --- a/rpcs3/Emu/SysCalls/Modules.cpp +++ b/rpcs3/Emu/SysCalls/Modules.cpp @@ -17,22 +17,7 @@ u32 add_ppu_func(ModuleFunc func) { for (auto& f : g_ppu_func_list) { - if (f.id == func.id) - { - // partial update - - if (func.func) - { - f.func = func.func; - } - - if (func.lle_func) - { - f.lle_func = func.lle_func; - } - - return (u32)(&f - g_ppu_func_list.data()); - } + assert(f.id != func.id); } g_ppu_func_list.push_back(func); @@ -48,7 +33,7 @@ u32 add_ppu_func_sub(StaticFunc func) u32 add_ppu_func_sub(const char group[8], const u64 ops[], const char* name, Module* module, ppu_func_caller func) { StaticFunc sf; - sf.index = add_ppu_func(ModuleFunc(get_function_id(name), module, func)); + sf.index = add_ppu_func(ModuleFunc(get_function_id(name), MFF_DONT_SAVE_RTOC, module, func)); sf.name = name; sf.group = *(u64*)group; sf.found = 0; @@ -98,14 +83,18 @@ void execute_ppu_func_by_index(PPUThread& CPU, u32 index) { if (auto func = get_ppu_func_by_index(index)) { - // save RTOC - vm::write64(vm::cast(CPU.GPR[1] + 0x28), CPU.GPR[2]); + if ((!func->lle_func || CPU.PC != vm::read32(func->lle_func.addr())) && !(func->flags & MFF_DONT_SAVE_RTOC)) + { + // save RTOC if necessary + vm::write64(vm::cast(CPU.GPR[1] + 0x28), CPU.GPR[2]); + } auto old_last_syscall = CPU.m_last_syscall; CPU.m_last_syscall = func->id; - if (func->lle_func) + if (func->lle_func && !(func->flags & MFF_FORCED_HLE)) { + // call LLE function if possible func->lle_func(CPU); } else if (func->func) diff --git a/rpcs3/Emu/SysCalls/Modules.h b/rpcs3/Emu/SysCalls/Modules.h index 6b724a1619..f0bbca1e8a 100644 --- a/rpcs3/Emu/SysCalls/Modules.h +++ b/rpcs3/Emu/SysCalls/Modules.h @@ -6,15 +6,27 @@ class Module; +enum : u32 +{ + MFF_DONT_SAVE_RTOC = (1 << 0), // don't save RTOC before calling + MFF_FORCED_HLE = (1 << 1), // always call HLE function +}; + struct ModuleFunc { u32 id; + u32 flags; Module* module; ppu_func_caller func; vm::ptr lle_func; - ModuleFunc(u32 id, Module* module, ppu_func_caller func, vm::ptr lle_func = vm::ptr::make(0)) + ModuleFunc() + { + } + + ModuleFunc(u32 id, u32 flags, Module* module, ppu_func_caller func, vm::ptr lle_func = vm::ptr::make(0)) : id(id) + , flags(flags) , module(module) , func(func) , lle_func(lle_func) @@ -121,9 +133,10 @@ u32 add_ppu_func_sub(const char group[8], const u64 ops[], const char* name, Mod void hook_ppu_funcs(u32* base, u32 size); -#define REG_FUNC(module, name) add_ppu_func(ModuleFunc(get_function_id(#name), &module, bind_func(name))) +#define REG_FUNC(module, name) add_ppu_func(ModuleFunc(get_function_id(#name), 0, &module, bind_func(name))) +#define REG_FUNC_FH(module, name) add_ppu_func(ModuleFunc(get_function_id(#name), MFF_FORCED_HLE, &module, bind_func(name))) -#define REG_UNNAMED(module, nid) add_ppu_func(ModuleFunc(0x##nid, &module, bind_func(_nid_##nid))) +#define REG_UNNAMED(module, nid) add_ppu_func(ModuleFunc(0x##nid, 0, &module, bind_func(_nid_##nid))) #define REG_SUB(module, group, name, ...) \ static const u64 name ## _table[] = {__VA_ARGS__ , 0}; \ diff --git a/rpcs3/Emu/SysCalls/Modules/cellSync.cpp b/rpcs3/Emu/SysCalls/Modules/cellSync.cpp index 6e3f4af9dc..6874cd110b 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSync.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellSync.cpp @@ -1081,7 +1081,7 @@ s32 syncLFQueueGetPushPointer(vm::ptr queue, s32& pointer, u32 s32 _cellSyncLFQueueGetPushPointer(vm::ptr queue, vm::ptr pointer, u32 isBlocking, u32 useEventQueue) { - cellSync.Todo("_cellSyncLFQueueGetPushPointer(queue_addr=0x%x, pointer_addr=0x%x, isBlocking=%d, useEventQueue=%d)", + cellSync.Warning("_cellSyncLFQueueGetPushPointer(queue_addr=0x%x, pointer_addr=0x%x, isBlocking=%d, useEventQueue=%d)", queue.addr(), pointer.addr(), isBlocking, useEventQueue); s32 pointer_value; @@ -1243,7 +1243,7 @@ s32 syncLFQueueCompletePushPointer(vm::ptr queue, s32 pointer, s32 _cellSyncLFQueueCompletePushPointer(vm::ptr queue, s32 pointer, vm::ptr fpSendSignal) { - cellSync.Todo("_cellSyncLFQueueCompletePushPointer(queue_addr=0x%x, pointer=%d, fpSendSignal_addr=0x%x)", + cellSync.Warning("_cellSyncLFQueueCompletePushPointer(queue_addr=0x%x, pointer=%d, fpSendSignal_addr=0x%x)", queue.addr(), pointer, fpSendSignal.addr()); return syncLFQueueCompletePushPointer(queue, pointer, fpSendSignal); @@ -1432,7 +1432,7 @@ s32 syncLFQueueGetPopPointer(vm::ptr queue, s32& pointer, u32 i s32 _cellSyncLFQueueGetPopPointer(vm::ptr queue, vm::ptr pointer, u32 isBlocking, u32 arg4, u32 useEventQueue) { - cellSync.Todo("_cellSyncLFQueueGetPopPointer(queue_addr=0x%x, pointer_addr=0x%x, isBlocking=%d, arg4=%d, useEventQueue=%d)", + cellSync.Warning("_cellSyncLFQueueGetPopPointer(queue_addr=0x%x, pointer_addr=0x%x, isBlocking=%d, arg4=%d, useEventQueue=%d)", queue.addr(), pointer.addr(), isBlocking, arg4, useEventQueue); s32 pointer_value; @@ -1594,7 +1594,7 @@ s32 syncLFQueueCompletePopPointer(vm::ptr queue, s32 pointer, c s32 _cellSyncLFQueueCompletePopPointer(vm::ptr queue, s32 pointer, vm::ptr fpSendSignal, u32 noQueueFull) { // arguments copied from _cellSyncLFQueueCompletePushPointer + unknown argument (noQueueFull taken from LFQueue2CompletePopPointer) - cellSync.Todo("_cellSyncLFQueueCompletePopPointer(queue_addr=0x%x, pointer=%d, fpSendSignal_addr=0x%x, noQueueFull=%d)", + cellSync.Warning("_cellSyncLFQueueCompletePopPointer(queue_addr=0x%x, pointer=%d, fpSendSignal_addr=0x%x, noQueueFull=%d)", queue.addr(), pointer, fpSendSignal.addr(), noQueueFull); return syncLFQueueCompletePopPointer(queue, pointer, fpSendSignal, noQueueFull); diff --git a/rpcs3/Emu/SysCalls/Modules/sys_net.cpp b/rpcs3/Emu/SysCalls/Modules/sys_net.cpp index 6dce42e229..86f4b2032c 100644 --- a/rpcs3/Emu/SysCalls/Modules/sys_net.cpp +++ b/rpcs3/Emu/SysCalls/Modules/sys_net.cpp @@ -504,7 +504,7 @@ s32 sys_net_free_thread_context() } // define additional macro for specific namespace -#define REG_FUNC_(name) add_ppu_func(ModuleFunc(get_function_id(#name), &sys_net, bind_func(sys_net_func::name))) +#define REG_FUNC_(name) add_ppu_func(ModuleFunc(get_function_id(#name), 0, &sys_net, bind_func(sys_net_func::name))) Module sys_net("sys_net", []() { diff --git a/rpcs3/Emu/SysCalls/SC_FUNC.h b/rpcs3/Emu/SysCalls/SC_FUNC.h index 84605cab03..562a174017 100644 --- a/rpcs3/Emu/SysCalls/SC_FUNC.h +++ b/rpcs3/Emu/SysCalls/SC_FUNC.h @@ -5,7 +5,7 @@ typedef void(*ppu_func_caller)(PPUThread&); namespace ppu_func_detail { - enum bind_arg_type + enum arg_class : u8 { ARG_GENERAL, ARG_FLOAT, @@ -13,50 +13,50 @@ namespace ppu_func_detail ARG_STACK, }; - template + template struct bind_arg; - template + template struct bind_arg { static_assert(sizeof(T) <= 8, "Invalid function argument type for ARG_GENERAL"); - static __forceinline T func(PPUThread& CPU) + static __forceinline T get_arg(PPUThread& CPU) { return cast_from_ppu_gpr(CPU.GPR[g_count + 2]); } }; - template + template struct bind_arg { static_assert(sizeof(T) <= 8, "Invalid function argument type for ARG_FLOAT"); - static __forceinline T func(PPUThread& CPU) + static __forceinline T get_arg(PPUThread& CPU) { return static_cast(CPU.FPR[f_count]); } }; - template + template struct bind_arg { static_assert(std::is_same::value, "Invalid function argument type for ARG_VECTOR"); - static __forceinline T func(PPUThread& CPU) + static __forceinline T get_arg(PPUThread& CPU) { return CPU.VPR[v_count + 1]; } }; - template + template struct bind_arg { static_assert(f_count <= 13, "TODO: Unsupported stack argument type (float)"); static_assert(v_count <= 12, "TODO: Unsupported stack argument type (vector)"); static_assert(sizeof(T) <= 8, "Invalid function argument type for ARG_STACK"); - static __forceinline T func(PPUThread& CPU) + static __forceinline T get_arg(PPUThread& CPU) { // TODO: check stack argument displacement const u64 res = CPU.GetStackArg(8 + std::max(g_count - 8, 0) + std::max(f_count - 13, 0) + std::max(v_count - 12, 0)); @@ -64,13 +64,13 @@ namespace ppu_func_detail } }; - template + template struct bind_result { static_assert(type == ARG_GENERAL, "Wrong use of bind_result template"); static_assert(sizeof(T) <= 8, "Invalid function result type for ARG_GENERAL"); - static __forceinline void func(PPUThread& CPU, const T& result) + static __forceinline void put_result(PPUThread& CPU, const T& result) { CPU.GPR[3] = cast_to_ppu_gpr(result); } @@ -81,7 +81,7 @@ namespace ppu_func_detail { static_assert(sizeof(T) <= 8, "Invalid function result type for ARG_FLOAT"); - static __forceinline void func(PPUThread& CPU, const T& result) + static __forceinline void put_result(PPUThread& CPU, const T& result) { CPU.FPR[1] = static_cast(result); } @@ -92,12 +92,29 @@ namespace ppu_func_detail { static_assert(std::is_same::value, "Invalid function result type for ARG_VECTOR"); - static __forceinline void func(PPUThread& CPU, const T& result) + static __forceinline void put_result(PPUThread& CPU, const T& result) { CPU.VPR[2] = result; } }; + struct arg_type_pack + { + arg_class type; + u8 g_count; + u8 f_count; + u8 v_count; + }; + + template + struct bind_arg_packed + { + static __forceinline T get_arg(PPUThread& CPU) + { + return bind_arg> 8, type_pack >> 16, type_pack >> 24>::get_arg(CPU); + } + }; + template struct call_impl { @@ -123,14 +140,14 @@ namespace ppu_func_detail return ppu_func_detail::call_impl::value, std::tuple_size::value>::call(f, std::forward(t)); } - template + template __forceinline std::tuple<> iterate(PPUThread& CPU) { // terminator return std::tuple<>(); } - template + template __forceinline std::tuple iterate(PPUThread& CPU) { static_assert(!std::is_pointer::value, "Invalid function argument type (pointer)"); @@ -138,14 +155,14 @@ namespace ppu_func_detail // TODO: check calculations const bool is_float = std::is_floating_point::value; const bool is_vector = std::is_same::value; - const bind_arg_type t = is_float + const arg_class t = is_float ? ((f_count >= 13) ? ARG_STACK : ARG_FLOAT) : (is_vector ? ((v_count >= 12) ? ARG_STACK : ARG_VECTOR) : ((g_count >= 8) ? ARG_STACK : ARG_GENERAL)); - const int g = g_count + (is_float || is_vector ? 0 : 1); - const int f = f_count + (is_float ? 1 : 0); - const int v = v_count + (is_vector ? 1 : 0); + const u32 g = g_count + (is_float || is_vector ? 0 : 1); + const u32 f = f_count + (is_float ? 1 : 0); + const u32 v = v_count + (is_vector ? 1 : 0); - return std::tuple_cat(std::tuple(bind_arg::func(CPU)), iterate(CPU)); + return std::tuple_cat(std::tuple(bind_arg::get_arg(CPU)), iterate(CPU)); } template @@ -155,7 +172,7 @@ namespace ppu_func_detail static_assert(!std::is_reference::value, "Invalid function result type (reference)"); static const bool is_float = std::is_floating_point::value; static const bool is_vector = std::is_same::value; - static const bind_arg_type value = is_float ? ARG_FLOAT : (is_vector ? ARG_VECTOR : ARG_GENERAL); + static const arg_class value = is_float ? ARG_FLOAT : (is_vector ? ARG_VECTOR : ARG_GENERAL); }; template @@ -166,9 +183,9 @@ namespace ppu_func_detail { typedef void(*func_t)(PPUThread&, T...); - static void do_call(PPUThread& CPU, func_t _func) + static void do_call(PPUThread& CPU, func_t func) { - call(_func, std::tuple_cat(std::tuple(CPU), iterate<0, 0, 0, T...>(CPU))); + call(func, std::tuple_cat(std::tuple(CPU), iterate<0, 0, 0, T...>(CPU))); } }; @@ -177,9 +194,9 @@ namespace ppu_func_detail { typedef void(*func_t)(T...); - static void do_call(PPUThread& CPU, func_t _func) + static void do_call(PPUThread& CPU, func_t func) { - call(_func, iterate<0, 0, 0, T...>(CPU)); + call(func, iterate<0, 0, 0, T...>(CPU)); } }; @@ -188,9 +205,9 @@ namespace ppu_func_detail { typedef RT(*func_t)(PPUThread&, T...); - static void do_call(PPUThread& CPU, func_t _func) + static void do_call(PPUThread& CPU, func_t func) { - bind_result::value>::func(CPU, call(_func, std::tuple_cat(std::tuple(CPU), iterate<0, 0, 0, T...>(CPU)))); + bind_result::value>::put_result(CPU, call(func, std::tuple_cat(std::tuple(CPU), iterate<0, 0, 0, T...>(CPU)))); } }; @@ -199,9 +216,9 @@ namespace ppu_func_detail { typedef RT(*func_t)(T...); - static void do_call(PPUThread& CPU, func_t _func) + static void do_call(PPUThread& CPU, func_t func) { - bind_result::value>::func(CPU, call(_func, iterate<0, 0, 0, T...>(CPU))); + bind_result::value>::put_result(CPU, call(func, iterate<0, 0, 0, T...>(CPU))); } }; } diff --git a/rpcs3/Loader/ELF32.cpp b/rpcs3/Loader/ELF32.cpp index 42de280949..9ea6b2b090 100644 --- a/rpcs3/Loader/ELF32.cpp +++ b/rpcs3/Loader/ELF32.cpp @@ -245,13 +245,8 @@ namespace loader { LOG_ERROR(LOADER, "Unknown function 0x%08x (addr=0x%x)", nid, addr); - psv_func unimplemented; - unimplemented.nid = nid; - unimplemented.module = nullptr; - unimplemented.name = "UNKNOWN"; // TODO: set correct name if possible - unimplemented.func = nullptr; - - index = add_psv_func(unimplemented); + // TODO: set correct name if possible + index = add_psv_func(psv_func(nid, 0, nullptr, "UNKNOWN", nullptr)); } vm::psv::write32(addr + 0, 0xe0700090 | (index & 0xfff0) << 4 | (index & 0xf)); // HACK instruction (ARM) diff --git a/rpcs3/Loader/ELF64.cpp b/rpcs3/Loader/ELF64.cpp index d1f646f72e..593590a666 100644 --- a/rpcs3/Loader/ELF64.cpp +++ b/rpcs3/Loader/ELF64.cpp @@ -398,7 +398,36 @@ namespace loader for (auto& f : m.second.exports) { - add_ppu_func(ModuleFunc(f.first, module, nullptr, vm::ptr::make(f.second))); + const u32 nid = f.first; + const u32 addr = f.second; + + u32 index; + + auto func = get_ppu_func_by_nid(nid, &index); + + if (!func) + { + index = add_ppu_func(ModuleFunc(nid, 0, module, nullptr, vm::ptr::make(addr))); + } + else + { + func->lle_func.set(addr); + + if (func->flags & MFF_FORCED_HLE) + { + u32 i_addr = 0; + + if (!vm::check_addr(addr, 8) || !vm::check_addr(i_addr = vm::read32(addr), 8)) + { + LOG_ERROR(LOADER, "Failed to inject code for function '%s' (opd=0x%x, 0x%x)", SysCalls::GetHLEFuncName(nid), addr, i_addr); + } + else + { + vm::write32(i_addr + 0, HACK(index)); + vm::write32(i_addr + 4, BLR()); + } + } + } } for (auto& f : m.second.imports) @@ -414,7 +443,7 @@ namespace loader { LOG_ERROR(LOADER, "Unimplemented function '%s' (0x%x)", SysCalls::GetHLEFuncName(nid), addr); - index = add_ppu_func(ModuleFunc(nid, module, nullptr)); + index = add_ppu_func(ModuleFunc(nid, 0, module, nullptr)); } else { @@ -635,7 +664,7 @@ namespace loader { LOG_ERROR(LOADER, "Unimplemented function '%s' in '%s' module (0x%x)", SysCalls::GetHLEFuncName(nid), module_name, addr); - index = add_ppu_func(ModuleFunc(nid, module, nullptr)); + index = add_ppu_func(ModuleFunc(nid, 0, module, nullptr)); } else { From 1e28611435f78ae7e5a694f2b5da8471a614f58a Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Tue, 24 Feb 2015 14:06:24 +0300 Subject: [PATCH 2/9] Compilation fix --- rpcs3/Emu/SysCalls/SC_FUNC.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rpcs3/Emu/SysCalls/SC_FUNC.h b/rpcs3/Emu/SysCalls/SC_FUNC.h index 562a174017..aa69811266 100644 --- a/rpcs3/Emu/SysCalls/SC_FUNC.h +++ b/rpcs3/Emu/SysCalls/SC_FUNC.h @@ -111,7 +111,7 @@ namespace ppu_func_detail { static __forceinline T get_arg(PPUThread& CPU) { - return bind_arg> 8, type_pack >> 16, type_pack >> 24>::get_arg(CPU); + return bind_arg> 8), (type_pack >> 16), (type_pack >> 24)>::get_arg(CPU); } }; From a8688bff855e2573a19bf9fc1710acd2e4344f33 Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Tue, 24 Feb 2015 17:04:25 +0300 Subject: [PATCH 3/9] RTOC saving fixed --- rpcs3/Emu/SysCalls/Modules.cpp | 18 ++++++++++-------- rpcs3/Emu/SysCalls/Modules.h | 12 ++++++++++-- rpcs3/Loader/ELF64.cpp | 2 +- 3 files changed, 21 insertions(+), 11 deletions(-) diff --git a/rpcs3/Emu/SysCalls/Modules.cpp b/rpcs3/Emu/SysCalls/Modules.cpp index e5b38d103b..fe14360ac4 100644 --- a/rpcs3/Emu/SysCalls/Modules.cpp +++ b/rpcs3/Emu/SysCalls/Modules.cpp @@ -33,7 +33,7 @@ u32 add_ppu_func_sub(StaticFunc func) u32 add_ppu_func_sub(const char group[8], const u64 ops[], const char* name, Module* module, ppu_func_caller func) { StaticFunc sf; - sf.index = add_ppu_func(ModuleFunc(get_function_id(name), MFF_DONT_SAVE_RTOC, module, func)); + sf.index = add_ppu_func(ModuleFunc(get_function_id(name), 0, module, func)); sf.name = name; sf.group = *(u64*)group; sf.found = 0; @@ -71,6 +71,8 @@ ModuleFunc* get_ppu_func_by_nid(u32 nid, u32* out_index) ModuleFunc* get_ppu_func_by_index(u32 index) { + index &= ~EIF_FLAGS; + if (index >= g_ppu_func_list.size()) { return nullptr; @@ -83,18 +85,18 @@ void execute_ppu_func_by_index(PPUThread& CPU, u32 index) { if (auto func = get_ppu_func_by_index(index)) { - if ((!func->lle_func || CPU.PC != vm::read32(func->lle_func.addr())) && !(func->flags & MFF_DONT_SAVE_RTOC)) + auto old_last_syscall = CPU.m_last_syscall; + CPU.m_last_syscall = func->id; + + if (!(index & EIF_DONT_SAVE_RTOC)) { // save RTOC if necessary vm::write64(vm::cast(CPU.GPR[1] + 0x28), CPU.GPR[2]); } - auto old_last_syscall = CPU.m_last_syscall; - CPU.m_last_syscall = func->id; - if (func->lle_func && !(func->flags & MFF_FORCED_HLE)) { - // call LLE function if possible + // call LLE function if available func->lle_func(CPU); } else if (func->func) @@ -103,7 +105,7 @@ void execute_ppu_func_by_index(PPUThread& CPU, u32 index) } else { - LOG_ERROR(HLE, "Unimplemented function %s", SysCalls::GetHLEFuncName(func->id)); + LOG_ERROR(HLE, "Unimplemented function: %s", SysCalls::GetHLEFuncName(func->id)); CPU.GPR[3] = 0; } @@ -217,7 +219,7 @@ void hook_ppu_funcs(u32* base, u32 size) { LOG_NOTICE(LOADER, "Function '%s' hooked (addr=0x%x)", g_ppu_func_subs[j].name, vm::get_addr(base + i * 4)); g_ppu_func_subs[j].found++; - base[i + 0] = re32(0x04000000 | g_ppu_func_subs[j].index); // hack + base[i + 0] = re32(0x04000000 | g_ppu_func_subs[j].index | EIF_DONT_SAVE_RTOC); // hack base[i + 1] = se32(0x4e800020); // blr i += 1; // skip modified code } diff --git a/rpcs3/Emu/SysCalls/Modules.h b/rpcs3/Emu/SysCalls/Modules.h index f0bbca1e8a..3167cfa09f 100644 --- a/rpcs3/Emu/SysCalls/Modules.h +++ b/rpcs3/Emu/SysCalls/Modules.h @@ -6,10 +6,18 @@ class Module; +// flags set in ModuleFunc enum : u32 { - MFF_DONT_SAVE_RTOC = (1 << 0), // don't save RTOC before calling - MFF_FORCED_HLE = (1 << 1), // always call HLE function + MFF_FORCED_HLE = (1 << 0), // always call HLE function +}; + +// flags passed with index +enum : u32 +{ + EIF_DONT_SAVE_RTOC = (1 << 25), // don't save RTOC before calling + + EIF_FLAGS = 0x2000000, // all flags }; struct ModuleFunc diff --git a/rpcs3/Loader/ELF64.cpp b/rpcs3/Loader/ELF64.cpp index 593590a666..7a5fd2ff88 100644 --- a/rpcs3/Loader/ELF64.cpp +++ b/rpcs3/Loader/ELF64.cpp @@ -423,7 +423,7 @@ namespace loader } else { - vm::write32(i_addr + 0, HACK(index)); + vm::write32(i_addr + 0, HACK(index | EIF_DONT_SAVE_RTOC)); vm::write32(i_addr + 4, BLR()); } } From 991fd015dee8b9a07666249e9f688e2e77f597b6 Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Tue, 24 Feb 2015 19:38:10 +0300 Subject: [PATCH 4/9] Size of injected code decreased --- rpcs3/Emu/SysCalls/Modules.cpp | 12 ++++++++---- rpcs3/Emu/SysCalls/Modules.h | 5 +++-- rpcs3/Loader/ELF32.cpp | 2 +- rpcs3/Loader/ELF64.cpp | 15 ++++++--------- 4 files changed, 18 insertions(+), 16 deletions(-) diff --git a/rpcs3/Emu/SysCalls/Modules.cpp b/rpcs3/Emu/SysCalls/Modules.cpp index fe14360ac4..a781784c06 100644 --- a/rpcs3/Emu/SysCalls/Modules.cpp +++ b/rpcs3/Emu/SysCalls/Modules.cpp @@ -88,7 +88,7 @@ void execute_ppu_func_by_index(PPUThread& CPU, u32 index) auto old_last_syscall = CPU.m_last_syscall; CPU.m_last_syscall = func->id; - if (!(index & EIF_DONT_SAVE_RTOC)) + if (index & EIF_SAVE_RTOC) { // save RTOC if necessary vm::write64(vm::cast(CPU.GPR[1] + 0x28), CPU.GPR[2]); @@ -109,6 +109,12 @@ void execute_ppu_func_by_index(PPUThread& CPU, u32 index) CPU.GPR[3] = 0; } + if (index & EIF_PERFORM_BLR) + { + // return if necessary + CPU.SetBranch(vm::cast(CPU.LR & ~3), true); + } + CPU.m_last_syscall = old_last_syscall; } else @@ -219,9 +225,7 @@ void hook_ppu_funcs(u32* base, u32 size) { LOG_NOTICE(LOADER, "Function '%s' hooked (addr=0x%x)", g_ppu_func_subs[j].name, vm::get_addr(base + i * 4)); g_ppu_func_subs[j].found++; - base[i + 0] = re32(0x04000000 | g_ppu_func_subs[j].index | EIF_DONT_SAVE_RTOC); // hack - base[i + 1] = se32(0x4e800020); // blr - i += 1; // skip modified code + base[i] = re32(0x04000000 | g_ppu_func_subs[j].index | EIF_PERFORM_BLR); // hack } } } diff --git a/rpcs3/Emu/SysCalls/Modules.h b/rpcs3/Emu/SysCalls/Modules.h index 3167cfa09f..c013bae9f1 100644 --- a/rpcs3/Emu/SysCalls/Modules.h +++ b/rpcs3/Emu/SysCalls/Modules.h @@ -15,9 +15,10 @@ enum : u32 // flags passed with index enum : u32 { - EIF_DONT_SAVE_RTOC = (1 << 25), // don't save RTOC before calling + EIF_SAVE_RTOC = (1 << 25), // save RTOC in [SP+0x28] before calling HLE/LLE function + EIF_PERFORM_BLR = (1 << 24), // do BLR after calling HLE/LLE function - EIF_FLAGS = 0x2000000, // all flags + EIF_FLAGS = 0x3000000, // all flags }; struct ModuleFunc diff --git a/rpcs3/Loader/ELF32.cpp b/rpcs3/Loader/ELF32.cpp index 9ea6b2b090..a6885f93ce 100644 --- a/rpcs3/Loader/ELF32.cpp +++ b/rpcs3/Loader/ELF32.cpp @@ -249,7 +249,7 @@ namespace loader index = add_psv_func(psv_func(nid, 0, nullptr, "UNKNOWN", nullptr)); } - vm::psv::write32(addr + 0, 0xe0700090 | (index & 0xfff0) << 4 | (index & 0xf)); // HACK instruction (ARM) + vm::psv::write32(addr, 0xe0700090 | (index & 0xfff0) << 4 | (index & 0xf)); // HACK instruction (ARM) code_end = std::min(addr, code_end); } diff --git a/rpcs3/Loader/ELF64.cpp b/rpcs3/Loader/ELF64.cpp index 7a5fd2ff88..3e3942b62b 100644 --- a/rpcs3/Loader/ELF64.cpp +++ b/rpcs3/Loader/ELF64.cpp @@ -417,14 +417,13 @@ namespace loader { u32 i_addr = 0; - if (!vm::check_addr(addr, 8) || !vm::check_addr(i_addr = vm::read32(addr), 8)) + if (!vm::check_addr(addr, 8) || !vm::check_addr(i_addr = vm::read32(addr), 4)) { - LOG_ERROR(LOADER, "Failed to inject code for function '%s' (opd=0x%x, 0x%x)", SysCalls::GetHLEFuncName(nid), addr, i_addr); + LOG_ERROR(LOADER, "Failed to inject code for exported function '%s' (opd=0x%x, 0x%x)", SysCalls::GetHLEFuncName(nid), addr, i_addr); } else { - vm::write32(i_addr + 0, HACK(index | EIF_DONT_SAVE_RTOC)); - vm::write32(i_addr + 4, BLR()); + vm::write32(i_addr, HACK(index | EIF_PERFORM_BLR)); } } } @@ -450,14 +449,13 @@ namespace loader LOG_NOTICE(LOADER, "Imported function '%s' (0x%x)", SysCalls::GetHLEFuncName(nid), addr); } - if (!vm::check_addr(addr, 8)) + if (!vm::check_addr(addr, 4)) { LOG_ERROR(LOADER, "Failed to inject code for function '%s' (0x%x)", SysCalls::GetHLEFuncName(nid), addr); } else { - vm::write32(addr + 0, HACK(index)); - vm::write32(addr + 4, BLR()); + vm::write32(addr, HACK(index | EIF_SAVE_RTOC | EIF_PERFORM_BLR)); } } } @@ -671,8 +669,7 @@ namespace loader LOG_NOTICE(LOADER, "Imported %sfunction '%s' in '%s' module (0x%x)", func->lle_func ? "LLE " : "", SysCalls::GetHLEFuncName(nid), module_name, addr); } - vm::write32(addr + 0, HACK(index)); - vm::write32(addr + 4, BLR()); + vm::write32(addr, HACK(index | EIF_SAVE_RTOC | EIF_PERFORM_BLR)); //if (!func || !func->lle_func) //{ From 0e33636aaf9c5e3a09c617ec9088d734e0c88108 Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Wed, 25 Feb 2015 13:28:43 +0300 Subject: [PATCH 5/9] Import fix --- rpcs3/Loader/ELF64.cpp | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/rpcs3/Loader/ELF64.cpp b/rpcs3/Loader/ELF64.cpp index 3e3942b62b..9f9ddcd263 100644 --- a/rpcs3/Loader/ELF64.cpp +++ b/rpcs3/Loader/ELF64.cpp @@ -274,8 +274,26 @@ namespace loader } } + assert(e.second != stub); e.second = stub; } + + for (auto &i : m.second.imports) + { + u32 stub = i.second; + + for (auto &s : info.segments) + { + if (stub >= s.initial_addr.addr() && stub < s.initial_addr.addr() + s.size_file) + { + stub += s.begin.addr() - s.initial_addr.addr(); + break; + } + } + + assert(i.second != stub); + i.second = stub; + } } return ok; @@ -432,7 +450,7 @@ namespace loader for (auto& f : m.second.imports) { const u32 nid = f.first; - const u32 addr = f.second + info.segments[0].begin.addr(); + const u32 addr = f.second; u32 index; From 432f0c36307f06e2f6a8527d5bb5ebbb3fdc62eb Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Wed, 25 Feb 2015 14:24:30 +0300 Subject: [PATCH 6/9] LLE logging --- rpcs3/Emu/SysCalls/Modules.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/rpcs3/Emu/SysCalls/Modules.cpp b/rpcs3/Emu/SysCalls/Modules.cpp index a781784c06..91e543ac84 100644 --- a/rpcs3/Emu/SysCalls/Modules.cpp +++ b/rpcs3/Emu/SysCalls/Modules.cpp @@ -97,6 +97,11 @@ void execute_ppu_func_by_index(PPUThread& CPU, u32 index) if (func->lle_func && !(func->flags & MFF_FORCED_HLE)) { // call LLE function if available + if (Ini.HLELogging.GetValue()) + { + LOG_NOTICE(HLE, "LLE function called: %s", SysCalls::GetHLEFuncName(func->id)); + } + func->lle_func(CPU); } else if (func->func) From 0b21474b79b45614956861cec25c7de6aa3a26fb Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Wed, 25 Feb 2015 14:48:12 +0300 Subject: [PATCH 7/9] Logging fixed --- rpcs3/Emu/Cell/PPUInterpreter.h | 28 +--------------------------- rpcs3/Emu/Cell/SPUInterpreter.h | 6 +----- rpcs3/Emu/SysCalls/Modules.cpp | 7 ++++++- rpcs3/Emu/SysCalls/SysCalls.cpp | 21 +++++++++++++++------ rpcs3/Emu/SysCalls/SysCalls.h | 2 +- 5 files changed, 24 insertions(+), 40 deletions(-) diff --git a/rpcs3/Emu/Cell/PPUInterpreter.h b/rpcs3/Emu/Cell/PPUInterpreter.h index a21a524fc6..9a96beeb30 100644 --- a/rpcs3/Emu/Cell/PPUInterpreter.h +++ b/rpcs3/Emu/Cell/PPUInterpreter.h @@ -18,10 +18,6 @@ #include -#if 0//def _DEBUG -#define HLE_CALL_DEBUG -#endif - extern u64 rotate_mask[64][64]; // defined in PPUThread.cpp, static didn't work correctly in GCC 4.9 for some reason inline void InitRotateMask() { @@ -107,28 +103,6 @@ private: if (fetestexcept(FE_OVERFLOW)) CPU.SetFPSCRException(FPSCR_OX); } - void Exit() {} - - void SysCall() - { - const u64 sc = CPU.GPR[11]; - const u64 old_sc = CPU.m_last_syscall; - - CPU.m_last_syscall = sc; - SysCalls::DoSyscall(CPU, (u32)sc); - - if(Ini.HLELogging.GetValue()) - { - LOG_WARNING(PPU, "SysCall[0x%llx ('%s')] done with code [0x%llx]! #pc: 0x%x", - sc, SysCalls::GetHLEFuncName((u32)sc).c_str(), CPU.GPR[3], CPU.PC); - } -#ifdef HLE_CALL_DEBUG - LOG_NOTICE(PPU, "SysCall[%lld] done with code [0x%llx]! #pc: 0x%x", sc, CPU.GPR[3], CPU.PC); -#endif - - CPU.m_last_syscall = old_sc; - } - void NULL_OP() { throw "Null operation"; @@ -2260,7 +2234,7 @@ private: { switch (lev) { - case 0x0: SysCall(); break; + case 0x0: SysCalls::DoSyscall(CPU, CPU.GPR[11]); break; case 0x1: throw "SC(): HyperCall LV1"; case 0x3: CPU.FastStop(); break; default: throw fmt::Format("SC(): unknown level (0x%x)", lev); diff --git a/rpcs3/Emu/Cell/SPUInterpreter.h b/rpcs3/Emu/Cell/SPUInterpreter.h index 7c56b4c9ac..774478c1d2 100644 --- a/rpcs3/Emu/Cell/SPUInterpreter.h +++ b/rpcs3/Emu/Cell/SPUInterpreter.h @@ -91,10 +91,6 @@ public: } private: - void SysCall() - { - } - //0 - 10 void STOP(u32 code) { @@ -1096,7 +1092,7 @@ private: } else if (result == 0.0f) { - if (a != 0.0f & b != 0.0f) + if (a != 0.0f && b != 0.0f) CPU.FPSCR.setSinglePrecisionExceptionFlags(w, FPSCR_SUNF | FPSCR_SDIFF); result = +0.0f; } diff --git a/rpcs3/Emu/SysCalls/Modules.cpp b/rpcs3/Emu/SysCalls/Modules.cpp index 91e543ac84..2797429603 100644 --- a/rpcs3/Emu/SysCalls/Modules.cpp +++ b/rpcs3/Emu/SysCalls/Modules.cpp @@ -106,11 +106,16 @@ void execute_ppu_func_by_index(PPUThread& CPU, u32 index) } else if (func->func) { + if (Ini.HLELogging.GetValue()) + { + LOG_NOTICE(HLE, "HLE function called: %s", SysCalls::GetHLEFuncName(func->id)); + } + func->func(CPU); } else { - LOG_ERROR(HLE, "Unimplemented function: %s", SysCalls::GetHLEFuncName(func->id)); + LOG_ERROR(HLE, "Unimplemented function: %s -> CELL_OK", SysCalls::GetHLEFuncName(func->id)); CPU.GPR[3] = 0; } diff --git a/rpcs3/Emu/SysCalls/SysCalls.cpp b/rpcs3/Emu/SysCalls/SysCalls.cpp index 6a6ed229d9..a5500723a6 100644 --- a/rpcs3/Emu/SysCalls/SysCalls.cpp +++ b/rpcs3/Emu/SysCalls/SysCalls.cpp @@ -921,23 +921,32 @@ void null_func(PPUThread& CPU) return; } - LOG_ERROR(HLE, "Unknown syscall: %d - %08x", code, code); + LOG_ERROR(HLE, "Unknown syscall: %d - %08x -> CELL_OK", code, code); CPU.GPR[3] = 0; return; } -void SysCalls::DoSyscall(PPUThread& CPU, u32 code) +void SysCalls::DoSyscall(PPUThread& CPU, u64 code) { + auto old_last_syscall = CPU.m_last_syscall; + CPU.m_last_syscall = code; + + if (code >= 1024) + { + throw "Invalid syscall number"; + } + //Auto Pause using simple singleton. Debug::AutoPause::getInstance().TryPause(code); - if(code < 1024) + if (Ini.HLELogging.GetValue()) { - sc_table[code](CPU); - return; + LOG_NOTICE(PPU, "SysCall called: %s [0x%llx]", "unknown", code); } - throw "Invalid syscall number"; + sc_table[code](CPU); + + CPU.m_last_syscall = old_last_syscall; } IdManager& SysCallBase::GetIdManager() const diff --git a/rpcs3/Emu/SysCalls/SysCalls.h b/rpcs3/Emu/SysCalls/SysCalls.h index 5cf99e50cd..5d27667da0 100644 --- a/rpcs3/Emu/SysCalls/SysCalls.h +++ b/rpcs3/Emu/SysCalls/SysCalls.h @@ -66,6 +66,6 @@ class PPUThread; class SysCalls { public: - static void DoSyscall(PPUThread& CPU, u32 code); + static void DoSyscall(PPUThread& CPU, u64 code); static std::string GetHLEFuncName(const u32 fid); }; From 9afdb429fa79483ad5a9960f5a646f4f876d93be Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Wed, 25 Feb 2015 15:08:22 +0300 Subject: [PATCH 8/9] Result logging restored --- rpcs3/Emu/SysCalls/Modules.cpp | 11 +++++++++++ rpcs3/Emu/SysCalls/SysCalls.cpp | 5 +++++ 2 files changed, 16 insertions(+) diff --git a/rpcs3/Emu/SysCalls/Modules.cpp b/rpcs3/Emu/SysCalls/Modules.cpp index 2797429603..e6d8327f39 100644 --- a/rpcs3/Emu/SysCalls/Modules.cpp +++ b/rpcs3/Emu/SysCalls/Modules.cpp @@ -97,12 +97,18 @@ void execute_ppu_func_by_index(PPUThread& CPU, u32 index) if (func->lle_func && !(func->flags & MFF_FORCED_HLE)) { // call LLE function if available + if (Ini.HLELogging.GetValue()) { LOG_NOTICE(HLE, "LLE function called: %s", SysCalls::GetHLEFuncName(func->id)); } func->lle_func(CPU); + + if (Ini.HLELogging.GetValue()) + { + LOG_NOTICE(HLE, "LLE function finished: %s -> 0x%llx", SysCalls::GetHLEFuncName(func->id), CPU.GPR[3]); + } } else if (func->func) { @@ -112,6 +118,11 @@ void execute_ppu_func_by_index(PPUThread& CPU, u32 index) } func->func(CPU); + + if (Ini.HLELogging.GetValue()) + { + LOG_NOTICE(HLE, "HLE function finished: %s -> 0x%llx", SysCalls::GetHLEFuncName(func->id), CPU.GPR[3]); + } } else { diff --git a/rpcs3/Emu/SysCalls/SysCalls.cpp b/rpcs3/Emu/SysCalls/SysCalls.cpp index a5500723a6..2adbd38fd2 100644 --- a/rpcs3/Emu/SysCalls/SysCalls.cpp +++ b/rpcs3/Emu/SysCalls/SysCalls.cpp @@ -946,6 +946,11 @@ void SysCalls::DoSyscall(PPUThread& CPU, u64 code) sc_table[code](CPU); + if (Ini.HLELogging.GetValue()) + { + LOG_NOTICE(PPU, "SysCall finished: %s [0x%llx] -> 0x%llx", "unknown", code, CPU.GPR[3]); + } + CPU.m_last_syscall = old_last_syscall; } From 99c5366f50571156cafef0e5989e871b399e8e71 Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Wed, 25 Feb 2015 15:26:22 +0300 Subject: [PATCH 9/9] Small fix --- rpcs3/Loader/ELF64.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/rpcs3/Loader/ELF64.cpp b/rpcs3/Loader/ELF64.cpp index 9f9ddcd263..77cd91dbed 100644 --- a/rpcs3/Loader/ELF64.cpp +++ b/rpcs3/Loader/ELF64.cpp @@ -684,7 +684,9 @@ namespace loader } else { - LOG_NOTICE(LOADER, "Imported %sfunction '%s' in '%s' module (0x%x)", func->lle_func ? "LLE " : "", SysCalls::GetHLEFuncName(nid), module_name, addr); + const bool is_lle = func->lle_func && !(func->flags & MFF_FORCED_HLE); + + LOG_NOTICE(LOADER, "Imported %sfunction '%s' in '%s' module (0x%x)", is_lle ? "LLE " : "", SysCalls::GetHLEFuncName(nid), module_name, addr); } vm::write32(addr, HACK(index | EIF_SAVE_RTOC | EIF_PERFORM_BLR));