0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

Linux Kernel(armv8-aarch64) 的原子操作的底层实现

冬至子 来源:Arm精选 作者:baron 2023-10-16 11:14 次阅读

通常我们代码中的a = a + 1这样的一行语句,翻译成汇编后蕴含着 3 条指令:

ldr x0, &a  
add x0,x0,#1  
str x0,&a


(1) 从内存中读取 a 变量到 X0 寄存器
(2)X0 寄存器加 1
(3) 将 X0 写入到内存 a 中

既然是 3 条指令,那么就有可能并发,也就意味着返回的结果可能不说预期的。

然后在 linux kernel 的操作系统中,提供访问原子变量的函数,用来解决上述问题。其中部分原子操作的 API 如下:

atomic_read
atomic_add_return(i,v)
atomic_add(i,v)
atomic_inc(v)
atomic_add_unless(v,a,u)
atomic_inc_not_zero(v)
atomic_sub_return(i,v)
atomic_sub_and_test(i,v)
atomic_sub(i,v)
atomic_dec(v)
atomic_cmpxchg(v,old,new)

那么操作系统 (仅仅是软件而已) 是如何保证原子操作的呢?(还是得靠硬件),硬件原理是什么呢?

以上的那些 API 函数,在底层调用的其实都是如下__lse_atomic_add_return##name宏的封装,这段代码中最核心的也就是ldadd指令了,这是 armv8.1 增加的 LSE(Large System Extension)feature。

(linux/arch/arm64/include/asm/atomic_lse.h)

static inline int __lse_atomic_add_return##name(int i, atomic_t *v)    
{                                    
    u32 tmp;                            
                                    
    asm volatile(                            
    __LSE_PREAMBLE                            
    "    ldadd" #mb "    %w[i], %w[tmp], %[v]n"            
    "    add    %w[i], %w[i], %w[tmp]"                
    : [i] "+r" (i), [v] "+Q" (v- >counter), [tmp] "=&r" (tmp)    
    : "r" (v)                            
    : cl);                                
                                    
    return i;                            
}

那么系统如果没有 LSE 扩展呢,即 armv8.0,其实现的原型如下所示,这段代码中最核心的也就是ldxrstxr指令了

(linux/arch/arm64/include/asm/atomic_ll_sc.h)

static inline void __ll_sc_atomic_##op(int i, atomic_t *v)
{                                    
    unsigned long tmp;                        
    int result;                            
                                    
    asm volatile("// atomic_" #op "n"                
    __LL_SC_FALLBACK(                        
"    prfm    pstl1strm, %2n"                    
"1:    ldxr    %w0, %2n"                        
"    " #asm_op "    %w0, %w0, %w3n"                
"    stxr    %w1, %w0, %2n"                        
"    cbnz    %w1, 1bn")                        
    : "=&r" (result), "=&r" (tmp), "+Q" (v- >counter)        
    : __stringify(constraint) "r" (i));                
}

那么在 armv8.0 之前呢,如 armv7 是怎样实现的?如下所示, 这段代码中最核心的也就是ldrexstrex指令了

(linux/arch/arm/include/asm/atomic.h)

static inline void atomic_##op(int i, atomic_t *v)            
{                                    
    unsigned long tmp;                        
    int result;                            
                                    
    prefetchw(&v- >counter);                        
    __asm__ __volatile__("@ atomic_" #op "n"            
"1:    ldrex    %0, [%3]n"                        
"    " #asm_op "    %0, %0, %4n"                    
"    strex    %1, %0, [%3]n"                        
"    teq    %1, #0n"                        
"    bne    1b"                            
    : "=&r" (result), "=&r" (tmp), "+Qo" (v- >counter)        
    : "r" (&v- >counter), "Ir" (i)                    
    : "cc");                            
}

总结:

在很早期,使用 arm 的 exclusive 机制来实现的原子操作,exclusive 相关的指令也就是ldrexstrex了,但在 armv8 后,exclusive 机制的指令发生了变化变成了ldxrstxr

但是又由于在一个大系统中,处理器是非常多的,竞争也激烈,使用独占的存储和加载指令可能要多次尝试才能成功,性能也就变得很差,在 armv8.1 为了解决该问题,增加了ldadd等相关的原子操作指令。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 处理器
    +关注

    关注

    68

    文章

    18296

    浏览量

    222205
  • 寄存器
    +关注

    关注

    30

    文章

    5036

    浏览量

    117763
  • Linux系统
    +关注

    关注

    4

    文章

    567

    浏览量

    26923
  • LSE
    LSE
    +关注

    关注

    0

    文章

    10

    浏览量

    10169
  • ARMv8
    +关注

    关注

    1

    文章

    35

    浏览量

    14057
收藏 人收藏

    评论

    相关推荐

    ARMv8-A AArch32主要特性

    Cortex-A32产品介绍ARMv8-A AArch32主要特性ARMv7-M与AArch32的不同之处软件从ARMv7-M移植到
    发表于 02-19 06:20

    编译出的bin文件用什么方式刷入开发板

    /target-aarch64_generic_musl/linux-layerscape_armv8_64b/ls1046ardb-kernel.bin > /home/forlinx/work/OK104x-
    发表于 01-05 07:46

    ARMv8架构资料分享

      随着开发工作逐渐迁移到 ARMv864 位平台,因此有必要尽快熟悉 ARMv8 架构。ARMv8 与先前较为熟悉的 ARMv7 架
    发表于 03-21 14:50

    ARMv8aarch64aarch32是怎样进行切换的

    ARMv8中,aarch64aarch32是通过异常进行切换的。而A32和T32是通过bx指令进行切换的。如下图:以下A64和A32混合编程,是在EL3为
    发表于 04-01 15:09

    ARMv8架构概述

    Armv8 OverviewARMv7与Armv8的升级示意如下:Aarch64指令集Aarch64的32个通用寄存器引用和描述如下,与Aarch
    发表于 05-13 10:31

    ARMV8-aarch64异常和中断处理概念详细介绍

    1、ARMV8-aarch64异常和中断处理概念(AArch64 Exception and Interrupt Handling)异常是指需要特权软件(an exception handler
    发表于 06-01 17:46

    请问Armv8-A到底是什么东西呢

    介绍了,后面的内容都是以A为基础。Armv8-A的执行状态有两种,AArch64AArch32。相应的Armv8-A支持两种指令集:AArch64
    发表于 08-22 15:39

    Cortex-A53使用AArch32 Kernel,可以直接使用ARMv7的所支持的CPU吗?

    CA53 run 32bit linux kernel, 发现arch/arm/kernel/perf_event_v7.c 只支持ARMv7 的 ca17, ca15, ca12,
    发表于 08-29 14:11

    AArch64异常模型指南

    AArch64异常模型指南介绍了Armv8-A中的异常和特权模型Armv9-A。它涵盖了Arm体系结构中不同类型的异常,以及处理器与异常的关系。 这些内容面向底层代码的开发人员,例如引
    发表于 08-02 06:03

    ARM Cortex-A系列ARMv8-A程序员指南

    。 GNU和Linux文档(Redhat和Fedora发行版除外)有时将AArch64称为ARM64。 因为ARMv8-A体系结构的许多概念都与AR
    发表于 08-22 07:22

    ARM64与ARM32 的Linux程序区别在哪里

    我本来打算将这篇文章称为“ARMv8 for Linux程序员的新功能?”然而,我认为“有什么不同”更为贴切。而且,仅仅为了记录,“ARMv8-A”是指AArch64,带有A
    的头像 发表于 08-09 09:51 2.6w次阅读
    ARM<b class='flag-5'>64</b>与ARM32 的<b class='flag-5'>Linux</b>程序区别在哪里

    使用Linux原子操作实现互斥点灯

    Linux原子操作是指不能再进一步分割的操作,一般原子操作用于变量或者位
    的头像 发表于 04-13 15:07 652次阅读
    使用<b class='flag-5'>Linux</b><b class='flag-5'>原子</b><b class='flag-5'>操作</b><b class='flag-5'>实现</b>互斥点灯

    SOC的多核启动流程和概念详解

    本文以为armv8-aarch64armv9为例、TF-A代码为例,不讨论其它硬件架构和固件软件中的设计。
    发表于 06-08 09:32 1321次阅读
    SOC的多核启动流程和概念详解

    最新的Linux aarch64 LSA驱动程序

    电子发烧友网站提供《最新的Linux aarch64 LSA驱动程序.zip》资料免费下载
    发表于 08-23 15:46 2次下载
    最新的<b class='flag-5'>Linux</b> <b class='flag-5'>aarch64</b> LSA驱动程序

    ARMv7-A工作模式介绍

    意思就是 64 位和 32 位,其中 AArch32 和 ARMv7基本一样(会多一些其他操作指令)。 安全不能仅仅依靠软件来实现,也是需要
    的头像 发表于 09-11 16:31 496次阅读
    <b class='flag-5'>ARMv</b>7-A工作模式介绍