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

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

3天内不再提示

CPU CACHE策略的初始化

冬至子 来源:Linux与SoC 作者:linux-soc 2023-06-05 15:03 次阅读

linux booting过程中会打印CACHE的写机制,打印信息如下:

OF: fdt: Machine model: V2P-CA9
Memory policy: Data cache writealloc

以上打印信息来自于函数

build_mem_type_table(void)

它的调用栈如下:

setup_arch
  |
  #ifdef CONFIG_MMU
    early_mm_init(mdesc);
  #endif
    |
    early_mm_init()
      |
      build_mem_type_table();

build_mem_type_table()函数的功能是获取当前CPU的CACHE类型,据此初始化mem_type。kernel根据mem_types数据结构的值,做后续的其他处理。

由于build_mem_type_table()属于early_mm_init()的一部分,因此,从early_mm_init()入手,逐步解析CACHE的写机制。

early_mm_init(mdesc)

early_mm_init()能否得到执行,取决于当前kernel是否使能了MMU。

图片

该函数的定义位于setup.c中

void __init early_mm_init(const struct machine_desc *mdesc)
{
 build_mem_type_table();
 early_paging_init(mdesc);
}

函数参数是struct machine_desc指针。数据结构machine_desc描述了CPU的硬件信息及一些初始化函数。

struct machine_desc {
 unsigned int  nr;
 const char  *name;
 unsigned long  atag_offset;
 const char *const  *dt_compat;
 unsigned int  nr_irqs;

#ifdef CONFIG_ZONE_DMA
 phys_addr_t  dma_zone_size;
#endif
 unsigned int  video_start;
 unsigned int  video_end;
 unsigned char  reserve_lp0 :1;
 unsigned char  reserve_lp1 :1;
 unsigned char  reserve_lp2 :1;
 enum reboot_mode reboot_mode;
 unsigned  l2c_aux_val;
 unsigned  l2c_aux_mask;
 void   (*l2c_write_sec)(unsigned long, unsigned);
 const struct smp_operations *smp;
 bool   (*smp_init)(void);
 void   (*fixup)(struct tag *, char **);
 void   (*dt_fixup)(void);
 long long  (*pv_fixup)(void);
 void   (*reserve)(void);
 void   (*map_io)(void);
 void   (*init_early)(void);
 void   (*init_irq)(void);
 void   (*init_time)(void);
 void   (*init_machine)(void);
 void   (*init_late)(void);
#ifdef CONFIG_GENERIC_IRQ_MULTI_HANDLER
 void   (*handle_irq)(struct pt_regs *);
#endif
 void   (*restart)(enum reboot_mode, const char *);
};

通过解析设备树镜像得到mdesc成员的具体值是什么。

if (atags_vaddr) {
 mdesc = setup_machine_fdt(atags_vaddr);
 if (mdesc)
  memblock_reserve(__atags_pointer,
     fdt_totalsize(atags_vaddr));
}

build_mem_type_table()

这个函数的核心作用是初始化struct mem_type数据结构,定义如下:

struct mem_type {
 pteval_t prot_pte;
 pteval_t prot_pte_s2;
 pmdval_t prot_l1;
 pmdval_t prot_sect;
 unsigned int domain;
};

该数据结构的历史:

author Russell King < rmk@dyn-67.arm.linux.org.uk > 2007-04-21 10:47:29 +0100
committer Russell King < rmk+kernel@arm.linux.org.uk > 2007-04-21 20:36:00 +0100
[ARM] mm 5: Use mem_types table in ioremap
We really want to be using the memory type table in ioremap, so we
only have to do the CPU type fixups in one place.

Signed-off-by: Russell King < rmk+kernel@arm.linux.org.uk >

Diffstat (limited to 'arch/arm/mm/mm.h')
-rw-r--r-- arch/arm/mm/mm.h 9 
  
1 files changed, 9 insertions, 0 deletions
diff --git a/arch/arm/mm/mm.h b/arch/arm/mm/mm.h
index a44e309706354..66f8612c5e5b9 100644
--- a/arch/arm/mm/mm.h
+++ b/arch/arm/mm/mm.h
+struct mem_type {
+ unsigned int prot_pte;
+ unsigned int prot_l1;
+ unsigned int prot_sect;
+ unsigned int domain;
+};
+
+const struct mem_type *get_mem_type(unsigned int type);
+

从commit信息中可以看到,struct mem_type最初的目的是给ioremap使用的,在这个patch中,增加了struct mem_type以及get_mem_type()。

到目前为止,这个数据结构的作用已经不仅限上面提及的内容。更为主要的作用是根据mem类型创建内核页表。

build_mem_type_table()函数根据ARM内核版本号例化不同的mem类型。 包括ARM v5/6/7。

int cpu_arch = cpu_architecture();

在mmu.c的init_default_cache_policy中会对cachepolicy进行初始化。

mmu.c (arch\\arm\\mm) line 64 : static unsigned int cachepolicy __initdata = CPOLICY_WRITEBACK;
init_default_cache_policy in mmu.c (arch\\arm\\mm) :    cachepolicy = i;

根据不同的CPU 架构类型对cachepolicy变量重新赋值。

build_mem_type_table in mmu.c (arch\\arm\\mm) :   if (cachepolicy > CPOLICY_BUFFERED)
build_mem_type_table in mmu.c (arch\\arm\\mm) :    cachepolicy = CPOLICY_BUFFERED;
build_mem_type_table in mmu.c (arch\\arm\\mm) :   if (cachepolicy > CPOLICY_WRITETHROUGH)
build_mem_type_table in mmu.c (arch\\arm\\mm) :    cachepolicy = CPOLICY_WRITETHROUGH;
build_mem_type_table in mmu.c (arch\\arm\\mm) :   if (cachepolicy >= CPOLICY_WRITEALLOC)
build_mem_type_table in mmu.c (arch\\arm\\mm) :    cachepolicy = CPOLICY_WRITEBACK;
build_mem_type_table in mmu.c (arch\\arm\\mm) :   if (cachepolicy != CPOLICY_WRITEALLOC) {
build_mem_type_table in mmu.c (arch\\arm\\mm) :    cachepolicy = CPOLICY_WRITEALLOC;

内核中定义了4中CACHE 写策略,分别是:

#define CPOLICY_BUFFERED 1
#define CPOLICY_WRITETHROUGH 2
#define CPOLICY_WRITEBACK 3
#define CPOLICY_WRITEALLOC 4

最后,根据cachepolicy的值例化数据结构struct cachepolicy *cp,

cp = &cache_policies[cachepolicy];

在我的环境中,cachepolicy的值为4,其对应的CACHE属性为writealloc。

static struct cachepolicy cache_policies[] __initdata = {
 {
  .policy  = "uncached",
  .cr_mask = CR_W|CR_C,
  .pmd  = PMD_SECT_UNCACHED,
  .pte  = L_PTE_MT_UNCACHED,
  .pte_s2  = s2_policy(L_PTE_S2_MT_UNCACHED),
 }, {
  .policy  = "buffered",
  .cr_mask = CR_C,
  .pmd  = PMD_SECT_BUFFERED,
  .pte  = L_PTE_MT_BUFFERABLE,
  .pte_s2  = s2_policy(L_PTE_S2_MT_UNCACHED),
 }, {
  .policy  = "writethrough",
  .cr_mask = 0,
  .pmd  = PMD_SECT_WT,
  .pte  = L_PTE_MT_WRITETHROUGH,
  .pte_s2  = s2_policy(L_PTE_S2_MT_WRITETHROUGH),
 }, {
  .policy  = "writeback",
  .cr_mask = 0,
  .pmd  = PMD_SECT_WB,
  .pte  = L_PTE_MT_WRITEBACK,
  .pte_s2  = s2_policy(L_PTE_S2_MT_WRITEBACK),
 }, {
  .policy  = "writealloc",
  .cr_mask = 0,
  .pmd  = PMD_SECT_WBWA,
  .pte  = L_PTE_MT_WRITEALLOC,
  .pte_s2  = s2_policy(L_PTE_S2_MT_WRITEBACK),
 }
};

writealloc结合了write back的功能,而write back是在CACHE hit时所采取的策略,alloc是在CACHE miss所采取的策略,当发生CACHE miss时,会从主存中读取数据并更新CACHE line到CACHE缓存中。对于SMP ARM而言,普遍采取的是这种CACHE 策略,结合ARM 的SCU完成缓存一致性的处理。可以查看ARM的如下寄存器确定CACHE所支持的策略类型。

图片

CACHE写策略

下图是一个标准的ARM处理器芯片版图布局,使用SRAM作为L1 CACHE,它在ARM core这一区域。通过DDR SDRAM interface访问位于芯片外部的主存DDR memory。简单而论,从二者布局布线的角度看,访问外部DDR memory的cycle明显高于内部L1 CACHE。

图片

当CPU执行数据写操作时,首先检查待写入的内存地址是否在CACHE中,若在CACHE中则称之为Hit,反之为Miss。在Hit命中的前提下,CACHE写策略分为Write back和Write through。

Write through

CACHE工作于write through模式时,数据同时更新到CACHE和主存当中。这种操作模式简单可靠,适用于写操作比较少的应用场景,或者预防突然断电的数据恢复机制中。当然,由于同时更新CACHE和外部主存,这种写模式的延时比较大。

图片

Write back

CACHE工作于write through模式时,数据仅更新到CACHE中而不会立即更新到主存。基于Belady’s Anomaly, LRU, FIFO, LIFO等算法,当CACHE中的数据需要被替换时,原数据会被更新到主存当中。在CACHE的每一个block中,使用一个dirty位来标记当前数据是否需要被替换,若dirty位被置位1,则需要将数据更新到主存。

图片

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

    关注

    0

    文章

    68

    浏览量

    19450
  • Linux系统
    +关注

    关注

    4

    文章

    567

    浏览量

    26920
  • ARM处理器
    +关注

    关注

    6

    文章

    346

    浏览量

    41324
  • MMU
    MMU
    +关注

    关注

    0

    文章

    91

    浏览量

    17944
  • cache技术
    +关注

    关注

    0

    文章

    41

    浏览量

    986
收藏 人收藏

    评论

    相关推荐

    字符型、指针型等变量该如何初始化

    在敲代码的时候,我们会给变量一个初始值,以防止因为编译器的原因造成变量初始值的不确定性。对于数值类型的变量往往初始化为0,但对于其他类型的变量,如字符型、指针型等变量等该如何初始化呢?
    发表于 09-23 11:50 1958次阅读

    关于TMS570LS3137的cache初始化

    各位TI专家,我想问一下,TMS570LS3137这个芯片的CACHE该如何初始化啊?另外,芯片CACHE的相关文档在哪里有下载呢?
    发表于 06-23 06:05

    AD9364初始化问题及标准初始化流程?

    AD9364初始化好像不成功。能否请官方给出一个使用外部晶体(如33MHz),FDD的标准初始化例子。
    发表于 09-28 14:56

    端口初始化初始化中断

    目录PA9(TX),PA10(RX)1、端口初始化2、初始化外设3、初始化中断4、使能中断5、使能外设5、发送数据PA9(TX),PA10(RX)1、端口初始化1.开启PA时钟2.PA
    发表于 08-16 06:54

    初始化封装

    初始化封装您可以在 Mask Editor 的 Initialization 窗格中添加 MATLAB® 代码以初始化封装模块。Simulink® 将执行这些初始化命令以便在关键时刻(如模型加载
    发表于 08-27 07:17

    【原创分享】变量的初始化技巧

    由于在嵌入式系统中必须考虑程序规模的问题,因此,对程序中的变量的初始化也需要进行慎重的考虑。在C语言中,基本数据结构(字符型、整型)的初始化相对简单;数组、结构体属于C语言中的构造类型,其变量在
    发表于 09-08 15:28

    浅析cache控制器的分配策略与替换策略

    cache的相关操作中,cache控制器需要根据需求做出许多不同的选择。例如:分配策略是否需要将数据从主存中分配到cache中;替换策略
    发表于 06-15 16:24

    ARM处理器中CACHE策略初始化简析

    1、CPU CACHE政策的初始化linux booting过程中会打印CACHE的写入机制,打印信息如下:上面的打印信息来自于函数build_mem_type_table(void)
    发表于 06-30 16:05

    基于修正LRU的压缩Cache替换策略

    以优化压缩cache的替换策略为目标,提出一种优化的基于修正LRU的压缩cache替换策略MLRU-C。MLRU-C策略能利用压缩
    发表于 04-15 09:51 36次下载

    RDA1846S初始化设置

    RDA1846S初始化设置RDA1846S初始化设置RDA1846S初始化设置
    发表于 01-15 17:08 0次下载

    鸿蒙内核源码:内核空间是怎么初始化的?

    data段 该段用于存储初始化的全局变量,初始化为0的全局变量出于编译优化的策略还是被保存在BSS段。
    的头像 发表于 04-26 14:43 1523次阅读
    鸿蒙内核源码:内核空间是怎么<b class='flag-5'>初始化</b>的?

    CPU Cache伪共享问题

    CPU想要访问主存中的元素时,会先查看Cache中是否存在,如果存在(称为Cache Hit),直接从Cache中获取,如果不存在(称为Cache
    的头像 发表于 12-12 09:17 515次阅读

    Cache替换策略和Write-through介绍

    信息到数据总线即可; 另一种是需要的数据尚未装入CacheCPU需要从主存中读取信息的同时,Cache替换部件把该地址所在的那块存储内容从主存复制到Cache中。若
    的头像 发表于 10-31 11:48 710次阅读

    secondary cpu初始化状态设置

    ,用于填写secondary cpu的入口地址。 uboot负责将这块内存的地址写入devicetree中,当内核初始化完成,需要启动secondary cpu时,就将其内核入口地址写到那块内存
    的头像 发表于 12-05 15:27 343次阅读
    secondary <b class='flag-5'>cpu</b><b class='flag-5'>初始化</b>状态设置

    字符型、指针型等变量等该如何初始化

     对于数值类型的变量往往初始化为0,但对于其他类型的变量,如字符型、指针型等变量等该如何初始化呢?
    的头像 发表于 03-18 11:02 211次阅读