diff --git a/src/core/arm/nce/patcher.cpp b/src/core/arm/nce/patcher.cpp index 7d2041d4d2..b1569ceee6 100644 --- a/src/core/arm/nce/patcher.cpp +++ b/src/core/arm/nce/patcher.cpp @@ -371,14 +371,9 @@ size_t Patcher::GetPreSectionSize() const noexcept { } void Patcher::WriteLoadContext(oaknut::VectorCodeGenerator& cg) { - // This function was called, which modifies X30, so use that as a scratch register. - // SP contains the guest X30, so save our return X30 to SP + 8, since we have allocated 16 bytes - // of stack. cg.STR(X30, SP, 8); - cg.MRS(X30, oaknut::SystemReg::TPIDR_EL0); - cg.LDR(X30, X30, offsetof(NativeExecutionParameters, native_context)); + cg.LDR(X30, SP, 0); - // Load system registers. cg.LDR(W0, X30, offsetof(GuestContext, fpsr)); cg.MSR(oaknut::SystemReg::FPSR, X0); cg.LDR(W0, X30, offsetof(GuestContext, fpcr)); @@ -386,7 +381,9 @@ void Patcher::WriteLoadContext(oaknut::VectorCodeGenerator& cg) { cg.LDR(W0, X30, offsetof(GuestContext, nzcv)); cg.MSR(oaknut::SystemReg::NZCV, X0); - // Load all vector registers. + cg.LDR(X0, X30, 8 * 30); + cg.STR(X0, SP, 0); + static constexpr size_t VEC_OFF = offsetof(GuestContext, vector_registers); for (int i = 0; i <= 30; i += 2) { cg.LDP(oaknut::QReg{i}, oaknut::QReg{i + 1}, X30, VEC_OFF + 16 * i); @@ -436,7 +433,7 @@ void Patcher::WriteSaveContext(oaknut::VectorCodeGenerator& cg) { cg.STR(W0, X30, offsetof(GuestContext, nzcv)); cg.LDR(X0, SP, POST_INDEXED, 16); - // Reload our return X30 from the stack, and return. + cg.MOV(X1, X30); cg.LDR(X30, SP, 8); cg.RET(); } @@ -457,8 +454,6 @@ void Patcher::WriteSvcTrampoline(ModuleDestLabel module_dest, u32 svc_id, oaknut // Now that we've saved all registers, we can use any registers as scratch. // Store PC + 4 to arm interface, since we know the instruction offset from the entry point. oaknut::Label pc_after_svc; - cg.MRS(X1, oaknut::SystemReg::TPIDR_EL0); - cg.LDR(X1, X1, offsetof(NativeExecutionParameters, native_context)); cg.LDR(X2, pc_after_svc); cg.STR(X2, X1, offsetof(GuestContext, pc)); @@ -514,24 +509,13 @@ void Patcher::WriteSvcTrampoline(ModuleDestLabel module_dest, u32 svc_id, oaknut // Host called this location. Save the return address so we can // unwind the stack properly when jumping back. - cg.MRS(X2, oaknut::SystemReg::TPIDR_EL0); - cg.LDR(X2, X2, offsetof(NativeExecutionParameters, native_context)); - cg.ADD(X0, X2, offsetof(GuestContext, host_ctx)); + cg.ADD(X0, X1, offsetof(GuestContext, host_ctx)); cg.STR(X30, X0, offsetof(HostContext, host_saved_regs) + 11 * sizeof(u64)); - // Reload all guest registers except X30 and PC. - // The function also expects 16 bytes of stack already allocated. - cg.STR(X30, SP, PRE_INDEXED, -16); + cg.STR(X1, SP, PRE_INDEXED, -16); cg.BL(load_ctx); cg.LDR(X30, SP, POST_INDEXED, 16); - // Use X1 as a scratch register to restore X30. - cg.STR(X1, SP, PRE_INDEXED, -16); - cg.MRS(X1, oaknut::SystemReg::TPIDR_EL0); - cg.LDR(X1, X1, offsetof(NativeExecutionParameters, native_context)); - cg.LDR(X30, X1, offsetof(GuestContext, cpu_registers) + sizeof(u64) * 30); - cg.LDR(X1, SP, POST_INDEXED, 16); - // Unlock the context. this->UnlockContext(cg);