上面我们说了如何去在系统中自己实现一个设置系统寄存器的一个方法,上面归根到底要进行物理地址到虚拟地址的映射
现在我们就说说IO_ADDRESS()的实现
#define __REG32ALI(addr) (*((volatile unsigned long *)((addr) - ALI_REGS_PHYS_BASE + ALI_REGS_VIRT_BASE))
#define readl(IO_ADDRESS(addr)) (*(volatile unsigned int *)(addr))
两个宏的功能都是一样的,所以对比可得:
IO_ADDRESS(addr) <==> (addr) - ALI_REGS_PHYS_BASE + ALI_REGS_VIRT_BASE
其中的addr都是物理地址,ALI_REGS_PHYS_BASE
是System IO基地址,(addr) - ALI_REGS_PHYS_BASE
就能得到偏移的地址,ALI_REGS_VIRT_BASE
是虚拟地址的基地址,这里的虚拟地址其实是DRAM里面的地址,即我们要操作他映射到DRAM里面的地址,我们看看ALI_REGS_VIRT_BASE的定义:
#define ALI_REGS_PHYS_BASE PHYS_SYSTEM
#define ALI_REGS_VIRT_BASE VIRT_SYSTEM
#define VMALLOC_END 0xfffffffff
#define SIZE_ALIIO 0x60000
#define VIRT_SYSTEM (VMALLOC_END - SIZE_ALIIO)
可以看出虚拟地址的基地址是人为划分出的,是VMALLOC_END - SIZE_ALIIO得到的,
VMALLOC_END是cpu address mapping中给虚拟地址的内核空间划分出的地址区间的末端地址,这个末端地址根据不同cpu的不同而有所不同,SIZE_ALIIO为可以使用的空间大小
这个宏只是一个工具,是操作静态映射后的宏的一种做法,在使用该宏前,必须已经对该IO地址所在的地址范围做了静态映射,即machine中对函数map_io中注册一下静态映射表,让系统可以知道这种映射关系,否则系统根据算出的虚拟地址是访问不到物理地址的,会出现异常。