From 9f91ba1f7357c61dd2c7c3b437ea203d467fd400 Mon Sep 17 00:00:00 2001 From: Liam Date: Fri, 17 Nov 2023 23:44:53 +0200 Subject: arm: Implement native code execution backend --- src/core/hle/kernel/code_set.h | 9 +++++++++ src/core/hle/kernel/k_address_space_info.cpp | 4 ++-- src/core/hle/kernel/k_process.cpp | 11 +++++++++++ src/core/hle/kernel/k_process.h | 9 +++++++++ src/core/hle/kernel/k_thread.h | 16 ++++++++++++++++ src/core/hle/kernel/physical_core.cpp | 14 +++++++++++++- 6 files changed, 60 insertions(+), 3 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/kernel/code_set.h b/src/core/hle/kernel/code_set.h index af1af2b78..d53da82f4 100644 --- a/src/core/hle/kernel/code_set.h +++ b/src/core/hle/kernel/code_set.h @@ -75,11 +75,20 @@ struct CodeSet final { return segments[2]; } + Segment& PatchSegment() { + return patch_segment; + } + + const Segment& PatchSegment() const { + return patch_segment; + } + /// The overall data that backs this code set. Kernel::PhysicalMemory memory; /// The segments that comprise this code set. std::array segments; + Segment patch_segment; /// The entry point address for this code set. KProcessAddress entrypoint = 0; diff --git a/src/core/hle/kernel/k_address_space_info.cpp b/src/core/hle/kernel/k_address_space_info.cpp index 32173e52b..3235a7a37 100644 --- a/src/core/hle/kernel/k_address_space_info.cpp +++ b/src/core/hle/kernel/k_address_space_info.cpp @@ -25,8 +25,8 @@ constexpr std::array AddressSpaceInfos{{ { .bit_width = 36, .address = 2_GiB , .size = 64_GiB - 2_GiB , .type = KAddressSpaceInfo::Type::MapLarge, }, { .bit_width = 36, .address = Size_Invalid, .size = 8_GiB , .type = KAddressSpaceInfo::Type::Heap, }, { .bit_width = 36, .address = Size_Invalid, .size = 6_GiB , .type = KAddressSpaceInfo::Type::Alias, }, -#ifdef ANDROID - // With Android, we use a 38-bit address space due to memory limitations. This should (safely) truncate ASLR region. +#ifdef ARCHITECTURE_arm64 + // With NCE, we use a 38-bit address space due to memory limitations. This should (safely) truncate ASLR region. { .bit_width = 39, .address = 128_MiB , .size = 256_GiB - 128_MiB, .type = KAddressSpaceInfo::Type::Map39Bit, }, #else { .bit_width = 39, .address = 128_MiB , .size = 512_GiB - 128_MiB, .type = KAddressSpaceInfo::Type::Map39Bit, }, diff --git a/src/core/hle/kernel/k_process.cpp b/src/core/hle/kernel/k_process.cpp index c6a200320..d2e9f2a2e 100644 --- a/src/core/hle/kernel/k_process.cpp +++ b/src/core/hle/kernel/k_process.cpp @@ -1214,6 +1214,17 @@ void KProcess::LoadModule(CodeSet code_set, KProcessAddress base_addr) { ReprotectSegment(code_set.CodeSegment(), Svc::MemoryPermission::ReadExecute); ReprotectSegment(code_set.RODataSegment(), Svc::MemoryPermission::Read); ReprotectSegment(code_set.DataSegment(), Svc::MemoryPermission::ReadWrite); + +#ifdef ARCHITECTURE_arm64 + if (Settings::IsNceEnabled()) { + auto& buffer = m_kernel.System().DeviceMemory().buffer; + const auto& code = code_set.CodeSegment(); + const auto& patch = code_set.PatchSegment(); + buffer.Protect(GetInteger(base_addr + code.addr), code.size, true, true, true); + buffer.Protect(GetInteger(base_addr + patch.addr), patch.size, true, true, true); + ReprotectSegment(code_set.PatchSegment(), Svc::MemoryPermission::None); + } +#endif } bool KProcess::InsertWatchpoint(KProcessAddress addr, u64 size, DebugWatchpointType type) { diff --git a/src/core/hle/kernel/k_process.h b/src/core/hle/kernel/k_process.h index 54b8e0a59..7b97d452b 100644 --- a/src/core/hle/kernel/k_process.h +++ b/src/core/hle/kernel/k_process.h @@ -112,6 +112,7 @@ private: std::array m_pinned_threads{}; std::array m_watchpoints{}; std::map m_debug_page_refcounts{}; + std::unordered_map m_post_handlers{}; std::atomic m_cpu_time{}; std::atomic m_num_process_switches{}; std::atomic m_num_thread_switches{}; @@ -467,6 +468,14 @@ public: static void Switch(KProcess* cur_process, KProcess* next_process); + std::unordered_map& GetPostHandlers() noexcept { + return m_post_handlers; + } + + KernelCore& GetKernel() noexcept { + return m_kernel; + } + public: // Attempts to insert a watchpoint into a free slot. Returns false if none are available. bool InsertWatchpoint(KProcessAddress addr, u64 size, DebugWatchpointType type); diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h index e1f80b04f..e9ca5dfca 100644 --- a/src/core/hle/kernel/k_thread.h +++ b/src/core/hle/kernel/k_thread.h @@ -655,6 +655,21 @@ public: return m_stack_top; } +public: + // TODO: This shouldn't be defined in kernel namespace + struct NativeExecutionParameters { + u64 tpidr_el0{}; + u64 tpidrro_el0{}; + void* native_context{}; + std::atomic lock{1}; + bool is_running{}; + u32 magic{Common::MakeMagic('Y', 'U', 'Z', 'U')}; + }; + + NativeExecutionParameters& GetNativeExecutionParameters() { + return m_native_execution_parameters; + } + private: KThread* RemoveWaiterByKey(bool* out_has_waiters, KProcessAddress key, bool is_kernel_address_key); @@ -914,6 +929,7 @@ private: ThreadWaitReasonForDebugging m_wait_reason_for_debugging{}; uintptr_t m_argument{}; KProcessAddress m_stack_top{}; + NativeExecutionParameters m_native_execution_parameters{}; public: using ConditionVariableThreadTreeType = ConditionVariableThreadTree; diff --git a/src/core/hle/kernel/physical_core.cpp b/src/core/hle/kernel/physical_core.cpp index 5ee869fa2..15434212e 100644 --- a/src/core/hle/kernel/physical_core.cpp +++ b/src/core/hle/kernel/physical_core.cpp @@ -1,8 +1,12 @@ // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include "common/settings.h" #include "core/arm/dynarmic/arm_dynarmic_32.h" #include "core/arm/dynarmic/arm_dynarmic_64.h" +#ifdef ARCHITECTURE_arm64 +#include "core/arm/nce/arm_nce.h" +#endif #include "core/core.h" #include "core/hle/kernel/k_scheduler.h" #include "core/hle/kernel/kernel.h" @@ -14,7 +18,8 @@ PhysicalCore::PhysicalCore(std::size_t core_index, Core::System& system, KSchedu : m_core_index{core_index}, m_system{system}, m_scheduler{scheduler} { #if defined(ARCHITECTURE_x86_64) || defined(ARCHITECTURE_arm64) // TODO(bunnei): Initialization relies on a core being available. We may later replace this with - // a 32-bit instance of Dynarmic. This should be abstracted out to a CPU manager. + // an NCE interface or a 32-bit instance of Dynarmic. This should be abstracted out to a CPU + // manager. auto& kernel = system.Kernel(); m_arm_interface = std::make_unique( system, kernel.IsMulticore(), @@ -28,6 +33,13 @@ PhysicalCore::PhysicalCore(std::size_t core_index, Core::System& system, KSchedu PhysicalCore::~PhysicalCore() = default; void PhysicalCore::Initialize(bool is_64_bit) { +#if defined(ARCHITECTURE_arm64) + if (Settings::IsNceEnabled()) { + m_arm_interface = std::make_unique(m_system, m_system.Kernel().IsMulticore(), + m_core_index); + return; + } +#endif #if defined(ARCHITECTURE_x86_64) || defined(ARCHITECTURE_arm64) auto& kernel = m_system.Kernel(); if (!is_64_bit) { -- cgit v1.2.3