最近在调试zynq7010 上双核运行linux和ucos的程序,经过仔细阅读官方UG1186后测试是可以跑起来了,但是有个严重问题,就是当我反复使用
echo start > /sys/class/remoteproc/remoteproc0/state
echo stop > /sys/class/remoteproc/remoteproc0/state
这两条命令去反复停止和重启remoteproc cpu2的程序时会内核oops崩溃,提示
vmap allocation for size 8392704 failed: use vmalloc=<size> to increase size
root@petalinuxAMP:~# echo start > /sys/class/remoteproc/remoteproc0/state
remoteproc remoteproc0: powering up remoteproc@0
remoteproc remoteproc0: Booting fw image image_echo_test, size 2556292
virtio_rpmsg_bus virtio0: rpmsg host is online
remoteproc@0#vdev0buffer: registered virtio0 (type 7)
virtio_rpmsg_bus virtio0: creating channel rpmsg-openamp-demo-channel addr 0x0
remoteproc remoteproc0: remote processor remoteproc@0 is now up
root@petalinuxAMP:~#
root@petalinuxAMP:~# echo stop > /sys/class/remoteproc/remoteproc0/state
remoteproc remoteproc0: stopped remote processor remoteproc@0
root@petalinuxAMP:~#
root@petalinuxAMP:~# echo start > /sys/class/remoteproc/remoteproc0/state
remoteproc remoteproc0: powering up remoteproc@0
remoteproc remoteproc0: Booting fw image image_echo_test, size 2556292
vmap allocation for size 8392704 failed: use vmalloc=<size> to increase size
remoteproc remoteproc0: Boot failed: -12
-sh: echo: write error: Cannot allocate memory
root@petalinuxAMP:~#
root@petalinuxAMP:~# echo 8 8 8 8 > /proc/sys/kernel/printk [Aroot@petalinuxAMP:~# echo 8 8 8 8 > /proc/sys/kernel/printk [K
root@petalinuxAMP:~#
root@petalinuxAMP:~# echo start > /sys/class/remoteproc/remoteproc0/state
remoteproc remoteproc0: powering up remoteproc@0
remoteproc remoteproc0: Booting fw image image_echo_test, size 2556292
vmap allocation for size 8392704 failed: use vmalloc=<size> to increase size
remoteproc remoteproc0: Boot failed: -12
-sh: echo: write error: Cannot allocate memory
root@petalinuxAMP:~#
然后就挂了,由于刚入门linux半个月,对linux内核基本是一窍不通的,所以当时是一头雾水,毫无头绪。只能继续测试其他程序看看是不是我的ucos工程有什么问题,结果用了官方的echo_test测试例子进行测试,发现死的更快,用我自己的ucos工程反复大概15次才会出bug,用官方echo_test例子两三次就挂掉了,所以开始怀疑这个是个BUG,不是我自己的ucos没设置好的原因。然后只能一顿搜索,去Xilinx官方论坛求助,郁闷了一星期都没找到办法,期间测试了官方petalinux 2019.2版本和petalinux 2020.2版本的程序,结果一样反复关闭重启 cpu1都会出现异常,不过在2019.2版本的petalinux会oops,但是在2020.2版本不会opps,只会提示vmalloc size不足,不能启动cpu1
没有办法了,只能硬着头皮去分析linux remoteproc驱动程序(基于petalinux 2020.2版本),先在petalinux工程目录下找到remoteproc目录,一共有几个文件和zynq 有关,其他的都是其他cpu相关的移植,可以不看
打开这几个文件,在文件头部添加 #define DEBUG 1 打开调试输出,然后 petalinux -build 重新编译程序

用sd卡启动petalinux,启动完成后root登陆,直接 输入 echo 8 8 8 8 > /proc/sys/kernel/printk 打开修改内核printf等级,否则是看不到debug输出信息的,然后启动cpu1程序可以看到如下输出内容
echo start > /sys/class/remoteproc/remoteproc0/state
remoteproc remoteproc0: powering up remoteproc@0
remoteproc remoteproc0: Booting fw image UCTEST.elf, size 3148072
zynq_remoteproc remoteproc@0: iommu not present
zynq_remoteproc remoteproc@0: zynq_parse_fw num_mems : 4
zynq_remoteproc remoteproc@0: zynq_parse_fw size 00800000 base 3E000000 name : rproc
zynq_remoteproc remoteproc@0: zynq_parse_fw mem : FA080000
zynq_remoteproc remoteproc@0: zynq_parse_fw size 00100000 base 3E808000 name : vdev0buffer
zynq_remoteproc remoteproc@0: zynq_parse_fw mem : 00000000
zynq_remoteproc remoteproc@0: zynq_parse_fw size 00004000 base 3E800000 name : vdev0vring0
zynq_remoteproc remoteproc@0: zynq_parse_fw mem : F0930000
zynq_remoteproc remoteproc@0: zynq_parse_fw size 00004000 base 3E804000 name : vdev0vring1
zynq_remoteproc remoteproc@0: zynq_parse_fw mem : F0938000
remoteproc remoteproc0: phdr: type 1 da 0x3e000000 memsz 0x1c2a8 filesz 0x1c2a8
remoteproc remoteproc0: rproc_da_to_va req da : 3E000000 len : 0001C2A8
remoteproc remoteproc0: rproc_da_to_va list carveout->da : 3E000000 offset : 00000000
remoteproc remoteproc0: phdr: type 1 da 0x3e100000 memsz 0x111180 filesz 0x108010
remoteproc remoteproc0: rproc_da_to_va req da : 3E100000 len : 00111180
remoteproc remoteproc0: rproc_da_to_va list carveout->da : 3E000000 offset : 00100000
remoteproc remoteproc0: rproc_da_to_va req da : 3E100000 len : 00100000
remoteproc remoteproc0: rproc_da_to_va list carveout->da : 3E000000 offset : 00100000
zynq_remoteproc remoteproc@0: zynq_rproc_start
remoteproc remoteproc0: remote processor remoteproc@0 is now up
可以到每次启动cpu1时linux都会给cpu1进行虚拟地址到物理地址的映射,方便remoteproc驱动进行资源分配和将cpu1的程序elf文件加载到实际的物理DDR内存中,经过多次启动和停止后可以发现申请的虚拟地址不停在变化升高,一直到提示内存不足就无法继续启动cpu1了。
分析了一下,实际上cpu1停止后按照正常思维应该是释放掉所有已经申请的内存资源才对,否则就是内存泄露了,然后检查了一下remoteproc在stop cpu1时都做了什么工作,代码在remoteproc_core.c文件内
static void rproc_resource_cleanup(struct rproc *rproc)
{
struct rproc_mem_entry *entry, *tmp;
struct rproc_debug_trace *trace, *ttmp;
struct rproc_vdev *rvdev, *rvtmp;
struct device *dev = &rproc->dev;
dev_dbg(dev, "rproc_resource_cleanup\n");
/* clean up debugfs trace entries */
list_for_each_entry_safe(trace, ttmp, &rproc->traces, node) {
rproc_remove_trace_file(trace->tfile);
rproc->num_traces--;
list_del(&trace->node);
kfree(trace);
}
/* clean up iommu mapping entries */
list_for_each_entry_safe(entry, tmp, &rproc->mappings, node) {
size_t unmapped;
unmapped = iommu_unmap(rproc->domain, entry->da, entry->len);
if (unmapped != entry->len) {
/* nothing much to do besides complaining */
dev_err(dev, "failed to unmap %u/%zu\n", entry->len,
unmapped);
}
list_del(&entry->node);
kfree(entry);
}
/* clean up carveout allocations */
list_for_each_entry_safe(entry, tmp, &rproc->carveouts, node) {
dev_dbg(dev, "rproc_resource_cleanup \n");
if (entry->release)
entry->release(rproc, entry);
list_del(&entry->node);
kfree(entry);
}
/* clean up remote vdev entries */
list_for_each_entry_safe(rvdev, rvtmp, &rproc->rvdevs, node)
kref_put(&rvdev->refcount, rproc_vdev_release);
rproc_coredump_cleanup(rproc);
}
其中dev_dbg(dev, "rproc_resource_cleanup \n");是我加入的,方便查看stop cpu1时是否运行到这里,结果如下
echo stop > /sys/class/remoteproc/remoteproc0/state
zynq_remoteproc remoteproc@0: zynq_rproc_stop
remoteproc remoteproc0: stopped remote processor remoteproc@0
remoteproc remoteproc0: rproc_resource_cleanup
remoteproc remoteproc0: rproc_resource_cleanup
remoteproc remoteproc0: rproc_resource_cleanup
remoteproc remoteproc0: rproc_resource_cleanup
remoteproc remoteproc0: rproc_resource_cleanup
root@petali

博主在调试Zynq7010上的Linux和uCOS程序时遇到一个问题:反复启动和停止远程处理器CPU1会导致内核oom崩溃。通过分析Linux remoteproc驱动源码,发现启动CPU1时进行了ioremap但停止时未进行相应的iounmap操作,导致内存资源泄露。在rproc_resource_cleanup函数中添加iounmap操作后,内存资源得以正确释放,问题得到解决。
最低0.47元/天 解锁文章
4553

被折叠的 条评论
为什么被折叠?



