zoukankan      html  css  js  c++  java
  • linux 应用程序直接读写寄存器或物理内存

    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 int dev_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     int i;
    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);
    }
    

      

  • 相关阅读:
    Python logging模块异步线程写日志实现过程解析
    Python数据分析实战项目介绍
    Pytorch 卷积中的 Input Shape用法
    Python 找出出现次数超过数组长度一半的元素实例
    Linux系统如何安装Python?新手教程
    MySQL 日志 复制数据库 InnoDB表空间模式 mysql默认数据库
    MySQL 8.0 窗口函数 排名、topN问题
    MySQL 求中位数 两个案例
    MySQL 创建表 复制表结构的两种方法 插入相同数据 重命名表 排查并修改字符集
    mysql if 和 case
  • 原文地址:https://www.cnblogs.com/fanguang/p/12284202.html
Copyright © 2011-2022 走看看