LDD3学习笔记(18):内存映射和DMA

简介:  1、介绍性材料#include #include 和内存管理相关的大部分函数和结构, 原型和定义在这些头文件.void *__va(unsigned long physaddr);unsigned long __pa(void *kaddr);在内核逻辑地址和物理地址之间转换的宏定义.
 

1、介绍性材料

#include <linux/mm.h>

#include <asm/page.h>

和内存管理相关的大部分函数和结构原型和定义在这些头文件.

void *__va(unsigned long physaddr);

unsigned long __pa(void *kaddr);

在内核逻辑地址和物理地址之间转换的宏定义.

PAGE_SIZE

PAGE_SHIFT 

常量给出底层硬件的页的大小(字节)和一个页面号必须被移位来转变为一个物理地址的位

.

struct page 

在系统内存映射中表示一个硬件页的结构.

struct page *virt_to_page(void *kaddr);

void *page_address(struct page *page);

struct page *pfn_to_page(int pfn);

宏定义在内核逻辑地址和它们相关的内存映射入口之间转换的. page_address 只用在低地址

页或者已被明确映射的高地址页. pfn_to_page 转换一个页面号到它的相关的 struct page 指针.

unsigned long kmap(struct page *page);

void kunmap(struct page *page);

kmap 返回一个内核虚拟地址被映射到给定页如果需要并创建映射. kunmap 为给定页删除

映射.

#include <linux/highmem.h>

#include <asm/kmap_types.h>

void *kmap_atomic(struct page *page, enum km_type type);

void kunmap_atomic(void *addr, enum km_type type);

kmap 的高性能版本结果的映射只能被原子代码持有对于驱动, type 应当是 KM_USER1, 

KM_USER1, KM_IRQ0, 或者 KM_IRQ1.

struct vm_area_struct;

描述一个 VMA 的结构.

2、实现 mmap

int remap_pfn_range(struct vm_area_struct *vma, unsigned long virt_add, unsigned long pfn, unsigned long 

size, pgprot_t prot);

int io_remap_page_range(struct vm_area_struct *vma, unsigned long virt_add, unsigned long phys_add, 

unsigned long size, pgprot_t prot);

位于 mmap 核心的函数它们映射 size 字节的物理地址从 pfn 指出的页号开始到虚拟地址 

virt_add. 和虚拟空间相关联的保护位在 prot 里指定. io_remap_page_range 应当在目标地址在 

I/O 内存空间里时被使用.

struct page *vmalloc_to_page(void *vmaddr);

转换一个由 vmalloc 获得的内核虚拟地址到它的对应的 struct page 指针.

3、实现直接 I/O

int get_user_pages(struct task_struct *tsk, struct mm_struct *mm, unsigned long start, int len, int write, int 

force, struct page **pages, struct vm_area_struct **vmas);

函数加锁一个用户空间缓冲到内存并且返回对应的 struct page 指针调用者必须持有 mm-

>mmap_sem.

SetPageDirty(struct page *page);

宏定义标识给定的页为""(被修改)并且需要写到它的后备存储在它被释放前.

void page_cache_release(struct page *page);

释放给定的页从页缓存中.

int is_sync_kiocb(struct kiocb *iocb);

宏定义返回非零如果给定的 IOCB 需要同步执行.

int aio_complete(struct kiocb *iocb, long res, long res2);

函数指示一个异步 I/O 操作完成.

4、直接内存存取

#include <asm/io.h>

unsigned long virt_to_bus(volatile void * address);

void * bus_to_virt(unsigned long address);

过时的不好的函数在内核虚拟和总线地址之间转换总线地址必须用来和外设通讯.

#include <linux/dma-mapping.h>

需要来定义通用 DMA 函数的头文件.

int dma_set_mask(struct device *dev, u64 mask);

对于无法寻址整个 32-位范围的外设这个函数通知内核可寻址的地址范围并且如果可进行 

DMA 返回非零.

void *dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *bus_addr, int flag);

void dma_free_coherent(struct device *dev, size_t size, void *cpuaddr, dma_handle_t bus_addr);

分配和释放一致 DMA 映射对一个将持续在驱动的生命周期中的缓冲.

#include <linux/dmapool.h>

struct dma_pool *dma_pool_create(const char *name, struct device *dev, size_t size, size_t align, size_t 

allocation);

void dma_pool_destroy(struct dma_pool *pool);

void *dma_pool_alloc(struct dma_pool *pool, int mem_flags, dma_addr_t *handle);

void dma_pool_free(struct dma_pool *pool, void *vaddr, dma_addr_t handle);

创建销毁和使用 DMA 池来管理小 DMA 区的函数.

enum dma_data_direction;

DMA_TO_DEVICE

DMA_FROM_DEVICE

DMA_BIDIRECTIONAL

DMA_NONE 

符号用来告知流映射函数在什么方向数据移入或出缓冲

dma_addr_t dma_map_single(struct device *dev, void *buffer, size_t size, enum dma_data_direction 

direction);

void dma_unmap_single(struct device *dev, dma_addr_t bus_addr, size_t size, enum dma_data_direction 

direction);

创建和销毁一个单使用流 DMA 映射.

void dma_sync_single_for_cpu(struct device *dev, dma_handle_t bus_addr, size_t size, enum 

dma_data_direction direction);

void dma_sync_single_for_device(struct device *dev, dma_handle_t bus_addr, size_t size, enumdma_data_direction direction);

同步一个由一个流映射的缓冲必须使用这些函数如果处理器必须存取一个缓冲当使用流

映射时.(当设备拥有缓冲时).

#include <asm/scatterlist.h>

struct scatterlist { /* ... */ };

dma_addr_t sg_dma_address(struct scatterlist *sg);

unsigned int sg_dma_len(struct scatterlist *sg);

这个散布表结构描述一个涉及不止一个缓冲的 I/O 操作宏 sg_dma_address he sg_dma_len 

用来抽取总线地址和缓冲长度来传递给设备当实现发散/汇聚操作时.

dma_map_sg(struct device *dev, struct scatterlist *list, int nents, enum dma_data_direction direction);

dma_unmap_sg(struct device *dev, struct scatterlist *list, int nents, enum dma_data_direction direction);

void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nents, enum dma_data_direction 

direction);

void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nents, enum dma_data_direction 

direction);

dma_map_sg 映射一个 发散/汇聚 操作并且 dma_unmap_sg 恢复这些映射如果在这个映射

被激活时缓冲必须被存取, dma_sync_sg_* 可用来同步.

/proc/dma 

包含在 DMA 控制器中的被分配的通道的文本快照的文件基于 PCI 的 DMA 不显示因为每

个板独立工作不需要分配一个通道在 DMA 控制器中.

#include <asm/dma.h>

定义或者原型化所有和 DMA 相关的函数和宏定义它必须被包含来使用任何下面符号.

int request_dma(unsigned int channel, const char *name);

void free_dma(unsigned int channel);

存取 DMA 注册注册必须在使用 ISA DMA 通道之前进行.

unsigned long claim_dma_lock( );

void release_dma_lock(unsigned long flags);

获取和释放 DMA 自旋锁它必须被持有在调用其他的在这个列表中描述的 ISA DMA 函数

之前它们在本地处理器上也关闭和重新使能中断

void set_dma_mode(unsigned int channel, char mode);

void set_dma_addr(unsigned int channel, unsigned int addr);

void set_dma_count(unsigned int channel, unsigned int count);

编程 DMA 信息在 DMA 控制器中. addr 是一个总线地址

void disable_dma(unsigned int channel);

void enable_dma(unsigned int channel);

一个 DMA 通道必须被关闭在配置期间这些函数改变 DMA 通道的状态.

int get_dma_residue(unsigned int channel);

如果这驱动需要知道一个 DMA 传送在进行它可调用这个函数返回尚未完成的数据传输

的数目在成功的 DMA 完成后这个函数返回 0; 值是不可预测的当数据仍然在传送时.

void clear_dma_ff(unsigned int channel);

DMA flip-flop 被控制器用来传送 16-位值通过 个 位操作它必须被清除在发送任何数

据给处理器之前.

目录
相关文章
|
2月前
|
传感器 人工智能 物联网
C 语言在计算机科学中尤其在硬件交互方面占据重要地位。本文探讨了 C 语言与硬件交互的主要方法,包括直接访问硬件寄存器、中断处理、I/O 端口操作、内存映射 I/O 和设备驱动程序开发
C 语言在计算机科学中尤其在硬件交互方面占据重要地位。本文探讨了 C 语言与硬件交互的主要方法,包括直接访问硬件寄存器、中断处理、I/O 端口操作、内存映射 I/O 和设备驱动程序开发,以及面临的挑战和未来趋势,旨在帮助读者深入了解并掌握这些关键技术。
51 6
|
16天前
|
存储 缓存 数据安全/隐私保护
DMA(Direct Memory Access):直接内存访问
DMA(Direct Memory Access)是一种允许外设直接与内存进行数据传输的技术,无需 CPU 干预。它通过减轻 CPU 负担、提高数据传输效率来提升系统性能。DMA 的工作模式包括直接模式和 FIFO 模式,数据传输方式有单字传送和块传送,寻址模式有增量寻址和非增量寻址。通过缓存一致性协议、同步机制、数据校验和合理的内存管理,DMA 确保了数据在内存中的一致性和完整性。
48 0
|
4月前
|
存储 缓存 Linux
用户态内存映射
【9月更文挑战第20天】内存映射不仅包括物理与虚拟内存间的映射,还涉及将文件内容映射至虚拟内存,使得访问内存即可获取文件数据。mmap 系统调用支持将文件或匿名内存映射到进程的虚拟内存空间,通过多级页表机制实现高效地址转换,并利用 TLB 加速映射过程。TLB 作为页表缓存,存储频繁访问的页表项,显著提升了地址转换速度。
|
3月前
|
Linux C++
Linux c/c++文件虚拟内存映射
这篇文章介绍了在Linux环境下,如何使用虚拟内存映射技术来提高文件读写的速度,并通过C/C++代码示例展示了文件映射的整个流程。
68 0
|
4月前
|
存储 安全 Linux
将文件映射到内存,像数组一样访问
将文件映射到内存,像数组一样访问
43 0
|
4月前
|
消息中间件 Linux 容器
共享内存的创建和映射过程
【9月更文挑战第1天】消息队列、共享内存及信号量在使用前需生成key并获取唯一ID,均通过`xxxget`函数实现。
|
5月前
|
存储 程序员 编译器
c++学习笔记08 内存分区、new和delete的用法
C++内存管理的学习笔记08,介绍了内存分区的概念,包括代码区、全局区、堆区和栈区,以及如何在堆区使用`new`和`delete`进行内存分配和释放。
55 0
|
7月前
|
存储 编译器 C语言
【C++】学习笔记——内存管理
【C++】学习笔记——内存管理
59 15
|
7月前
|
存储 C++
C primer plus 学习笔记 第12章 存储类别、链接和内存管理
C primer plus 学习笔记 第12章 存储类别、链接和内存管理
|
7月前
|
监控 Linux
深入了解Linux的pmap命令:进程内存映射的利器
`pmap`是Linux下分析进程内存映射的工具,显示内存区域、权限、大小等信息。通过`/proc/[pid]/maps`获取数据,特点包括详细、实时和灵活。参数如`-x`显示扩展信息,`-d`显示设备。示例:`pmap -x 1234`查看进程1234的映射。注意权限、实时性和准确性。结合其他工具定期监控,排查内存问题。

热门文章

最新文章