linux io映射,【原创】Linux 文件系统移植全解密以linux-2.6.35内核源码为例说明一下IO静态映射的过程...

最近不断有人跟我说起静态映射的问题,今天就以linux-2.6.35内核源码为例说明一下IO静态映射的过程(ARM平台)。

//init/main.c

asmlinkage void __init start_kernel(void){

...

setup_arch(&command_line);

...

}

//arch/arm/kernel/setup.c

void __init setup_arch(char **cmdline_p){

...

paging_init(mdesc);

...

}

//arch/arm/mm/mmu.c

void __init paging_init(struct machine_desc *mdesc){

...

devicemaps_init(mdesc);

...

}

//arch/arm/mm/mmu.c

static void __init devicemaps_init(struct machine_desc *mdesc){

...

if (mdesc->map_io)  //回调map_io

mdesc->map_io();

...

}

//arch/arm/include/asm/mach/arch.h

struct machine_desc {

/*

* Note! The first four elements are used

* by assembler code in head.S, head-common.S

*/

unsigned int        nr;        /* architecture number    */

unsigned int        phys_io;    /* start of physical io    */

unsigned int        io_pg_offst;    /* byte offset for io page tabe entry    */

const char        *name;        /* architecture name    */

unsigned long        boot_params;    /* tagged list        */

unsigned int        video_start;    /* start of video RAM    */

unsigned int        video_end;    /* end of video RAM    */

unsigned int        reserve_lp0 :1;    /* never has lp0    */

unsigned int        reserve_lp1 :1;    /* never has lp1    */

unsigned int        reserve_lp2 :1;    /* never has lp2    */

unsigned int        soft_reboot :1;    /* soft reboot        */

void            (*fixup)(struct machine_desc *,struct tag *, char **,struct meminfo *);

void            (*map_io)(void);/* IO mapping function    */

void            (*init_irq)(void);

struct sys_timer    *timer;        /* system tick timer    */

void            (*init_machine)(void);

};

该结构体对象初始化在对应板子的BSP文件中(这里以S5PC100平台为例)

//arch/arm/mach-s5pc100/mach-smdkc100.c

MACHINE_START(SMDKC100, "SMDKC100")

/* Maintainer: Byungho Min */

.phys_io    = S3C_PA_UART & 0xfff00000,

.io_pg_offst    = (((u32)S3C_VA_UART) >> 18) & 0xfffc,

.boot_params    = S5P_PA_SDRAM + 0x100,

.init_irq    = s5pc100_init_irq,

.map_io        = smdkc100_map_io,

.init_machine    = smdkc100_machine_init,

.timer        = &s3c24xx_timer,

MACHINE_END

//MACHINE_START宏定义在arch/arm/include/asm/mach/arch.h

#define MACHINE_START(_type,_name)            \

static const struct machine_desc __mach_desc_##_type    \

__used                            \

__attribute__((__section__(".arch.info.init"))) = {    \

.nr        = MACH_TYPE_##_type,        \

.name        = _name,

#define MACHINE_END                \

即struct machine_desc中的域.map_io登记为smdkc100_map_io

static void __init smdkc100_map_io(void)

{

s5p_init_io(NULL, 0, S5P_VA_CHIPID);

...

}

//arch/arm/plat-s5p/cpu.c

/* minimal IO mapping */

static struct map_desc s5p_iodesc[] __initdata = {

{

.virtual    = (unsigned long)S5P_VA_CHIPID,

.pfn        = __phys_to_pfn(S5P_PA_CHIPID),

.length        = SZ_4K,

.type        = MT_DEVICE,

}, {

.virtual    = (unsigned long)S3C_VA_SYS,

.pfn        = __phys_to_pfn(S5P_PA_SYSCON),

.length        = SZ_64K,

.type        = MT_DEVICE,

}, {

.virtual    = (unsigned long)S3C_VA_UART,

.pfn        = __phys_to_pfn(S3C_PA_UART),

.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,

.pfn        = __phys_to_pfn(S5P_PA_GPIO),

.length        = SZ_4K,

.type        = MT_DEVICE,

},

};

/* read cpu identification code */

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));

}

上面的 iotable_init函数完成IO映射。

结构体static struct map_desc定义在asm/io.h中

struct map_desc {

unsigned long virtual; //映射后的虚拟地址

unsigned long pfn;      //被映射的物理地址所在页帧号

unsigned long length;//被映射的IO资源长度

unsigned int type;        //IO类型

};

这里比较难理解的是“映射后的虚拟地址virtual”,这个是自己定义的,可以修改,但是不能和已经映射的重复。

可以参看内核文档\Documentation\arm\memory.txt,其中描述如下:

VMALLOC_START    VMALLOC_END-1    vmalloc() / ioremap() space.

Memory returned by vmalloc/ioremap will

be dynamically placed in this region.

VMALLOC_START may be based upon the value

of the high_memory variable.

VMALLOC_START 定义在arch/arm/include/asm/pgtable.h中

/*

* Just any arbitrary offset to the start of the vmalloc VM area: the

* current 8MB value just means that there will be a 8MB "hole" after the

* physical memory until the kernel virtual memory starts.  That means that

* any out-of-bounds memory accesses will hopefully be caught.

* The vmalloc() routines leaves a hole of 4kB between each vmalloced

* area for the same reason. ;)

*

* Note that platforms may override VMALLOC_START, but they must provide

* VMALLOC_END.  VMALLOC_END defines the (exclusive) limit of this space,

* which may not overlap IO space.

*/

#ifndef VMALLOC_START

#define VMALLOC_OFFSET        (8*1024*1024)

#define VMALLOC_START        (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))

#endif

S5PC100中IO映射从S3C_ADDR_BASE开始线性偏移

#define S3C_ADDR_BASE    (0xF4000000)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值