Xilinx AMP多核异构原理以及RPU开发以及RPU源代码分析(1)

xilinx AMP多核异构原理以及RPU开发以及RPU源代码分析

author:Swing

date:2024/1/4

前言

​ 本文所有内容由自己语言简述,我认为这是一种自己的理解过程,并且在一些问题的论述上需要不断的去查询相关资料。希望某些人尊重劳动成果,转载标明出处。

​ 可能在本文中会有错误,欢迎大家指出,有偿感谢费用(奶茶钱)。本文所使用的主控为zu7ev。

​ 参考文档:

​ 1:Straight Line Speculation Vulnerability • Libmetal and OpenAMP User Guide (UG1186) • 阅读器 • AMD 自适应计算文档门户 (xilinx.com)

​ 2:OpenAMP Base Hardware Configurations - Xilinx Wiki - Confluence (atlassian.net)

1. AMP相关

1.1. 介绍

​ AMP在芯片领域,一般指:非对称多处理(Asymmetric Multiprocessing)。既然有非对称,那就有对称多处理(SMP)。经常听说遥遥领先的麒麟9000是泰山架构,拥有多少个大核加上多少个小核,这也属于一种多核异构。

​ SMP:指所有的核心都拥有相同的性能以及处理能力,能处理其他核心能处理的任务。他们可以共享内存和性能。

​ AMP:指处理器核心有不相同的性能,不同的处理器拥有不同的功能,他可以处理不同类型的任务。

1.2. 用途

​ 目前控制类领域国产芯片有流行的大核+小核组合,大核跑Linux系统,小核跑裸机或者跑实时系统,通过内存共享的当时进行通信。例如:豪威的SOC,君正的x2000,还有全志的mips架构的SOC,CanMV-K230等等。为了实时性,小核直接处理对实时性要求高的任务。

​ 优点:不需要像以前一样,电路上一个SOC再加上单片机的组合,降低了物料上的成本。

​ 缺点:若芯片厂商在这类开发没有给出详细的说明,下游的厂商开发难度会增大。

2. Xilinx AMP介绍

2.1. zu7ev介绍

image-20240104172810681

​ 这个为主控芯片的总体框图,拥有4个cortex-a53 + 2个cortex-r5 处理核心(硬核)。Xilinx官方适配了openamp和libmetal两种remote框架。R核的程序使用赛灵思的Vitis IDE进行开发,通过编译后的elf文件烧录到指定的内存,然后去启动他。启动R核原理主要去使能R核的控制器,并将R核的PC,SP指针指向启动的内存。

2.2. openamp介绍

本文使用openamp框架,是一个开源的远程控制子系统(rproc),属于协处理器的一个驱动程序。(下图来源于Xilinx UG1186)

image-20240104174108214

openamp可以从Linux的内核空间与R核裸机交互,也可以从Linux的用户空间与R核裸机交互,他们通讯的最主要手段是 内存共享(IPC: Shared Memory)和核间中断(IPC: Interrupts)。在Xilinx的维基百科上有详细的介绍对这一方面。

2.3. 内存分区

​ ZYNQ的PS端,实际上R核和A53都存在于PS端内,只是R核没有参与Linux系统的CPU调度。一般R核程序运行的内存分区是写死的,因为R核跑另外一个裸机或者操作系统,需要bootload,以及通过链接脚本文件的指定内存端,例如bss,code,text端等。之前我在想是不是可以在Linux通过动态内存申请的方式,然后再映射的方式得到物理地址,但是这样的话每次申请都需要把R核的链接文件重新修改,在开发上面会非常麻烦。并且在内存高负载的情况下,在Linux上的动态内存管理可能会出现意想不到的问题。

​ 以下为ZYNQ的内存分区情况,可以在Linux下通过看/proc/iomem的RAM分区情况。

cat /proc/iomem

image-20240108105605202

所以可以得出ZYNQMP的大致分区为:

image-20240108141933283

R核的内存区域是可以通过在设备树上指定划出一片分区出来。在设备树上划出来的reserved也属于system ram

3. 使用方法

3.1. RPU 方面

​ RPU的程序是可以通过petalinux编译出来,也可以用xilinx vitis编译出来。通过编译后的elf文件,写入指定的内存并赋值给RPU的PC指针到指定的内存地址并使能运行。注意:这里的Cortex-R5是一个32位的核心,并不是64位的核心。所以RPU的寄存器寻址范围是(2^32): 0 ~ 0xffffffff。本文使用vitis的方式编译,因为用petalinux编译你得手动重新编写Makefile,费时费力不讨好效率低的话,咱不干。

3.1.1. Vitis 新建工程

​ 新建vitis工程选择R5核心,这里我选择了R5_0,因为7EV是有两个R5核心。你可以选择split模式,也可以选择lockstep模式。

​ split模式:是指 把RPU分成多个处理器,处理不同的任务。

​ lockstep模式:指把相同的核心来执行相同的操作,由于lockstep模式笔者目前还没有使用过。这里使用的是split模式。

注意:这里的模式并不是在Vitis软件上配置,是在Linux的设备树上配置。

image-20240108112520752

image-20240108112544259

上图的操作系统选择standlone,不依赖任何,指裸机程序。

image-20240108112647231

这里的例程选择open amp echo-test。新建完工程和例程后,打开rpmsg-echo.c文件可以看到他的int main函数所执行的任务。

image-20240108112806473

在开发R核心的时候,基于他的官方例程,照葫芦画瓢对RPU进行开发。

3.1.2. Vitis 链接文件以及内存映射

在工程的.spr可以看到该平台的物理地址映射表,这里是硬件的空间地址映射。也就是R核可以访问到的物理地址。

image-20240108113404992

在工程目录的src文件夹下,可以看到程序的运行地址。

image-20240108113726488

这里写死了从0x3ED00000地址开始运行。所以你在linux的设备树上得给他弄这段地址给他使用。

3.1.3. Vitis 的编译

编译后的elf文件是我们所需要的,在工程目录下的DEBUG目录。

image-20240108112942858

可以对他右键找到他的目录,拷贝到7ev板子上去运行。

image-20240108113021583

image-20240108113111141

3.2. Petalinux 方面

3.2.2. Kernel配置

进入Petalinux工程中,已经我已经新建了工程,就不重新建造一个了。进入内核配置菜单。

petalinux-config -c kernel

选中R核所需要的驱动选项(参考Xilinx UG1186)

CONFIG_UIO_PDRV_GENIRQ=m
CONFIG_RPMSG_CHAR=m
CONFIG_RPMSG_VIRTIO=m
CONFIG_RPMSG=m
CONFIG_VIRTIO=m
CONFIG_REMOTEPROC=y
CONFIG_ZYNQMP_R5_REMOTEPROC=m
CONFIG_SPARSEMEM_VMEMMAP=y

第二步需要修改设备树,给裸机程序所需要用到的内存进行预留。在3.1.2.章节可以看到他的链接地址。

这里的RPU控制器的寄存器地址说实话,我在Xilinx的官方没有找到相对应的寄存器手册,是根据Xilinx UG1186文档的说明直接给他贴上去。也就是这个0xFF9A00000xff990600 这两个地址,如果有这方面的懂哥,非常欢迎告诉我如何找到他这个寄存器的说明手册。

这里是在petalinux工程目录下,下面这个设备树上进行添加。

project-spec/meta-user/recipes-bsp/device-tree/files/system-user.dtsi
	reserved-memory {
		#address-cells = <2>;
		#size-cells = <2>;
		ranges;
		rpu0vdev0vring0: rpu0vdev0vring0@3ed40000 {
			no-map;
			reg = <0x0 0x3ed40000 0x0 0x4000>;
		};
		rpu0vdev0vring1: rpu0vdev0vring1@3ed44000 {
			no-map;
			reg = <0x0 0x3ed44000 0x0 0x4000>;
		};
		rpu0vdev0buffer: rpu0vdev0buffer@3ed48000 {
			no-map;
			reg = <0x0 0x3ed48000 0x0 0x100000>;
		};
		rproc_0_reserved: rproc@3ed00000 {
			no-map;
			reg = <0x0 0x3ed00000 0x0 0x40000>;
		};
	};
	zynqmp-rpu {
		compatible = "xlnx,zynqmp-r5-remoteproc-1.0";
		#address-cells = <2>;
		#size-cells = <2>;
		ranges;
		core_conf = "lockstep";
		reg = <0x0 0xFF9A0000 0x0 0x10000>;
		r5_0: r5@0 {
			#address-cells = <2>;
			#size-cells = <2>;
			ranges;
			memory-region = <&rproc_0_reserved>, <&rpu0vdev0buffer>, <&rpu0vdev0vring0>, <&rpu0vdev0vring1>;
			pnode-id = <0x7>;
			mboxes = <&ipi_mailbox_rpu0 0>, <&ipi_mailbox_rpu0 1>;
			mbox-names = "tx", "rx";
			tcm_0_a: tcm_0@0 {
				reg = <0x0 0xFFE00000 0x0 0x10000>;
				pnode-id = <0xf>;
			};
			tcm_0_b: tcm_0@1 {
				reg = <0x0 0xFFE20000 0x0 0x10000>;
				pnode-id = <0x10>;
			};
		};
	};

	zynqmp_ipi1 {
		compatible = "xlnx,zynqmp-ipi-mailbox";
		interrupt-parent = <&gic>;
		interrupts = <0 29 4>;
		xlnx,ipi-id = <7>;
		#address-cells = <1>;
		#size-cells = <1>;
		ranges;

	/* APU<->RPU0 IPI mailbox controller */
		ipi_mailbox_rpu0: mailbox@ff90000 {
			reg = <0xff990600 0x20>,
					<0xff990620 0x20>,
					<0xff9900c0 0x20>,
					<0xff9900e0 0x20>;
			reg-names = "local_request_region",
					"local_response_region",
					"remote_request_region",
					"remote_response_region";
			#mbox-cells = <1>;
			xlnx,ipi-id = <1>;
		};
	};

3.2.2. Rootfs 配置(可选可不选)

看某一些博客说,选中他的Rootfs是为了用户空间有他的动态库,但是我并没有在Xilinx官方的测试程序看到有关于openamp的依赖库。

image-20240108092524065

image-20240108092434724

所有我把这个标题写为可选可不选。我测试时候并没有选中,直接把他编译后的文件直接ssh直接拉进系统内运行了。

在Petalinux工程中,输入命令

petalinux-config -c rootfs

image-20240108092900279

这里有Xilinx官方的R核测试程序。

3.3. RPU固件烧录

r5_test.elf 文件是我从vitis编译后的文件,上电后先看RPU驱动是否加载起来了。

image-20240108114914754

使用echo命令,把文件烧录进去。通过RPU驱动的sys虚拟文件写入到指定的内存地址。

把在vitis编译后的elf文件写入下图所示位置

image-20240108115156107

然后再这样!

image-20240108115225557

他就起来运行了。

image-20240108140511528

4. Linux RPU驱动源代码分析

根据设备树的compatible,xlnx,zynqmp-r5-remoteproc-1.0 搜索内核源码可以找到Xilinx的这个rproc驱动代码。

image-20240108141717370

源码使用的是一个platform框架

image-20240108141808070

这个proc函数先从设备树里面搜索设备节点的各类属性,然后保存到变量里面

image-20240108142152935

image-20240108142241269

进入该函数后,这里是主要实现RPU程序运行和烧录的操作函数。

image-20240108142421754

image-20240108142429815

先从烧录固件函数开始分析,看是rproc_elf_load_segments函数,但先看看其他的函数是干嘛的。进入zynqmp_r5_parse_fw函数

image-20240108142815222

先搜索了设备树的一个属性image-20240108142836003

也就是内存划分。

image-20240108142924956

这里的函数操作是把RPU固件的内存保存进变量里面。再看rproc_elf_load_segments 函数的实现。

image-20240108143132533

这里就是把固件的数据直接memcpy到了指定的内存,挺粗暴的。这里烧录固件没啥好看的,就是最主要memcpy到指定的内存。

再看一下zynqmp_r5_rproc_start 函数。一般来说启动核心的代码,是对RPU的寄存器进行使能,不知道RPU上处理器的通用寄存器和PC,SP的指针

是否在驱动内赋值;继续往下翻翻看。

image-20240108143326272

image-20240108143748759

这里可以看到eemi_ops结构体内有这些函数指针,进行设置。

image-20240108143830612

看到这个指针在前面的probe被赋值了。

image-20240108143918204

找一下这个函数的实现。

image-20240108143942047

image-20240108143949127

发现在这里

image-20240108144013724

看了里面的代码,是跟ARM的CPU指令有关的操作。虽然对ARM的指令集并不是特别懂,但不妨碍我们继续往下分析。

image-20240108144623398

跳入zynqmp_pm_invoke_fn 函数内。

image-20240108144733633

看一下do_fw_call

image-20240108144945459

这里的备注说他可能调用do_fw_call_smc或者调用do_fw_call_hvc。看一下do_fw_call_smc

image-20240108145118355

看一下arm_smccc_smc函数。

image-20240108150111506

这是一个把指赋值给R5核心通用寄存器a0 ~ a7。这个函数的实现是由ARM的编译器提供。

这样思路就清晰了。

image-20240108151028724

实际上这里的eemi_ops->ioctl是把形参1,2,3,4的值进行处理后

	smc_arg[0] = PM_SIP_SVC | pm_api_id;
	smc_arg[1] = ((u64)arg1 << 32) | arg0;
	smc_arg[2] = ((u64)arg3 << 32) | arg2;

传给处理器的通用寄存器 A0 ~ A3。也就是所说的数据入栈

并且返回结果到val这个变量内。

那么这时就会有一个问题,ZYNQMP有6个处理器,4个Cortex-a53和2个Cortex-r5。他这里的值是赋值给哪个CPU呢?

这里涉及到了ARM-A的系统架构原理,ATF-A以及Linux系统CPU调度的原理实现。

由于笔者知识目前够不到这里,这里的代码无法再进一步进行分析。等我学会了再发另一边笔记对该内容继续分析。

因为这里涉及到了CPU的中断陷入的原理,目前对ARM的体系化以及CPU运行原理的知识不足充足。

5. 额外小知识

5.1. Cortex-R5 寄存器介绍

Cortex-R5核心是一种针对实时应用设计的ARM处理器核心。它具有一组特定的寄存器,用于执行和控制处理器的操作。以下是Cortex-R5核心的一些常见寄存器:

  1. 通用寄存器(General-Purpose Registers):
    • R0-R12:12个通用寄存器,用于存储通用数据。
    • SP:栈指针,用于管理函数调用时的堆栈操作。
    • LR:链接寄存器,存储函数调用返回地址。
    • PC:程序计数器,存储当前执行指令的地址。
  2. 控制寄存器(Control Registers):
    • CPSR(Current Program Status Register):当前程序状态寄存器,存储处理器的当前运行状态和条件码信息。
    • SPSR(Saved Program Status Register):保存程序状态寄存器,用于存储中断或异常处理程序之前的状态。
  3. 中断控制寄存器(Interrupt Control Registers):
    • ICCPMR(Interrupt Controller CPU Priority Mask Register):中断控制器CPU优先级屏蔽寄存器,用于控制中断的优先级。
    • ICCEOIR(Interrupt Controller End Of Interrupt Register):中断控制器结束中断寄存器,用于通知中断控制器中断处理的完成。

5.2. Cortex-A53 寄存器介绍

Cortex-A53 是一种 ARMv8 架构下的 CPU 核心,它具有一组通用寄存器、特权级别寄存器和其他特殊寄存器。以下是 Cortex-A53 CPU 核心的主要寄存器:

  1. 通用寄存器(General-Purpose Registers):
    • x0-x30(或者称为 r0-r30):共有 31 个通用寄存器,用于存储数据和计算。
    • xzr(或者称为 r31):零寄存器,固定为零值。
  2. 程序状态寄存器(Program Status Registers):
    • CPSR(Current Program Status Register):当前程序状态寄存器,包含条件标志位、中断使能位等。
    • SPSR (Saved Program Status Register):保存的程序状态寄存器,在异常处理过程中保存之前的 CPSR 值。
  3. 异常相关寄存器:
    • ELR (Exception Link Register):异常链接寄存器,用于保存异常返回地址。
    • SP (Stack Pointer):堆栈指针,指向当前使用的堆栈区域。
    • PC (Program Counter):程序计数器,指向当前正在执行的指令地址。
    • LR (Link Register):链接寄存器,用于保存函数调用的返回地址。
  4. 特殊寄存器:
    • TTBR0/TTBR1 (Translation Table Base Registers):用于虚拟地址转换的页表基地址寄存器。
    • MAIR (Memory Attribute Indirection Register):内存属性间接寄存器,用于定义不同内存区域的访问属性。
    • TCR (Translation Control Register):内存转换控制寄存器,用于配置页面大小、缓存策略等。
    • ID_AA64PFR0_EL1(AArch64 Processor Feature Register 0):用于描述当前处理器的架构和功能。

5.3. 什么是smc,什么是hvc

SMC(Secure Monitor Call)和 HVC(Hypervisor Call)是 ARM 架构下的两种不同的调用方式。

SMC 是一种用于进入安全监控模式的指令,安全监控模式是 ARM 架构中特权级别最高的系统模式,用于执行与安全相关的任务,如信任环境的切换、加密解密等。SMC 指令可以使当前运行在非特权级别的代码进入安全监控模式,并执行受保护的操作。SMC 指令的参数和返回值通过寄存器传递。

HVC 是一种用于进入虚拟化模式的指令,虚拟化模式是 ARM 架构中用于支持虚拟化的一种特殊模式。HVC 指令可以使当前运行在非虚拟化模式下的代码进入虚拟化模式,并在虚拟环境中执行受保护的操作。HVC 指令的参数和返回值同样也是通过寄存器传递。

  • 32
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Xilinx授权公开全部源代码的PCIe DMA引擎是一种用于数据传输和处理的技术。DMA代表直接存取存储器,是一种处理器和外部设备之间直接进行数据传输的机制。PCIe(Peripheral Component Interconnect Express)则是一种高速串行总线接口标准,广泛应用于计算机系统中。 由于Xilinx授权公开全部源代码的PCIe DMA引擎,意味着用户可以获得完整的源代码,并据此进行自定义和修改以满足特定需求。这是一个非常有价值的授权,因为源代码的开放性允许用户深入了解引擎的工作原理和内部结,并在此基础上进行个性化的优化和改进。用户可以根据自己的需求添加新的功能、调整性能参数、优化数据处理流程,甚至将引擎与其他硬件或软件系统集成。 公开全部源代码的PCIe DMA引擎授权的另一个优势是提供了更大的灵活性和可扩展性。用户可以根据自己的项目需求选择合适的硬件平台,并通过自定义代码来实现所需的性能和功能。这种可定制性有助于降低系统成本,因为用户可以精确地配置所需的功能,避免不必要的硬件或软件开销。 总之,Xilinx授权公开全部源代码的PCIe DMA引擎为用户提供了一个高度定制化的数据传输和处理解决方案。这种授权不仅使用户能够更好地理解和改进引擎的性能,还为用户提供了更大的灵活性和可扩展性。这对于需要高性能数据传输和处理的应用领域来说是非常有价值的。 ### 回答2: Xilinx授权是指Xilinx公司对其产品中的PCIe DMA引擎进行授权,允许用户公开全部的源代码。PCIe DMA引擎是一种用于处理数据传输的硬件模块,能够实现高效的数据传输和管理。 通过授权公开全部源代码,用户可以深入了解和学习PCIe DMA引擎的工作原理及其实现方式。对于开发人员来说,这是一个非常重要的资源,可以帮助他们更好地理解和使用该引擎,以满足自己特定的需求。 使用公开源代码的好处是,用户可以根据自身需求进行定制和优化。他们可以根据自己的应用场景进行修改和改进,以提高性能并满足特定需求。同时,公开源代码还促进了更广泛的协作和共享,使得更多的开发人员可以共同参与和贡献,推动引擎的不断发展与完善。 另外,公开源代码也有助于考虑和解决潜在的安全问题。通过对源代码的审查和分析,可以发现潜在的漏洞和安全隐患,并及时修复和增强相应的安全措施,从而提高系统的安全性和可靠性。 总之,Xilinx授权公开全部源代码的PCIe DMA引擎为开发人员提供了宝贵的资源和灵活性,使他们能够更好地利用和定制该引擎。这一举措促进了开发人员之间的合作与共享,推动了引擎的进一步发展,并提高了系统的性能、安全性和可靠性。 ### 回答3: Xilinx授权是指Xilinx公司开放并公开了他们的PCIe DMA引擎的全部源代码。 PCIe DMA引擎是一种用于数据传输和处理的技术,可以在计算机系统内的不同设备之间进行高速数据传输。通常,DMA引擎用于在计算机和外设之间进行数据传输,以减轻CPU的负担并提高数据传输的效率。 Xilinx是一家专门从事可编程逻辑器件的设计和制造的公司,他们的FPGA(现场可编程门阵列)器件非常流行。作为FPGA技术的先锋,Xilinx提供了许多解决方案和工具,用于开发各种应用程序,其中包括PCIe DMA引擎。 通过授权公开全部源代码Xilinx向广大开发者提供了使用和定制PCIe DMA引擎的机会。使用源代码开发者可以深入了解和探索该引擎的内部工作原理,以及它如何与其他系统组件进行交互。这使得开发者可以更好地优化引擎,以满足特定应用程序的需求。 此外,公开源代码还带来了更多的灵活性和可扩展性。开发者可以根据他们的需求进行修改和定制,并将其整合到自己的设计中。这种定制能力可以帮助开发者更好地适应各种应用场景,提高系统性能和效率。 总之,通过Xilinx授权公开全部源代码的PCIe DMA引擎,开发者能够更好地理解和使用该引擎,实现高速数据传输和处理。这对于加快应用程序的开发和优化,提高系统性能具有重要的意义。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值