使用mmap函数读取寄存器的值

实例代码

#define MAP_SIZE 	0x1000
#define MAP_MASK	(MAP_SIZE-1)
#define TARGET 		0x01C22000
#define VOLUME_VALUE 0x1000003A

void* readRegValue(void* args)
{
	int fd;	
	void* map_base;
	void* virt_addr;
	unsigned long read_sult;

    fd = open("/dev/mem",O_RDWR|O_SYNC);
	if(fd == -1)
	{
		printf("%s:open fd fail\n",__FUNCTION__);
		return NULL;
	}
	
	printf("%s:open fd %d successfully\n",__FUNCTION__,fd);
    printf("%s: %d\n",__FUNCTION__,getpagesize());

	//将内核空间映射到用户空间
	//第一个参数,所要映射到的虚拟地址,为NULL时,由系统分配
	//最后一个参数,所要映射的物理地址,需要进行对齐
	map_base = mmap(NULL,MAP_SIZE,PROT_READ|PROT_WRITE,MAP_SHARED,fd,TARGET & (~(getpagesize()-1)));
	if(map_base == MAP_FAILED)
	{
		printf("%s:number %d errno:%s\n", __FUNCTION__,errno,strerror(errno));
		printf("%s:mmap fail\n",__FUNCTION__);
		close(fd);
		return NULL;
	}
		
	printf("%s:0x%x %p\n",__FUNCTION__,TARGET & ~MAP_MASK,map_base);
	virt_addr = map_base + (TARGET & MAP_MASK);
	read_sult = *((unsigned long *)virt_addr);
	printf("%s:mmap  0x%x\n",__FUNCTION__,read_sult);
	printf("%s:0x%x %p 0x%x\n",__FUNCTION__,TARGET & ~MAP_MASK,virt_addr,read_sult);
	fflush(stdout);
	if(munmap(map_base,MAP_SIZE) == -1)
	{
		printf("%s:munmap fail\n",__FUNCTION__);
		printf("%s:number %d errno:%s\n", __FUNCTION__,errno,strerror(errno));
		close(fd);
		return NULL;
	}
    //所需业务处理。

    close(fd);
}

所涉及函数说明:

1.open函数

open函数是C语言中用于打开文件的一个函数。其原型如下:

#include <fcntl.h>
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);

其中,pathname表示文件的路径名;flags表示打开方式和操作模式;mode表示文件权限,仅在创建文件时有效。

下面对open函数的参数和返回值进行详细解释。

参数
pathname

pathname是被打开的文件路径名,可以是绝对路径或相对路径,也可以是一个符号链接文件。

flags

flags参数表示打开文件的方式和操作模式,其取值为以下标志位的组合:

标志位含义
O_RDONLY只读方式打开文件。
O_WRONLY只写方式打开文件。
O_RDWR读写方式打开文件。
O_CREAT文件不存在时创建文件。
O_TRUNC在打开文件时将文件内容清空。
O_APPEND在文件最后追加数据。
O_EXCL与O_CREAT一起使用,如果文件已存在不创建,并返回错误信息。
O_NOCTTY不分配控制终端。
O_NONBLOCK非阻塞方式打开文件。
O_DIRECTORY如果pathname不是一个目录,打开文件会失败。
O_CLOEXEC执行exec()函数时会关闭文件。
O_SYNC使用同步I/O方式打开文件。
mode

mode参数仅在创建文件时有效,用于指定文件的权限(即文件的读写权限),其取值由以下标志位的组合构成:

标志位含义
S_IRWXU文件所有者具有读、写、执行权限。
S_IRUSR文件所有者具有读权限。
S_IWUSR文件所有者具有写权限。
S_IXUSR文件所有者具有执行权限。
S_IRWXG文件所属组具有读、写、执行权限。
S_IRGRP文件所属组具有读权限。
S_IWGRP文件所属组具有写权限。
S_IXGRP文件所属组具有执行权限。
S_IRWXO其他用户具有读、写、执行权限。
S_IROTH其他用户具有读权限。
S_IWOTH其他用户具有写权限。
S_IXOTH其他用户具有执行权限。
返回值

当open函数调用成功时,返回文件描述符(file descriptor);当open调用失败时,返回-1。文件描述符是对文件的引用,是用于标识打开的文件的整数值。如果打开同一个文件两次,将得到两个不同的文件描述符,但它们引用的仍是同一个文件。

注意事项
  1. open函数可以打开普通文件、目录文件、字符设备文件和块设备文件等不同类型的文件。但是,在打开设备文件时,需要root权限。

  2. 如果使用O_CREAT标志位创建文件,需要使用mode参数指定文件的权限,否则无法访问。

  3. 本质上,open函数的返回值是一个文件描述符,可以通过read、write等函数对文件进行读写操作,操作完成后需要使用close函数关闭文件。

  4. 由于open函数是标准库函数,而非系统调用,因此在打开文件时会进行缓冲,所以open函数打开文件的速度较慢,如果需要高效率地打开文件,可以使用系统调用open()函数来代替。

  5. 在使用open函数时,需要注意文件路径名的正确性,否则会出现打开文件失败的情况。

  6. 打开文件时需要根据实际需求指定合适的文件访问方式和权限,并且需要注意判断打开文件是否成功。

2.close函数

在C语言中,close函数是用来关闭一个打开的文件描述符的。它的函数原型如下:

#include <unistd.h>

int close(int fd);

其中,fd是需要关闭的文件描述符。

close函数的功能是将文件描述符fd所代表的文件关闭,释放该文件描述符所占用的系统资源。同时,也会将fd指向的文件与该进程的连接断开。

使用close函数后,fd就不能再用于读写文件了。

下面是一个简单的使用close函数的例子:

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>

int main() 
{
    int fd = open("myfile.txt", O_RDONLY);

    /* do something with the file */

    close(fd);
    return 0;
}

在这个例子中,我们打开了一个名为“myfile.txt”的文件,并在操作文件后使用close函数关闭了这个文件。在关闭文件后,我们就无法再使用fd进行文件操作了。

3.getpagesize函数

getpagesize是一个系统调用函数,其作用是获取系统的页面大小。

函数原型:long getpagesize(void);

函数返回值:返回系统页面大小,通常为4KB。

函数说明:

  1. 页面大小是操作系统内存管理的一个重要概念,指的是操作系统内存分页机制每一块的大小,通常为4KB、8KB或者16KB等。

  2. 在程序中调用getpagesize函数可以获取当前系统的页面大小,通常可以用于需要手动进行内存管理的程序中。

示例代码:

#include <stdio.h>
#include <unistd.h>

int main() {
    long page_size = getpagesize();
    printf("Page size is %ld bytes\n", page_size);
    return 0;
}

可能的输出为:

Page size is 4096 bytes

4.strerror函数

在C语言中,errno是一个全局变量,用于保存最近一次发生的错误代码。strerror()函数可以将errno的值解释为人类可读的错误消息。

函数原型:char *strerror(int errnum);

参数说明:errnum表示错误码,如果errnum为0,则返回一个空指针。

返回值:返回一个指向错误消息的指针。如果errnum没有对应的错误消息,则返回一个表示未知错误的消息。

示例代码:

#include<stdio.h>
#include<string.h>
#include<errno.h>

int main(){
    FILE *file = fopen("nonexistent.txt","r");
    if(file == NULL){
        printf("Failed to open file: %s\n", strerror(errno));
    }
    return 0;
}

执行结果:

Failed to open file: No such file or directory

上面的例子演示了如何使用strerror()函数来打印错误消息。在这个例子中,我们试图打开一个不存在的文件,并使用strerror()函数来打印错误消息。strerror()函数解释了errno的值,并将其转换为人类可读的错误消息。

5.fflush函数

fflush函数是C标准库<stdio.h>中的一个函数,其作用是刷新缓冲区。

缓冲区是在程序执行中为了减少I/O(输入输出)调用次数而设计的一种机制。在将数据从程序写入到文件或终端时,数据不会立即被输出,而是先存储到缓冲区中,等到缓冲区满了再一起输出。同样,在从文件或终端中读取数据时,也是先将数据存储到缓冲区中,等到缓冲区满了再一次性读取。

fflush函数可以强制将缓冲区的数据立即输出,而不必等到缓冲区满了。这对于需要实时显示输出结果的程序非常有用。

fflush函数的使用格式为:

int fflush(FILE *stream);

参数stream是一个指向文件流对象的指针,如果stream为NULL,则将所有缓冲区都刷新。

fflush函数的返回值为0表示成功,否则表示失败。

以下是一个简单的fflush函数使用示例:

#include <stdio.h>
int main(){
   char buffer[1024];
   FILE *fp = fopen("test.txt", "w");
   fprintf(fp, "This is testing for fflush...\n");
   fflush(fp);
   fputs("这里插入文字", fp);
   fclose(fp);
   return 0;
}

在这个例子中,我们先向文件写入了一行文字并调用了fflush函数强制将缓冲区中的内容写入文件,然后在文件末尾插入了一些文字,并最终关闭了文件。

6.mmap函数

mmap函数是Linux/Unix系统中的一个系统调用函数,用于将文件或设备映射到进程的地址空间中,使得进程可以直接读取和写入该文件或设备的数据。该函数通常用于高速I/O和共享内存等操作。

mmap函数的使用格式如下:

void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);

其中各参数的含义如下:

  • addr:指定映射区域的起始地址,如果为NULL,则表示让系统自动选择。
  • length:指定映射区域的长度,以字节为单位。
  • prot:指定映射区域的保护方式,可能的值为PROT_READ(可读),PROT_WRITE(可写),PROT_EXEC(可执行)和PROT_NONE(不可访问)。
  • flags:指定映射区域的标志,可能的值为MAP_SHARED(共享映射)和MAP_PRIVATE(私有映射)等。
  • fd:指定要映射的文件的文件描述符,如果映射的是一个设备,fd通常为-1。
  • offset:指定映射区域在文件中的偏移量。

mmap函数的返回值为映射区域的起始地址,如果出现错误,返回MAP_FAILED。

以下是一个简单的mmap函数使用示例:

#include <stdio.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

int main(int argc, char *argv[]) {
    int fd;
    void *addr;
    struct stat sb;

    if (argc < 2) {
        fprintf(stderr, "Usage: %s <file>\n", argv[0]);
        return -1;
    }

    fd = open(argv[1], O_RDONLY);
    if (fd == -1) {
        perror("open");
        return -1;
    }

    if (fstat(fd, &sb) == -1) {
        perror("fstat");
        return -1;
    }

    addr = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
    if (addr == MAP_FAILED) {
        perror("mmap");
        return -1;
    }

    printf("Mapped file: %s\n", argv[1]);
    printf("File size: %lld bytes\n", (long long) sb.st_size);
    printf("Mapped address: %p\n", addr);
    printf("Contents of the file:\n");
    printf("%.*s", (int) sb.st_size, (char *) addr);

    munmap(addr, sb.st_size);
    close(fd);

    return 0;
}

在这个例子中,我们首先打开了一个指定的文件,并获取了该文件的大小,然后调用mmap函数将该文件映射到进程的地址空间中,最后读取了该文件的内容并输出。注意,在使用完mmap函数后,需要调用munmap函数释放映射区域。

总结

mmap函数可以用于将设备寄存器映射到进程的地址空间中,从而可以通过对该映射区域的读写操作来读写设备寄存器。这种方式相比直接使用in/out指令或其他I/O操作函数,具有更高的灵活性和效率。

在使用mmap函数时,需要先打开设备文件,然后调用mmap函数将设备寄存器映射到进程的地址空间中。通常情况下,通过ioctl函数可以获取设备寄存器的地址和长度信息,以便正确地指定映射区域的起始地址和长度。

在读取设备寄存器时,可以将设备寄存器的地址作为指针来访问映射区域中的相应位置,从而达到读取寄存器的目的。在写入设备寄存器时,也可以将相应的值直接写入映射区域中的相应位置。

需要注意的是,在使用mmap函数读写设备寄存器时,需要确保操作的安全性和正确性,尤其是在多线程或多进程环境下,需要进行适当的同步和互斥操作。此外,需要根据不同的体系结构和操作系统进行相应的调整和优化,来达到更好的性能和稳定性。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

茶包不是trouble

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值