linux 应用程序直接读写寄存器或物理内存

摘要:
这是一个可以访问应用层中底层寄存器的应用程序源代码。第40行添加了O_ DSYNC标志,以防止由于缓存=5){21printf;22printf、23printf,24printf和25return-1;26}2728,如果{29flag=0;30value=strtol;31}32else{33flag=1;34value=strstol;35}3637base=strto;38addr=结构;3940dev_ fd=打开;4142if43{44printf;45return0;46}4748addr&=~0x3;49align_ addr=地址&~0xff;5051map_大小=地址+0x100;52打印f;53map_ base=mmap;54if55{56printf;57错误;58返回-1;59}6061如果{6263表示{64if{65printf(“”);66打印f;67}68打印f;69}70printf(“”);7172}73否则{74printf;75*=值;76}77printf(“”);7879if80关闭;8182munmap;8384返回0;85}3.内核设备文件实现内核源代码位置:/drivers/char/mem C/dev/mem设备文件mmap函数实现:静态int mmap_mem{size_tsize=vma-˃vm_end-vma-˃vm_start;phys_addr_tofset=vma-˃vm_pgoff˂˂PAGE_SHIFT!

1.程序说明:

调试驱动程序时,经常遇到候需要查看或设置寄存器的情况,但是直接更改内核代码又不方便。

这里提供一个应用程序源码能在应用层访问底层寄存器。(网上找到的,进行过更改)。

这里只提供4字节数据的访问,如果需要其他字节宽度则需要更改代码。

line40 增加了O_DSYNC标志,防止cache导致数据写入不及时。

2.应用程序源码

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <time.h>
 4 #include <unistd.h>
 5 #include <fcntl.h>
 6 #include <unistd.h>
 7 #include <stdint.h>
 8 #include <sys/mman.h>
 9 #include <errno.h>
10 
11 static intdev_fd;
12 int main(int argc, char **argv)
13 {
14     uint32_t addr, value, map_size,base;
15     void *align_addr;
16     int flag = 0;
17     inti;
18     unsigned char *map_base;
19 
20     if (argc != 5) {
21         printf("usage:   m_reg r base address readcount
");
22         printf("example: m_reg r 0x50008000 20 1
");
23         printf("usage:   m_reg w base address writevalue
");
24         printf("example: m_reg w 0x50008000 20 0xffffffff
");
25         return -1;
26 }
27 
28     if (argv[1][0] == 'r') {
29         flag = 0;
30         value = strtol(argv[4], NULL, 10);
31 }
32     else{
33         flag = 1;
34         value = strtol(argv[4], NULL, 16);
35 }
36 
37     base = strtol(argv[2], NULL, 16);
38     addr = strtol(argv[3], NULL, 16);
39 
40     dev_fd = open("/dev/mem", O_RDWR | O_NDELAY |O_DSYNC);
41 
42     if (dev_fd < 0)
43 {
44         printf("open(/dev/mem) failed.");
45         return 0;
46 }
47 
48     addr &= ~0x3;
49     align_addr = addr & ~0xff;
50 
51     map_size = addr + 0x100;
52     printf("map base:0x%x size:0x%x
",base,map_size);
53     map_base = (unsigned int * )mmap(NULL, map_size, PROT_READ | PROT_WRITE, MAP_SHARED, dev_fd, base);
54     if(map_base == -1)
55 {
56         printf("map err %d
",errno);
57         perror("errno:");
58         return -1;
59 }
60     
61     if (flag == 0) {
62 
63         for (i = 0; i < value; i++) {
64             if (i % 4 == 0) {
65                 printf("
");
66                 printf("0x%08x	", addr+i*4);
67 }
68             printf("%08x ", *(volatile unsigned int *)(map_base+addr+i*4));
69 }
70         printf("
");
71 
72 }
73     else{
74         printf("0x%08x	 value:0x%x", addr,value);
75         *(volatile unsigned int *)(map_base + addr) =value;
76 }
77     printf("
");
78 
79     if(dev_fd)
80 close(dev_fd);
81 
82     munmap((unsigned int *)map_base, map_size);
83 
84     return 0;
85 }

3. 内核设备文件实现

内核源码位置:/drivers/char/mem.c

/dev/mem设备文件mmap函数实现:

static int mmap_mem(struct file *file, struct vm_area_struct *vma)
{
	size_t size = vma->vm_end - vma->vm_start;
	phys_addr_t offset = (phys_addr_t)vma->vm_pgoff << PAGE_SHIFT;

	/* It's illegal to wrap around the end of the physical address space. */
	if (offset + (phys_addr_t)size - 1 < offset)
		return -EINVAL;

	if (!valid_mmap_phys_addr_range(vma->vm_pgoff, size))
		return -EINVAL;

	if (!private_mapping_ok(vma))
		return -ENOSYS;

	if (!range_is_allowed(vma->vm_pgoff, size))
		return -EPERM;

	if (!phys_mem_access_prot_allowed(file, vma->vm_pgoff, size,
						&vma->vm_page_prot))
		return -EINVAL;

	vma->vm_page_prot = phys_mem_access_prot(file, vma->vm_pgoff,
						 size,
						 vma->vm_page_prot);

	vma->vm_ops = &mmap_mem_ops;

	/* Remap-pfn-range will mark the range VM_IO */
	if (remap_pfn_range(vma,
			    vma->vm_start,
			    vma->vm_pgoff,
			    size,
			    vma->vm_page_prot)) {
		return -EAGAIN;
	}
	return 0;
}

phys_mem_access_prot函数获得映射内存访问权限

static pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
				     unsigned long size, pgprot_t vma_prot)
{
#ifdef pgprot_noncached
	phys_addr_t offset = pfn << PAGE_SHIFT;

	if (uncached_access(file, offset))
		return pgprot_noncached(vma_prot);
#endif
	return vma_prot;
}

O_DSYNC标志将会使用不带cache的映射方式,该标志在打开设备文件时指定。

static int uncached_access(struct file *file, phys_addr_t addr)
{
	/*
	 * Accessing memory above the top the kernel knows about or through a
	 * file pointer
	 * that was marked O_DSYNC will be done non-cached.
	 */
	if (file->f_flags & O_DSYNC)
		return 1;
	return addr >= __pa(high_memory);
}

免责声明:文章转载自《linux 应用程序直接读写寄存器或物理内存》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇APP测试之Monkey压力测试(一)关于deciaml的类型转换问题下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Linux 的字符串截取很有用。有八种方法。

假设有变量 var=http://www.aaa.com/123.htm 1. # 号截取,删除左边字符,保留右边字符。 echo ${var#*//} 其中 var 是变量名,# 号是运算符,*// 表示从左边开始删除第一个 // 号及左边的所有字符 即删除 http:// 结果是 :www.aaa.com/123.htm 2. ## 号截取,删除左...

linux 树莓派 debian ffmpeg alsa v4l2 录制音频 视频 cannot open audio device 无法播放 声音模糊 画面卡顿 ALSA buffer xrun Thread message queue blocking -pix_fmt

一个基本的命令: ffmpeg -f alsa -i <device> out.mp3 其中, -f 表示设置格式,有format的意思,out.mp3前面可以加上 -f mp3, 因为带了mp3后缀,就省略了。 alsa 表示alsa音频驱动程序的编码格式,它保证后面的音频流可以由alsa解码。具体可根据驱动程序选择。(alsa主页https...

Windows 任务管理器中的几个内存概念

我们使用的大部分 PC 是基于 Intel微处理器的 x86 和 x64 架构计算机. 因此, 我们面对的 windows 避免不了和 Intel 架构有些设计上的契合. 比如接下来要说到的内存管理.为简单起见, 我们只讨论 x86 体系架构的内存管理. 不考虑换页文件影响. 进程的内存 图 1(本图摘自 ref 2) 对于系统中的每一个进程而言, 都...

linux清理内存命令

  1.清理前内存使用情况 free -m 2.开始清理  echo 1 > /proc/sys/vm/drop_caches3.清理后内存使用情况 free -m4.完成!查看内存条数命令: dmidecode | grep -A16 "Memory Device$" ++++++++++++++++++++++++++++++++++++...

linux为 rsync 添加开机启动

[root@rsync-server-1 /]# echo "/usr/bin/rsync --daemon" >> /etc/rc.local [root@rsync-server-1 /]# grep daemon /etc/rc.local # rsyncd service daemon by sun 20140628 /usr/bin/...

龙芯CAN测试(sja1000)

测试方案 CAN0和CAN1相连,互相收发数据。连接方式如下图: 使用扩展模式CAN1发送数据CAN0接收数据。 使用标准模式CAN1发送数据CAN0接收数据。 使用EJTAG中bin文件夹内的can.c代码,使用callbin的方式测试CAN的收发。Can.c中CAN默认工作在扩展模式。当测试CAN的标准模式时需要对代码进行如下修改。 软件...