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

嵌入式 Linux 对内存的直接读写(devmem)

https://blog.csdn.net/xy010902100449/article/details/47028497
【摘要】 在Linux开发中着实用到的调试工具并不是很多。devmem的方式是提供给驱动开发人员,在应用层能够侦测内存地址中的数据变化,以此来检测驱动中对内存或者相关配置的正确性验证。

http://blog.csdn.net/hens007/article/details/7268447

这个工具的原理也比较简单,就是应用程序通过mmap函数实现对/dev/mem驱动中mmap方法的使用,映射了设备的内存到用户空间,实现对这些物理地址的读写操作。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <fcntl.h>
#include <ctype.h>
#include <termios.h>
#include <sys/types.h>
#include <sys/mman.h>

#define FATAL do { fprintf(stderr, "Error at line %d, file %s (%d) [%s]\n", \
__LINE__, __FILE__, errno, strerror(errno)); exit(1); } while(0)

#define MAP_SIZE 4096UL
#define MAP_MASK (MAP_SIZE - 1)

int main(int argc, char **argv) {
int fd;
void *map_base, *virt_addr;
unsigned long read_result, writeval;
off_t target;
int access_type = 'w';

if(argc < 2) {//若参数个数少于两个则打印此工具的使用方法
fprintf(stderr, "\nUsage:\t%s { address } [ type [ data ] ]\n"
"\taddress : memory address to act upon\n"
"\ttype : access operation type : [b]yte, [h]alfword, [w]ord\n"
"\tdata : data to be written\n\n",
argv[0]);
exit(1);
}
target = strtoul(argv[1], 0, 0);

if(argc > 2)
access_type = tolower(argv[2][0]);


if((fd = open("/dev/mem", O_RDWR | O_SYNC)) == -1) FATAL;
printf("/dev/mem opened.\n");
fflush(stdout);

/* Map one page */ //将内核空间映射到用户空间
map_base = mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, target & ~MAP_MASK);
if(map_base == (void *) -1) FATAL;
printf("Memory mapped at address %p.\n", map_base);
fflush(stdout);

virt_addr = map_base + (target & MAP_MASK);
//针对不同的参数获取不同类型内存数据
&nbsp; switch(access_type) {
case 'b':
read_result = *((unsigned char *) virt_addr);
break;
case 'h':
read_result = *((unsigned short *) virt_addr);
break;
case 'w':
read_result = *((unsigned long *) virt_addr);
break;
default:
fprintf(stderr, "Illegal data type '%c'.\n", access_type);
exit(2);
}
printf("Value at address 0x%X (%p): 0x%X\n", target, virt_addr, read_result);
fflush(stdout);
//若参数大于3个,则说明为写入操作,针对不同参数写入不同类型的数据
if(argc > 3) {
writeval = strtoul(argv[3], 0, 0);
switch(access_type) {
case 'b':
*((unsigned char *) virt_addr) = writeval;
read_result = *((unsigned char *) virt_addr);
break;
case 'h':
*((unsigned short *) virt_addr) = writeval;
read_result = *((unsigned short *) virt_addr);
break;
case 'w':
*((unsigned long *) virt_addr) = writeval;
read_result = *((unsigned long *) virt_addr);
break;
}
printf("Written 0x%X; readback 0x%X\n", writeval, read_result);
fflush(stdout);
}

if(munmap(map_base, MAP_SIZE) == -1) FATAL;
close(fd);
return 0;
}

memdev:直接读写内存。
可以在busybox的杂项中找到:

CONFIG_USER_BUSYBOX_DEVMEM:

devmem is a small program that reads and writes from physical
memory using /dev/mem.

Symbol: USER_BUSYBOX_DEVMEM [=y]
Prompt: devmem
Defined at ../user/busybox/busybox-1.14.3/miscutils/Kconfig:216
Depends on: USER_BUSYBOX_BUSYBOX
Location:
-> BusyBox (USER_BUSYBOX_BUSYBOX [=y])
-> Miscellaneous Utilities

[用法]
Usage: devmem ADDRESS [WIDTH [VALUE]]
读取:在地址0x97000000读取32bit值(WIDTH默认等于32, 可选值为[8, 16, 32, 64])
/dev # devmem 0x97000000
0x11111111
读取:在地址0x97000000读取16bit值
/dev # devmem 0x97000000 16
0x1111

写入:在地址0x97000000写入32bit值0x7777ABCD
/dev # devmem 0x97000000 32 0x7777ABCD
/dev # devmem 0x97000000
0x7777ABCD

注意:如果/dev下没有mem这个node,会出现错误:
/dev # devmem 0x97000000
devmem: can't open '/dev/mem': No such file or directory

这时可以在Host系统中手动创建一个(例如在NFS root filesystem模式):
host@host-laptop:~/embedded/tftpboot/nfsroot/dev$ sudo mknod mem -m666 c 1 1
注意这里的权限是666,允许任何人任意读写,可以很好的配合程序debug。

/dev # devmem 0x97000000
0x7777ABCD
---------------------
作者:狂奔的乌龟
来源:CSDN
原文:https://blog.csdn.net/xy010902100449/article/details/47028497
版权声明:本文为博主原创文章,转载请附上博文链接!

转载于:https://www.cnblogs.com/Ph-one/p/10209472.html

相关文章:

  • C语言三个结束符:EOF ‘\0’ '\n'
  • Ymodem协议(参考STM32)
  • android uboot中的mmc命令
  • stm32最简单的实现BootLoader
  • 变参标准函数的重新封装,如printf
  • 导数与梯度
  • linux /Android 平台下使用 i2c-tools
  • 在android下使用i2c tools
  • ubuntu查看文件和文件夹大小
  • matlab的三维绘图和四维绘图
  • Matlab绘制三维曲面(以二维高斯函数为例)
  • VSCode 预览 .md 文件
  • 右侧添加悬浮打赏功能
  • Git错误non-fast-forward后的冲突解决
  • linux物理网卡检测命令mii-tool
  • 【React系列】如何构建React应用程序
  • 【vuex入门系列02】mutation接收单个参数和多个参数
  • 【翻译】babel对TC39装饰器草案的实现
  • input的行数自动增减
  • Magento 1.x 中文订单打印乱码
  • PHP 的 SAPI 是个什么东西
  • SpriteKit 技巧之添加背景图片
  • vue从创建到完整的饿了么(18)购物车详细信息的展示与删除
  • 包装类对象
  • 成为一名优秀的Developer的书单
  • 深入 Nginx 之配置篇
  • 线上 python http server profile 实践
  • 终端用户监控:真实用户监控还是模拟监控?
  • Hibernate主键生成策略及选择
  • ionic异常记录
  • 通过调用文摘列表API获取文摘
  • ​​​​​​​​​​​​​​汽车网络信息安全分析方法论
  • (06)Hive——正则表达式
  • (16)Reactor的测试——响应式Spring的道法术器
  • (附源码)springboot 智能停车场系统 毕业设计065415
  • (个人笔记质量不佳)SQL 左连接、右连接、内连接的区别
  • (论文阅读23/100)Hierarchical Convolutional Features for Visual Tracking
  • (论文阅读笔记)Network planning with deep reinforcement learning
  • .a文件和.so文件
  • .NET Compact Framework 3.5 支持 WCF 的子集
  • .NET CORE 2.0发布后没有 VIEWS视图页面文件
  • .NET MVC之AOP
  • .net web项目 调用webService
  • .net 调用php,php 调用.net com组件 --
  • .net 发送邮件
  • .Net 垃圾回收机制原理(二)
  • .NET 使用 ILRepack 合并多个程序集(替代 ILMerge),避免引入额外的依赖
  • .NET/C# 使窗口永不激活(No Activate 永不获得焦点)
  • .NET性能优化(文摘)
  • @KafkaListener注解详解(一)| 常用参数详解
  • @modelattribute注解用postman测试怎么传参_接口测试之问题挖掘
  • @RequestMapping-占位符映射
  • [ vulhub漏洞复现篇 ] Celery <4.0 Redis未授权访问+Pickle反序列化利用
  • [bzoj1006]: [HNOI2008]神奇的国度(最大势算法)
  • [BZOJ4566][HAOI2016]找相同字符(SAM)