《ARM Architecture Reference Manual ARMv8-A》裏面有Memory層級框架圖,從中能夠看出L一、L二、DRAM、Disk、MMU之間的關係,以及他們在整個存儲系統中扮演的角色。html
涉及到的相關文檔有:linux
《ARM Architecture Reference Manual ARMv8-A》:E2 The AArch32 Application Level Memory Model和G3 The AArch32 System Level Memory Model兩個章節,從整體架構上介紹了ARMv8-A Memory系統。git
《Cortex-A53 TRM》:6 Level 1 Memory System、5 Memory Management Unit、7 Level 2 Memory System三個章節介紹了MMU/L1/L2三個模塊在A53上的實現。github
具體到MMU:算法
《MMU-500 TRM》:MMU-500技術參考手冊。緩存
《ARM SMMUv2》:System MMU 架構規格 version 2.0。架構
具體到L2:app
《L2C-310 TRM》:L2控制器技術參考手冊。框架
在Linux內核中查看L1/L2/L3緩存:electron
lscpu ... L1d cache: 32K L1i cache: 32K L2 cache: 256K L3 cache: 6144K ... 或者讀取節點: cat /sys/devices/system/cpu/cpu0/cache/indexx/size cat /sys/devices/system/cpu/cpu0/cache/indexx/level
VA:Virtual Address
PA:Physical Address
IPA:Intermediate Physical Address
MMU-500是系統級的存儲管理單元,它基於自身寄存器和轉換表中的地址映射和存儲器屬性,將虛擬地址轉換成物理地址。
將這個轉換過程分爲兩個階段:
MMU-500能夠將 轉換表查找結果緩存到TLB中。
MMU-500包含一下主要部件:
TBU(Translation Buffer Unit) - 包含緩存頁表的TLB,MMU-500給每一個Master配置了一個TBU,專屬於Master。
TCU(Translation Control Unit) - 控制和管理地址轉換,一個MMU-500僅包含一個TCU。
Interconnect - 多TBU到TCU之間的鏈接。
Master可能包括GPU、Video engines、DMA Controller、LCD Controller、Network Controller等。
從Figure 1-1可知,一個MMU有多個TBU和一個TCU。TBU包含TLB,主要用於緩存常常使用的地址範圍;TCU主要查找頁表。
摘錄A53規格書中關於L2 Cache一段屬性描述:
Optional tightly-coupled L2 cache that includes:
— Configurable L2 cache size of 128KB, 256KB, 512KB, 1MB and 2MB.---多種大小可配置
— Fixed line length of 64 bytes.------------------------------------每條Cache Line大小是64Bytes — Physically indexed and tagged cache. — 16-way set-associative cache structure. — Optional ACP interface if an L2 cache is configured. — Optional ECC protection
Cache Line能夠簡單的理解爲CPU Cache中的最小緩存單位。
大小爲64Bytes大小的Cache Line,128KB的L2 Cache,一共有128KB/64B=2048個Cache Line。
那麼Cache存放規則是什麼呢?Fully Associative、Direct Mapped、N-Way Set Associative。
Fully Associative是全關聯的意思:若是在一個Cache集內,任何一個地址的數據均可以緩存在任何一個Cache Line裏,那麼咱們稱這個Cache是Fully Associative。
給一個內存地址,要知道他是否存在於Cache中,就須要遍歷全部Cache Line並比較緩存內容的地址。
Direct Mapped給定一個內存地址,就惟一肯定了一條Cache Line。以4GB內存空間,128KB L2 Cache,64B Cache Line,那麼4GB/(128KB/64B)=2MB共用一條Cache Line,使用率過低。
N-Way Set Associative是吧一個緩存按照N個Cache Line做爲一組(Set),緩存按組劃爲等分。
一樣以上面32位系統中L2 Cache規格爲例,低6位是Cache Line中的偏移量;128KB/16/64B=128,中間7位表示Cache組號(Set Index);剩餘高19位就是內存地址的惟一ID。
給定一個內存地址能夠惟一對應一個Set,對於Set中只需遍歷16個元素就能夠肯定對象是否在緩存中。
128KB的Cache,分紅128個Set;一個Set包含16根Cache Line;每根Cache Line大小64Byte。
即在連續內存地址中每Cache Line Offset+Set Index長度8KB就會出現一個處於同一Cache Set的緩存對象,爭搶一個僅有16個空位的緩存池。
每Cache Line Offset+Set Index+16 Way=128KB纔會致使一個Set內的Conflict。
#
# Processor Type
#
CONFIG_CPU_V7=y
CONFIG_CPU_32v6K=y
CONFIG_CPU_32v7=y
CONFIG_CPU_ABRT_EV7=y
CONFIG_CPU_PABRT_V7=y
CONFIG_CPU_CACHE_V7=y
CONFIG_CPU_CACHE_VIPT=y
CONFIG_CPU_COPY_V6=y
CONFIG_CPU_TLB_V7=y
CONFIG_CPU_HAS_ASID=y
CONFIG_CPU_CP15=y
CONFIG_CPU_CP15_MMU=y
#
# Processor Features
#
CONFIG_OUTER_CACHE=y CONFIG_OUTER_CACHE_SYNC=y CONFIG_MIGHT_HAVE_CACHE_L2X0=y CONFIG_CACHE_L2X0=y CONFIG_CACHE_PL310=y CONFIG_ARM_L1_CACHE_SHIFT_6=y CONFIG_ARM_L1_CACHE_SHIFT=6 CONFIG_ARM_DMA_MEM_BUFFERABLE=y CONFIG_ARM_NR_BANKS=8 CONFIG_CPU_HAS_PMU=y CONFIG_MULTI_IRQ_HANDLER=y # CONFIG_ARM_ERRATA_430973 is not set # CONFIG_ARM_ERRATA_458693 is not set # CONFIG_ARM_ERRATA_460075 is not set CONFIG_PL310_ERRATA_588369=y CONFIG_ARM_ERRATA_720789=y CONFIG_PL310_ERRATA_727915=y CONFIG_ARM_ERRATA_743622=y CONFIG_ARM_ERRATA_751472=y CONFIG_PL310_ERRATA_753970=y CONFIG_ARM_ERRATA_754322=y CONFIG_PL310_ERRATA_769419=y # CONFIG_ARM_ERRATA_775420 is not set # CONFIG_FIQ_DEBUGGER is not set
在setup_processor中將cache相關操做函數賦給cpu_cache,同時還包括cpu_tld和cpu_user。
start_kernel--> setup_arch--> setup_processor--> static void __init setup_processor(void) { ... list = lookup_processor_type(read_cpuid_id()); ... processor = *list->proc; cpu_tlb = *list->tlb; cpu_user = *list->user; cpu_cache = *list->cache; ... }
內核對這些函數的使用又進行了封裝,同時對應底層彙編(以v7爲例)。在arch/arm/mm/proc-v7.S中實現了彙編函數。
extern struct cpu_cache_fns cpu_cache; #define __cpuc_flush_icache_all cpu_cache.flush_icache_all #define __cpuc_flush_kern_all cpu_cache.flush_kern_all #define __cpuc_flush_user_all cpu_cache.flush_user_all #define __cpuc_flush_user_range cpu_cache.flush_user_range #define __cpuc_coherent_kern_range cpu_cache.coherent_kern_range #define __cpuc_coherent_user_range cpu_cache.coherent_user_range #define __cpuc_flush_dcache_area cpu_cache.flush_kern_dcache_area /* * These are private to the dma-mapping API. Do not use directly. * Their sole purpose is to ensure that data held in the cache * is visible to DMA, or data written by DMA to system memory is * visible to the CPU. */ #define dmac_map_area cpu_cache.dma_map_area #define dmac_unmap_area cpu_cache.dma_unmap_area #define dmac_flush_range cpu_cache.dma_flush_range
TCM(Tighyly Coupled Memory,緊耦合內存)是一個固定大小的RAM,緊密地耦合至處理器內核,提供與cache至關的性能。
相比於cache的有點是,程序代碼能夠精確地控制什麼函數或什麼代碼放在哪兒。固然TCM永遠不會被踢出主存儲器,他會有一個用戶預設性能,而不是cache那樣是統計特性的提升。
TCM對於如下幾種狀況的代碼是很是有用、也是須要的:可預見的實時處理(中斷處理)、時間可預見(加密算法)、避免cache分析(加密算法)、或者只是要求高性能的代碼(編解碼功能)。
隨着cache大小的增長以及總線性能的規模,TCM將會變得愈來愈不重要,可是他提供了一個讓你權衡的機會。
再支持TCM的處理上,包含頭文件#include <asm/tcm.h>。
使用__tcmdata、__tcmconst、__tcmfunc、__tcmlocalfunc修飾符,將變量、函數放到特定的tcm段中。
還可使用tcm_alloc/tcm_free申請釋放內存。
延伸閱讀:
《對ARM緊緻內存TCM的理解》- 關於TCM的介紹,以及和Cache相比的優劣。
《內核中tcm(arm)與sram代碼》- 如何使用TCM。