arm上ldrex和strexeq指令用来尝试获取独占内存权限和设置在独占权限时回写
来源:互联网 发布:算法导论 第四版 编辑:程序博客网 时间:2024/05/01 22:14
【duan注】关于LDREX 和 STREX这两对指令的具体使用方法,及其作用(独占访问存储器),请查看 DUI0204IC_rvct_assembler_guide.pdf 手册的148页。 __raw_spin_lock在ARM处理器上的实现/******include/asm-arm/spinlock_types.h***/ typedef struct { volatile unsigned int lock; } raw_spinlock_t;#define __RAW_SPIN_LOCK_UNLOCKED { 0 }/******include/asm-arm/spinlock.h***/#if __LINUX_ARM_ARCH__ < 6 #error SMP not supported on pre-ARMv6 CPUs //ARMv6后,才有多核ARM处理器 #endif …… static inline void __raw_spin_lock(raw_spinlock_t *lock) { unsigned long tmp; __asm__ __volatile__( "1: ldrex %0, [%1]\n" //取lock->lock放在 tmp里,并且设置&lock->lock这个内存地址为独占访问 " teq %0, #0\n" // 测试lock_lock是否为0,影响标志位z #ifdef CONFIG_CPU_32v6K " wfene\n" #endif " strexeq %0, %2, [%1]\n" //如果lock_lock是0,并且是独占访问这个内存,就向lock->lock里写入1,并向tmp返回0,同时清除独占标记 " teqeq %0, #0\n" //如果lock_lock是0,并且strexeq返回了0,表示加锁成功,返回 " bne 1b" //如果上面的条件(1:lock->lock里不为0,2:strexeq失败)有一个符合,就在原地打转 : "=&r" (tmp) //%0:输出放在tmp里,可以是任意寄存器 : "r" (&lock->lock), "r" (1) //%1:取&lock->lock放在任意寄存器,%2:任意寄存器放入1 : "cc"); //状态寄存器可能会改变 smp_mb(); }上述代码关键在于LDREX和STREX指令的应用。DREX和STREX指令是在V6以后才出现的,代替了V6以前的 swp指令。可以让bus监控LDREX和STREX指令之间有无其它CPU和DMA来存取过这个地址,若有的话STREX指令的第一个寄存器里设置为 1(动作失败),若没有,指令的第一个寄存器里设置为0(动作成功)。不仅是自旋锁用到LDREX和STREX指令,信号量的实现也是利用LDREX和STREX指令来实现的。
文件:Spinlock_types.h (\kernel\arch\arm\include\asm)#define TICKET_SHIFT<span style="white-space:pre"></span>16 //在lock时,用到它来讲0x100加到slock上,也即加到next成员上typedef struct {<span style="white-space:pre"></span>union {<span style="white-space:pre"></span>u32 slock; //当spin lock成功后,slock的高16位的值比低16位值大1,否则两部分的的值相等<span style="white-space:pre"></span>struct __raw_tickets { #ifdef __ARMEB__<span style="white-space:pre"></span>u16 next;<span style="white-space:pre"></span>u16 owner;#else<span style="white-space:pre"></span>u16 owner; //与slock成员构成了一个union体。owner是低地址<span style="white-space:pre"></span>u16 next;#endif<span style="white-space:pre"></span>} tickets;<span style="white-space:pre"></span>};} arch_spinlock_t;文件:Spinlock.h (\kernel\arch\arm\include\asm)//枷锁static inline void arch_spin_lock(arch_spinlock_t *lock) {<span style="white-space:pre"></span>unsigned long tmp, flags = 0;<span style="white-space:pre"></span>u32 newval;<span style="white-space:pre"></span>arch_spinlock_t lockval;<span style="white-space:pre"></span>//从以下可以看出,当spin lock成功后,slock的高16位的值比低16位值大1.<span style="white-space:pre"></span>__asm__ __volatile__("1:<span style="white-space:pre"></span>ldrex<span style="white-space:pre"></span>%0, [%3]\n" //lockval=lock->slock"<span style="white-space:pre"></span>add<span style="white-space:pre"></span>%1, %0, %4\n" //newval=lockval+0x100"<span style="white-space:pre"></span>strex<span style="white-space:pre"></span>%2, %1, [%3]\n" //lock->slock=newval;如果LDREX和STREX指令之间无其它CPU和DMA来存取过这个地址&lock->slock,则STREX返回0表示枷锁成功(否则返回1),返回值放到tmp中"<span style="white-space:pre"></span>teq<span style="white-space:pre"></span>%2, #0\n" //检查tmp的值"<span style="white-space:pre"></span>bne<span style="white-space:pre"></span>1b"<span style="white-space:pre"></span>: "=&r" (lockval), "=&r" (newval), "=&r" (tmp)<span style="white-space:pre"></span>: "r" (&lock->slock), "I" (1 << TICKET_SHIFT)<span style="white-space:pre"></span>: "cc");<span style="white-space:pre"></span>while (lockval.tickets.next != lockval.tickets.owner) {<span style="white-space:pre"></span>if (msm_krait_need_wfe_fixup) { //不满足<span style="white-space:pre"></span>local_save_flags(flags);<span style="white-space:pre"></span>local_fiq_disable();<span style="white-space:pre"></span>__asm__ __volatile__(<span style="white-space:pre"></span>"mrc<span style="white-space:pre"></span>p15, 7, %0, c15, c0, 5\n"<span style="white-space:pre"></span>: "=r" (tmp)<span style="white-space:pre"></span>:<span style="white-space:pre"></span>: "cc");<span style="white-space:pre"></span>tmp &= ~(0x10000);<span style="white-space:pre"></span>__asm__ __volatile__(<span style="white-space:pre"></span>"mcr<span style="white-space:pre"></span>p15, 7, %0, c15, c0, 5\n"<span style="white-space:pre"></span>:<span style="white-space:pre"></span>: "r" (tmp)<span style="white-space:pre"></span>: "cc");<span style="white-space:pre"></span>isb();<span style="white-space:pre"></span>}<span style="white-space:pre"></span>wfe();<span style="white-space:pre"></span>if (msm_krait_need_wfe_fixup) {<span style="white-space:pre"></span>tmp |= 0x10000;<span style="white-space:pre"></span>__asm__ __volatile__(<span style="white-space:pre"></span>"mcr<span style="white-space:pre"></span>p15, 7, %0, c15, c0, 5\n"<span style="white-space:pre"></span>:<span style="white-space:pre"></span>: "r" (tmp)<span style="white-space:pre"></span>: "cc");<span style="white-space:pre"></span>isb();<span style="white-space:pre"></span>local_irq_restore(flags);<span style="white-space:pre"></span>}<span style="white-space:pre"></span>lockval.tickets.owner = ACCESS_ONCE(lock->tickets.owner);<span style="white-space:pre"></span>}<span style="white-space:pre"></span>smp_mb();}//解锁static inline void arch_spin_unlock(arch_spinlock_t *lock){<span style="white-space:pre"></span>smp_mb();<span style="white-space:pre"></span>lock->tickets.owner++; //owner++使得它与next的值相等<span style="white-space:pre"></span>dsb_sev();}
0 0
- arm上ldrex和strexeq指令用来尝试获取独占内存权限和设置在独占权限时回写
- arm上ldrex和strexeq指令用来尝试获取独占内存权限和设置在独占权限时回写
- arm上ldrex和strexeq指令用来尝试获取独占内存权限和设置在独占权限时回写
- ARM平台下独占访问指令LDREX和STREX的原理与使用详解
- ARM平台下独占访问指令LDREX和STREX的原理与使用详解
- ARM平台下独占访问指令LDREX和STREX的原理与使用详解
- arm架构的独占读写指令ldrex和strex的使用详解(原子操作和自旋锁实现的基本原理)
- ARM的SWP和LDREX STREX指令
- cpu独占和亲和性
- 同步锁和独占锁
- 独占锁和共享锁
- SQLServer数据库还原无独占的访问权限解决办法
- linux权限和指令
- TortoiseSVN设置独占锁
- ARM命令LDREX和STREX实现spinlock
- 端口重用SO_REUSEADDR 和端口独占 SO_EXCLUSIVEADDRUSE
- 多线程访问共享锁和独占锁
- 原子操作的实现 ARM的SWP和LDREX STREX指令
- wlan组网介绍(HW)
- POJ 1423 Big Number——数学题
- Cookie Session Cache
- quagga 的原理解析 zebra原理解析
- 项目1:线性链表的基本操作
- arm上ldrex和strexeq指令用来尝试获取独占内存权限和设置在独占权限时回写
- java就是这样一个东西
- Babelfish
- 黑马程序员【类加载器与双亲委派模型】
- poj1659Havel
- Nginx Location配置语法介绍、优先级说明、nginx的root和alias指令的区别
- Spark1.0.1集群部署
- 添加资源到android源码中-修改framework层
- android:configChanges属性,横竖屏切换