Linux读写物理内存
一、基础知识
1.打开设备文件:
mem是一个字符设备文件,是计算机主存的一个映像。通常只有root用户对其有读写权限。因此只有root用户能进行这些操作。
如果要打开设备文件/dev/mem,需要系统调用open()函数,作用是打开一个文件或设备,其函数原型为:
int open(const char *path, int flags);
返回值:如果操作成功则返回一个文件描述符,否则返回-1
形 参:
path 被打开文件的路径即文件名描述。
flags 文件的访问模式描述,可常用的选项见下:
O_RDONLY 只读方式
O_WRONLY 只写方式
O_RDWR 可读写方式
说 明:此函数用于打开文件或者设备
头文件:#include <fcntl.h> #include <stat.h> 定义在/usr/include/fcntl.h中
2.读取内存映像:
内存映像其实在内存中创建一个与外存中文件完全相同的映像。用户可以将整个文件映射到内存中,也可以将文件的一部分映射到内存中。
使用操作内存的方法对文件进行操作。系统会将内存映像文件所做的改动反映到真实文件中去。
在内存映像I/O的实现过程中需要用到一些系统调用:
首先是创建内存映像文件的系统调用mmap()函数,其函数原型为:
void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset);
返回值:成功时,返回值为指向内存映像起始地址的指针,当调用失败时,返回值为-1
形 参:
start 一个void指针,表示希望将文件映射到此指针指向的位置,通常为NULL。
length 定义内存映像文件所占用的内存空间大小,以字节计。
prot 内存映像文件的安全属性,注意和open函数中的flags属性保持一致。它的可使用的选项如下:
Flags 含义
PROT_EXEC 被映像内存可能含义机器码,可被执行
PROT_NONE 映像内存不允许访问
PROT_READ 映像内存可读
PROT_WRITE 映像内存可写
flags 内存映像的标志,选项如下:
Flags 含义
MAP_FIXED 指定映射起始地址,如果由start和len指定的内存区重叠于现存的映射空间,重叠部分将会被丢弃。
如果指定的起始地址不可用,操作将会失败。并且起始地址必须落在页的边界上。
MAP_SHARED 与其它所有映射这个对象的进程共享映射空间。对共享区的写入,相当于输出到文件。
直到msync()或者munmap()被调用,文件实际上不会被更新。
MAP_PRIVATE 建立一个写入时拷贝的私有映射。内存区域的写入不会影响到原文件。
这个标志和以上标志是互斥的,只能使用其中一个。
MAP_NORESERVE 不要为这个映射保留交换空间。当交换空间被保留,对映射区修改的可能会得到保证。
当交换空间不被保留,同时内存不足,对映射区的修改会引起段违例信号。
MAP_LOCKED 锁定映射区的页面,从而防止页面被交换出内存。
MAP_GROWSDOWN 用于堆栈,告诉内核VM系统,映射区可以向下扩展。
MAP_ANONYMOUS 匿名映射,映射区不与任何文件关联。
MAP_ANON MAP_ANONYMOUS的别称,不再被使用。
MAP_FILE 兼容标志,被忽略。
MAP_32BIT 将映射区放在进程地址空间的低2GB,MAP_FIXED指定时会被忽略。
当前这个标志只在x86-64平台上得到支持。
MAP_POPULATE 为文件映射通过预读的方式准备好页表。随后对映射区的访问不会被页违例阻塞。
MAP_NONBLOCK 仅和MAP_POPULATE一起使用时才有意义。不执行预读,只为已存在于内存中的页面建立页表入口。
fd 要映射的文件的描述符。
offset 所映射的数据内容 距离文件头的偏移量。
说 明:此函数用于将一个文件或它的一部分映射到内存中。
头文件:#include <sys/mman.h> #include <sys/types.h> 函数定义在/usr/include/sys/mman.h
3.撤销内存映像的修改
另外我们使用完内存映像文件后,要用系统调用函数munmap()函数来撤销,其函数原型为:
int munmap(void *start, size_t length);
返回值:成功时,返回值为0;调用失败时返回值为 -1,并将errno设置为相应值。
形 参:
start 要撤销的内存映像文件的起始地址。
length 要撤销的内存映像文件的大小。
说 明:当进程结束或利用exec相关函数来执行其他程序时,映射内存会自动解除,但关闭对应的文件描述词时不会解除映射。
头文件:#include <sys/mman.h>
4.将内存映像的改动保存到外存中
最后,如果我们要将内存映像的改动保存到外存中,还需要系统调用msync()函数,其函数原型为:
int msync(const void *start,size_t length,int flags);
返回值:成功时,返回值为0;调用失败时返回值为 -1,并将errno设置为相应值。
形 参:
start 要保存到外存的那些源文件的起始地址。
length 表示内存映像文件的大小。
flags 设置了函数的相应操作,其具体选项如下:
Flags 含义
MS_ASYNC 调用一个写操作并返回
MS_INVALIDATE 映像到相同文件的内存映像数据更新
MS_SYNC 完成写操作后函数返回
说 明:进程在映射空间的对共享内容的改变并不直接写回到磁盘文件中,往往在调用munmap()后才执行该操作。
可以通过调用msync()函数来实现磁盘文件内容与共享内存区中的内容一致,即同步操作。
头文件:#include <sys/mman.h>
5.通过/dev/mem设备文件和mmap系统调用,可以将线性地址描述的物理内存映射到进程的地址空间,然后就可以直接访问这段内存了。
二、一个例子
- #include <stdio.h>
- #include <unistd.h>
- #include <sys/mman.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- int main (int args, char* arg[])
- {
- int i;
- int fd;
- char* mem;
- char *buff = "HELLO";
- //open /dev/mem with read and write mode
- if((fd = open ("/dev/mem", O_RDWR)) < 0)
- {
- perror ("open error");
- return -1;
- }
- //map physical memory 0-10 bytes
- mem = mmap (0, 10, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
- if (mem == MAP_FAILED)
- {
- perror ("mmap error:");
- return 1;
- }
- //Read old value
- for (i = 0; i < 5; i++)
- {
- printf("\nold mem[%d]:%d", i, mem[i]);
- }
- printf(The value is 0x%x\n, *((int *)mem));
- //write memory
- memcpy(mem, buff, 5);
- //Read new value
- for (i = 0; i<5 ; i++)
- {
- printf("\nnew mem[%d]:%c", i, mem[i]);
- }
- printf("\n");
- munmap (mem, 10); //destroy map memory
- close (fd); //close file
- return 0;
- }使用 hexedit /dev/mem 可以显示所有物理内存中的信息。 运用mmap将/dev/mem map出来,然后直接对其读写可以实现用户空间的内核操作。
以下是我写的一个sample
#include<stdio.h>
#include<unistd.h>
#include<sys/mman.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
int main()
{
unsigned char * map_base;
FILE *f;
int n, fd;
fd = open("/dev/mem", O_RDWR|O_SYNC);
if (fd == -1)
{
return (-1);
}
map_base = mmap(NULL, 0xff, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0x20000);
if (map_base == 0)
{
printf("NULL pointer!\n");
}
else
{
printf("Successfull!\n");
}
unsigned long addr;
unsigned char content;
int i = 0;
for (;i < 0xff; ++i)
{
addr = (unsigned long)(map_base + i);
content = map_base[i];
printf("address: 0x%lx content 0x%x\t\t", addr, (unsigned int)content);
map_base[i] = (unsigned char)i;
content = map_base[i];
printf("updated address: 0x%lx content 0x%x\n", addr, (unsigned int)content);
}
close(fd);
munmap(map_base, 0xff);
return (1);
}上面的例子将起始地址0x20000(物理地址), 长度为0xff映射出来。 然后就可以像普通数组一样操作内存。
下面是输出结果
address: 0x7f3f95391000 content 0x0 updated address: 0x7f3f95391000 content 0x0
address: 0x7f3f95391001 content 0x0 updated address: 0x7f3f95391001 content 0x1
address: 0x7f3f95391002 content 0x0 updated address: 0x7f3f95391002 content 0x2
address: 0x7f3f95391003 content 0x0 updated address: 0x7f3f95391003 content 0x3
address: 0x7f3f95391004 content 0x0 updated address: 0x7f3f95391004 content 0x4
。。。我的测试机器是64位机。 该例子将物理地址0x20000映射到了虚拟地址0x7f3f95391000。
首先将当前地址下的内容输出, 然后写入新值。
可以通过 hexedit /dev/mem 验证新值已经写入。
如果想在用户态处理kernel分配的地址可以这么做。 首先用virt_addr = get_free_pages(GFP_KERNEL, order)分配内存,通过phy_addr = __pa(virt_addr)得到物理地址,然后在用户态将/dev/mem用mmap 映射出来, offset就是phy_addr, length设为 2^order。 此时就可以在用户态读写内核分配的内存了。
注:该操作需要有root权限。
————————————————
版权声明:本文为CSDN博主「zhanglei4214」的原创文章,遵循CC 4.0 by-sa版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/zhanglei4214/article/details/6653568
Linux读写物理内存的更多相关文章
- Linux就这个范儿 第15章 七种武器 linux 同步IO: sync、fsync与fdatasync Linux中的内存大页面huge page/large page David Cutler Linux读写内存数据的三种方式
Linux就这个范儿 第15章 七种武器 linux 同步IO: sync.fsync与fdatasync Linux中的内存大页面huge page/large page David Cut ...
- Linux就这个范儿 第18章 这里也是鼓乐笙箫 Linux读写内存数据的三种方式
Linux就这个范儿 第18章 这里也是鼓乐笙箫 Linux读写内存数据的三种方式 P703 Linux读写内存数据的三种方式 1.read ,write方式会在用户空间和内核空间不断拷贝数据, ...
- Linux查看物理内存信息
Linux查看物理内存信息 1. 查看内存大小 dmidecode|grep Size 输出 Runtime Size: 64 kB ROM Size: 4608 kB Installed Size: ...
- devmem读写物理内存和devkmem读取内核虚拟内存
关键词:/dev/mem./dev/kmem.mmap.__va.__pa.remap_pfn_range等等. 在日常工作中常有直接操作寄存器或者某一物理地址的需求,busybox中提供了devme ...
- 浅谈linux读写同步机制RCU
RCU是linux系统的一种读写同步机制,说到底他也是一种内核同步的手段,本问就RCU概率和实现机制,给出笔者的理解. [RCU概率] 我们先看下内核文档中对RCU的定义: RCU is a sync ...
- LINUX读写文件
body, table{font-family: 微软雅黑; font-size: 10pt} table{border-collapse: collapse; border: solid gray; ...
- Linux 释放物理内存和虚拟内存
1.查看内存占用情况 $ free -m -h total used free shared buff/cache available Mem: .7G .0G .9G 385M 780M .0G S ...
- Linux读写执行权限
Linux 将访问文件的用户分为 3 类,分别是文件的所有者,所属组(也就是文件所属的群组)以及其他人. 最常见的文件权限有 3 种,即对文件的读(用 r 表示). 写(用 w 表示). 执行(用 x ...
- linux读写ntfs
frankly speaking, i hope to get a higher salary. yours frankly= yours sincerely = sincerely yours =y ...
随机推荐
- 百度编辑器ueditor上传图片失败,显示上传错误,实际上图片已经传到服务器或者本地
报错,上传失败,图片没有显示,且调试response没有信息,但是图片已经上传到了本地 这个问题是因为ueditor里面的Upload.class.php里面__construct()方法里面的ico ...
- HyperV - glossary
Root Partition - sometimes called partition. Manages machine-level functions such as device drivers, ...
- leetcode-mid-backtracking -22. Generate Parentheses-NO
mycode 没有思路,大早上就有些萎靡,其实和上一个电话号码的题如出一辙啦 参考: class Solution(object): def generateParenthesis(self, ...
- DNS 搜索 - dig 命令
dig 命令_互动百科 示例: # 全部 dig www.zjffun.com # 只显示 ANSWER SECTION dig www.zjffun.com +noall +answer
- set_option()函数
这个函数用于设置dataframe的输出显示, import pandas as ps pd.set_option('expand_frame_repr', True) # True就是可以换行显示. ...
- Linux安装MySql5.7及配置(yum安装)
Linux安装MySql5.7及配置(yum安装) [root@xld ~]# rpm -q centos-release centos-release-7-7.1908.0.el7.centos.x ...
- 正则表达式断言(Assertions)
一 零宽正向先行断言 x(?=y) 仅匹配被y跟随的x. const regExp = /Jack(?=Sparrow|Dawson)/g; const str = 'JackJones JackSp ...
- QA的工作职责是什么?
目前不知道,后续一点一点查资料补充吧 QA不管做什么的类型的测试,最基础的功能测试,需要搭建测试环境:进阶部分的性能压力测试,对搭建环境的要求更高:接口功能测试,搭建测试环境,和功能测试的差不多: 测 ...
- 【MM系列】SAP MR21修改标准价
公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[MM系列]在SAP里查看数据的方法 前言部 ...
- 深入理解java:1.1. 类加载器
从java的动态性到类加载机制 我们知道,Java是一种动态语言. 那么怎样理解这个“动态”呢? 或者说一门语言具备了什么特性,才能称之为动态语言呢? 对于java,我是这样理解的. 我们都知道J ...