zoukankan      html  css  js  c++  java
  • kuser_cmpxchg_check 原子操作

      对于ARM体系结构,每一个由用户态到内核态的中断或异常处理路径都经过kuser_cmpxchg_check,kuser_cmpxchg_check中检查被中断的地址是否大于TASK_SIZE;TASK_SIZE是内核与用户空间的分界点,那么对于ARM体系而言,为什么在用户态时其执行路径会“顺利”地进入内核空间?

     查了下,在Documentation/zh_CN/arm/kernel/kernel_user_helpers.txt中解释了对于ARM体系结构,由于没有类似x86的“比较交换”指令,因此在用户态下完成一些原子操作时需要借助于内核空间的一些操作来完成(此时,仍处于用户态,只是执行的程序地址位于高1G空间),此时发生中断时,内核需要恢复到适当的断点继续执行,因此此时需要修正pt_regs中的返回地址pc值。 

        .macro  kuser_cmpxchg_check
    +---  4 lines: #if !defined(CONFIG_CPU_32v6K) && !defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG)------------------------
        @ Make sure our user space atomic helper is restarted
        @ if it was interrupted in a critical region.  Here we                                                         
        @ perform a quick test inline since it should be false
        @ 99.9999% of the time.  The rest is done out of line.
        cmp r4, #TASK_SIZE
        blhs    kuser_cmpxchg64_fixup
    __kuser_cmpxchg64:              @ 0xffff0f60
    +-- 32 lines: #if defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG)--------------------------------------------------------
    
    #ifdef CONFIG_MMU
    
        /*
         * The only thing that can break atomicity in this cmpxchg64
         * implementation is either an IRQ or a data abort exception
         * causing another process/thread to be scheduled in the middle of
         * the critical sequence.  The same strategy as for cmpxchg is used.
         */
        stmfd   sp!, {r4, r5, r6, lr}
        ldmia   r0, {r4, r5}            @ load old val
        ldmia   r1, {r6, lr}            @ load new val
    1:  ldmia   r2, {r0, r1}            @ load current val
        eors    r3, r0, r4          @ compare with oldval (1)
        eoreqs  r3, r1, r5          @ compare with oldval (2)
    2:  stmeqia r2, {r6, lr}            @ store newval if eq
        rsbs    r0, r3, #0          @ set return val and C flag
        ldmfd   sp!, {r4, r5, r6, pc}
    
        .text
    kuser_cmpxchg64_fixup:
        @ Called from kuser_cmpxchg_fixup.
        @ r4 = address of interrupted insn (must be preserved).
        @ sp = saved regs. r7 and r8 are clobbered.
        @ 1b = first critical insn, 2b = last critical insn.
        @ If r4 >= 1b and r4 <= 2b then saved pc_usr is set to 1b.
        mov r7, #0xffff0fff
        sub r7, r7, #(0xffff0fff - (0xffff0f60 + (1b - __kuser_cmpxchg64)))
        subs    r8, r4, r7
        rsbcss  r8, r8, #(2b - 1b)
        strcs   r7, [sp, #S_PC]
    +---  3 lines: #if __LINUX_ARM_ARCH__ < 6--------------------------------------------------------------------------
        mov pc, lr

    如下内容,部分引述自:http://baike.baidu.com/view/809659.htm

      在单处理器系统(UniProcessor)中,能够在单条指令中完成的操作都可以认为是" 原子操作",因为中断只能发生于指令之间。这也是某些CPU指令系统中引入了test_and_set、test_and_clear等指令用于临界资源互斥的原因。但是,在对称多处理器(Symmetric Multi-Processor)结构中就不同了,由于系统中有多个处理器在独立地运行,即使能在单条指令中完成的操作也有可能受到干扰。

      原子性不可能由软件单独保证--必须需要硬件的支持,因此是和架构相关的。

      在x86 平台上,CPU提供了在指令执行期间对总线加锁的手段。CPU芯片上有一条引线#HLOCK pin,如果汇编语言的程序中在一条指令前面加上前缀"LOCK",经过汇编以后的机器代码就使CPU在执行这条指令的时候把#HLOCK pin的电位拉低,持续到这条指令结束时放开,从而把总线锁住,这样同一总线上别的CPU就暂时不能通过总线访问内存了,保证了这条指令在多处理器环境中的原子性。

            在ARMv6架构上,引入了ldrex、strex。个人理解,在使用ldrex和strex的过程中总线将会监控有无其它主设备(CPU、DMA等)来访问同样的地址,如果有,则使操作失效,并且在给出的寄存器中置1以示意失败,如果给出的寄存器中置为0则示意成功。

    引述自:http://blog.roodo.com/use_the_force/archives/3420371.html

                  http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dht0008a/ch01s02s01.html

    The LDREX and STREX instructions split the operation of atomically updating memory into two separate steps. Together, they provide atomic updates in conjunction with exclusive monitors that track exclusive memory accesses, see Exclusive monitors. Load-Exclusive and Store-Exclusive must only access memory regions marked as Normal.
    
    The LDREX instruction loads a word from memory, initializing the state of the exclusive monitor(s) to track the synchronization operation. For example, LDREX R1, [R0] performs a Load-Exclusive from the address in R0, places the value into R1 and updates the exclusive monitor(s).
    
    The STREX instruction performs a conditional store of a word to memory. If the exclusive monitor(s) permit the store, the operation updates the memory location and returns the value 0 in the destination register, indicating that the operation succeeded. If the exclusive monitor(s) do not permit the store, the operation does not update the memory location and returns the value 1 in the destination register. This makes it possible to implement conditional execution paths based on the success or failure of the memory operation. For example, STREX R2, R1, [R0] performs a Store-Exclusive operation to the address in R0, conditionally storing the value from R1 and indicating success or failure in R2.
  • 相关阅读:
    Oracle使用手册<收藏>
    Oracle 连接串方式
    通过多线程为基于 .NET 的应用程序实现响应迅速的用户
    PL/SQL三种集合类型的比较<收藏>
    关于Application.DoEvents() 避免假死<收藏>
    Inserting/Retrieving CLOB/NCLOB Data
    从procedure返回結果集<收藏>
    oracle ReadBlobs
    使用Update...returning...into为什么会出现ORA01036,ORA24369错误 <收藏>
    DevExpress document 地址
  • 原文地址:https://www.cnblogs.com/openix/p/3287824.html
Copyright © 2011-2022 走看看