在Linux内核中,arch_spin_lock()的实现如下:
static inline void arch_spin_lock(arch_spinlock_t *lock)
{
unsigned int tmp;
arch_spinlock_t lockval, newval;
asm volatile(
/* Atomically increment the next ticket. */
" prfm pstl1strm, %3\n"
"1: ldaxr %w0, %3\n"
" add %w1, %w0, %w5\n"
" stxr %w2, %w1, %3\n"
" cbnz %w2, 1b\n"
/* Did we get the lock? */
" eor %w1, %w0, %w0, ror #16\n"
" cbz %w1, 3f\n"
/*
* No: spin on the owner. Send a local event to avoid missing an
* unlock before the exclusive load.
*/
" sevl\n"
"2: wfe\n"
" ldaxrh %w2, %4\n"
" eor %w1, %w2, %w0, lsr #16\n"
" cbnz %w1, 2b\n"
/* We got the lock. Critical section starts here. */
"3:"
: "=&r" (lockval), "=&r" (newval), "=&r" (tmp), "+Q" (*lock)
: "Q" (lock->owner), "I" (1 << TICKET_SHIFT)
: "memory");
}
请注意,“wfe”指令将处理器置于低功耗模式,并等待事件寄存器被设置。 ARMv8手册指定如果清除了PE的全局监视器(D1.17.1节),则将生成一个事件。这应该由解锁部分完成。但是,让我们看一下arch_spin_unlock()部分:
static inline void arch_spin_unlock(arch_spinlock_t *lock)
{
asm volatile(
" stlrh %w1, %0\n"
: "=Q" (lock->owner)
: "r" (lock->owner + 1)
: "memory");
}
没有SEV !!那么,什么在唤醒WFE锁呢?
PS:我一直在寻找任何ARM64汇编教程,但是没有发现任何问题。如果有人有任何建议,那将很棒。谢谢!
最佳答案
锁定时,线" ldaxrh %w2, %4\n"
在wfe
执行锁的排他加载获取之后。如前一条评论所述,这将用全局监视器标记锁的地址。
解锁代码在相同的地址上执行存储释放" stlrh %w1, %0\n"
这将生成事件。这就是为什么他们在锁定功能中使用负载获取而不是常规负载的原因,并且为什么在解锁时不需要SEV。
关于assembly - 在Linux/ARM64中如何唤醒自旋锁?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/32276313/