我們知道在我們的驅動裡面一般操作的寄存器的地址都是虛擬地址, 然而一般在cpu的datasheet裡描述的寄存器的地址都是物理地址, 那linux內核是如何把我們驅動中指定操作的虛擬地址轉換成正真可尋址並操作的物理地址的呢? 這篇文檔以s3c2410為例, 將詳細的描述這麼一個實現流程。通過這篇文章,將能夠很好了解的虛實映射的過程。(本篇文章並非本人原著,只是整理以提供給大家交流學習。分析的不錯)
S3C2410使用的是arm920T的核,它支持MMU,正因為這樣它才可以進行虛擬地址到物理地址的轉換。而諸如使用arm7核的CPU一般都無法進行類似的轉換, 就在於它沒有MMU,所以它上面能跑的操作系統也是去掉了MMU功能後的linux如uClinux, 關於MMU的原理可參考相關文檔。
我們先來看文件Map.h
include\asm-arm\arch-s3c2410\Map.h:
#ifndef __ASSEMBLY__
#define S3C2410_ADDR(x) ((void __iomem __force *)0xF0000000 + (x))
#else
#define S3C2410_ADDR(x) (0xF0000000 + (x))
#endif
#define S3C2400_ADDR(x) S3C2410_ADDR(x)
/* interrupt controller is the first thing we put in, to make
* the assembly code for the irq detection easier
*/
#define S3C24XX_VA_IRQ S3C2410_ADDR(0x00000000)
#define S3C2400_PA_IRQ (0x14400000)
#define S3C2410_PA_IRQ (0x4A000000)
#define S3C24XX_SZ_IRQ SZ_1M
/* memory controller registers */
#define S3C24XX_VA_MEMCTRL S3C2410_ADDR(0x00100000)
#define S3C2400_PA_MEMCTRL (0x14000000)
#define S3C2410_PA_MEMCTRL (0x48000000)
#define S3C24XX_SZ_MEMCTRL SZ_1M
……
我們可以看到IRQ的寄存器虛擬地址定義為0xF0000000, 而物理地址為0x4A000000(這可從2410的datasheet上查到), memory控制器的寄存器虛擬地址定義為0xF0000000 + 0x00100000的地址處,物理地址為0x48000000, 其他如lcd 等寄存器都在這裡定義了虛擬地址,當然這裡僅僅是定義而已, 還沒有和物理地址達成映射的聯系。 我們接著看。
我們來看2410的machine_desc結構:
arch\arm\mach-s3c2410\Mach-smdk2410.c:
MACHINE_START(SMDK2410, "SMDK2410") /* @TODO: request a new identifier and switch
* to SMDK2410 */
/* Maintainer: Jonas Dietsche */
.phys_io = S3C2410_PA_UART,
.io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
.boot_params = S3C2410_SDRAM_PA + 0x100,
.map_io = smdk2410_map_io,
.init_irq = s3c24xx_init_irq,
.init_machine = smdk2410_init,
.timer = &s3c24xx_timer,
MACHINE_END
這裡定義了一個描述2410開發板的結構, 其中的map_io, init_irq, init_machine都會在系統跑起來的時候被調用, 我們這裡要看的是smdk2410_map_io, 這個函數完成後我們的虛擬地址和物理地址的映射關系就完成了。