linux驱动(五)内核中静态映射表的建立

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

原文地址:https://www.cnblogs.com/biaohc/p/6626062.html