转:https://blog.csdn.net/charliewangg12/article/details/41518549

在驱动开发时,我们都是以一块开发板为基础移植驱动程序。每一块开发板对应一个板级文件,如开发

TI AM335x系列,则对应board-am335xevm.c,这个文件完成芯片和板级的初始化工作。对于驱动开发,还有

一个很重要的文件devices.c,这个文件主要是设备接口相关资源。

今天就来说说board-am335xevm.c文件,如何全面的了解这个文件呢?先找到这个文件的入口,在文件的

最后几行:

  1. MACHINE_START(AM335XEVM, "am335xevm")
  2. /* Maintainer: Texas Instruments */
  3. .atag_offset    = 0x100,
  4. .map_io     = am335x_evm_map_io,
  5. .init_irq   = ti816x_init_irq,
  6. .init_early = am335x_init_early,
  7. .timer      = &omap3_am33xx_timer,
  8. .init_machine   = am335x_evm_init,
  9. MACHINE_END

看以看出,am335x_evm_map_io,i816x_init_irq,am335x_init_early,am335x_evm_init就是各个初始化函数

的总入口函数。

下面来分析一下这几个函数是如何被调用,何时被调用的?

  1. #define MACHINE_START(_type,_name)          \
  2. static const struct machine_desc __mach_desc_##_type    \
  3. __used                         \
  4. __attribute__((__section__(".arch.info.init"))) = {    \
  5. .nr     = MACH_TYPE_##_type,        \
  6. .name       = _name,
  7. #define MACHINE_END             \
  8. };

宏展开之后得到:

  1. static const struct machine_desc __mach_desc_AM335XEVM  \
  2. __attribute__((__used__))              \
  3. __attribute__((__section__(".arch.info.init"))) = {    \
  4. .nr     = MACH_TYPE_AM335XEVM,      \
  5. .name       = _name,
  6. .atag_offset    = 0x100,
  7. .map_io     = am335x_evm_map_io,
  8. .init_irq   = ti816x_init_irq,
  9. .init_early = am335x_init_early,
  10. .timer      = &omap3_am33xx_timer,
  11. .init_machine   = am335x_evm_init,
  12. };

__mach_desc_AM335XEVM是一个struct machine_desc 类型结构体,这个结构体存放的段是

.arch.info.init,这里注意一下,后边匹配machine_desc的时候就是到这个段中寻找,然后根据nr的值匹配。

  1. struct machine_desc {
  2. unsigned int        nr;     /* architecture number  */
  3. const char      *name;      /* architecture name    */
  4. unsigned long       boot_params;    /* tagged list      */
  5. unsigned long       atag_offset;    /* tagged list (relative) */
  6. const char      **dt_compat;    /* array of device tree
  7. * 'compatible' strings */
  8. unsigned int        nr_irqs;    /* number of IRQs */
  9. #ifdef CONFIG_ZONE_DMA
  10. unsigned long       dma_zone_size;  /* size of DMA-able area */
  11. #endif
  12. unsigned int        video_start;    /* start of video RAM   */
  13. unsigned int        video_end;  /* end of video RAM */
  14. unsigned int        reserve_lp0 :1; /* never has lp0    */
  15. unsigned int        reserve_lp1 :1; /* never has lp1    */
  16. unsigned int        reserve_lp2 :1; /* never has lp2    */
  17. unsigned int        soft_reboot :1; /* soft reboot      */
  18. void            (*fixup)(struct machine_desc *,
  19. struct tag *, char **,
  20. struct meminfo *);
  21. void            (*reserve)(void);/* reserve mem blocks  */
  22. void            (*map_io)(void);/* IO mapping function  */
  23. void            (*init_early)(void);
  24. void            (*init_irq)(void);
  25. struct sys_timer    *timer;     /* system tick timer    */
  26. void            (*init_machine)(void);
  27. #ifdef CONFIG_MULTI_IRQ_HANDLER
  28. void            (*handle_irq)(struct pt_regs *);
  29. #endif
  30. };

内核启动的时候跳转的C语言入口在main.c/start_kernel(void),start_kernel(void)会调用setup_arch(),

接下来看看setup_arch():

  1. void __init setup_arch(char **cmdline_p)
  2. {
  3. struct machine_desc *mdesc;
  4. unwind_init();
  5. setup_processor();
  6. /*__atags_pointer是uboot传递的参数地址 0x80000100*/
  7. mdesc = setup_machine_fdt(__atags_pointer);
  8. /*由于参数非设备树结构,返回NULL*/
  9. if (!mdesc)
  10. mdesc = setup_machine_tags(machine_arch_type);
  11. machine_desc = mdesc;
  12. machine_name = mdesc->name
  13. .........
  14. }

首先使用mdesc = setup_machine_fdt(__atags_pointer)获取mdes,__atags_pointer是uboot传递的

参数存放位置,这里等于0x80000100,后边会解释。setup_machine_fdt()起作用的话,需要uboot传递的

参数是设备树device tree的存放方式,我们实际使用的是tags_list方式,所以这里返回值为NULL。
所以是通过mdesc =  setup_machine_tags(machine_arch_type)获得的machine desc,machine_arch_type

是uboot传递的machid。
setup_machine_tags()中:

  1. for_each_machine_desc(p)
  2. f (nr == p->nr) {
  3. printk("Machine: %s\n", p->name);
  4. mdesc = p;
  5. break;

nr= machid=MACH_TYPE_AM335XEVM=3589是uboot传递过来的,内核中的MACH_TYPE_AM335XEVM

在/include/generated/mach-types.h中定义,这个文件是动态产生的。产生过程请参考

http://blog.csdn.net/charliewangg12/article/details/41483261

在mach-types.h中定义:
 #define MACH_TYPE_AM335XEVM  3589

如何确定是哪个machine_desc,从machine_desc存放的段中选择机器码与从uboot传递过来的机器号

nr比较,相等即得到了machine_desc。

  1. #define for_each_machine_desc(p) for (p = __arch_info_begin; p < __arch_info_end; p++)

__arch_info_begin是machine_desc存放的位置,通过属性定义

  1. //在setup_machine_fdt(__atags_pointer)中使用的__atags_pointer由此传递

uboot的参数传递给内核:
uboot的板级文件evm.c中定义了板级信息

  1. int board_evm_init()
  2. {
  3. gd->bd->bi_arch_number=MACH_TYPE_TIAM335EVM;
  4. gd->bd->bi_boot_params=PHYS_DRAM_1+0x100;  //PHYS_DRAM_1=0x80000000
  5. }

当使用bootm启动内核的时候,调用了do_bootm_linux函数:

  1. int do_bootm_linux(int flag ,int argc ,char *argv[] , bootm_headers_t *images)
  2. {
  3. bd_t *bd=gd->bd;
  4. int machid=bd->bi_arch_number;
  5. /*使用device tree 结构传递参数,我们没有使用这种方式*/
  6. #ifdef CONFIG_OF_LIBFDT
  7. if(images->ft_len)
  8. return bootm_linux_fdt(machid,images);
  9. #endif
  10. #if defined (CONFIG_SETUP_MEMORY_TAGS) || defined (CONFIG_CMDLINE_TAG) || .........
  11. setup_start_tag(bd);
  12. #endif
  13. #if  defined (CONFIG_CMDLINE_TAG)
  14. setup_commandline_tag(bd,commandline);
  15. #endif
  16. kernel_entry(0,machid,bd->bi_arch_number);
  17. //r0=0,
  18. //r1=machid=3589  machine type number,在setup_machine_tags(machine_arch_type)中<pre name="code" class="cpp"><span style="white-space:pre">    </span>//machine_arch_type由此传递
  19. // r2=bd->bi_arch_number=0x80000100  physical address of tagged list in system RAM,<pre name="code" class="cpp"><span style="white-space:pre">   </span>//在setup_machine_fdt(__atags_pointer)中使用的__atags_pointer由此传递
  1. }


通过以上分析,已经可以知道内核是如何找到__mach_desc_AM335XEVM,那何时去使用这个结构体定义

的函数呢?
我们知道全局变量赋值给machine_desc = mdesc,后边使用machine_desc指向各个函数进行调用。

.map_io:
/init/main.c/start_kernel(void)->setup_arch-> paging_init(mdesc) ->paging_init(mdesc)->devicemaps_init

init_early:
setup_arch-> mdesc->init_early()

init_irq:
/init/main.c/start_kernel(void)->init_IRQ()->machine_desc->init_irq()
(mdesc) ->devicemaps_init() -> mdesc->map_io()
time_init:
start_kernel() --> time_init()->system_timer = machine_desc->timer;system_timer->init()

init_machine,是通过arch_initcall(customize_machine)调用的。
.init_machine :

  1. setup.c/arch_initcall(customize_machine);
  2. static int __init customize_machine(void)
  3. {
  4. /* customizes platform devices, or adds new ones */
  5. if (machine_desc->init_machine)
  6. machine_desc->init_machine();
  7. return 0;
  8. }
  9. arch_initcall(customize_machine);

调用先后顺序是:
map_io
init_early
init_irq
time_init
init_machine
全部是在start_kernel()和setup_arch()中完成的。

MACHINE_START-内核板级初始化实现机制(linux3.1.0)的更多相关文章

  1. Linux内核源码分析--内核启动之(3)Image内核启动(C语言部分)(Linux-3.0 ARMv7)

    http://blog.chinaunix.net/uid-20543672-id-3157283.html Linux内核源码分析--内核启动之(3)Image内核启动(C语言部分)(Linux-3 ...

  2. u-boot启动流程分析(2)_板级(board)部分

    转自:http://www.wowotech.net/u-boot/boot_flow_2.html 目录: 1. 前言 2. Generic Board 3. _main 4. global dat ...

  3. (linux)BSP板级支持包开发理解

    1. 概述 嵌入式系统由硬件环境.嵌入式操作系统和应用程序组成,硬件环境是操作系统和应用程序运行的硬件平台,它随应用的不同而有不同的要求.硬件平台的多样性是嵌入式系统的主要特点,如何使嵌入式操作系统在 ...

  4. 痞子衡嵌入式:快速定位i.MXRT600板级设计ISP[2:0]启动模式引脚上电时序问题的方法

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是一种快速定位i.MXRT600板级设计ISP[2-0]启动模式引脚上电时序问题的方法. 我们知道恩智浦i.MXRT600是主打音频市场的 ...

  5. Linux 内核中的 Device Mapper 机制

    本文结合具体代码对 Linux 内核中的 device mapper 映射机制进行了介绍.Device mapper 是 Linux 2.6 内核中提供的一种从逻辑设备到物理设备的映射框架机制,在该机 ...

  6. 【转】深入Windows内核——C++中的消息机制

    上节讲了消息的相关概念,本文将进一步聊聊C++中的消息机制. 从简单例子探析核心原理 在讲之前,我们先看一个简单例子:创建一个窗口和两个按钮,用来控制窗口的背景颜色.其效果 图1.效果图  Win32 ...

  7. 板级支持包(BSP)

    板级支持包(BSP)是介于主板硬件和操作系统中驱动层程序之间的一层,一般认为它属于操作系统一部分,主要是实现对操作系统的支持,为上层的驱动程序提供访问硬件设备寄存器的函数包,使之能够更好的运行于硬件主 ...

  8. 【原创】MIPS中断系统的板级验证及实例测试

    “五一”假期前后这约五天时间,终于将MIPS中断系统进行了板级验证及实例测试.因为老师给的交叉编译工具不会用,所以测试代码完全用MIPS汇编编写.使用MARS而没有用QtSpim,其实我觉得SPIM这 ...

  9. bsp板级支持包

    定义 2作用 ▪ 建立让操作系统运行的基本环境  ▪ 完善操作系统运行的环境 3开发流程     1定义 板级支持包(BSP)是介于主板硬件和操作系统中驱动层程序之间的一层,一般认为它属于操作系统一部 ...

随机推荐

  1. sessionstorage:本地临时存储

    HTML5 web存储有两个重要对象: localStorage - 没有时间限制的数据存储 sessionStorage - 针对一个 session 的数据存储(关闭窗口,存储的数据清空) 一般涉 ...

  2. htm5 俄罗斯方块

    <!DOCTYPE html> <html manifest="tetris.manifest"> <!--在HTML标签里manifest=”cac ...

  3. android:clearTaskOnLaunch的用法

    比如你的应用里有N个Activity,其中有个是设置页面,你从主页面进入到设置页面设置了一些东西之后,突然,按了下Home键,回到了Android的Home,这时候你做了些别的事情,然后你再次点击你的 ...

  4. Eclipse 悬浮提示

    Eclipse 悬浮提示 使用悬浮提示 java 编辑器中包含了不同类型的悬浮提示,悬浮提示提供了鼠标指针指向元素的额外信息.所有java编辑器中相关的悬浮提示可以通过 preference(首选项) ...

  5. FIR滤波器与IIR滤波器

    FIR(Finite Impulse Response)滤波器 有限长单位冲激响应滤波器,又称为非递归型滤波器 特点: FIR滤波器的最主要的特点是没有反馈回路,稳定性强,故不存在不稳定的问题: FI ...

  6. ios -WKWebView 高度 准确,留有空白的解决方案

    #import "ViewController.h" #import <WebKit/WebKit.h> @interface ViewController ()< ...

  7. mysql小知识点汇总

    附录:(更新于2013-11-21) sql必知必会学习笔记:http://www.cnblogs.com/IPrograming/category/509859.html mysql 基本命令学习: ...

  8. CodeIgniter框架——知识要点汇总

    NO1.学习要点: 一.CodeIgniter 框架的简介 二.CodeIgniter 框架的安装 三.CodeIgniter 框架的目录结构分析 四.CodeIgniter 框架是如何工作的? 五. ...

  9. Django项目部署(django+guncorn+virtualenv+nginx)

    一.说明 为了django项目部署到生产环境上,能够稳定的运行,且能够同时指出http和https的访问,对django的部署进行了一些研究,决定采用django + gunicorn + virtu ...

  10. poj2528

    Mayor's posters Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 56864   Accepted: 16445 ...