linux I/O内存访问
先看一个在无操作系统的情况下,用C语言访问片上寄存器的范例,这是访问S3C2440UART1的FIFO控制寄存器的示例,先定义FIFO控制寄存器为UFCON1:
1 | #define UFCON1 (*(volatile unsigned *)Ox50004008) //*UART 1 FIFO控制寄存器 |
给UFCON1赋值:
1 | UFCON1 = Ox00; //禁止FIFO功能 |
这个示例的使用条件是禁止CPU的MMU。在禁止MMU的情况下,可以直接访问CPU的物理地址。
Linux内核运行后,开启了MMU,所以不能直接访问CPU的物理地址,也就是说,不能直接使用物理地址访问系统的IO内存。必须将物理地址转换为虚拟地址,内核通过虚拟地址来访问系统的IO内存。
在内核中,物理地址到虚拟地址的转换,可以采用静态IO映射,还可以采用动态IO映射。通常情况下,CPU片上寄存器和内部总线都采用静态IO映射,外部总线扩展IO则通常采用动态IO映射,也可以添加到系统中,采用静态IO映射的方式。
下面分别来看这两种方式的实现和使用方法。
1、静态VO映射 、
静态I/O映射在内核中很常见,最常见的是处理器的片内寄存器的操作,如GPIO、串口、定时器等等这些片上外设的寄存器,在内核中都通过静态IO映射后被访问。一般的操作方式是这样的:
1 2 | _raw_writel(camdivn, S3C2440_CAMDIVN); submsk =_raw_readl(S3C2410_INTSUBMSK); |
(1)io_p2v
要实现静态IO映射,首先需要定义物理地址到虚拟地址的转换规则,在内核中用宏定义io_p2v(x)实现,将物理地址映射到3G~4G的内核地址空间。不同处理器的具体实现是不同的,但是前提是必须能将处理器的全部有效IO空间映射到内核空间。对于一个32位的处理器,最大可访问地址空间为232,即4G,但是实际上绝大部分地址空间都是保留的,可访问的有效地址仅仅局限于有实际物理外设地址空间。
2、动态IO映射
动态IO映射无需将物理IO内存空间写入映射表,调用ioremap即可映射到虚拟地址空间。这种方式使用起来比较灵活,不过在外扩总线设备寄存器较多的情况下使用起来就不太方便了,一般建议在寄存器较少的情况下使用。操作完毕后,用iounmap取消IO映射。
ioremap 和 iounmap相关定义在<asm/io.h>文件中:
3、IO内存访问函数
1 2 3 4 5 6 | __raw_readb/readb 从 I/O 端口读取 8 位数 __raw_readw/readw 从 I/O 端口读取 16 位数 __raw_readl/readl 从 I/O 端口读取 32 位数 __raw_writeb/writeb 往 I/O 端口写入 8 位数 __raw_writew/writew 往 I/O 端口写入 16 位数 __raw_writel/writel 往 I/O 端口写入 32 位数 |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
2019-12-27 DVB-C\DVB-S\DVB-T知识介绍
2019-12-27 广播与电视波段频率划分表