diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | src/core/hle/service/jit/jit.cpp | 59 | ||||
| -rw-r--r-- | src/core/hle/service/jit/jit_code_memory.cpp | 54 | ||||
| -rw-r--r-- | src/core/hle/service/jit/jit_code_memory.h | 49 |
4 files changed, 146 insertions, 18 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 96ab39cb8..a8b3d480c 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt | |||
| @@ -987,6 +987,8 @@ if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64) | |||
| 987 | arm/dynarmic/dynarmic_cp15.h | 987 | arm/dynarmic/dynarmic_cp15.h |
| 988 | arm/dynarmic/dynarmic_exclusive_monitor.cpp | 988 | arm/dynarmic/dynarmic_exclusive_monitor.cpp |
| 989 | arm/dynarmic/dynarmic_exclusive_monitor.h | 989 | arm/dynarmic/dynarmic_exclusive_monitor.h |
| 990 | hle/service/jit/jit_code_memory.cpp | ||
| 991 | hle/service/jit/jit_code_memory.h | ||
| 990 | hle/service/jit/jit_context.cpp | 992 | hle/service/jit/jit_context.cpp |
| 991 | hle/service/jit/jit_context.h | 993 | hle/service/jit/jit_context.h |
| 992 | hle/service/jit/jit.cpp | 994 | hle/service/jit/jit.cpp |
diff --git a/src/core/hle/service/jit/jit.cpp b/src/core/hle/service/jit/jit.cpp index a94d05e19..77aa6d7d1 100644 --- a/src/core/hle/service/jit/jit.cpp +++ b/src/core/hle/service/jit/jit.cpp | |||
| @@ -4,11 +4,11 @@ | |||
| 4 | #include "core/arm/debug.h" | 4 | #include "core/arm/debug.h" |
| 5 | #include "core/arm/symbols.h" | 5 | #include "core/arm/symbols.h" |
| 6 | #include "core/core.h" | 6 | #include "core/core.h" |
| 7 | #include "core/hle/kernel/k_code_memory.h" | ||
| 8 | #include "core/hle/kernel/k_transfer_memory.h" | 7 | #include "core/hle/kernel/k_transfer_memory.h" |
| 9 | #include "core/hle/result.h" | 8 | #include "core/hle/result.h" |
| 10 | #include "core/hle/service/ipc_helpers.h" | 9 | #include "core/hle/service/ipc_helpers.h" |
| 11 | #include "core/hle/service/jit/jit.h" | 10 | #include "core/hle/service/jit/jit.h" |
| 11 | #include "core/hle/service/jit/jit_code_memory.h" | ||
| 12 | #include "core/hle/service/jit/jit_context.h" | 12 | #include "core/hle/service/jit/jit_context.h" |
| 13 | #include "core/hle/service/server_manager.h" | 13 | #include "core/hle/service/server_manager.h" |
| 14 | #include "core/hle/service/service.h" | 14 | #include "core/hle/service/service.h" |
| @@ -23,10 +23,12 @@ struct CodeRange { | |||
| 23 | 23 | ||
| 24 | class IJitEnvironment final : public ServiceFramework<IJitEnvironment> { | 24 | class IJitEnvironment final : public ServiceFramework<IJitEnvironment> { |
| 25 | public: | 25 | public: |
| 26 | explicit IJitEnvironment(Core::System& system_, Kernel::KProcess& process_, CodeRange user_rx, | 26 | explicit IJitEnvironment(Core::System& system_, |
| 27 | CodeRange user_ro) | 27 | Kernel::KScopedAutoObject<Kernel::KProcess>&& process_, |
| 28 | : ServiceFramework{system_, "IJitEnvironment"}, process{&process_}, | 28 | CodeMemory&& user_rx_, CodeMemory&& user_ro_) |
| 29 | context{process->GetMemory()} { | 29 | : ServiceFramework{system_, "IJitEnvironment"}, process{std::move(process_)}, |
| 30 | user_rx{std::move(user_rx_)}, user_ro{std::move(user_ro_)}, | ||
| 31 | context{system_.ApplicationMemory()} { | ||
| 30 | // clang-format off | 32 | // clang-format off |
| 31 | static const FunctionInfo functions[] = { | 33 | static const FunctionInfo functions[] = { |
| 32 | {0, &IJitEnvironment::GenerateCode, "GenerateCode"}, | 34 | {0, &IJitEnvironment::GenerateCode, "GenerateCode"}, |
| @@ -39,10 +41,13 @@ public: | |||
| 39 | RegisterHandlers(functions); | 41 | RegisterHandlers(functions); |
| 40 | 42 | ||
| 41 | // Identity map user code range into sysmodule context | 43 | // Identity map user code range into sysmodule context |
| 42 | configuration.user_ro_memory = user_ro; | 44 | configuration.user_rx_memory.size = user_rx.GetSize(); |
| 43 | configuration.user_rx_memory = user_rx; | 45 | configuration.user_rx_memory.offset = user_rx.GetAddress(); |
| 44 | configuration.sys_ro_memory = user_ro; | 46 | configuration.user_ro_memory.size = user_ro.GetSize(); |
| 45 | configuration.sys_rx_memory = user_rx; | 47 | configuration.user_ro_memory.offset = user_ro.GetAddress(); |
| 48 | |||
| 49 | configuration.sys_rx_memory = configuration.user_rx_memory; | ||
| 50 | configuration.sys_ro_memory = configuration.user_ro_memory; | ||
| 46 | } | 51 | } |
| 47 | 52 | ||
| 48 | void GenerateCode(HLERequestContext& ctx) { | 53 | void GenerateCode(HLERequestContext& ctx) { |
| @@ -318,6 +323,8 @@ private: | |||
| 318 | } | 323 | } |
| 319 | 324 | ||
| 320 | Kernel::KScopedAutoObject<Kernel::KProcess> process; | 325 | Kernel::KScopedAutoObject<Kernel::KProcess> process; |
| 326 | CodeMemory user_rx; | ||
| 327 | CodeMemory user_ro; | ||
| 321 | GuestCallbacks callbacks; | 328 | GuestCallbacks callbacks; |
| 322 | JITConfiguration configuration; | 329 | JITConfiguration configuration; |
| 323 | JITContext context; | 330 | JITContext context; |
| @@ -335,6 +342,7 @@ public: | |||
| 335 | RegisterHandlers(functions); | 342 | RegisterHandlers(functions); |
| 336 | } | 343 | } |
| 337 | 344 | ||
| 345 | private: | ||
| 338 | void CreateJitEnvironment(HLERequestContext& ctx) { | 346 | void CreateJitEnvironment(HLERequestContext& ctx) { |
| 339 | LOG_DEBUG(Service_JIT, "called"); | 347 | LOG_DEBUG(Service_JIT, "called"); |
| 340 | 348 | ||
| @@ -380,20 +388,35 @@ public: | |||
| 380 | return; | 388 | return; |
| 381 | } | 389 | } |
| 382 | 390 | ||
| 383 | const CodeRange user_rx{ | 391 | CodeMemory rx, ro; |
| 384 | .offset = GetInteger(rx_mem->GetSourceAddress()), | 392 | Result res; |
| 385 | .size = parameters.rx_size, | ||
| 386 | }; | ||
| 387 | 393 | ||
| 388 | const CodeRange user_ro{ | 394 | res = rx.Initialize(*process, *rx_mem, parameters.rx_size, |
| 389 | .offset = GetInteger(ro_mem->GetSourceAddress()), | 395 | Kernel::Svc::MemoryPermission::ReadExecute, generate_random); |
| 390 | .size = parameters.ro_size, | 396 | if (R_FAILED(res)) { |
| 391 | }; | 397 | LOG_ERROR(Service_JIT, "rx_mem could not be mapped for handle=0x{:08X}", rx_mem_handle); |
| 398 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 399 | rb.Push(res); | ||
| 400 | return; | ||
| 401 | } | ||
| 402 | |||
| 403 | res = ro.Initialize(*process, *ro_mem, parameters.ro_size, | ||
| 404 | Kernel::Svc::MemoryPermission::Read, generate_random); | ||
| 405 | if (R_FAILED(res)) { | ||
| 406 | LOG_ERROR(Service_JIT, "ro_mem could not be mapped for handle=0x{:08X}", ro_mem_handle); | ||
| 407 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 408 | rb.Push(res); | ||
| 409 | return; | ||
| 410 | } | ||
| 392 | 411 | ||
| 393 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 412 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 394 | rb.Push(ResultSuccess); | 413 | rb.Push(ResultSuccess); |
| 395 | rb.PushIpcInterface<IJitEnvironment>(system, *process, user_rx, user_ro); | 414 | rb.PushIpcInterface<IJitEnvironment>(system, std::move(process), std::move(rx), |
| 415 | std::move(ro)); | ||
| 396 | } | 416 | } |
| 417 | |||
| 418 | private: | ||
| 419 | std::mt19937_64 generate_random{}; | ||
| 397 | }; | 420 | }; |
| 398 | 421 | ||
| 399 | void LoopProcess(Core::System& system) { | 422 | void LoopProcess(Core::System& system) { |
diff --git a/src/core/hle/service/jit/jit_code_memory.cpp b/src/core/hle/service/jit/jit_code_memory.cpp new file mode 100644 index 000000000..2b480488a --- /dev/null +++ b/src/core/hle/service/jit/jit_code_memory.cpp | |||
| @@ -0,0 +1,54 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "core/hle/service/jit/jit_code_memory.h" | ||
| 5 | |||
| 6 | namespace Service::JIT { | ||
| 7 | |||
| 8 | Result CodeMemory::Initialize(Kernel::KProcess& process, Kernel::KCodeMemory& code_memory, | ||
| 9 | size_t size, Kernel::Svc::MemoryPermission perm, | ||
| 10 | std::mt19937_64& generate_random) { | ||
| 11 | auto& page_table = process.GetPageTable(); | ||
| 12 | const u64 alias_code_start = | ||
| 13 | GetInteger(page_table.GetAliasCodeRegionStart()) / Kernel::PageSize; | ||
| 14 | const u64 alias_code_size = page_table.GetAliasCodeRegionSize() / Kernel::PageSize; | ||
| 15 | |||
| 16 | // NOTE: This will retry indefinitely until mapping the code memory succeeds. | ||
| 17 | while (true) { | ||
| 18 | // Generate a new trial address. | ||
| 19 | const u64 mapped_address = | ||
| 20 | (alias_code_start + (generate_random() % alias_code_size)) * Kernel::PageSize; | ||
| 21 | |||
| 22 | // Try to map the address | ||
| 23 | R_TRY_CATCH(code_memory.MapToOwner(mapped_address, size, perm)) { | ||
| 24 | R_CATCH(Kernel::ResultInvalidMemoryRegion) { | ||
| 25 | // If we could not map here, retry. | ||
| 26 | continue; | ||
| 27 | } | ||
| 28 | } | ||
| 29 | R_END_TRY_CATCH; | ||
| 30 | |||
| 31 | // Set members. | ||
| 32 | m_code_memory = std::addressof(code_memory); | ||
| 33 | m_size = size; | ||
| 34 | m_address = mapped_address; | ||
| 35 | m_perm = perm; | ||
| 36 | |||
| 37 | // Open a new reference to the code memory. | ||
| 38 | m_code_memory->Open(); | ||
| 39 | |||
| 40 | // We succeeded. | ||
| 41 | R_SUCCEED(); | ||
| 42 | } | ||
| 43 | } | ||
| 44 | |||
| 45 | void CodeMemory::Finalize() { | ||
| 46 | if (m_code_memory) { | ||
| 47 | R_ASSERT(m_code_memory->UnmapFromOwner(m_address, m_size)); | ||
| 48 | m_code_memory->Close(); | ||
| 49 | } | ||
| 50 | |||
| 51 | m_code_memory = nullptr; | ||
| 52 | } | ||
| 53 | |||
| 54 | } // namespace Service::JIT | ||
diff --git a/src/core/hle/service/jit/jit_code_memory.h b/src/core/hle/service/jit/jit_code_memory.h new file mode 100644 index 000000000..6376d4c4e --- /dev/null +++ b/src/core/hle/service/jit/jit_code_memory.h | |||
| @@ -0,0 +1,49 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <random> | ||
| 7 | |||
| 8 | #include "core/hle/kernel/k_code_memory.h" | ||
| 9 | |||
| 10 | namespace Service::JIT { | ||
| 11 | |||
| 12 | class CodeMemory { | ||
| 13 | public: | ||
| 14 | YUZU_NON_COPYABLE(CodeMemory); | ||
| 15 | |||
| 16 | explicit CodeMemory() = default; | ||
| 17 | |||
| 18 | CodeMemory(CodeMemory&& rhs) { | ||
| 19 | std::swap(m_code_memory, rhs.m_code_memory); | ||
| 20 | std::swap(m_size, rhs.m_size); | ||
| 21 | std::swap(m_address, rhs.m_address); | ||
| 22 | std::swap(m_perm, rhs.m_perm); | ||
| 23 | } | ||
| 24 | |||
| 25 | ~CodeMemory() { | ||
| 26 | this->Finalize(); | ||
| 27 | } | ||
| 28 | |||
| 29 | public: | ||
| 30 | Result Initialize(Kernel::KProcess& process, Kernel::KCodeMemory& code_memory, size_t size, | ||
| 31 | Kernel::Svc::MemoryPermission perm, std::mt19937_64& generate_random); | ||
| 32 | void Finalize(); | ||
| 33 | |||
| 34 | size_t GetSize() const { | ||
| 35 | return m_size; | ||
| 36 | } | ||
| 37 | |||
| 38 | u64 GetAddress() const { | ||
| 39 | return m_address; | ||
| 40 | } | ||
| 41 | |||
| 42 | private: | ||
| 43 | Kernel::KCodeMemory* m_code_memory{}; | ||
| 44 | size_t m_size{}; | ||
| 45 | u64 m_address{}; | ||
| 46 | Kernel::Svc::MemoryPermission m_perm{}; | ||
| 47 | }; | ||
| 48 | |||
| 49 | } // namespace Service::JIT | ||