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