在LINUX应用开发中,可能需要使用连续的物理地址来存储一些数据或者进行DMA操作,但是由于LINUX具备MMU功能,MMU模块会自动的将物理地址与虚拟地址之间建立页表对应关系(但并不是线性对应),用户能访问的只是虚拟地址,虚拟地址上的连续并不一定代表物理地址上的连续。如果需要使用连续的物理地址,就需要进行预留内存,来将一部分内存保留起来,不用做LINUX建立页表使用,也就是说用户程序中是无法直接通过访问虚拟地址来访问预留内存的,而是通过/dev/mem的方式来访问预留内存。
对于LINUX预留内存的方式,要针对LINUX版本进行区分:
1.对于无设备树的LINUX版本,kernel的参数是由uboot直接通过cmdline传递过去的,所以只需要修改uboot传递给kernel的参数就行。
Linux内核启动参数cmdline提供了大量的选项,用来设置内核启动的参数和配置。其中“mem”选项就是用来限制内核可以看到的系统内存的大小,因此通过设置”mem”参数就能实现保留内存。当”mem”参数指定的size小于系统实际可用的物理内存大小时,实际系统内存中出去mem指定的剩下部分就是reserved memory。例如如果某个系统有64G物理内存,通过添加mem=48G到kernel command line,就能保留最末尾的(64-48)=16G高端内存
2. 对于有设备树的LINUX版本,kernel的参数是通过设备树传入的,因此需要修改设备树中的内容。Devicetree 提供了两种方式预留内存:
reserved-memory和memreserve
◎memreserve用法:在设备树dts文件中添加如下代码
/memreserve/ 0x40000000 0x01000000
在zynqMP中实现该方法遇到的问题:利用PETALINUX工具来编译镜像时,设备树(dts)是直接由HDF文件生成的,手动去修改dts文件无效,在运行petalinux-build时,手动修改的dts文件会直接被覆盖掉;但是将该语句添加在system-user.dtsi中,编译会出现语法错误,xilinx论坛上关于此方法出现的问题并未解答。
- reserved- memory {
- #address-cells = <1>;
- #size-cells = <1>;
- ranges;
- ipu_cma@ 90000000 {
- compatible = "shared-dma-pool";
- reg = < 0x90000000 0x4000000>;
- reusable;
- status = "okay";
- };
◎reserved-memory用法:在设备树dts文件中添加如下代码
在zynqMP中实现reserved-memory方法,可以参照LINUX内核源码的
linux-xlnx-xilinx-v2017.4\Documentation\devicetree\bindings\reserved-memory.txt有以下几点需要注意:
(1)针对zynq和zynqMP需要区别对待,address-cells与size-cells需要保持与根节点一致,例如在zynqMP中:
compatible = "xlnx,zynqmp";
#address-cells = <2>;
#size-cells = <2>;
那么在设备树中添加reserved-memory节点时,就需要设置为
#address-cells = <2>;
#size-cells = <2>;
如果设置为1,内核将无法预留内存,在zynqMP中已经验证了设置为1时,预留内存失败。
(2)compatible属性一栏,如果是给特定的驱动使用预留的内存,需要加上compatible,例如给CMA使用的内存。但对于通用性的内存使用,不需要添加compatible栏。
(3)no-map是将预留内存设置为不可虚拟地址映射的区域,此处的虚拟地址映射是指利用/dev/mem来访问物理地址的方法,添加no-map属性后,只能直接访问物理地址。
(4)reusable属性是将预留内存设置为操作系统可以使用此区域中的内存拥有该区域的设备驱动程序所需要的限制可以把它收回来。通常这意味着操作系统可以使用该区域存储易失性或缓存的数据。
在system-user.dtsi中添加如下代码,就可以实现预留内存:
- reserved-memory {
- #address-cells = <2>;
- #size-cells = <2>;
- ranges;
- reserved: buffer@0 {
- reg = <0x0 0x30000000 0x0 0x10000000 >;
- //将0x30000000-0x40000000总共256M的大小的空间作为预留内存
- } ;
- } ;
在命令行中输入:dmesg |grep cma 可以看到如下打印信息:
root@xxx:~# dmesg |grep cma
[ 0.000000] cma: Reserved 256 MiB at 0x0000000020000000
[ 0.000000] Memory: 492900K/1048576K available (6652K kernel code, 472K rwdata, 2008K rodata, 448K init, 336K bss, 293532K reserved, 262144K cma-reserved)
其中预留的内存为:293532K = 286M * 1024 =(256+30)*1024,与前面设置的正好对应起来了