diff options
| author | xbzk <xbzk@eden-emu.dev> | 2026-09-30 00:58:29 +0200 |
|---|---|---|
| committer | crueter <crueter@eden-emu.dev> | 2026-09-30 00:58:29 +0200 |
| commit | 3f78512c83fca84a36bb450a10043b368830f8b0 (patch) | |
| tree | 892899ab08939bab924ef9f0e080275f73e19b01 /src | |
| parent | a82f31a310c5dc7cae50c47b3306510a24cc36a6 (diff) | |
[ro] add TLS patching for runtime NROs (#4492)
- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md)
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.
-------------------
Aimed to fix Biomutant which stucks in a bootloop due to guest being unable to reach correct thread local storage (TLS)
This fixes runtime NRO loading by properly patching the guest TLS (TPIDR_EL0) path. Steps:
-Read the loaded NRO image into a temporary buffer.
-Run the NCE patcher on it.
-Produce a patch section / relocated code.
-Map that patch section as executable memory in the target process.
Game still has intermittent visual issues which can be solved with GPU level accurate, but that causes a huge performance drop in exchange. Someone else will resume this one.
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4492
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Reviewed-by: lizzie <lizzie@eden-emu.dev>
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/hle/service/ro/ro.cpp | 34 |
1 files changed, 31 insertions, 3 deletions
diff --git a/src/core/hle/service/ro/ro.cpp b/src/core/hle/service/ro/ro.cpp index 13de9f96c8..b847811fe5 100644 --- a/src/core/hle/service/ro/ro.cpp +++ b/src/core/hle/service/ro/ro.cpp @@ -16,6 +16,10 @@ #include "core/hle/service/ro/ro_types.h" #include "core/hle/service/server_manager.h" #include "core/hle/service/service.h" +#ifdef HAS_NCE +#include "core/arm/nce/patcher.h" +#include "core/hle/kernel/k_shared_memory.h" +#endif namespace Service::RO { @@ -386,7 +390,7 @@ public: R_SUCCEED(); } - Result MapManualLoadModuleMemory(u64* out_address, size_t context_id, u64 nro_address, + Result MapManualLoadModuleMemory(Kernel::KernelCore& kernel, u64* out_address, size_t context_id, u64 nro_address, u64 nro_size, u64 bss_address, u64 bss_size) { // Get context. ProcessContext* context = this->GetContextById(context_id); @@ -421,7 +425,31 @@ public: R_TRY(context->ValidateNro(std::addressof(nro_info->module_id), std::addressof(rx_size), std::addressof(ro_size), std::addressof(rw_size), nro_info->base_address, nro_size, bss_size)); - +#ifdef HAS_NCE + if (Settings::IsNceEnabled()) { + auto* process = context->GetProcess(); + auto& memory = process->GetMemory(); + + std::vector<u8> image(total_size); + memory.ReadBlock(nro_info->base_address, image.data(), rx_size); + + Kernel::CodeSet::Segment code{.size = static_cast<u32>(rx_size)}; + Core::NCE::Patcher patch; + patch.PatchText(image, code); + patch.RelocateAndCopy(nro_info->base_address, code, image, nullptr); + + const u64 patch_address = nro_info->base_address + total_size; + const size_t patch_size = patch.GetSectionSize(); + constexpr auto permission = Kernel::Svc::MemoryPermission::ReadExecute; + + auto* patch_memory = Kernel::KSharedMemory::Create(kernel); + R_TRY(patch_memory->Initialize(kernel, kernel.System().DeviceMemory(), process, permission, permission, patch_size)); + std::memcpy(patch_memory->GetPointer(), image.data() + total_size, patch_size); + R_TRY(process->AddSharedMemory(kernel, patch_memory, patch_address, patch_size)); + R_TRY(patch_memory->Map(*process, patch_address, patch_size, permission)); + memory.WriteBlock(nro_info->base_address, image.data(), rx_size); + } +#endif // Set NRO perms. R_TRY(SetNroPerms(context->GetProcess(), nro_info->base_address, rx_size, ro_size, rw_size + bss_size)); @@ -531,7 +559,7 @@ public: Result MapManualLoadModuleMemory(Out<u64> out_load_address, ClientProcessId client_pid, u64 nro_address, u64 nro_size, u64 bss_address, u64 bss_size) { R_TRY(m_ro->ValidateProcess(m_context_id, *client_pid)); - R_RETURN(m_ro->MapManualLoadModuleMemory(out_load_address.Get(), m_context_id, nro_address, + R_RETURN(m_ro->MapManualLoadModuleMemory(system.Kernel(), out_load_address.Get(), m_context_id, nro_address, nro_size, bss_address, bss_size)); } |
