MACHINE_START-内核板级初始化实现机制(linux3.1.0)
2014-11-26 17:03
267 查看
在驱动开发时,我们都是以一块开发板为基础移植驱动程序。每一块开发板对应一个板级文件,如开发
TI AM335x系列,则对应board-am335xevm.c,这个文件完成芯片和板级的初始化工作。对于驱动开发,还有
一个很重要的文件devices.c,这个文件主要是设备接口相关资源。
今天就来说说board-am335xevm.c文件,如何全面的了解这个文件呢?先找到这个文件的入口,在文件的
最后几行:
看以看出,am335x_evm_map_io,i816x_init_irq,am335x_init_early,am335x_evm_init就是各个初始化函数
的总入口函数。
下面来分析一下这几个函数是如何被调用,何时被调用的?
宏展开之后得到:
__mach_desc_AM335XEVM是一个struct machine_desc 类型结构体,这个结构体存放的段是
.arch.info.init,这里注意一下,后边匹配machine_desc的时候就是到这个段中寻找,然后根据nr的值匹配。
内核启动的时候跳转的C语言入口在main.c/start_kernel(void),start_kernel(void)会调用setup_arch(),
接下来看看setup_arch():
首先使用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()中:
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。
__arch_info_begin是machine_desc存放的位置,通过属性定义
uboot的参数传递给内核:
uboot的板级文件evm.c中定义了板级信息
通过以上分析,已经可以知道内核是如何找到__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 :
调用先后顺序是:
map_io
init_early
init_irq
time_init
init_machine
全部是在start_kernel()和setup_arch()中完成的。
TI AM335x系列,则对应board-am335xevm.c,这个文件完成芯片和板级的初始化工作。对于驱动开发,还有
一个很重要的文件devices.c,这个文件主要是设备接口相关资源。
今天就来说说board-am335xevm.c文件,如何全面的了解这个文件呢?先找到这个文件的入口,在文件的
最后几行:
MACHINE_START(AM335XEVM, "am335xevm") /* Maintainer: Texas Instruments */ .atag_offset = 0x100, .map_io = am335x_evm_map_io, .init_irq = ti816x_init_irq, .init_early = am335x_init_early, .timer = &omap3_am33xx_timer, .init_machine = am335x_evm_init, MACHINE_END
看以看出,am335x_evm_map_io,i816x_init_irq,am335x_init_early,am335x_evm_init就是各个初始化函数
的总入口函数。
下面来分析一下这几个函数是如何被调用,何时被调用的?
#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 \ };
宏展开之后得到:
static const struct machine_desc __mach_desc_AM335XEVM \ __attribute__((__used__)) \ __attribute__((__section__(".arch.info.init"))) = { \ .nr = MACH_TYPE_AM335XEVM, \ .name = _name, .atag_offset = 0x100, .map_io = am335x_evm_map_io, .init_irq = ti816x_init_irq, .init_early = am335x_init_early, .timer = &omap3_am33xx_timer, .init_machine = am335x_evm_init, };
__mach_desc_AM335XEVM是一个struct machine_desc 类型结构体,这个结构体存放的段是
.arch.info.init,这里注意一下,后边匹配machine_desc的时候就是到这个段中寻找,然后根据nr的值匹配。
struct machine_desc { unsigned int nr; /* architecture number */ const char *name; /* architecture name */ unsigned long boot_params; /* tagged list */ unsigned long atag_offset; /* tagged list (relative) */ const char **dt_compat; /* array of device tree * 'compatible' strings */ unsigned int nr_irqs; /* number of IRQs */ #ifdef CONFIG_ZONE_DMA unsigned long dma_zone_size; /* size of DMA-able area */ #endif 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 (*reserve)(void);/* reserve mem blocks */ void (*map_io)(void);/* IO mapping function */ void (*init_early)(void); void (*init_irq)(void); struct sys_timer *timer; /* system tick timer */ void (*init_machine)(void); #ifdef CONFIG_MULTI_IRQ_HANDLER void (*handle_irq)(struct pt_regs *); #endif };
内核启动的时候跳转的C语言入口在main.c/start_kernel(void),start_kernel(void)会调用setup_arch(),
接下来看看setup_arch():
void __init setup_arch(char **cmdline_p) { struct machine_desc *mdesc; unwind_init(); setup_processor(); /*__atags_pointer是uboot传递的参数地址 0x80000100*/ mdesc = setup_machine_fdt(__atags_pointer); /*由于参数非设备树结构,返回NULL*/ if (!mdesc) mdesc = setup_machine_tags(machine_arch_type); machine_desc = mdesc; machine_name = mdesc->name ......... }
首先使用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()中:
for_each_machine_desc(p) if (nr == p->nr) { printk("Machine: %s\n", p->name); mdesc = p; 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。
#define for_each_machine_desc(p) for (p = __arch_info_begin; p < __arch_info_end; p++)
__arch_info_begin是machine_desc存放的位置,通过属性定义
//在setup_machine_fdt(__atags_pointer)中使用的__atags_pointer由此传递
uboot的参数传递给内核:
uboot的板级文件evm.c中定义了板级信息
int board_evm_init() { gd->bd->bi_arch_number=MACH_TYPE_TIAM335EVM; gd->bd->bi_boot_params=PHYS_DRAM_1+0x100; //PHYS_DRAM_1=0x80000000 }当使用bootm启动内核的时候,调用了do_bootm_linux函数:
int do_bootm_linux(int flag ,int argc ,char *argv[] , bootm_headers_t *images) { bd_t *bd=gd->bd; int machid=bd->bi_arch_number; /*使用device tree 结构传递参数,我们没有使用这种方式*/ #ifdef CONFIG_OF_LIBFDT if(images->ft_len) return bootm_linux_fdt(machid,images); #endif #if defined (CONFIG_SETUP_MEMORY_TAGS) || defined (CONFIG_CMDLINE_TAG) || ......... setup_start_tag(bd); #endif #if defined (CONFIG_CMDLINE_TAG) setup_commandline_tag(bd,commandline); #endif kernel_entry(0,machid,bd->bi_arch_number); //r0=0, //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由此传递 // 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由此传递
}
通过以上分析,已经可以知道内核是如何找到__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 :
setup.c/arch_initcall(customize_machine); static int __init customize_machine(void) { /* customizes platform devices, or adds new ones */ if (machine_desc->init_machine) machine_desc->init_machine(); return 0; } arch_initcall(customize_machine);
调用先后顺序是:
map_io
init_early
init_irq
time_init
init_machine
全部是在start_kernel()和setup_arch()中完成的。
相关文章推荐
- MACHINE_START-内核板级初始化实现机制(linux3.1.0)
- Linux 2.6.10内核下PCI Express Native热插拔框架的实现机制
- 【转】深入剖析linux内核的定时器实现机制-动态刷新维护
- Linux2.6.6 内核下 ACPI PCI Hot-Plug 的实现机制(上)
- Linux内核抢占实现机制分析
- Linux内核中实现Wineserver机制浅析
- 用Linux 2.6内核中的文件系统变化通知机制inotify可实现跨机文件同步
- linux路由内核实现分析(四)---路由缓存机制(2)
- Linux2.6.6内核下ACPI PCI Hot-Plug的实现机制(下)
- linux路由内核实现分析(四)---路由缓存机制(4)
- linux内核中的xx_initcall和module_init实现机制(linux3.1.0)
- Linux内核防火墙Netfilter实现机制
- Linux内核抢占实现机制分析
- Linux内核抢占实现机制分析(转)
- linux内核初始化及启动之start_kernel
- linux路由内核实现分析(四)---路由缓存机制
- 《Linux 系统内核空间与用户空间通信的实现与分析》 Netlink 机制实现
- Linux2.6.10内核下PCIExpressNative热插拔框架的实现机制
- Linux用户进程间通信机制在内核的实现
- Linux内核抢占实现机制分析(转)