1:我们在linux内核中都是开启mmu的所以都是用的虚拟地址,需要建立VA到PA的映射表;
我们内核中映射表在arch/arm/mach-s5pv210/mach-smdkc110.c文件中
建立映射的函数是,smdkc110_map_io建立映射表
smdkc110_map_io 这个函数调用s5p_init_io函数真正
s5p_init_io
iotable_init
s3c24xx_init_clocks
s5pv210_gpiolib_init
s3c24xx_init_uarts
smdkc110_map_io 这个函数调用s5p_init_io函数,s5p_init_io
void __init s5p_init_io(struct map_desc *mach_desc, int size, void __iomem *cpuid_addr)
我们来看一下s5p_init_io函数的原型需要三个参数:参数1:结构体数组指针,参数2:数组的成员个数;参数三:虚拟地址基地址
函数s5p_init_io 在调用iotable_init函数建立静态映射表,实际上我们看一下iotable_init函数中跟没有用到之前传的参数2、参数3;
直接把s5p_iodesc数组名当做数组首地址作为iotable_init函数的第一个参数、ARRAY_SIZE这个时自动计算的这个数组有几个成员组成;
iotable_init(s5p_iodesc, ARRAY_SIZE(s5p_iodesc));
下面我们来分析一下这个man_desc 这个类型的结构体
struct map_desc {
unsigned long virtual; //虚拟地址
unsigned long pfn; //物理地址 .pfn = __phys_to_pfn(S5P_PA_CHIPID), 这里把物理地址放入__phys_to_pfn函数中传给.pfn
unsigned long length; //长度
unsigned int type; //type
};
static struct map_desc s5p_iodesc为一个全局变量,实际上只需要有我们初始化好的这个全局变量数组
static struct map_desc s5p_iodesc[] __initdata = { { .virtual = (unsigned long)S5P_VA_CHIPID, //0xFD70_0000 .pfn = __phys_to_pfn(S5P_PA_CHIPID), //0xE000_0000 >> 12 .length = SZ_4K, //4k .type = MT_DEVICE, //0 }, { .virtual = (unsigned long)S3C_VA_SYS, //0xFD10_0000 .pfn = __phys_to_pfn(S5P_PA_SYSCON), //0xE010_0000 >> 12 .length = SZ_64K, //64k .type = MT_DEVICE, }, { .virtual = (unsigned long)S3C_VA_UART, //0xFE00_0000 .pfn = __phys_to_pfn(S3C_PA_UART), //0xE290_0000 >> 12 .length = SZ_4K, .type = MT_DEVICE, }, { .virtual = (unsigned long)VA_VIC0, .pfn = __phys_to_pfn(S5P_PA_VIC0), .length = SZ_16K, .type = MT_DEVICE, }, { .virtual = (unsigned long)VA_VIC1, .pfn = __phys_to_pfn(S5P_PA_VIC1), .length = SZ_16K, .type = MT_DEVICE, }, { .virtual = (unsigned long)S3C_VA_TIMER, .pfn = __phys_to_pfn(S5P_PA_TIMER), .length = SZ_16K, .type = MT_DEVICE, }, { .virtual = (unsigned long)S5P_VA_GPIO, //0xFD50_0000
.pfn = __phys_to_pfn(S5P_PA_GPIO), //0xE020_0000
.length = SZ_4K, //大小 4k
.type = MT_DEVICE, //0
}, };
我们有了这个map_desc结构体通过iotable_init函数就可以创建我们再map_desc数组中的设置好的物理地址到虚拟地址映射;
而真正建立虚拟地址到物理地址映射的函数是:create_mapping这个函数;
static void __init smdkc110_map_io(void) { s5p_init_io(NULL, 0, S5P_VA_CHIPID); s3c24xx_init_clocks(24000000); s5pv210_gpiolib_init(); s3c24xx_init_uarts(smdkc110_uartcfgs, ARRAY_SIZE(smdkc110_uartcfgs)); s5p_reserve_bootmem(smdkc110_media_devs, ARRAY_SIZE(smdkc110_media_devs)); #ifdef CONFIG_MTD_ONENAND s5pc110_device_onenand.name = "s5pc110-onenand"; #endif #ifdef CONFIG_MTD_NAND s3c_device_nand.name = "s5pv210-nand"; #endif s5p_device_rtc.name = "smdkc110-rtc"; }
void __init s5p_init_io(struct map_desc *mach_desc, int size, void __iomem *cpuid_addr) { unsigned long idcode; /* initialize the io descriptors we need for initialization */ iotable_init(s5p_iodesc, ARRAY_SIZE(s5p_iodesc)); if (mach_desc) iotable_init(mach_desc, size); idcode = __raw_readl(cpuid_addr); s3c_init_cpu(idcode, cpu_ids, ARRAY_SIZE(cpu_ids)); }
void __init iotable_init(struct map_desc *io_desc, int nr) { int i; for (i = 0; i < nr; i++) create_mapping(io_desc + i); }
关于create_maping函数如何建立映射表参考
http://blog.csdn.net/huyugv_830913/article/details/5884628
http://blog.csdn.net/longyue0917/article/details/7424536
映射表建立函数被调用
http://blog.csdn.net/tongxinv/article/details/54698188