linux booting過程中會打印CACHE的寫機制,打印信息如下:
OF:fdt:Machinemodel:V2P-CA9Memorypolicy:Datacachewritealloc以上打印信息來自於函數build_mem_type_table(void)它的調用棧如下:
setup_arch|#ifdefCONFIG_MMUearly_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__initearly_mm_init(conststructmachine_desc*mdesc){build_mem_type_table();early_paging_init(mdesc);}函數參數是struct machine_desc指針。數據結構machine_desc描述了CPU的硬件信息及一些初始化函數。
structmachine_desc{unsignedintnr;constchar*name;unsignedlongatag_offset;constchar*const*dt_compat;unsignedintnr_irqs;#ifdefCONFIG_ZONE_DMAphys_addr_tdma_zone_size;#endifunsignedintvideo_start;unsignedintvideo_end;unsignedcharreserve_lp0:1;unsignedcharreserve_lp1:1;unsignedcharreserve_lp2:1;enumreboot_modereboot_mode;unsignedl2c_aux_val;unsignedl2c_aux_mask;void(*l2c_write_sec)(unsignedlong,unsigned);conststructsmp_operations*smp;bool(*smp_init)(void);void(*fixup)(structtag*,char**);void(*dt_fixup)(void);longlong(*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);#ifdefCONFIG_GENERIC_IRQ_MULTI_HANDLERvoid(*handle_irq)(structpt_regs*);#endifvoid(*restart)(enumreboot_mode,constchar*);};通過解析設備樹鏡像得到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數據結構,定義如下:
structmem_type{pteval_tprot_pte;pteval_tprot_pte_s2;pmdval_tprot_l1;pmdval_tprot_sect;unsignedintdomain;};該數據結構的歷史:
authorRussellKing<rmk@dyn-67.arm.linux.org.uk>2007-04-2110:47:29+0100committerRussellKing<rmk+kernel@arm.linux.org.uk>2007-04-2120:36:00+0100[ARM]mm5:Usemem_typestableinioremapWereallywanttobeusingthememorytypetableinioremap,soweonlyhavetodotheCPUtypefixupsinoneplace.Signed-off-by:RussellKing<rmk+kernel@arm.linux.org.uk>Diffstat(limitedto'arch/arm/mm/mm.h')-rw-r--r--arch/arm/mm/mm.h91fileschanged,9insertions,0deletionsdiff--gita/arch/arm/mm/mm.hb/arch/arm/mm/mm.hindexa44e309706354..66f8612c5e5b9100644---a/arch/arm/mm/mm.h+++b/arch/arm/mm/mm.h+structmem_type{+unsignedintprot_pte;+unsignedintprot_l1;+unsignedintprot_sect;+unsignedintdomain;+};++conststructmem_type*get_mem_type(unsignedinttype);+從commit信息中可以看到,struct mem_type最初的目的是給ioremap使用的,在這個patch中,增加了struct mem_type以及get_mem_type()。
到目前為止,這個數據結構的作用已經不僅限上面提及的內容。更為主要的作用是根據mem類型創建內核頁表。
build_mem_type_table()函數根據ARM內核版本號例化不同的mem類型。 包括ARM v5/6/7。
intcpu_arch=cpu_architecture();在mmu.c的init_default_cache_policy中會對cachepolicy進行初始化。
mmu.c(arch\arm\mm)line64:staticunsignedintcachepolicy__initdata=CPOLICY_WRITEBACK;init_default_cache_policyinmmu.c(arch\arm\mm):cachepolicy=i;根據不同的CPU 架構類型對cachepolicy變量重新賦值。
build_mem_type_tableinmmu.c(arch\arm\mm):if(cachepolicy>CPOLICY_BUFFERED)build_mem_type_tableinmmu.c(arch\arm\mm):cachepolicy=CPOLICY_BUFFERED;build_mem_type_tableinmmu.c(arch\arm\mm):if(cachepolicy>CPOLICY_WRITETHROUGH)build_mem_type_tableinmmu.c(arch\arm\mm):cachepolicy=CPOLICY_WRITETHROUGH;build_mem_type_tableinmmu.c(arch\arm\mm):if(cachepolicy>=CPOLICY_WRITEALLOC)build_mem_type_tableinmmu.c(arch\arm\mm):cachepolicy=CPOLICY_WRITEBACK;build_mem_type_tableinmmu.c(arch\arm\mm):if(cachepolicy!=CPOLICY_WRITEALLOC){build_mem_type_tableinmmu.c(arch\arm\mm):cachepolicy=CPOLICY_WRITEALLOC;內核中定義了4中CACHE 寫策略,分別是:
#defineCPOLICY_BUFFERED1#defineCPOLICY_WRITETHROUGH2#defineCPOLICY_WRITEBACK3#defineCPOLICY_WRITEALLOC4最後,根據cachepolicy的值例化數據結構struct cachepolicy *cp,
cp=&cache_policies[cachepolicy];在我的環境中,cachepolicy的值為4,其對應的CACHE屬性為writealloc。
staticstructcachepolicycache_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所支持的策略類型。

下圖是一個標準的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 throughCACHE工作於write through模式時,數據同時更新到CACHE和主存當中。這種操作模式簡單可靠,適用於寫操作比較少的應用場景,或者預防突然斷電的數據恢復機制中。當然,由於同時更新CACHE和外部主存,這種寫模式的延時比較大。

CACHE工作於write through模式時,數據僅更新到CACHE中而不會立即更新到主存。基於Belady’s Anomaly, LRU, FIFO, LIFO等算法,當CACHE中的數據需要被替換時,原數據會被更新到主存當中。在CACHE的每一個block中,使用一個dirty位來標記當前數據是否需要被替換,若dirty位被置位1,則需要將數據更新到主存。
掃描二維碼添加微信,共同學習討論

歡迎點讚和在看,讓知識傳遞下去