关于虚拟地址的Tips
1.所有能被总线访问到的外设均需要通过MMU来进行虚拟地址映射从而得到其物理地址
2.物理内存(SRAM)在虚拟地址中最多能表现为4GB,但并不是说一定能够完整地拥有这4GB,期间这4GB还得与GPIO等一起使用。
3.MMU只是起到一个映射关系的工具而已。
4.ARM中使用的是内存映射方式,使得CPU可以像访问内存单元一样访问I/O端口(可能是利用内核空间中的固定映射的线性地址和Vmalloc映射区来映射的),故在驱动程序中无法通过物理地址直接访问到寄存器,而需要通过ioremap将寄存器的物理地址映射到虚拟地址中,然后通过虚拟地址来访问。
5.访问GPIO寄存器时,访问的是IO空间,不需要进行物理页的分配,访问SRAM区域即内存条区域的时候需要进行物理页的分配
6.一个物理地址可以对应多个虚拟地址,一个虚拟地址只能指向一个物理地址
7.在内核中虚拟地址的映射可以采用静态映射和动态映射。
a) 静态映射:属于一一对应的关系,建立之后联系就一直存在着,是Linux系统根据用户事先指定的映射关系,在内核启动的时候自动将物理地址映射为虚拟地址。
b) 动态映射:物理地址根据用户实际需要,通过ioremap等函数来进行虚拟地址的映射,映射关系不唯一,可以更好地利用内存的空间。当内核空间大到一定程度的时候也可以全部采用直接映射而不采用动态映射,但用户空间还是得采用虚拟地址映射。【动态映射使用ioremap函数时,实际上是将虚拟地址中的内核空间的Vmalloc空间的虚拟地址分配到相应的IO空间上去】
ARM-静态映射简述
动态映射IO空间:
void *ioremap(physaddr, size)
参数:
physaddr:待映射的物理地质
size:映射的区域长度
返回值:映射后的虚拟地址
静态映射:
1.如何事先指定映射关系
答:通过定义内核中的map_desc结构来指明物理地址和虚拟地址的映射关系
struct map_desc{
unsigned long virtual; //映射后的虚拟地址
unsigned long pfn; //物理地址所在的页帧号,此处采用二级页表,故一页 //为4KB,所以pfn=物理地址/4KB
unsigned long length; //映射长度
unsigned int type; //映射的设备类型
};
pfn可以利用内核中的_phys_to_pfn(物理地址)来计算出其页帧号
2.内核启动时,在什么地方完成自动映射?
答:在s5pv210_map_io处使用iotable_init来完成映射。
Tips:
1.在驱动程序中对寄存器写值使用了writel等函数是为了跨平台的能力,在其他平台上,IO空间可能是与内存独立开来的,无法通过直接访问地址的方式来进行读写,而是需要使用writel等函数来进行操作,故此处使用一个宏定义来保证其可移植性
2.内核中静态映射的map_desc结构是在s5pv210_iodesc中定义的,之后在s5pv210_map_io处完成映射。
3.在完成静态映射后,仍可以进行动态映射,应为一个物理地址可以对应多个虚拟地址