@ -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 ) ;
code . pause ( ) ;
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 . 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 * ) > ( ) ;