计算机组成原理

参考链接

1.计算机的组成

计算机通常包括以下几部分:

  • 输入设备
  • 输出设备
  • CPU:运算器 + 控制器 + 寄存器 + Cache + MMU + TLB…
  • 总线:数据总线 + 地址总线 + 控制总线
  • 存储器

image-20240902185043231

2.存储器

存储器包含以下几种==类别==,不同类别的存储器单字节成本、访问速度都不同

  • 寄存器:CPU可直接访问、访问速度最快,差不多等于CPU的时钟周期
  • 高速缓冲存储器(Cache):CPU可直接访问,用于存放当前运行程序中的活跃部分,以便快速向CPU提供数据和指令,Cache又分为L1、L2、L3缓存,大小依次增大,速度依次减小
  • 主存储器:CPU可直接访问,广义上的运行内存(RAM),用于存放当前运行程序的数据和指令
  • 辅助存储器:CPU不可直接访问,用于存放当前暂时不用的程序的数据和指令,用到时再拷贝到RAM中

访问速度:

  • Cache:几百到上千GB/s
  • 内存:几十GB/s
  • 磁盘:几百MB/s
image-20240903150636778

3.CPU的运行原理

image-20240903153947085

CPU就包含3大部分:控制单元、运算单元和寄存器。运算单元只能访问寄存器里的数据,所以需要先把数据和指令从内存读取到寄存器中

CPU的运行可以概括为一句话:首先从内存中取出指令和数据,再在CPU内部执行指令,进行运算,运算完毕后再传回内存中

4.指令执行的步骤

  • 取指令:CPU的控制器根据指令计数器从内存中读取一条指令并放到指令寄存器里
  • 指令译码:译码指令寄存器里存放的指令,得到该指令进行什么操作、操作数的地址
  • 执行指令:分为“取操作数”和“执行运算”2个步骤
  • 修改指令计数器:决定下一条指令的地址
image-20240903154746864

5.流水线

CPU的流水线(Pipeline)是一种提高处理器执行效率的技术,将指令执行过程划分为多个阶段,并使多个指令在不同阶段之间并行执行,从而实现指令级并行

CPU流水线通常包括以下几个阶段:

  1. 取指(Instruction Fetch):从内存中获取下一条指令
  2. 译码(Instruction Decode):将指令解析成对应的操作码和操作数,并为执行阶段做准备
  3. 执行(Execute):执行指令的具体操作,如算术运算、逻辑运算等
  4. 访存(Memory Access):如果指令需要访问内存,这个阶段用于进行数据的读取或写入操作
  5. 写回(Write Back):将执行结果写回到寄存器中,更新寄存器的内容

每条指令在流水线中按顺序通过不同的阶段,形成一个连续的流水线操作。当一个指令完成当前阶段的操作后,就会进入下一阶段,同时下一条指令进入到当前阶段,从而实现指令的并行执行。

通过流水线技术,CPU可以实现更高的处理能力和更好的性能指标,因为在同一时钟周期内可以同时执行多个指令。然而,流水线也会引入一些问题,如流水线的阻塞、冲突和分支预测问题,可能导致流水线效率下降。为了解决这些问题,还可以采取一些技术手段,如超标量流水线、动态调度、乱序执行等。

ARM3级流水线步骤

  1. 取指
  2. 译码
  3. 执行

6.协处理器

ARM体系结构允许通过增加协处理器来扩展指令集,一般的协处理器是用于控制片上系统功能的,比如:控制Cache、MMU、中断向量表

  • 在程序运行的过程中,每个协处理器忽略属于ARM处理器和其他协处理器的指令
  • 当一个协处理器收到它不支持的指令时,会产生一个未定义的异常中断,但是在中断中可以通过软件模拟该硬件的操作

7.冯诺依曼和哈佛架构

  • 冯诺依曼架构:指令和数据不加区分的存储在存储器中,由同一组总线(地址总线、数据总线、控制总线)传输。优点是总线开销小,控制逻辑简单,缺点是执行效率低(多用于台式机和服务器)

  • 哈佛架构:指令和数据分开存储,优点是执行效率高,缺点是总线开销大,控制逻辑复杂(多用于MCU)

体系 冯诺依曼 哈佛 改进的哈佛(现代ARM)
数据与程序存储方式 存储在一起 分开存储 分开存储
CPU总线条数 1*(地址+数据) 2*(地址+数据) 1*(地址+数据)(新增cache,cpu由1条总线读cache,cache有2条总线)
取指操作与取数据操作 串行 并行,可预取指 并行,可预取指
缺点 成本低 成本高 综合
优点 执行效率低 效率高,流水线(取指、译码、执行) 同哈佛

image-20240903153107357

image-20240903153147919

我们之前用的CortexM系列的STM32、8051,其实是属于哈佛架构的,程序和数据分别存在了MCU中的Flash和RAM上

而Cortex A系列的Soc,或者PC上的CPU,一般都是改进哈佛架构的,在CPU外部,程序和数据都存在RAM中,但是在CPU内部又有iROM和iRAM,用于Soc启动时的引导

8.Cache

Cache(缓存)是CPU内部的一种用于临时存储数据的==高速存储器==,目的是减少处理器访问主内存的时间,提高计算机系统的整体性能。一般是SRAM。它位于==处理器和外部RAM之间==。通常,缓存存储着频繁访问的数据或指令,这样可以避免每次都从较慢的主内存中读取数据

Cache的作用

  • 提高性能:由于缓存是高速存储器,能够显著减少访问主内存的次数,从而提高计算机系统的执行效率
  • 降低延迟:访问缓存的数据通常比访问主内存的时间要短得多,这对于提升系统响应时间至关重要

Cache的工作原理

局部性原理:缓存利用程序访问数据时具有的局部性原理(时间局部性和空间局部性)。时间局部性意味着程序会重复访问最近使用的数据;空间局部性则是指访问某一数据后,附近的数据也有可能被访问。因此,缓存会将这些数据存储起来,方便之后的快速访问

Cache的层次结构

  • L1 Cache:通常位于处理器内核内部,存取速度最快,容量最小。每个处理器核心通常都有独立的L1缓存。又被分为I-Cache和D-Cache
  • L2 Cache:一般比L1大,速度稍慢,但仍然比主内存快
  • L3 Cache:通常比L2更大且更慢,多个处理器核心可能共享L3缓存

一般一个核内部最多有L1、L2Cache,L3Cache一般多个核共享

image-20250521091306900

Cache的物理结构

Cache实际上是由多个Cacheline组成的,Cacheline是CPU从缓存中读写数据的基本单位(一般是多个字节)也是缓存从内存中读取/写入数据的基本单位,它的结构如下:

1
2
| Tag (20~40 bits) | State (MESI) | Valid | Dirty | Data (512 bits = 64 Bytes) |
|------------------|--------------|-------|-------|----------------------------|
字段 位数 作用
数据块 64字节(举个例子) 存储从主存加载的实际数据
标记(Tag) 20~40位 标识该缓存行对应的主存物理地址的高位部分(用于匹配内存块)
状态位 2~4位 维护缓存一致性协议的状态(如 MESI 中的 Modified/Exclusive/Shared/Invalid)
有效位 1位 标记该缓存行是否包含有效数据(1=有效,0=无效),CPU能否使用
脏位 1位(可选) 标记数据是否被相对于内存中的有更新
仅写回策略需要,写直达策略不需要

Cache的组织方式

Q:假设我们主存中有32个块,而我们的cache一共有8个cacheline,那么我的第12块内存应该放到Cache中的哪个Cacheline呢?

缓存通过将内存地址划分为索引(Index)+ 标记(Tag)+ 偏移(Offset)字段来决定数据放到哪个Cacheline,具体分为三种映射方式:

1.直接映射(Direct mapped):

  • 每个主存块只能映射到缓存中唯一固定的位置(类似哈希表)
  • 易发生冲突(多个主存块竞争同一缓存行)

2.全相连(Fully associative):

  • 主存块可以放在cache的任何位置
  • 无冲突,但硬件成本高(需并行比较所有标记)

3.组相连(set associative):

  • 缓存分为多个组(Set),每组包含多个缓存行(Way)。主存块可映射到同一组内的任意行
1
2
组号 = (主存地址 / 缓存行大小) % 组数  
组内行选择:LRU(最近最少使用)或随机替换。

内存地址的划分

假设一个 32位内存地址64字节缓存行(Cache Line),可以通过如下方式划分内存地址:

1
2
| 31 ------------------------ 12 | 11 ----- 6 | 5 -- 0 |
| Tag (20位) | Index (6位) | Offset (6位) |
  • Offset(偏移):
    • 作用:定位缓存行内的具体字节
    • 位数:由缓存行大小决定
      • 若缓存行为 32字节,则 Offset 为 5位
  • Index(索引):
    • 作用:选择缓存中的组(组相联缓存)或直接映射的行(直接映射缓存)
    • 位数:由 缓存组数决定。
      • 例如:64组缓存 = 2^6=64 → 6位 Index
  • Tag(标记):
    • 作用:与Cacheline的Tag字段对比,来找到内存对应的Cache
    • 位数:剩余高位地址(32位地址 - Index - Offset)
      • 上例中:32 - 6 - 6 = 20位 Tag

根据映射时拆分的内存地址到底是物理地址还是虚拟地址,可以分为以下几类:

  • 物理索引物理标记(PIPT):
    • 缓存使用物理地址的 Tag|Index|Offset
    • 优点:无别名问题(多个虚拟地址映射同一物理地址时数据一致)
    • 缺点:需先查 TLB(页表)获取物理地址,延迟高
  • 虚拟索引虚拟标记(VIVT):
    • 缓存使用虚拟地址的 Tag|Index|Offset
    • 优点:无需 TLB,速度快
    • 缺点:别名问题(需操作系统处理,如页着色)
  • 虚拟索引物理标记(VIPT):
    • IndexOffset 用虚拟地址,Tag 用物理地址
    • 折中方案:常见于现代 CPU(如 ARM Cortex-A、Intel/AMD)

Cache替换策略

当缓存满时,需要决定哪些数据应该被替换掉以腾出空间。这通常通过替换策略来决定,如最近最少使用(LRU,Least Recently Used)、最不常用(LFU,Least Frequently Used)等

Cache的写入策略

当CPU执行sd指令即往内存中写数据的时候,首先需要对Cache进行写入操作,那Cache何时==把数据真正地写入内存==呢?此时Cache的行为也分为2个类型:

  • 写直达(Write-through):把数据同时写入Cache和内存

    • 如果数据已经在 Cache 里面,先将数据更新到 Cache 里面,再写入到内存里面
    • 如果数据没有在 Cache 里面,就直接把数据更新到内存里面,再写到Cache里
    • 问题:性能低
  • 写回(Write-back):当发生写操作时,新的数据仅仅被写入CacheLine里,只有当修改过的CacheLine「被替换」时才把数据写到内存中

    • 数据已经在 Cache 里面(Tag匹配上了)

      • 如果对应CacheLine的dity位=0,则不会写到内存里,只更新Cache里的数据,并更新dity位=1
      • 如果对应CacheLine的dity位=1,替换一个CacheLine,并将被替换的CacheLine的数据写回内存,新的数据还是不会写到内存
    • 数据没在 Cache 里面(组里所有Cacheline的Tag都不匹配)

      • 使用LRU等策略选择一个被替换的Cacheline进行写入,如果它的dirty=1,则将被替换的Cacheline的数据写回内存

缓存一致性问题

定义:在多处理器系统中,确保同一份数据在多个缓存(内存层次)中保持一致的机制。如果有人修改了这块数据,而其他设备的缓存还没更新,就会造成“数据不同步”问题,因此需要协议来维护一致性

缓存不一致的原因

  • 核间缓存不一致:现代 CPU 采用 多级缓存(L1/L2/L3) 结构,每个核心有独立的 L1/L2 缓存,共享 L3 缓存或主存。当某个核心修改了自己的缓存数据时,其他核心的缓存副本可能仍然是旧值。
  • DMA缓存不一致:此外,DMA会绕过CPU直接将外设中的数据写入内存,但CPU中的Cache并未更新,此时CPU可能也会读取到旧值

解决办法

核间缓存一致性

MESI协议是一种多核 CPU 间的缓存一致性协议,它通过 4 种缓存行状态和总线嗅探机制,确保所有核看到的内存数据始终一致

  • 总线嗅探机制:某个CPU核心更新了Cache中的数据后,会把该事件广播通过总线通知到其他核心,并且实现了事务串行化
  • MESI只用于CPU和CPU之间,不管DMA
  • MESI是CPU硬件级的缓存一致性协议,由CPU内部的Cache控制器在总线层自动完成。驱动开发者不需要实现MESI,但需要理解它的原理

1.Cacheline的状态

状态 含义 说明
M (Modified) 已修改 缓存行被修改,和内存不一致(只有本核有,脏数据)
E (Exclusive) 独占 缓存行未修改,和内存一致(只有本核有,干净数据)
S (Shared) 共享 缓存行未修改,和内存一致(多个核都可以有副本)
I (Invalid) 无效 缓存行无效(不能用)

基本思想:

在系统中,任意时刻,同一个物理地址的数据:

  • 要么只存在于一个cache,并处于”已修改”或”独占”状态
  • 要么存在于多个cache,并处于”共享”状态
  • 不可能同时既”已修改”又”共享”(防止不一致)

2.总线事务

多个 CPU 核心共享一条总线。当一个 CPU对cache miss的数据发起访问时,它通过总线发出“请求事务”。其他核通过嗅探(Snooping)监听这些事务,并更新自己的 cache 状态。这就是 MESI 的通信机制

MESI协议定义了以下总线事务

名称 全称 触发原因 作用
BusRd Bus Read cache miss(读) 请求读取一行数据
BusRdX Bus Read Exclusive cache miss(写) 请求读取并获得写权限
BusUpgr Bus Upgrade 当前有该行(S),想写 请求使其他副本失效
BusWB Bus Write Back 驱逐 M 行 把脏数据写回内存

3.状态转换机制:

(1)读操作

  • cache hit,且此cacheline是M/E/S状态

    • 直接读
  • cache miss → 发总线事务(BusRd)

    • 别的核已缓存该数据:
      • 若它是 M:先写回内存(BusWB),然后变为 S
      • 若它是 E/S:保持 S,并返回数据
      • 本 CPU 拿到数据,也设为 S
    • 别的核都没有缓存该数据:
      • 内存相应BusRd,取出数据 → 状态为E

(2)写操作

  • cache hit
    • 若本核状态是M:直接写,不发总线事务
    • 若状态是E :升级为M,本地写,不发总线事务
    • 若状态是S → 发出BusUpgr,使其他核对应 cache line 变为 I,然后本地cacheline更新为M,数据写入
  • cache miss
    • 发BusRdX(读并独占写权限),其他 cache 嗅探后,若持有该行(M/E/S),都变为 I,内存或其他核返回数据,本 cache 状态设为M,数据写入

(3)驱除

当 cache 满了,需要替换行:

  • 若该行是 M:发BusWB写回内存
  • 若是 E/S:直接丢弃(因为干净)
  • 若是 I:直接覆盖
DMA缓存一致性
场景 问题 解决方法
CPU 写 → DMA 读 DMA 读到旧数据 CPU 需写回缓存 (flush)
DMA 写 → CPU 读 CPU 读到旧数据 CPU 需无效化缓存 (invalidate)
  • DMA从外设–>内存:当DMA将数据写入内存后,CPU需要无效化(Invalidate)相关缓存行,确保后续读取时从主存加载最新数据
  • 现代CPU缓存控制器会自动检测并无效化相关Cacheline
  • 如果不支持硬件自动无效化缓存,需要手动通过一些汇编代码无效化相关Cacheline
  • DMA从内存–>外设:当CPU写入数据后,可能发生Cache更新了但内存还未更新的情况,此时用DMA把内存中的数据写到外设,可能写的是旧数据,因此需要刷回(Flush)Cacheline到主存

在驱动开发时,Linux内核在DMA框架里已经提供了一整套机制来维护缓存一致性

操作 作用 常用函数
分配一致性内存 内核保证 CPU/DMA 一致 dma_alloc_coherent()
映射/同步 DMA buffer 手动管理缓存 dma_map_single() / dma_sync_single_for_cpu() / dma_sync_single_for_device()

1.一致性内存:使用如下API分配,此内存位于内核空间的DMA映射区。内核通过禁用cache等机制维护缓存一致性,不需要手动 flush / invalidate

1
void *dma_buf = dma_alloc_coherent(dev, size, &dma_handle, GFP_KERNEL);
  • 这个API的重点是缓存一致性,不一定保证分配的内存的物理地址是连续的(在有IOMMU的平台下)
  • 底层立即调用alloc_pages不会Lazy Allocation

不同架构的 CPU 和 DMA 控制器可能有==不同的==缓存一致性处理方式

X86架构:通常通过禁用Cache来保证一致性的

  • CPU cache不会缓存该区域的内存,所以每次都直接从DDR读取,DMA控制器也直接从DDR读取该数据
  • 缺点:没法用Cache,每次访问都是直接读DDR,效率比较低

ARM架构:

  • 内核自动调用flush/invalidate Cache以及内存屏障相关的API,来保证缓存一致性

2.非一致性内存:通过dma_map_single手动映射成DMA buffer的内存属于非一致性内存,内核不会自动保证缓存同步,需要在数据方向改变时手动刷新或失效缓存

1
2
3
4
5
// CPU→DMA前, flush cache
dma_sync_single_for_device(dev, dma_handle, size, DMA_TO_DEVICE);

// DMA→CPU后, invalidate cache
dma_sync_single_for_cpu(dev, dma_handle, size, DMA_FROM_DEVICE);
  • 这2个API底层都是调用了和cache相关的汇编指令

参考链接

面试问题

1.二维数组是逐行读取快还是逐列读取快?为什么

  • 哪种读法快取决于该语言中2维数组在内存中怎么存的。以C为例,二维数组在内存中是以行优先的方式存放的,同一行相邻元素在内存中是连续的,由于CPU每次从内存中读数据都是以Cacheline为单位,即一次会读多个字节的内容到Cache中,所以当我们访问a[i][j]时,该行的后面多个元素a[i][j+n]都会被加载到缓存中,后边访问就比较快了。所以针对C/C++,逐行读取快

2.如何提高cache命中率

3.多核的Cache问题怎么处理?

  • 硬件层面:使用缓存一致性协议(如MESI)
  • 软件层面:内存屏障、原子操作

4.如何解决核内缓存一致性:

  • 最直观的方式就是flush/invalidate缓存
  • Linux为我们提供了个API(dma_alloc_coherent),通过在内核空间的直接映射区分配连续内存,并且使用这块内存时关闭cache,从而避免缓存一致性问题

5.什么是Cache一致性问题

  • 在多核CPU系统中,由于每个核心都有自己的缓存,同一数据可能在多个缓存中存在副本。当某个核心修改了自己的缓存数据时,其他核心的缓存副本可能仍然是旧值,导致数据不一致
  • 在使用了DMA时,DMA直接修改内存中的数据,而没有更新缓存,CPU从缓存中读取数据,这也会导致数据不一致

9.MMU

MMU(Memory Management Unit,内存管理单元)是CPU中用于管理虚拟内存和物理内存之间映射的硬件组件。它的核心功能是将程序访问的虚拟地址转换为实际的物理地址,同时进行内存保护、分页(或分段)等操作。

image-20250522091744316

MMU的物理结构

MMU内部主要包含2个组件:

  • TLB:一个高速缓存,用于缓存页表转换的结果,从而缩短页表查询的时间
  • TWU:一个页表遍历模块,页表是由操作系统维护在物理内存中,但是页表的==遍历查询是由TWU完成==的,这样减少对CPU资源的消耗

MMU的主要功能

  1. 虚拟地址到物理地址的转换
    • 虚拟内存:现代操作系统使用虚拟内存技术,将程序的地址空间与物理内存分离。每个程序认为自己有独立的内存空间,这种空间称为虚拟地址空间
    • 地址转换:当程序访问某个虚拟地址时,MMU会将该虚拟地址转换为相应的物理地址。这个过程通常通过查阅页表(Page Table)来完成,页表存储了虚拟地址与物理地址的映射关系
  2. 内存保护: MMU可以为不同的进程提供内存隔离,防止一个进程非法访问另一个进程的内存空间。例如,可以设置特定区域的内存为只读或禁止访问,从而增强系统的稳定性和安全性
  3. 分页管理
    • 分页(Paging)是将虚拟地址空间划分为固定大小的块,称为(Page),而物理内存则被划分为同样大小的块,称为页框(Page Frame)
    • MMU会使用一个页表(Page Table)来管理虚拟页和物理页之间的映射关系。每当程序访问一个虚拟地址时,MMU通过查阅页表,将虚拟地址转换为物理地址
    • 当虚拟地址需要访问的页不在物理内存中/物理页被置换/权限不对时,会发生页面错误(Page Fault),操作系统会将数据从硬盘调入内存。
  4. 缓存管理: 为了提高虚拟地址到物理地址转换的效率,现代MMU通常配备了TLB(Translation Lookaside Buffer,翻译后备缓冲区),它是MMU内的一个高速缓存,用于存储最近使用的虚拟地址到物理地址的映射。通过查阅TLB,MMU能够更快地完成地址转换
  5. 分段管理(可选): 除了分页外,MMU还可以支持分段(Segmentation)机制。分段将内存划分为==大小不等==的块(段),每个段有自己的基地址和长度。程序访问某一段时,MMU根据段号和偏移量进行转换。分段可以用于更灵活的内存管理,特别是在需要支持不同类型内存区(如代码段、数据段、堆栈段等)的情况下。

MMU的工作原理

MMU是一个硬件,它对于内存的映射都是自动的,只要通过设置对应的控制寄存器就能开启MMU,在设置了其页表地址的寄存器后,再访问内存地址时,他就会自动的根据页表来把虚拟地址翻译成物理地址。且在进程切换时,也要修改对应的寄存器来切换页表

页表是就是个保存了va–>pa映射关系的一个数组,它由OS内核维护,每个PCB都有一个独立的页表

MMU的工作流程

  1. 程序发出对某个虚拟地址的访问请求
  2. MMU接收到虚拟地址,并查阅TLB来检查该虚拟地址是否有对应的物理地址映射
    • 如果TLB命中,MMU直接使用该映射地址进行访问
    • 如果TLB未命中,MMU查阅页表来找到虚拟地址对应的物理地址,并将该映射加载到TLB中,以备后续使用
  3. 当 CPU 访问一个虚拟地址时,若其对应的页表项(PTE)中不存在有效的物理地址映射(或权限不足),则会触发 Page Fault,操作系统将从硬盘加载相应的页面到内存

MMU的地址转换机制

MMU的地址转换过程通常是通过多级页表虚拟地址的分段来实现的

虚拟地址通常分为以下几部分:

  • 页目录索引(Page Directory Index)
  • 页表索引(Page Table Index)
  • 页内偏移(Page Offset)

参考链接

面试问题

1.说下CPU访问内存过程

  • 首先看TLB缓存是否命中。命中的话直接使用TLB中的映射地址进行访问
  • 若TLB未命中,CPU会发出请求,请求MMU进行地址转换,MMU会先检查页表是否有该虚拟地址的映射,如果有,MMU会将该映射加载到TLB中,以备后续使用
  • 如果页表中没有该映射,MMU会发出Page Fault,操作系统会将数据从硬盘调入内存,然后再将该映射加载到TLB中,以备后续使用

2.有没有操作过MMU

  • XV6开发中操纵RISC-V的satp寄存器,修改页表基址、几级页表
  • 切换页表是使用sfence.vma指令,刷新TLB缓存

3.知道MMU吗?

4.如何快速的去操作内存地址?

  • 减少内存访问次数:用批量访问代替逐字节访问
  • 提高缓存命中率
  • 使用内存池,避免频繁分配内存

5.MMU实现内存地址映射的原理

  • 以RISC-V的sv39分页机制为例,对于RV64来说,虽然一个地址有64位,但只有低39位有效,这39为又可看成4部分,高27位分别是L0、L1、L2级page directory中PTE的索引,低12位为页内偏移,在进行地址转换时,首先将当前进程的页目录基址装载到satp寄存器,然后进行TWU,经过多级页表,找到最后的PTE,里面存了相应的物理页号,再加上页内偏移,得到物理地址,完成地址转换

6.什么是IOMMU

  • IOMMU是集成在 SoC 系统互连中的硬件单元,它位于外设(如 GPU、网卡)和主内存之间。它的核心功能是为设备发起的 DMA 操作提供地址转换(将设备虚拟地址 IOVA 映射为物理地址 PA),从而实现内存保护、隔离(防止恶意 DMA 访问)和 I/O 虚拟化(让虚拟机安全使用物理设备)

10.TLB

TLB(Translation Lookaside Buffer,翻译后备缓冲区)是一种高速缓存,用于加速虚拟地址到物理地址的转换。注意:==TLB是MMU内部的一个组件==

TLB的作用

缓存最近使用的虚拟地址到物理地址的映射。通过缓存这些映射,TLB可以减少每次访问内存时MMU查找页表的时间,从而加速内存访问

TLB的工作原理

当CPU发出对虚拟地址的访问请求时,TLB会首先检查这个虚拟地址是否已经在缓存中

  1. TLB命中:如果TLB中已有该虚拟地址的映射,MMU可以直接使用该物理地址进行内存访问,无需查找页表
  2. TLB未命中:如果TLB中没有该映射,MMU会查找页表获取虚拟地址到物理地址的映射,并将该映射加载到TLB中,以便后续使用

TLB的结构

TLB中的每一条条目包含以下信息:

  • 虚拟页号(VPN):虚拟地址中的一部分,用于在页表中查找对应的物理地址
  • 物理页号(PPN):物理地址中的一部分,表示内存中的位置
  • 有效位(Valid bit):标记该条目是否有效,无效条目可能会被替换
  • 权限位:如只读、可执行、用户/内核模式等
  • 标记位:标记该映射是否已被修改,或者用于其他一些标志

TLB的类型

  1. 一级TLB(L1 TLB):直接集成在CPU核心内部,通常较小,但速度非常快。每个CPU核心通常有自己的L1 TLB
  2. 二级TLB(L2 TLB):在一些处理器中,L2 TLB用于多个核心共享,容量比L1 TLB大一些,但访问速度稍慢。通常用于存储更大范围的虚拟地址到物理地址的映射
  3. 多级TLB:一些高级处理器可能具有多个级别的TLB,比如L1和L2共享部分地址映射,而L3可能用于更广泛的映射

TLB的替换策略

当TLB缓存满时,需要选择一个条目进行替换。常见的替换策略包括:

  • LRU(Least Recently Used):替换最近最少使用的条目
  • FIFO(First In First Out):替换最早加载的条目
  • 随机替换:随机选择一个条目进行替换

TLB一致性问题

在多核处理器系统中,每个核心可能会有自己的TLB。如果一个核心更新了虚拟地址到物理地址的映射,其他核心的TLB可能会变得过时,导致一致性问题。为了避免这种情况,现代处理器通常会采用TLB一致性协议来确保各个核心的TLB保持同步

11.总线

总线是计算机系统中用于在不同硬件组件(如CPU、内存、外设等)之间传输数据、地址和控制信号的通道(物理上来看就是电路板上的几根线,由于这几根线是个整体,所以叫总线)。它是系统内部各个部件之间通信的基础设施。总线设计的好坏直接影响系统的性能和稳定性

总线的组成

总线通常由多个信号线组成,每一条信号线承担不同的功能,一种总线由以下部分组成:

  • 数据总线:用于传输数据,数据总线的宽度(即信号线的数量)决定了每次传输的数据量,通常为8位、16位、32位或64位
  • 地址总线:用于传输内存地址或外设的地址。地址总线的宽度决定了系统能够访问的内存空间的大小。例如,32位地址总线可以寻址2^32个内存地址(即4GB内存)
  • 控制总线:用于传输控制信号,协调各个硬件部件的工作。例如,控制信号可以指示内存是否需要读取或写入数据,或者表示数据的方向(从CPU到内存还是从内存到CPU)

总线的工作原理

总线的工作原理依赖于计算机系统中不同组件之间的协调。具体来说,数据传输过程通常包括以下几个步骤:

  1. 发起传输请求:当CPU需要从内存读取数据或向内存写入数据时,它通过控制总线发起传输请求
  2. 地址传输:CPU将目标地址传送到地址总线上,标明要访问的内存位置或外设地址
  3. 数据传输:数据通过数据总线传输到目标组件,数据总线将存储在寄存器中的数据传输到内存或外设,反之亦然
  4. 控制信号:控制总线发送信号来确保数据传输的正确性,如控制读/写操作、数据传输的方向等

总线的带宽与速度

总线的带宽(即每秒钟能传输的数据量)和速度(即数据传输的速度)是两个重要的性能指标。总线带宽通常与总线的位宽和时钟频率相关:

  • 位宽:总线的位宽决定了每次数据传输的比特数,例如,32位总线每次能传输32个比特的数据
  • 时钟频率:总线的时钟频率越高,单位时间内传输的数据量越大,从而提高总线的传输速度

例如,PCI Express(PCIe)是一种高速的串行总线标准,具有较高的带宽和速度,可以支持多个设备并行通信

常见的总线类型

  1. PCI/PCI Express(PCIe):广泛用于计算机主板中,用于连接各种扩展卡(如显卡、网卡、硬盘控制器等)。PCIe采用串行传输,支持高带宽,且逐渐取代了传统的PCI总线
  2. USB:主要用于连接外设,如鼠标、键盘、打印机、硬盘等。USB支持热插拔,并提供电力给设备,具有较强的扩展性
  3. SATA(串行ATA):主要用于连接硬盘、光驱等存储设备,采用串行传输,速度相较于并行ATA有显著提升
  4. I2C/SPI:用于连接低速外设,如传感器、显示器等。I2C是串行的双线总线,而SPI支持高速的数据传输,常用于嵌入式系统
  5. AHB/APB/AXI:是AMBA总线标准中的一些总线,用于SoC内部各种硬件(CPU、DMA、各种外设间)的连接

12.DMA

DMA(Direct Memory Access)是用于高效数据传输的一种技术,能够实现外设和内存之间直接交换数据,而无需CPU干预,它通常以独立的控制器存在。DMA不仅减轻了CPU负担,提高了数据传输效率,还能在数据传输过程中保持CPU的并行计算能力,适用于大数据量、高带宽的应用场景

DMA的工作模式

DMA有几种常见的传输模式,具体方式取决于传输的源和目标设备以及数据的传输方向:

  1. 内存到内存
    • 数据从一个内存位置传输到另一个内存位置
    • 通常用于大数据块的移动,如从一个缓冲区复制数据到另一个缓冲区
  2. 外设到内存
    • 数据从外设(例如传感器、ADC)传输到内存
    • 比如一个传感器的测量结果可以直接写入内存供后续处理
  3. 内存到外设
    • 数据从内存传输到外设
    • 比如,将数据从内存直接写入到输出设备(如DAC、显示器)
  4. 外设到外设
    • 数据从一个外设传输到另一个外设
    • 比如在某些设备之间直接传输数据,而不通过内存(例如数据采集系统中,数据直接从一个外设转移到另一个外设)

DMA控制器的工作流程

  1. 请求:外设发起DMA请求,告诉DMA控制器需要进行数据传输
  2. 授予:DMA控制器检查是否可以访问总线如果没有其他设备正在使用总线,则控制器将授予DMA传输权限
  3. 传输:DMA控制器执行数据传输过程,直接在内存与外设之间传输数据
  4. 完成:传输完成后,DMA控制器会生成中断信号通知CPU此时,CPU可以处理传输后的数据

DMA的优势

  • 减轻CPU负担:CPU可以将时间集中在计算和其他任务上,而不需要管理低效的数据传输操作
  • 并行处理:DMA可以与CPU并行工作,CPU和DMA可以在同一时刻执行不同的任务,从而提高系统效率
  • 高效传输:在大规模数据传输(如音视频流、网络传输等)中,DMA的效率要比传统的CPU控制的方式高得多

DMA的缺点

  • 硬件需求:需要专门的DMA控制器,有时这可能增加硬件设计的复杂度和成本
  • 可能的冲突:DMA控制器直接访问内存时,可能会与CPU访问内存发生冲突,特别是在高频繁数据访问的情况下。现代系统通过总线仲裁来解决这个问题
  • 中断管理复杂:DMA传输完毕后需要通过中断通知CPU,这可能会带来中断处理的开销,尤其在高频率的传输中

DMA的实际应用

  • 音视频数据传输:DMA常用于音视频设备中,大数据的传输速度要求非常高,CPU不可能直接参与每个数据的传输,因此使用DMA可以让外设与内存之间高效交换数据
  • 网络数据传输:在网络芯片与内存之间的数据交换中,DMA大幅度提升了吞吐量
  • 存储设备:如硬盘、固态硬盘(SSD)等设备的数据传输,也通常使用DMA来提升性能
  • 嵌入式系统:在一些传感器数据读取、显示驱动等任务中,DMA也被广泛应用

面试题

1.有解决过CPU和DMA的问题吗?

  • 回答解决使用DMA引入的缓存一致性问题

2.DMA使用的内存如何分配

  • DMA必须使用连续的内存,所以得用kalloc()或者dma_alloc_coherent()分配,不能用vmalloc()分配
  • kalloc()分配的内存时,要手动处理缓存一致性问题

13.IOMMU

IOMMU(Input–Output Memory Management Unit,输入输出内存管理单元)是一个专门用于外设(DMA 设备)的 地址转换与保护单元。它在现代操作系统和硬件平台中扮演着类似于 CPU MMU 的角色,但作用对象是外设的DMA访问

作用

功能 说明
地址转换(DMA remapping) 将外设发出的 DMA 虚拟地址(IOVA, I/O Virtual Address)转换为物理内存地址。设备可以使用 IOVA,就像 CPU 使用虚拟地址一样
隔离保护 防止外设访问不属于自己的内存区域,类似于 CPU 的内存保护,增强系统安全
支持虚拟化 在虚拟机环境中,IOMMU 可以让多个虚拟机安全地共享物理设备,同时每个虚拟机看到的 DMA 地址是虚拟化后的地址
扩展 DMA 能力 支持 64 位 DMA 地址、打破物理连续性限制;设备不再必须访问物理连续内存
  • 打破物理连续性限制

    • 没有 IOMMU 时,设备进行 DMA 访问时必须访问物理连续内存,这在大内存、碎片化严重的系统中很难保证

    • 有了 IOMMU,设备可以访问 不连续物理页,IOMMU 会把连续的 IOVA 映射到实际的物理页

  • 增加安全性

    • 防止 DMA 攻击(恶意设备或驱动访问任意内存)

    • 通过 IOMMU,可以只允许设备访问指定的内存区域

  • 支持虚拟化

    • 虚拟机中的设备可以访问 DMA 虚拟地址

    • IOMMU 将这些地址映射到宿主机的物理内存,实现 DMA 隔离

工作原理

  • 设备发出 DMA 请求,提供 IOVA(类似虚拟地址)
  • IOMMU 查 页表,将 IOVA 转换为实际物理地址
  • DMA 控制器通过物理总线访问物理内存
  • CPU 也可以通过内核提供的接口管理 IOMMU 表