上面我們說瞭如何去在系統中自己實現一個設置系統寄存器的一個方法,上面歸根到底要進行物理地址到虛擬地址的映射 現在我們就說說IO_ADDRESS()的實現 兩個巨集的功能都是一樣的,所以對比可得: 其中的addr都是物理地址, 是System IO基地址, 就能得到偏移的地址, 是虛擬地址的基地址,這裡 ...
上面我們說瞭如何去在系統中自己實現一個設置系統寄存器的一個方法,上面歸根到底要進行物理地址到虛擬地址的映射
現在我們就說說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中註冊一下靜態映射表,讓系統可以知道這種映射關係,否則系統根據算出的虛擬地址是訪問不到物理地址的,會出現異常。