最近不断有人跟我说起静态映射的问题,今天就以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)

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

  1. 基础IO(文件接口、安装内核源码超详细步骤图解、静态库与动态库)

    基础IO C语言的文件操作接口 fopen fclose fread fwrite fseek 系统调用文件接口 open close read write lseek 安装内核源码 文件描述符&am ...

  2. 39 解决全志h3 linux内核源码里的关于script.fex的bug

    在script.fex里有关于io口的配置: Port:端口+组内序号<功能分配><内部电阻状态><驱动能力><输出电平状态>[gpio_para]gp ...

  3. Linux移植:正点原子阿尔法IMX6ULL开发板Linux内核源码移植详细步骤(4.1.15版本内核)

    Linux移植:正点原子阿尔法IMX6ULL开发板Linux内核源码移植详细步骤(4.1.15版本内核) 文章目录 Linux移植:正点原子阿尔法IMX6ULL开发板Linux内核源码移植详细步骤(4 ...

  4. iostat IO统计原理linux内核源码分析----基于单通道SATA盘

    iostat IO统计原理linux内核源码分析----基于单通道SATA盘 先上一个IO发送submit_bio流程图,本文基本就是围绕该流程讲解. 内核版本 3.10.96 详细的源码注释:htt ...

  5. Linux内核移植之一:内核源码结构与Makefile分析

    内容来自 韦东山<嵌入式Linux应用开发完全手册> 一.内核介绍 1.版本及其特点 Linux内核的版本号可以从源代码的顶层目录下的Makefile中看到,比如下面几行它们构成了Linu ...

  6. linux内核源码分析之虚拟文件系统VFS(一)

    目录 一.文件系统类型 二.VFS虚拟文件系统 三.VFS中主要的对象类型 四.结构体之间的关系 五.inode 节点 一.文件系统类型 基于磁盘的文件系统:在非易失介质上存储文件,在多次会话间保持文 ...

  7. 【技术分享篇】Linux内核——手把手带你实现一个Linux内核文件系统丨Linux内核源码分析

    手把手带你实现一个Linux内核文件系统 1. 内核文件系统架构分析 2. 行行珠玑,代码实现 [技术分享篇]Linux内核--手把手带你实现一个Linux内核文件系统丨Linux内核源码分析 更多L ...

  8. linux内核源码实战_3.2理解设备驱动和文件系统

    linux内核源码实战_3.2理解设备驱动和文件系统 linux内核源码实战_理解设备驱动和文件系统 理解设备驱动和文件系统 理解设备驱动和文件系统详解 7-文件系统-proc文件系统实现 总结 li ...

  9. Linux内核源码组织结构

    本文主要参考韦东山老师的<嵌入式Linux应用开发完全手册>,基于Linux-2.6.32.2源码. 概要:本文内容包含Linux源码树结构分析.Linux Makefile分析.Kcon ...

最新文章

  1. JavaScript服务器端开发基础之Math对象小结
  2. Linux命令(007) -- systemctl
  3. 吴恩达深度学习课程deeplearning.ai课程作业:Class 1 Week 4 assignment4_2
  4. 计算机科学 理学,077500计算机科学与技术(理学).doc
  5. java 控制台刷屏 dll_Java刷屏问题,下面是我编的代码,请大神帮忙解决下,谢谢...
  6. R语言的常用函数速查
  7. 列车控制matlab仿真,基于matlab的列车纵向碰撞建模仿真研究
  8. 如何从“人肉运维”升级为“智能运维”?
  9. 想做合格的产品经理,你需要这个证书
  10. 使用JSONP解决跨域
  11. 个人永久性免费-Excel催化剂功能第29波-追加中国特色的中文相关自定义函数
  12. 浙大版《C语言程序设计(第3版)》题目集习题4-11 兔子繁衍问题 (15 分)
  13. 打印100以内的质数
  14. 集成电路只有丝印如何识别引脚顺序
  15. oracle elsif和else if,ORACLE ELSIF 与 ELSE IF
  16. 码刀客-pandas中将一张表中数据拆分成多个sheet_name
  17. 别了,我的程序员生涯!
  18. Unity IK动画
  19. 基于SSM 和 layui 的增删查改
  20. wcs无线计算服务器,BKR/拜卡 WCS-10M

热门文章

  1. Spark _10_补充部分算子【三】
  2. 【Java文件操作(六)】借助内存复制图片:ByteArrayOutputStream\ByteArrayInputStream\FileOutputStream\FileInputStream辨析
  3. AbstractByteBuf源码分析
  4. 操作系统(5) -- 输入/输出管理
  5. leetcode-- 124. 二叉树中的最大路径和
  6. 【0ms优化】剑指 Offer 18. 删除链表的节点
  7. [leetcode]111.二叉树的最小深度
  8. linux设置docker自动启动,CentOS7安装Docker配置服务端和容器自启动
  9. android ndk使用c 11,使用c 11 std :: async在android ndk中使用不完整类型无效
  10. linux快捷命令怎么拼日期,liunx常用命令,快捷键