1. 关于linux系统下的物理内存映射
内存是一种存储设备,现在一般是ddrsdram,地址是用来标记内存的数据的。版在操作系统中物理内存指实际的ddrsdram,而虚权拟内存指的是在硬盘中的缓存,windows中是页面文件,linux中是swap分区。cpu产生的地址是虚拟地址也可以称作有效地址,而在cpu外地址线上的信号称作实际地址或物理地址。这2类地址有某种对应关系,由操作系统管理。如果是x86架构的话,物理地址和虚拟地址中间还有线性地址的概念。
2. Linux I/O内存静态映射
在将Linux移植到目标电路板的过程中,有得会建立外设IO内存物理地址到虚拟地址的静态映射,这个映射通过在与电路板对应的map_desc结构体数组中添加新的成员来完成。iotable_init()是最终建立页映射的函数,它通过ACHINE_START、MACHINE_END宏赋值给电路板的map_io())函数。将Linux操作系统移植到特定平台上,MACHINE_START(或者DT_MACHINE_START)、MACHINE_END宏之间的定义针对特定电路板而设计,其中的map_io ()成员函数完成IO内存的静态映射。在一个已经移植好操作系统的内核中,驱动工程师可以对非常规内存区域的IO内存(外设控制器寄存器、MCU内部集成的外设控制器寄存器等)依照电路板的资源使用情况添加到map_desc数组中,但是目前该方法已经不值得推荐。Cache和DMA本身似乎是两个毫不相关的事物。Cache被用作CPU针对内存的缓存,利用程序的空间局部性和时间局部性原理,达到较高的命中率,从而避免CPU每次都必须要与相对慢速的内存交互数据来提高数据的访问速率。DMA可以作为内存与外设之间传输数据的方式,在这种传输方式之下,数据并不需要经过CPU中转。假设DMA针对内存的目的地址与Cache缓存的对象没有重叠区域,DMA和Cache之间将相安无事。但是,如果DMA的目的地址与Cache所缓存的内存地址访问有重叠,经过DMA操作,与Cache缓存对应的内存中的数据已经被修改,而CPU本身并不知道,它仍然认为Cache中的数据就是内存中的数据,那在以后访问Cache映射的内存时,它仍然使用陈旧的Cache数据。这样就会发生Cache与内存之间数据“不一致性”的错误。
3. 一个文本文件用内存映射打开后,如何一行一行地进行读取 Linux下C语言
//mbuf为文件的内存映射地址,buf为你要保存字符串的地回址。答char *readline(const char *mbuf, char *buf, int maxlen){ int len=0; while(len<maxlen-1 && *(mbuf+len)!='\n') { *(buf+len)=*(mbuf+len); len++; } *(buf+len)='\0'; return buf;}
4. Linux将设备地址映射到用户空间内存映射与VMA
一般情况下,用户空间是不可能也不应该直接访问设备的,但是,设备驱动程序中可实现mmap ()函数,这个函数可使得用户空间能直接访问设备的物理地址。实际上,mmap ()实现了这样的一个映射过程:它将用户空间的一段内存与设备内存关联,当用户访问用户空间的这段地址范围时,实际上会转化为对设备的访问。这种能力对于显示适配器一类的设备非常有意义,如果用户空间可直接通过内存映射访问显存的话,屏幕帧的各点像素将不再需要一个从用户空间到内核空间的复制的过程。mmap ()必须以PAGE_SIZE为单位进行映射,实际上,内存只能以页为单位进行映射,若要映射非PAGE_SIZE整数倍的地址范围,要先进行页对齐,强行以PAGE_SIZE的倍数大小进行映射。从file_operations文件操作结构体可以看出,驱动中mmap ()函数的原型如下:int ( *mmap)(struct file *, struct vm_area_struct* ) ;驱动中的mmap () 函数将在用户进行mmap ()系统调用时最终被调用,mmap ()系统调用的原型与file_operations中mmap ()的原型区别很大,如下所示:caddr_t mmap (caddr_t addr,size_t len,int prot,int flags,int fd,off_t offset);参数fd为文件描述符,一般由open ()返回,fd也可以指定为-1,此时需指定flags参数中的MAP_ANON,表明进行的是匿名映射。len是映射到调用用户空间的字节数,它从被映射文件开头offset个字节开始算起,offset参数一般设为0,表示从文件头开始映射。prot参数指定访问权限,可取如下几个值的“或”:PROT_READ(可读)、PROT_WRITE(可写)、PROT_EXEC(可执行)和PROT_NONE(不可访问)。参数addr指定文件应被映射到用户空间的起始地址,一般被指定为NULL,这样,选择起始地址的任务将由内核完成,而函数的返回值就是映射到用户空间的地址。其类型caddr_t实际上就是void*。当用户调用mmap ())的时候,内核会进行如下处理。1)在进程的虚拟空间查找一块VMA。2)将这块VMA进行映射。3)如果设备驱动程序或者文件系统的file_operations定义了mmap ()操作,则调用它。4)将这个VMA插入进程的VMA链表中。file_operations中mmap ()函数的第一个参数就是步骤1)找到的VMA。由mmap ()系统调用映射的内存可由munmap ()解除映射,这个函数的原型如下:int munmap(caddr_t addr, size_t len ) ;驱动程序中mmap ()的实现机制是建立页表,并填充VMA结构体中vm_operations_struct指针。
5. linux设备驱动物理内存映射
int video_qsb_mmap(struct file *file,struct vm_area_struct *vma) { int ret; u32 size = vma->vm_end – vma->vm_start; vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); vma->vm_flags |= VM_RESERVED; if(frm_num<qsb_dev.mmap_num) { ret = remap_pfn_range(vma,vma->vm_start,align_addr>>PAGE_SHIFT,qsb_dev.stride*1944,vma->vm_page_prot); align_addr=PAGE_ALIGN(align_addr+2592*1944);if(ret != 0) { return -EAGAIN; } frm_num++; } return 0; } 这是我自己的函数,我是在UBOOT里规定系统只能用前192M,其它的由应用层调用MMAP函数实现映射,贴过来格式乱了,你参考参考,是可以用的。大概就是申请1张图片的大小,并进行页对齐。不懂的问,你查查这几个函数的作用参数照着写应该就可以实现你得目的了。
6. Linux I/O内存静态映射
将Linux移植到目标电路板的过程中,有得会建立外设IO内存物理地址到虚拟地址的静态映射,这个映射通过在与电路板对应的map_desc结构体数组中添加新的成员来完成。iotable_init()是最终建立页映射的函数,它通过ACHINE_START、MACHINE_END宏赋值给电路板的map_io())函数。将Linux操作系统移植到特定平台上,MACHINE_START(或者DT_MACHINE_START)、MACHINE_END宏之间的定义针对特定电路板而设计,其中的map_io ()成员函数完成IO内存的静态映射。在一个已经移植好操作系统的内核中,驱动工程师可以对非常规内存区域的IO内存(外设控制器寄存器、MCU内部集成的外设控制器寄存器等)依照电路板的资源使用情况添加到map_desc数组中,但是目前该方法已经不值得推荐。Cache和DMA本身似乎是两个毫不相关的事物。Cache被用作CPU针对内存的缓存,利用程序的空间局部性和时间局部性原理,达到较高的命中率,从而避免CPU每次都必须要与相对慢速的内存交互数据来提高数据的访问速率。DMA可以作为内存与外设之间传输数据的方式,在这种传输方式之下,数据并不需要经过CPU中转。假设DMA针对内存的目的地址与Cache缓存的对象没有重叠区域,DMA和Cache之间将相安无事。但是,如果DMA的目的地址与Cache所缓存的内存地址访问有重叠,经过DMA操作,与Cache缓存对应的内存中的数据已经被修改,而CPU本身并不知道,它仍然认为Cache中的数据就是内存中的数据,那在以后访问Cache映射的内存时,它仍然使用陈旧的Cache数据。这样就会发生Cache与内存之间数据“不一致性”的错误。
7. c++在linux系统,用内存映射删除文件任意一行(如:第一行),每行1000字符,删除后写回原文件,完整代码
文件又不是一定都是文本文件,你这一行是什么意思阿…linux下内存映射的API是mmap。先把文件映内射到内容存,然后直接把某部分的数据清零,把清零区域后面的数据往前挪动,把空白的地方覆盖掉。搞定之后unmmap一下就好了。不过你还需要用ftruncate把文件的尺寸变化到正确的大小,也就是把文件多余的尾部截掉。代码就不用了吧…应该不会超过50行…
8. LINUX内存映射问题
Linux的内存模型,一般为:地址 作用 说明 >=0xc000 0000 内核虚拟存储器 用户代码不可见区域 <0xc000 0000 Stack(用户栈) ESP指向栈顶↓↑空闲内存 >=0x4000 0000 文件映射区<0x4000 0000↑空闲内存Heap(运行时堆) 通过brk/sbrk系统调用扩大堆,向上增长。.data、.bss(读写段) 从可执行文件中加载 >=0x0804 8000(0x00008000 for arm linux) .init、.text、.rodata(只读段) 从可执行文件中加载 <0x0804 8000(0x00008000 for arm linux) 保留区域运行一个测试程序,观察其结果:#include <stdio.h>int main(int argc, char* argv[]){ int first = 0; int* p0 = malloc(1024); int* p1 = malloc(1024 * 1024); int* p2 = malloc(512 * 1024 * 1024 ); int* p3 = malloc(1024 * 1024 * 1024 ); printf("main=%p print=%p\n", main, printf); printf("first=%p\n", &first); printf("p0=%p p1=%p p2=%p p3=%p\n", p0, p1, p2, p3);getchar();return 0;}运行后,输出结果为:main=0x8048404 print=0x8048324first=0xbfcd1264p0=0x9253008 p1=0xb7ec0008 p2=0x97ebf008 p3=0x57ebe008my pc (fc5)输出结果如下:main=0x80483f4 print=0x8048324first=0xbf848660p0=0x9ab2008 p1=0xb7e38008 p2=0x97e37008 p3=(nil)arm-linux输出如下结果:main=0x8528 print=0x8404first=0xbec9fe10p0=0x11008 p1=0x4005a008 p2=(nil) p3=(nil) main和print两个函数是代码段(.text)的,其地址符合表一的描述。 first是第一个临时变量,由于在first之前还有一些环境变量,它的值并非0xbfffffff,而是0xbfcd1264,这是正常的。 p0是在堆中分配的,其地址小于0x4000 0000,这也是正常的。 但p1和p2也是在堆中分配的,而其地址竟大于0x4000 0000,与表一描述不符。原因在于:运行时堆的位置与内存管理算法相关,也就是与malloc的实现相关。关于内存管理算法的问题,我们在后继文章中有详细描述,这里只作简要说明。在glibc实现的内存管理算法中,Malloc小块内存是在小于0x4000 0000的内存中分配的,通过brk/sbrk不断向上扩展,而分配大块内存,malloc直接通过系统调用mmap实现,分配得到的地址在文件映射区,所以其地址大于0x4000 0000。
未经允许不得转载:山九号 » 内存映射文件linux|c++在linux系统用内存映射删除文件任意一行(如:第一行)每行1000字符删除后写回原文件完整代码