当前位置: 首页 > web >正文

D2000平台上Centos使用mmap函数遇到的陷阱

----------原创不易,欢迎点赞收藏。广交嵌入式开发的朋友,讨论技术和产品-------------

在飞腾D2000平台上,安装了麒麟linux系统,我写了个GPIO点灯的程序,在应用层利用mmap函数将内核空间映射到用户态,然后直接操作GPIO方向和数据寄存器即可控制LED管脚的电压,实现闪灯功能。

核心代码如下,利用/dev/mem设备,内核将硬件地址空间映射到用户态空间

    if ((fd_mem = open("/dev/mem", O_RDWR, 0755)) < 0){printf("\r\n open /dev/mem err: %d-%s. \n", errno, strerror(errno));return 0;}mapped_gpio = (volatile unsigned char *)mmap(0, 0x1000, PROT_READ|PROT_WRITE, MAP_SHARED, fd_mem, GPIO1_BASE_ADDR);if (tmp == (void*)-1){	printf("mmap error : %d-%s. \n", errno, strerror(errno));close(fd_mem);return 1;}

然后交叉编译后,将目标二进制文件上传到单板上运行,闪灯正常。

于是乎把这源码和可执行文件发给客户使用,结果报错。打印如下信息,提示非法参数
在这里插入图片描述
我将mmap的几个参数都研究了一下:
1、应该不是权限问题,对方用的是root账户执行的;
2、查看了单板上内核空间,看是否有GPIO物理地址的定义
#define GPIO1_BASE_ADDR 0x28005000 //PHYTIUM D2000 GPIO
cat /proc/iomem 执行结果如下,有0x28005000的空间
在这里插入图片描述
3、PROT_READ|PROT_WRITE这两个参数应该没有问题;
4、想到重要的一个因素,mmap必须以页表大小对齐的起始地址,才能做映射。于是查看当前系统的页表大小,用如下命令:getconf PAGESIZE。
在这里插入图片描述
在麒麟系统查到结果是4KB的小页面,在centos下查询得到的是65536,64KB的页面。这个参数在内核编译的时候可以设定的。肯定是centos没有设定小页面模式。关于MMU和内存页的知识,本文不叙述。有兴趣的朋友自己去研究学习。

于是乎将代码修改了一下,考虑不管多大页面都能兼容

    int pagesize;u32 mmap_base;u32 mmap_offset;volatile unsigned char *tmp;pagesize = sysconf(_SC_PAGESIZE);if (pagesize == -1) {printf("Error, sysconf for _SC_PAGESIZE \n");return 1;} else {printf("Page size: %d bytes \n", pagesize);}mmap_base   = GPIO1_BASE_ADDR & ~(pagesize - 1);mmap_offset = GPIO1_BASE_ADDR & (pagesize - 1);printf("Hardware address = 0x%x,  mmap_base = 0x%x, mmap_offset = 0x%x \n", GPIO1_BASE_ADDR, mmap_base, mmap_offset);if ((fd_mem = open("/dev/mem", O_RDWR, 0755)) < 0){printf("\r\n open /dev/mem err: %d-%s. \n", errno, strerror(errno));return 0;}tmp = (volatile unsigned char *)mmap(0, pagesize, PROT_READ|PROT_WRITE, MAP_SHARED, fd_mem, mmap_base);if (tmp == (void*)-1){	printf("mmap error : %d-%s. \n", errno, strerror(errno));close(fd_mem);return 1;}mapped_gpio = (volatile unsigned int *)((unsigned long)tmp + mmap_offset);printf(" mapped_base = %p, mapped_gpio = %p \n", tmp, mapped_gpio);printf("GPIO_SWPORTA_DR  = 0x%x \n",    *mapped_gpio);    //GPIO_SWPORTA_DRprintf("GPIO_SWPORTA_DDR = 0x%x \n\n",  *(mapped_gpio+1)); //GPIO_SWPORTA_DDR

重新编译后在多个版本上验证可行。当初写这个功能程序,太匆忙,没有考虑太细致。不过也很快定位解决了。这也告诫搞研发的朋友,虽然同一套代码不修改,在不同环境上也不一定成功执行。陷阱无处不在,大家谨慎小写,写出健壮可靠的代码。

http://www.xdnf.cn/news/9497.html

相关文章:

  • 【机器学习基础】机器学习入门核心算法:隐马尔可夫模型 (HMM)
  • 【赵渝强老师】OceanBase的部署架构
  • 基于Qt的MCP LLM代理服务开发实战:从0到1扩展大语言模型
  • 本地(Linux)编译 MySQL 源码
  • Java高频面试之并发编程-23
  • FPGA实现CNN卷积层:高效窗口生成模块设计与验证
  • Transformer 通关秘籍11:Word2Vec 及工具的使用
  • 智能嗅探AJAX触发:机器学习在动态渲染中的创新应用
  • js中后台框架的增删改查要点
  • 影响沉金价格的因素如何体现在多层电路板制造上?
  • Eclipse 插件开发 5.2 编辑器 获取当前编辑器
  • C语言循环结构实战:while和for到底用哪个?
  • 时序数据库IoTDB如何快速高效地存储时序数据
  • 芯科科技推出首批第三代无线开发平台SoC,高度集成的解决方案推动下一波物联网实现突破
  • 国产化Excel处理组件Spire.XLS教程:如何使用 C# 将 Excel(XLS 或 XLSX)文件转换为 PDF
  • 如何在网页中嵌入UE/Unity/WebGL程序,并与网页端通信
  • 第 85 场周赛:矩阵重叠、推多米诺、新 21 点、相似字符串组
  • CMake指令:source_group()
  • 【数据分析】特征工程-特征选择
  • Git 使用规范
  • 关于git的使用流程
  • 2025年中国电商618年中大促策略分析:存量博弈与生态重构
  • 深度 |推动公共数据按需有序安全流动
  • mock库知识笔记(持续更新)
  • 如何解决网站服务器的异常问题?
  • 班翎流程平台 | 流程变量赋值事件,简化流程配置,灵活构建流程
  • 8.8 Primary ODSA service without ODSA Portal
  • LLaDa——基于 Diffusion 的大语言模型 打平 LLama 3
  • DM达梦数据库开启SQL日志记录功能
  • java导入excel