linux内核 dma,Linux内核的DMA-(1)

linux内核的内存管理

Linux内核中,地址分为以下的几种类型:用户虚拟地址、物理地址、总线地址、内核逻辑地址、内核虚拟地址。

用户虚拟地址

这种地址是用户所见的常规地址,一般32或64位。每个进程的都有自己独立的虚拟地址空间。

物理地址

这种地址在处理器和系统内存中间使用。在某些情况,32位系统可以使用64位物理内存(PAE?)。

总线地址

这个地址在外围总线和内存之间使用。一些计算机体系结构提供了I/O内存管理单元,实现了总线和主内存之间的重新映射。

内核逻辑地址

内核逻辑地址组成了内核的常规地址空间。这个地址映射了部分的内存,并经常视为物理地址。

内核虚拟地址

所有的逻辑地址都是内核虚拟地址。

物理地址和页

在linux系统中,许多对内存的操作都是基于单个页的,页的大小通常随体系结构的不同而不同,大多数系统都是4k。内存地址大多被分为一个页号和一个偏移量。4k的页,最后的12位是偏移量(2^12),剩下的高位指页号。页帧指去除地址的页偏移量,并将剩余的部分右移到右端的部分。

高端和低端内存

内核将4G的虚拟地址空间划分为用户空间和内核空间。一个典型的分割是3G用户空间,1G内核空间。对于使用了PAE的内核来说,内核必须建立明确的虚拟映射来使该页在内核地址空间中被访问。所以许多的内核数据必须被放置在低端内存中。高端内存更趋向分配给用户。

内存映射和页结构

为了支持高端内存(高端内存无法直接使用逻辑地址访问),内核中使用指向page结构的的指针来访问页面。page结构体的主要成员如下:

atomic int count; //对该页的访问计数。如果等于0,那么这个页将会被返回给空闲链表。

void *virtual; //如果被映射,那么指向这一页的内核虚拟地址;如果没有被映射,那么指向NULL.低端内存页总是被映射,高端内存页通常不被映射。访问该成员请使用page_address宏。

unsigned long flags; //描述页状态的一系列标志。PG_locked表示内存中的页被锁住,PG_reserved表示禁止MMU访问这个页。

虚拟内存区

进程的内存映射至少包含:

程序的可执行代码区域(text)

多个数据区,其中包含初始化数据(.data)、非初始化数据(.bss)以及程序堆栈

与每个活动的内存映射对应的区域

可以通过查看/proc/的方法了解的内存区域。该文件中的每一项对应vm_area_struct中的一个成员:

start-end perm offset major:minor inode image

start-end:该内存区域的起始处和结束处的虚拟地址

perm:内存区域的读写执行权限的位掩码

offset:内存区域在映射文件中的起始位置

major:minor:拥有映射文件的设备的主次设备号。对于设备映射来说,指包含设备的特殊文件的磁盘分区。

inode:被映射的文件的索引节点号。

image:被映射文件的名称。

vm_area_struct结构

vm_area_struct的结构如下所述。

unsigned long vm_start;

unsigned long vm_end;//该VMA的内存地址的起讫点

struct file *vm_file;//指向与该区域相关联的file结构指针

unsigned long vm_pgoff;//以页为单位,文件中该区域的偏移量。

unsigned long vm_flags;//描述该区域的一套标志。

struct vm_operations_struct *vm_ops;//内核能调用的一套函数。

void *vm_private_data;//驱动程序用来保存自身信息的成员。

void (*open) (struct vm_area_struct *vma);//内核调用这个函数来初始化VMA。

void (*close) (struct vm_area_struct *vma);//销毁一个区域时内核调用这个函数。注意,VMA没有引用计数,所以每个使用区域的进程只能打开或关闭一次。

struct page *(*nopage)(struct vm_area_struct *vma, unsigned long address, int *type);//缺页调用此函数。

int (*populate)(struct vm_area_struct *vm, unsigned long address, unsigned long len, pgprot_t prot, unsigned long pgoff, int nonblock);//在用户空间访问页前,该函数允许内核将这些页预先装入内存。

mmap设备操作

mmap有以下的几个限制:串口和面向流的设备不能使用mmap,并且mmap必须以PAGE_SIZE为单位进行映射。起始地址也得是整数倍(不是强制)。

mmap是file_operations结构的一部分。

mmap通常有以下的原型:

mmap (caddr_t addr, size_t len, int prot, int flags, int fd, off_t offset);

但是文件操作声明如下:

int (*mmap) (struct file *filp, struct vm_area_struct *vma);

建立页表有两种方法:remap_pfn_range一次性全部建立或者nopage VMA一次建立一个。如果驱动程序要把设备内存线性地址映射到用户地址空间中,只需要调用remap_pfn_range函数。具体代码参考书上。

当用户访问VMA中的页,而该页不在内存中时,使用nopage映射内存。该函数还调用get_page宏来增加使用页面的引用计数。对于PCI,必须使用remap_to_range.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值