mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-10-06 14:09:58 +00:00
experiment to address some TPIDR_EL0 stalls
This commit is contained in:
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user