在arm系统中,对cpu核的设计。使用了位技术变量来代表每个cpu的使用情况。
但是这里考虑到多核对同一变量的设置,因为有了多核访问,于是乎就需要防止冲突的机制。真样产生了特殊情况的操作位接口--> macro bitop, name, instr。
使用汇编的形式来完成。主要的技术,是arm arch6中的strex, ldrex。
STREX指令的英文解释如下:
STREX (Store Register Exclusive) performs a conditional store to memory. The store only occurs if the
executing processor has exclusive access to the memory addressed.
也就是说,这条存储指令具有cpu核的排它性。只有cpu具有独立访问该memor addressed的时候,才可以存储。否则,cpu存储指令失败。接下来就看看具体的使用方式。
语法如下:
Syntax
STREX{<cond>} <Rd>, <Rm>, [<Rn>]
where:
<cond> Is the condition under which the instruction is executed. The conditions are defined in The
condition field on page A3-3. If <cond> is omitted, the AL (always) condition is used.
<Rd> Specifies the destination register for the returned status value. The value returned is:
0
if the operation updates memory
1
if the operation fails to update memory.
<Rm> Specifies the register containing the word to be stored to memory.
<Rn> Specifies the register containing the address.
Rd是一个返回该存储状态寄存器,这里可以知道这次存储的状况。
Rm保留了需要存储到memory的值。
Rn 指定了将Rm值保存到memory的地址。
LDREX指令的英文解释如下:
LDREX (Load Register Exclusive) loads a register from memory, and:
• if the address has the Shared memory attribute, marks the physical address as exclusive access for the
executing processor in a shared monitor
• causes the executing processor to indicate an active inclusive access in the local monitor.
语法如下:
LDREX{<cond>} <Rd>, [<Rn>]
where:
<cond> Is the condition under which the instruction is executed. The conditions are defined in The
condition field on page A3-3. If <cond> is omitted, the AL (always) condition is used.
<Rd> Specifies the destination register for the memory word addressed by <Rd>.
<Rn> Specifies the register containing the address.
操作如下:
MemoryAccess(B-bit, E-bit) if ConditionPassed(cond) then processor_id = ExecutingProcessor() Rd = Memory[Rn,4] physical_address = TLB(Rn) if Shared(Rn) == 1 then MarkExclusiveGlobal(physical_address,processor_id,4) MarkExclusiveLocal(physical_address,processor_id,4) /* See Summary of operation on page A2-49 */
在ARM手册中有如下说明使用STREX与LDREX的范围:
Use STREX in combination with LDREX to implement inter-process communication in multiprocessor and
shared memory systems
Use LDREX in combination with STREX to implement inter-process communication in shared memory
multiprocessor systems. For more information see Synchronization primitives on page A2-44. The
mechanism can also be used locally to ensure that an atomic load-store sequence occurs with no intervening
context switch.
指令总结:
1,这条指令是用于多核处理器中,用于处理多核访问共享内存的排他性而设计的,单核最好不要使用。
因为比一般的存储指令要耗时。
从STREX指令的伪操作可以猜测出:
MemoryAccess(B-bit, E-bit) processor_id = ExecutingProcessor() if ConditionPassed(cond) then if (CP15_reg1_Ubit == 0) then if address[0] == 0b0 then Memory[address,2] = Rd[15:0] else Memory[address,2] = UNPREDICTABLE else /* CP15_reg1_Ubit ==1 */ Memory[address,2] = Rd[15:0] if Shared(address) then /* ARMv6 */ physical_address = TLB(address) ClearExclusiveByAddress(physical_address,processor_id
2,LDREX与STREX要一起共同使用构成同步原语。
有了这些知识点的普及, 我们在来分析bitop这个宏汇编是如何实现设置一个long数组中的某个位。
bitop宏代码如下:
.macro bitop, name, instr ENTRY( \name ) UNWIND( .fnstart ) ands ip, r1, #3 strneb r1, [ip] @ assert word-aligned mov r2, #1 and r3, r0, #31 @ Get bit offset mov r0, r0, lsr #5 add r1, r1, r0, lsl #2 @ Get word offset mov r3, r2, lsl r3 1: ldrex r2, [r1] \instr r2, r2, r3 strex r0, r2, [r1] cmp r0, #0 bne 1b bx lr UNWIND( .fnend ) ENDPROC(\name ) .endm
我们使用实例,
set_bit(cpumask_check(cpu), cpumask_bits(dstp));来分析该汇编代码。
化间成:
set_bit(int cpu, long * (maskp)->bits);
所以对于汇编来说:bitop _set_bit, orr 展开前。
r0 = cpu;
r1 = long型数据的首地址,用于存放位状态的存储器。
instr = orr指令。
第一模块: 内存对齐检测
ands ip, r1, #3
strneb r1, [ip] @ assert word-aligned
主要看一看long型的数据首地址是否位word-aligned, 如果不对齐,去访问0地址空间,引起NULL异常。
第二模块:将r0与32位进行mod操作,获取位偏移量,和long数组的偏移量。
mov r2, #1
and r3, r0, #31 @ Get bit offset
mov r0, r0, lsr #5
add r1, r1, r0, lsl #2 @ Get word offset
mov r3, r2, lsl r3
1,将r2 = = 1 (mov r2, #1)
2,%操作,保留r0中32位中的余数到r3寄存器中,也就是位的偏移量。(and r3, r0, #31)
3,获得参数中parm0中的word偏移量(mov r0, r0, lsr #5),这个时候,r0为原始parm0中的long数组偏移量。
4,将指针转到parm1,long数组中的目标long数据地址。(add r1, r1, r0, lsl #2),r1存放的是param1中相应parm0位的整数偏移量。
5,r3是param0中具体某个long数据的偏移量设置成1(mov r3, r2, lsl r3)
第三模块:orr操作,并且保存结果到memory中。
1: ldrex r2, [r1]
\instr r2, r2, r3
strex r0, r2, [r1]
cmp r0, #0
bne 1b
1,使用多核同步原语 ldrex, 获取r1地址中的数据。保存到r2中。(ldrex r2, [r1])
2,使用orr,或操作, 将保存在r3中的设置位与r1地址中的数据进行or操作,完成指定位的操作。(\instr r2, r2, r3)
3,通过多核同步原语将r2中的新值存储到r1指定的地址。
4,判断该多核存储操作是否完成,如果完成,返回,否则重复进行。
到这里, 就完成了arm set_bit的汇编代码分析。 可以看到,这里使用了ldrex与strex同步原语。
避免了多核之间的数据不同步问题。
(该博客是原创,转载请注明原创地址。 谢谢!)