ARM ASID/VMID 编程接口

简介: 提问一般来说,我们使用ASID来标识进程的ID, 使用VMID来标识虚拟机ID,那么具体CPU/加速器/PCIe发起的一次操作,如何从硬件角度识别,并透传到后续模块呢?即如何标识不同的流?软硬件的编程接口是如何配合的?CPU视角ASID 首先,站在CPU视角,CPU通过TTBR0/TTBR1来控制不同EL等级下的内存域。当CPU下发操作的时候,通过访问地址的VA,确定当前应该使用TTBR0还是TT

提问

一般来说,我们使用ASID来标识进程的ID, 使用VMID来标识虚拟机ID,那么具体CPU/加速器/PCIe发起的一次操作,如何从硬件角度识别,并透传到后续模块呢?即如何标识不同的流?软硬件的编程接口是如何配合的?


CPU视角

ASID 

首先,站在CPU视角,CPU通过TTBR0/TTBR1来控制不同EL等级下的内存域。当CPU下发操作的时候,通过访问地址的VA,确定当前应该使用TTBR0还是TTBR1:

简而言之,换做Linux,TTBR0管用户态,TTBR1管内核态(包括EL2),无论哪个level的TTBR寄存器,基本的组成形式如下:

其中寄存器域63-48合计16个bit标识ASID(这里存在一个卷绕的问题,内核巧妙的进行了处理)。

通过TTBR寄存器,可以识别不同的进程使用的页表,也就是说页表信息跟随进程绑定,我们在内核的task_struct里面可以看到这一点:

struct task_struct {
	...
  struct mm_struct                *mm;
	struct mm_struct                *active_mm;
	...
}

在进程切换的时候,我们可以看到ASID的切换:

因此ASID通过页表,TTBR,task_struct全部串联起来。


VMID

如果在虚拟化场景,多个虚拟机之间的ASID可能存在一样的情况,这个时候,系统主要通过VMID区分两者。

在ARM SPEC中,VMID主要设置于:

那么多个虚拟机之间的流怎么区分呢?

虚拟化场景下,CPU发出的请求是需要通过VA->IPA->PA的过程,在VA->IPA 的时候不需要关心VMID,因为此时在虚拟机内部,当IPA到PA的时候,就需要通过VTTBR获取VMID,从而标识这条流的ASID以及VMID。

因此VMID只有在虚拟机切换的时候会需要进行装载,因此在内核代码中,我们可以看到:

__kvm_vcpu_run->__kvm_vcpu_run_vhe->__load_guest_stage2

因此,Linux将ASID跟task_struct进程绑定,VMID跟kvm_vcpu 虚拟机绑定,完成了CPU 侧的stream id的编程。


IO视角

IO视角其实与CPU非常一致,可以将PCIe设备当成一个CPU来处理,传统的DMA编程模型下,如果CPU填充PCIe的是PA,此时SMMU要么是关闭,要么是直接透传。

在关闭的情况下,设备发出的请求是没有携带标识的(除非在出口处做了处理),在透传的情况下,相当于进行了stage1的转换。

在SMMU的spec中,使用了类似ASID以及VMID的标识来区分不同等级的流,即STREAMID,SUBSTREAMID(PCIe体系中,命名为RequesterID和PASID)。

当只进行了一级的转换,只需要给转换的流携带STREAMID即可,而SUBSTREAMID在stage2的时候使用,目前看到的场景,仅在虚拟化中使用SVA可能会使用到。

pasid同样在结构体mm_struct中定义:

那么在虚拟机中的设备如何绑定某个进程的呢?(因为SVM跟进程相关,不同进程使用的地址空间不一样)

首先,进程 DMA前会通过bind,将进程地址空间跟设备绑定起来:

其次,会通sva_bind分配一个pasid给对应的进程:

注意,iommu_bond这个结构并不对外, 用iommu_sva_bind_device/unbind接口时,函数参数都是mm_struct(进程地址空间)。使用SVA的设备可以把一个设备的一些资源和一个进程地址空间绑定,这种绑定关系是灵活的,比如可以一个设备上的不同资源和不用的进程地址空间绑定(bond 1, bond 2),还可以同一个设备上的资源都绑定在一个进程的地址空间上(bond 3,bond 4)。从进程地址空间的角度看,一个进程地址空间可能和多个设备资源绑定。iommu_bond指的就是一个绑定,io_mm指的是绑定了外设资源的一个进程地址空间。io_pgtables是指内核dma接口申请内存的页表。

              ___________________________
             |  IOMMU domain A           |
             |  ________________         |
             | |  IOMMU group   |        +------- io_pgtables
             | |                |        |
             | |   dev 00:00.0 ----+------- bond 1 --- io_mm X
             | |________________|   \    |
             |                       '----- bond 2 ---.
             |___________________________|             \
              ___________________________               \
             |  IOMMU domain B           |             io_mm Y
             |  ________________         |             / /
             | |  IOMMU group   |        |            / /
             | |                |        |           / /
             | |   dev 00:01.0 ------------ bond 3 -' /
             | |   dev 00:01.1 ------------ bond 4 --'
             | |________________|        |
             |                           +------- io_pgtables
             |___________________________|

                                PASID tables
                                 of domain A
                              .->+--------+
                             / 0 |        |-------> io_pgtable
                            /    +--------+
            Device tables  /   1 |        |-------> pgd X
              +--------+  /      +--------+
      00:00.0 |      A |-'     2 |        |--.
              +--------+         +--------+   \
              :        :       3 |        |    \
              +--------+         +--------+     --> pgd Y
      00:01.0 |      B |--.                    /
              +--------+   \                  |
      00:01.1 |      B |----+   PASID tables  |
              +--------+     \   of domain B  |
                              '->+--------+   |
                               0 |        |-- | --> io_pgtable
                                 +--------+   |
                               1 |        |   |
                                 +--------+   |
                               2 |        |---'
                                 +--------+
                               3 |        |
                                 +--------+

需要使用SVA特性的社区驱动在调用上面的接口后,可以建立起静态的数据结构。

至此,所有关系都已经建立完成。

目录
相关文章
|
6月前
|
存储 缓存 物联网
DP读书:鲲鹏处理器 架构与编程(二)服务器与处理器——高性能处理器的并行组织结构、ARM处理器
DP读书:鲲鹏处理器 架构与编程(二)服务器与处理器——高性能处理器的并行组织结构、ARM处理器
324 0
|
Linux C++ 流计算
基于ARM_contexA9 led驱动编程
基于ARM_contexA9 led驱动编程
68 0
|
IDE Linux 编译器
ARM架构与编程(基于I.MX6ULL): keil_gcc_Makefile(八)(上)
ARM架构与编程(基于I.MX6ULL): keil_gcc_Makefile(八)
377 1
ARM架构与编程(基于I.MX6ULL): keil_gcc_Makefile(八)(上)
|
芯片 数据格式
ARM架构与编程(基于I.MX6ULL): 串口UART编程(七)(下)
ARM架构与编程(基于I.MX6ULL): 串口UART编程(七)
314 1
ARM架构与编程(基于I.MX6ULL): 串口UART编程(七)(下)
|
定位技术 芯片
ARM架构与编程(基于I.MX6ULL): 串口UART编程(七)(上)
ARM架构与编程(基于I.MX6ULL): 串口UART编程(七)
269 1
ARM架构与编程(基于I.MX6ULL): 串口UART编程(七)(上)
|
算法
嵌入式ARM设计编程(五) 实现信号的FIR滤波操作
嵌入式ARM设计编程(五) 实现信号的FIR滤波操作
101 0
嵌入式ARM设计编程(五) 实现信号的FIR滤波操作
|
C语言 芯片
ARM架构与编程--基于STM32F103 (1)LED原理图
当我们学习C语言的时候,我们会写个Hello程序。那当我们写ARM程序,也该有一个简单的程序引领我们入门,这个程序就是点亮LED。 我们怎样去点亮一个LED呢? 分为三步: 1.看原理图,确定控制LED的引脚; 2.看主芯片的芯片手册,确定如何设置控制这个引脚; 3.写程序;
162 0
|
算法 C语言
嵌入式ARM设计编程(四) ARM启动过程控制
嵌入式ARM设计编程(四) ARM启动过程控制
159 0
嵌入式ARM设计编程(四) ARM启动过程控制
|
存储 算法
嵌入式ARM设计编程(三) 处理器工作模式
嵌入式ARM设计编程(三) 处理器工作模式
111 0
嵌入式ARM设计编程(三) 处理器工作模式
|
存储 算法
嵌入式ARM设计编程(二) 字符串拷贝
嵌入式ARM设计编程(二) 字符串拷贝
111 0
嵌入式ARM设计编程(二) 字符串拷贝