arm_nce.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394
  1. // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include <cinttypes>
  4. #include <memory>
  5. #include "common/signal_chain.h"
  6. #include "core/arm/nce/arm_nce.h"
  7. #include "core/arm/nce/patch.h"
  8. #include "core/core.h"
  9. #include "core/memory.h"
  10. #include "core/hle/kernel/k_process.h"
  11. #include <signal.h>
  12. #include <sys/syscall.h>
  13. #include <unistd.h>
  14. namespace Core {
  15. namespace {
  16. struct sigaction g_orig_action;
  17. // Verify assembly offsets.
  18. using NativeExecutionParameters = Kernel::KThread::NativeExecutionParameters;
  19. static_assert(offsetof(NativeExecutionParameters, native_context) == TpidrEl0NativeContext);
  20. static_assert(offsetof(NativeExecutionParameters, lock) == TpidrEl0Lock);
  21. static_assert(offsetof(NativeExecutionParameters, magic) == TpidrEl0TlsMagic);
  22. fpsimd_context* GetFloatingPointState(mcontext_t& host_ctx) {
  23. _aarch64_ctx* header = reinterpret_cast<_aarch64_ctx*>(&host_ctx.__reserved);
  24. while (header->magic != FPSIMD_MAGIC) {
  25. header = reinterpret_cast<_aarch64_ctx*>(reinterpret_cast<char*>(header) + header->size);
  26. }
  27. return reinterpret_cast<fpsimd_context*>(header);
  28. }
  29. } // namespace
  30. void* ARM_NCE::RestoreGuestContext(void* raw_context) {
  31. // Retrieve the host context.
  32. auto& host_ctx = static_cast<ucontext_t*>(raw_context)->uc_mcontext;
  33. // Thread-local parameters will be located in x9.
  34. auto* tpidr = reinterpret_cast<NativeExecutionParameters*>(host_ctx.regs[9]);
  35. auto* guest_ctx = static_cast<GuestContext*>(tpidr->native_context);
  36. // Retrieve the host floating point state.
  37. auto* fpctx = GetFloatingPointState(host_ctx);
  38. // Save host callee-saved registers.
  39. std::memcpy(guest_ctx->host_ctx.host_saved_vregs.data(), &fpctx->vregs[8],
  40. sizeof(guest_ctx->host_ctx.host_saved_vregs));
  41. std::memcpy(guest_ctx->host_ctx.host_saved_regs.data(), &host_ctx.regs[19],
  42. sizeof(guest_ctx->host_ctx.host_saved_regs));
  43. // Save stack pointer.
  44. guest_ctx->host_ctx.host_sp = host_ctx.sp;
  45. // Restore all guest state except tpidr_el0.
  46. host_ctx.sp = guest_ctx->sp;
  47. host_ctx.pc = guest_ctx->pc;
  48. host_ctx.pstate = guest_ctx->pstate;
  49. fpctx->fpcr = guest_ctx->fpcr;
  50. fpctx->fpsr = guest_ctx->fpsr;
  51. std::memcpy(host_ctx.regs, guest_ctx->cpu_registers.data(), sizeof(host_ctx.regs));
  52. std::memcpy(fpctx->vregs, guest_ctx->vector_registers.data(), sizeof(fpctx->vregs));
  53. // Return the new thread-local storage pointer.
  54. return tpidr;
  55. }
  56. void ARM_NCE::SaveGuestContext(GuestContext* guest_ctx, void* raw_context) {
  57. // Retrieve the host context.
  58. auto& host_ctx = static_cast<ucontext_t*>(raw_context)->uc_mcontext;
  59. // Retrieve the host floating point state.
  60. auto* fpctx = GetFloatingPointState(host_ctx);
  61. // Save all guest registers except tpidr_el0.
  62. std::memcpy(guest_ctx->cpu_registers.data(), host_ctx.regs, sizeof(host_ctx.regs));
  63. std::memcpy(guest_ctx->vector_registers.data(), fpctx->vregs, sizeof(fpctx->vregs));
  64. guest_ctx->fpsr = fpctx->fpsr;
  65. guest_ctx->fpcr = fpctx->fpcr;
  66. guest_ctx->pstate = static_cast<u32>(host_ctx.pstate);
  67. guest_ctx->pc = host_ctx.pc;
  68. guest_ctx->sp = host_ctx.sp;
  69. // Restore stack pointer.
  70. host_ctx.sp = guest_ctx->host_ctx.host_sp;
  71. // Restore host callee-saved registers.
  72. std::memcpy(&host_ctx.regs[19], guest_ctx->host_ctx.host_saved_regs.data(),
  73. sizeof(guest_ctx->host_ctx.host_saved_regs));
  74. std::memcpy(&fpctx->vregs[8], guest_ctx->host_ctx.host_saved_vregs.data(),
  75. sizeof(guest_ctx->host_ctx.host_saved_vregs));
  76. // Return from the call on exit by setting pc to x30.
  77. host_ctx.pc = guest_ctx->host_ctx.host_saved_regs[11];
  78. // Clear esr_el1 and return it.
  79. host_ctx.regs[0] = guest_ctx->esr_el1.exchange(0);
  80. }
  81. bool ARM_NCE::HandleGuestFault(GuestContext* guest_ctx, void* raw_info, void* raw_context) {
  82. auto& host_ctx = static_cast<ucontext_t*>(raw_context)->uc_mcontext;
  83. auto* info = static_cast<siginfo_t*>(raw_info);
  84. // Try to handle an invalid access.
  85. // TODO: handle accesses which split a page?
  86. const Common::ProcessAddress addr =
  87. (reinterpret_cast<u64>(info->si_addr) & ~Memory::YUZU_PAGEMASK);
  88. if (guest_ctx->system->ApplicationMemory().InvalidateNCE(addr, Memory::YUZU_PAGESIZE)) {
  89. // We handled the access successfully and are returning to guest code.
  90. return true;
  91. }
  92. // We can't handle the access, so trigger an exception.
  93. const bool is_prefetch_abort = host_ctx.pc == reinterpret_cast<u64>(info->si_addr);
  94. guest_ctx->esr_el1.fetch_or(
  95. static_cast<u64>(is_prefetch_abort ? HaltReason::PrefetchAbort : HaltReason::DataAbort));
  96. // Forcibly mark the context as locked. We are still running.
  97. // We may race with SignalInterrupt here:
  98. // - If we lose the race, then SignalInterrupt will send us a signal we are masking,
  99. // and it will do nothing when it is unmasked, as we have already left guest code.
  100. // - If we win the race, then SignalInterrupt will wait for us to unlock first.
  101. auto& thread_params = guest_ctx->parent->running_thread->GetNativeExecutionParameters();
  102. thread_params.lock.store(SpinLockLocked);
  103. // Return to host.
  104. SaveGuestContext(guest_ctx, raw_context);
  105. return false;
  106. }
  107. void ARM_NCE::HandleHostFault(int sig, void* raw_info, void* raw_context) {
  108. return g_orig_action.sa_sigaction(sig, static_cast<siginfo_t*>(raw_info), raw_context);
  109. }
  110. HaltReason ARM_NCE::RunJit() {
  111. // Get the thread parameters.
  112. // TODO: pass the current thread down from ::Run
  113. auto* thread = Kernel::GetCurrentThreadPointer(system.Kernel());
  114. auto* thread_params = &thread->GetNativeExecutionParameters();
  115. {
  116. // Lock our core context.
  117. std::scoped_lock lk{lock};
  118. // We should not be running.
  119. ASSERT(running_thread == nullptr);
  120. // Check if we need to run. If we have already been halted, we are done.
  121. u64 halt = guest_ctx.esr_el1.exchange(0);
  122. if (halt != 0) {
  123. return static_cast<HaltReason>(halt);
  124. }
  125. // Mark that we are running.
  126. running_thread = thread;
  127. // Acquire the lock on the thread parameters.
  128. // This allows us to force synchronization with SignalInterrupt.
  129. LockThreadParameters(thread_params);
  130. }
  131. // Assign current members.
  132. guest_ctx.parent = this;
  133. thread_params->native_context = &guest_ctx;
  134. thread_params->tpidr_el0 = guest_ctx.tpidr_el0;
  135. thread_params->tpidrro_el0 = guest_ctx.tpidrro_el0;
  136. thread_params->is_running = true;
  137. HaltReason halt{};
  138. // TODO: finding and creating the post handler needs to be locked
  139. // to deal with dynamic loading of NROs.
  140. const auto& post_handlers = system.ApplicationProcess()->GetPostHandlers();
  141. if (auto it = post_handlers.find(guest_ctx.pc); it != post_handlers.end()) {
  142. halt = ReturnToRunCodeByTrampoline(thread_params, &guest_ctx, it->second);
  143. } else {
  144. halt = ReturnToRunCodeByExceptionLevelChange(thread_id, thread_params);
  145. }
  146. // Unload members.
  147. // The thread does not change, so we can persist the old reference.
  148. guest_ctx.tpidr_el0 = thread_params->tpidr_el0;
  149. thread_params->native_context = nullptr;
  150. thread_params->is_running = false;
  151. // Unlock the thread parameters.
  152. UnlockThreadParameters(thread_params);
  153. {
  154. // Lock the core context.
  155. std::scoped_lock lk{lock};
  156. // On exit, we no longer have an active thread.
  157. running_thread = nullptr;
  158. }
  159. // Return the halt reason.
  160. return halt;
  161. }
  162. HaltReason ARM_NCE::StepJit() {
  163. return HaltReason::StepThread;
  164. }
  165. u32 ARM_NCE::GetSvcNumber() const {
  166. return guest_ctx.svc_swi;
  167. }
  168. ARM_NCE::ARM_NCE(System& system_, bool uses_wall_clock_, std::size_t core_index_)
  169. : ARM_Interface{system_, uses_wall_clock_}, core_index{core_index_} {
  170. guest_ctx.system = &system_;
  171. }
  172. ARM_NCE::~ARM_NCE() = default;
  173. void ARM_NCE::Initialize() {
  174. thread_id = gettid();
  175. // Setup our signals
  176. static std::once_flag flag;
  177. std::call_once(flag, [] {
  178. using HandlerType = decltype(sigaction::sa_sigaction);
  179. sigset_t signal_mask;
  180. sigemptyset(&signal_mask);
  181. sigaddset(&signal_mask, ReturnToRunCodeByExceptionLevelChangeSignal);
  182. sigaddset(&signal_mask, BreakFromRunCodeSignal);
  183. sigaddset(&signal_mask, GuestFaultSignal);
  184. struct sigaction return_to_run_code_action {};
  185. return_to_run_code_action.sa_flags = SA_SIGINFO | SA_ONSTACK;
  186. return_to_run_code_action.sa_sigaction = reinterpret_cast<HandlerType>(
  187. &ARM_NCE::ReturnToRunCodeByExceptionLevelChangeSignalHandler);
  188. return_to_run_code_action.sa_mask = signal_mask;
  189. Common::SigAction(ReturnToRunCodeByExceptionLevelChangeSignal, &return_to_run_code_action,
  190. nullptr);
  191. struct sigaction break_from_run_code_action {};
  192. break_from_run_code_action.sa_flags = SA_SIGINFO | SA_ONSTACK;
  193. break_from_run_code_action.sa_sigaction =
  194. reinterpret_cast<HandlerType>(&ARM_NCE::BreakFromRunCodeSignalHandler);
  195. break_from_run_code_action.sa_mask = signal_mask;
  196. Common::SigAction(BreakFromRunCodeSignal, &break_from_run_code_action, nullptr);
  197. struct sigaction fault_action {};
  198. fault_action.sa_flags = SA_SIGINFO | SA_ONSTACK | SA_RESTART;
  199. fault_action.sa_sigaction =
  200. reinterpret_cast<HandlerType>(&ARM_NCE::GuestFaultSignalHandler);
  201. fault_action.sa_mask = signal_mask;
  202. Common::SigAction(GuestFaultSignal, &fault_action, &g_orig_action);
  203. // Simplify call for g_orig_action.
  204. // These fields occupy the same space in memory, so this should be a no-op in practice.
  205. if (!(g_orig_action.sa_flags & SA_SIGINFO)) {
  206. g_orig_action.sa_sigaction =
  207. reinterpret_cast<decltype(g_orig_action.sa_sigaction)>(g_orig_action.sa_handler);
  208. }
  209. });
  210. }
  211. void ARM_NCE::SetPC(u64 pc) {
  212. guest_ctx.pc = pc;
  213. }
  214. u64 ARM_NCE::GetPC() const {
  215. return guest_ctx.pc;
  216. }
  217. u64 ARM_NCE::GetSP() const {
  218. return guest_ctx.sp;
  219. }
  220. u64 ARM_NCE::GetReg(int index) const {
  221. return guest_ctx.cpu_registers[index];
  222. }
  223. void ARM_NCE::SetReg(int index, u64 value) {
  224. guest_ctx.cpu_registers[index] = value;
  225. }
  226. u128 ARM_NCE::GetVectorReg(int index) const {
  227. return guest_ctx.vector_registers[index];
  228. }
  229. void ARM_NCE::SetVectorReg(int index, u128 value) {
  230. guest_ctx.vector_registers[index] = value;
  231. }
  232. u32 ARM_NCE::GetPSTATE() const {
  233. return guest_ctx.pstate;
  234. }
  235. void ARM_NCE::SetPSTATE(u32 pstate) {
  236. guest_ctx.pstate = pstate;
  237. }
  238. u64 ARM_NCE::GetTlsAddress() const {
  239. return guest_ctx.tpidrro_el0;
  240. }
  241. void ARM_NCE::SetTlsAddress(u64 address) {
  242. guest_ctx.tpidrro_el0 = address;
  243. }
  244. u64 ARM_NCE::GetTPIDR_EL0() const {
  245. return guest_ctx.tpidr_el0;
  246. }
  247. void ARM_NCE::SetTPIDR_EL0(u64 value) {
  248. guest_ctx.tpidr_el0 = value;
  249. }
  250. void ARM_NCE::SaveContext(ThreadContext64& ctx) const {
  251. ctx.cpu_registers = guest_ctx.cpu_registers;
  252. ctx.sp = guest_ctx.sp;
  253. ctx.pc = guest_ctx.pc;
  254. ctx.pstate = guest_ctx.pstate;
  255. ctx.vector_registers = guest_ctx.vector_registers;
  256. ctx.fpcr = guest_ctx.fpcr;
  257. ctx.fpsr = guest_ctx.fpsr;
  258. ctx.tpidr = guest_ctx.tpidr_el0;
  259. }
  260. void ARM_NCE::LoadContext(const ThreadContext64& ctx) {
  261. guest_ctx.cpu_registers = ctx.cpu_registers;
  262. guest_ctx.sp = ctx.sp;
  263. guest_ctx.pc = ctx.pc;
  264. guest_ctx.pstate = ctx.pstate;
  265. guest_ctx.vector_registers = ctx.vector_registers;
  266. guest_ctx.fpcr = ctx.fpcr;
  267. guest_ctx.fpsr = ctx.fpsr;
  268. guest_ctx.tpidr_el0 = ctx.tpidr;
  269. }
  270. void ARM_NCE::SignalInterrupt() {
  271. // Lock core context.
  272. std::scoped_lock lk{lock};
  273. // Add break loop condition.
  274. guest_ctx.esr_el1.fetch_or(static_cast<u64>(HaltReason::BreakLoop));
  275. // If there is no thread running, we are done.
  276. if (running_thread == nullptr) {
  277. return;
  278. }
  279. // Lock the thread context.
  280. auto* params = &running_thread->GetNativeExecutionParameters();
  281. LockThreadParameters(params);
  282. if (params->is_running) {
  283. // We should signal to the running thread.
  284. // The running thread will unlock the thread context.
  285. syscall(SYS_tkill, thread_id, BreakFromRunCodeSignal);
  286. } else {
  287. // If the thread is no longer running, we have nothing to do.
  288. UnlockThreadParameters(params);
  289. }
  290. }
  291. void ARM_NCE::ClearInterrupt() {
  292. guest_ctx.esr_el1 = {};
  293. }
  294. void ARM_NCE::ClearInstructionCache() {
  295. // TODO: This is not possible to implement correctly on Linux because
  296. // we do not have any access to ic iallu.
  297. // Require accesses to complete.
  298. std::atomic_thread_fence(std::memory_order_seq_cst);
  299. }
  300. void ARM_NCE::InvalidateCacheRange(u64 addr, std::size_t size) {
  301. // Clean cache.
  302. auto* ptr = reinterpret_cast<char*>(addr);
  303. __builtin___clear_cache(ptr, ptr + size);
  304. }
  305. void ARM_NCE::ClearExclusiveState() {
  306. // No-op.
  307. }
  308. void ARM_NCE::PageTableChanged(Common::PageTable& page_table,
  309. std::size_t new_address_space_size_in_bits) {
  310. // No-op. Page table is never used.
  311. }
  312. } // namespace Core