|
|
@ -22,17 +22,46 @@ static const auto default_cg_mode = nullptr; //Allow RWE |
|
|
|
|
|
|
|
|
namespace Dynarmic { |
|
|
namespace Dynarmic { |
|
|
|
|
|
|
|
|
void EmitSpinLockLock(Xbyak::CodeGenerator& code, Xbyak::Reg64 ptr, Xbyak::Reg32 tmp) { |
|
|
|
|
|
|
|
|
void EmitSpinLockLock(Xbyak::CodeGenerator& code, Xbyak::Reg64 ptr, Xbyak::Reg32 tmp, bool waitpkg) { |
|
|
|
|
|
// TODO: this is because we lack regalloc - so better to be safe :(
|
|
|
|
|
|
if (waitpkg) { |
|
|
|
|
|
code.push(Xbyak::util::eax); |
|
|
|
|
|
code.push(Xbyak::util::ebx); |
|
|
|
|
|
code.push(Xbyak::util::edx); |
|
|
|
|
|
} |
|
|
Xbyak::Label start, loop; |
|
|
Xbyak::Label start, loop; |
|
|
|
|
|
|
|
|
code.jmp(start, code.T_NEAR); |
|
|
code.jmp(start, code.T_NEAR); |
|
|
code.L(loop); |
|
|
code.L(loop); |
|
|
|
|
|
if (waitpkg) { |
|
|
|
|
|
// TODO: This clobbers EAX and EDX did we tell the regalloc?
|
|
|
|
|
|
// ARM ptr for address-monitoring
|
|
|
|
|
|
code.umonitor(ptr); |
|
|
|
|
|
// tmp.bit[0] = 0: C0.1 | Slow Wakup | Better Savings
|
|
|
|
|
|
// tmp.bit[0] = 1: C0.2 | Fast Wakup | Lesser Savings
|
|
|
|
|
|
// edx:eax is implicitly used as a 64-bit deadline timestamp
|
|
|
|
|
|
// Use the maximum so that we use the operating system's maximum
|
|
|
|
|
|
// allowed wait time within the IA32_UMWAIT_CONTROL register
|
|
|
|
|
|
// Enter power state designated by tmp and wait for a write to lock_ptr
|
|
|
|
|
|
code.mov(Xbyak::util::eax, 0xFFFFFFFF); |
|
|
|
|
|
code.mov(Xbyak::util::edx, Xbyak::util::eax); |
|
|
|
|
|
// TODO: We can only be here because tmp is 1 already - however we repeatedly overwrite it...
|
|
|
|
|
|
code.mov(Xbyak::util::ebx, 1); |
|
|
|
|
|
code.umwait(Xbyak::util::ebx); |
|
|
|
|
|
// CF == 1 if we hit the OS-timeout in IA32_UMWAIT_CONTROL without a write
|
|
|
|
|
|
// CF == 0 if we exited the wait for any other reason
|
|
|
|
|
|
} else { |
|
|
code.pause(); |
|
|
code.pause(); |
|
|
|
|
|
} |
|
|
code.L(start); |
|
|
code.L(start); |
|
|
code.mov(tmp, 1); |
|
|
code.mov(tmp, 1); |
|
|
/*code.lock();*/ code.xchg(code.dword[ptr], tmp); |
|
|
/*code.lock();*/ code.xchg(code.dword[ptr], tmp); |
|
|
code.test(tmp, tmp); |
|
|
code.test(tmp, tmp); |
|
|
code.jnz(loop, code.T_NEAR); |
|
|
code.jnz(loop, code.T_NEAR); |
|
|
|
|
|
if (waitpkg) { |
|
|
|
|
|
code.pop(Xbyak::util::edx); |
|
|
|
|
|
code.pop(Xbyak::util::ebx); |
|
|
|
|
|
code.pop(Xbyak::util::eax); |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void EmitSpinLockUnlock(Xbyak::CodeGenerator& code, Xbyak::Reg64 ptr, Xbyak::Reg32 tmp) { |
|
|
void EmitSpinLockUnlock(Xbyak::CodeGenerator& code, Xbyak::Reg64 ptr, Xbyak::Reg32 tmp) { |
|
|
@ -60,7 +89,7 @@ void SpinLockImpl::Initialize() noexcept { |
|
|
Xbyak::Reg64 const ABI_PARAM1 = Backend::X64::HostLocToReg64(Backend::X64::ABI_PARAM1); |
|
|
Xbyak::Reg64 const ABI_PARAM1 = Backend::X64::HostLocToReg64(Backend::X64::ABI_PARAM1); |
|
|
code.align(); |
|
|
code.align(); |
|
|
lock = code.getCurr<void (*)(volatile int*)>(); |
|
|
lock = code.getCurr<void (*)(volatile int*)>(); |
|
|
EmitSpinLockLock(code, ABI_PARAM1, code.eax); |
|
|
|
|
|
|
|
|
EmitSpinLockLock(code, ABI_PARAM1, code.eax, false); |
|
|
code.ret(); |
|
|
code.ret(); |
|
|
code.align(); |
|
|
code.align(); |
|
|
unlock = code.getCurr<void (*)(volatile int*)>(); |
|
|
unlock = code.getCurr<void (*)(volatile int*)>(); |
|
|
|