地址映射

MMU的相关概念可参考:https://www.cnblogs.com/lethe1203/p/18064515
Linux驱动开发在某些情况也会直接操作寄存器
 
MMU主要完成的功能:
1、完成虚拟空间到物理空间的映射
2、内存保护,设置存储器的访问权限,设置虚拟存储空间的缓冲特性
对于32位的处理器来说,虚拟地址范围为:2^32 = 4GB,假设开发板上有512MB的DDR,这个512M就是物理内存,经过MMU就可以将512M映射到4GB的虚拟空间。
0
涉及到内存管理单元(MMU)以及虚拟内存系统的设计。解决地址冲突的问题可以通过以下几种方式:
  1. 分页机制
使用分页机制将物理地址映射到虚拟地址空间。操作系统会将虚拟地址空间划分为固定大小的页面,并将每个页面映射到物理内存上。通过合理地设置页表,可以将512M的物理地址映射到4G的虚拟地址空间,同时避免地址冲突。
  1. 地址空间布局随机化
通过地址空间布局随机化(ASLR)的技术,可以在每次进程启动时随机地分配虚拟地址空间,从而降低恶意攻击者利用固定的地址空间进行攻击的可能性。
  1. 内存映射和区域分配
操作系统可以通过内存映射和区域分配的方式,在虚拟地址空间中为不同的进程或内核模块分配独立的地址空间,从而避免地址冲突。
 
在操作系统中,不同的进程有各自独立的虚拟地址空间,因此它们对于同一个物理地址的访问所使用的虚拟地址是不同的。这意味着即使多个进程同时访问同一个物理地址,它们在虚拟地址空间中所使用的地址会有所不同。
每个进程都有自己的虚拟地址空间,其中包含了从0开始的一系列虚拟地址,这些地址被映射到实际的物理地址。虚拟地址空间的划分使得不同进程之间彼此隔离,每个进程都认为自己是在独占地访问内存,从而确保了进程间的安全性和隔离性。
因此,即使不同进程访问同一个物理地址,它们使用的虚拟地址也是不同的,这种映射关系是由操作系统的内存管理单元(MMU)负责管理和维护的
 

实现物理内存和虚拟内存转换:

1、ioremap函数

ioremap 函 数 用 于 获 取 指 定 物 理 地 址 空 间 对 应 的 虚 拟 地 址 空 间 , 定 义 在arch/arm/include/asm/io.h 文件中,定义如下:
#define ioremap(cookie,size)            __arm_ioremap((cookie), (size), MT_DEVICE)

 void __iomem *
  __arm_ioremap(phys_addr_t phys_addr, size_t size, unsigned int mtype)
 {
         return arch_ioremap_caller(phys_addr, size, mtype,
                 __builtin_return_address(0));
 }
 EXPORT_SYMBOL(__arm_ioremap);
 
 // 参数说明
 phys_addr:要映射给的物理起始地址
 size:要映射的内存空间大小
 mtype:ioremap 的类型,可以选择 MT_DEVICE、MT_DEVICE_NONSHARED、MT_DEVICE_CACHED 和 MT_DEVICE_WC,ioremap 函数选择 MT_DEVICE。
 返回值:__iomem 类型的指针,指向映射后的虚拟空间首地址。
 

2、iounmap函数

卸载驱动的时候需要使用 iounmap 函数释放掉 ioremap 函数所做的映射,iounmap 函数原型如下:
void iounmap (volatile void __iomem *addr)
iounmap 只有一个参数 addr,此参数就是要取消映射的虚拟地址空间首地址
 

I/O内存访问函数:

I/O 端口和 I/O 内存。当外部寄存器或内存映射到 IO 空间时,称为 I/O 端口。当外部寄存器或内存映射到内存空间时,称为 I/O 内存。但是对于 ARM 来说没有 I/O 空间这个概念,因此 ARM 体系下只有 I/O 内存(可以直接理解为内存)。使用 ioremap 函数将寄存器的物理地址映射到虚拟地址以后,我们就可以直接通过指针访问这些地址,但是 Linux 内核不建议这么做,而是推荐使用一组操作函数来对映射后的内存进行读写操作。

1、读操作函数

u8 readb(const volatile void __iomem *addr)        // 8bit操作函数
u16 readw(const volatile void __iomem *addr)        // 16bit操作函数
u32 readl(const volatile void __iomem *addr)        // 32bit操作函数

 

2、写操作函数

void writeb(u8 value, volatile void __iomem *addr)
void writew(u16 value, volatile void __iomem *addr)
void writel(u32 value, volatile void __iomem *addr)
writeb、writew 和 writel 这三个函数分别对应 8bit、16bit 和 32bit 写操作,参数 value 是要写入的数值,addr 是要写入的地址。
posted @ 2024-03-23 17:00  lethe1203  阅读(15)  评论(0编辑  收藏  举报