现在的位置: 首页 > 综合 > 正文

Linux/Android启动 之 (module_init和machine-init函数)

2013年10月23日 ⁄ 综合 ⁄ 共 4353字 ⁄ 字号 评论关闭

                                    Linux/Android启动之Machine-Init函数

基础知识

1. Linux启动过程中驱动模块初始化的位置

Linux OS的启动过程中将会去创建线程kernel_init,该线程负责Driver初始化等一系列工作。线程kernel_init将会依次调用do_basic_setup()
-->
do_initcalls()-->do_one_initcall(),并在do_initcalls()中完成对各个驱动模块Init函数的调用。

这部分代码如下:

函数do_basic_setup()如下:

/*

* Ok, the machine is now initialized. None of the devices

* have been touched yet, but the CPU subsystem is up and

* running, and memory and process management works.

*

* Now we can finally start doing some real work..

*/

static void __init do_basic_setup(void)

{

rcu_init_sched(); /* needed by module_init stage. */

init_workqueues();

usermodehelper_init();

driver_init();

init_irq_proc();

do_initcalls();

}

函数do_initcalls()

extern initcall_t __initcall_start[], __initcall_end[], __early_initcall_end[];

static void __init do_initcalls(void)

{

initcall_t *call;

 

for (call = __early_initcall_endcall < __initcall_endcall++)

do_one_initcall(*call);

 

/* Make sure there is no pending stuff from the initcall sequence */

flush_scheduled_work();

}

函数do_one_initcall(initcall_t fn)如下:

int initcall_debug;

core_param(initcall_debuginitcall_debugbool, 0644);

 

int do_one_initcall(initcall_t fn)

{

int count = preempt_count();

ktime_t calltimedeltarettime;

char msgbuf[64];

struct boot_trace_call call;

struct boot_trace_ret ret;

 

if (initcall_debug) {

call.caller = task_pid_nr(current);

printk("calling  %pF @ %i/n"fncall.caller);

calltime = ktime_get();

trace_boot_call(&callfn);

enable_boot_trace();

}

 

ret.result = fn();

 

if (initcall_debug) {

disable_boot_trace();

rettime = ktime_get();

delta = ktime_sub(rettimecalltime);

ret.duration = (unsigned long longktime_to_ns(delta) >> 10;

trace_boot_ret(&retfn);

printk("initcall %pF returned %d after %Ld usecs/n"fn,

ret.resultret.duration);

}

 

msgbuf[0] = 0;

 

if (ret.result && ret.result != -ENODEV && initcall_debug)

sprintf(msgbuf"error code %d "ret.result);

 

if (preempt_count() != count) {

strlcat(msgbuf"preemption imbalance "sizeof(msgbuf));

preempt_count() = count;

}

if (irqs_disabled()) {

strlcat(msgbuf"disabled interrupts "sizeof(msgbuf));

local_irq_enable();

}

if (msgbuf[0]) {

printk("initcall %pF returned with %s/n"fnmsgbuf);

}

 

return ret.result;

}

二.Machine-Init函数被调用的位置

Machine-Init也将在函数do_one_initcall(initcall_t fn)中伴随其它的模块Init函数一起被调用,不同之处在于Machine-Init的优先级最高。

三.Machine-Init函数相关解析过程

1. 重要结构体machine_desc说明

struct machine_desc描述了机器(machine, 也就是目标板)对内核初始阶段资源分配至关重要的一些参数。

首先,来看一下结构体machine_des的内容(在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 intnr;/* architecture number,记录体系结构*/

unsigned intphys_io;/* start of physical io*/

unsigned intio_pg_offst;/* byte offset for io 

* page tabe entry*/

 

const char*name;/* architecture name,体系结构名字*/

unsigned longboot_params;/* tagged list*/

 

unsigned intvideo_start;/* start of video RAM*/

unsigned intvideo_end;/* end of video RAM*/

 

unsigned intreserve_lp0 :1;/* never has lp0*/

unsigned intreserve_lp1 :1;/* never has lp1*/

unsigned intreserve_lp2 :1;/* never has lp2*/

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

};

其中,结构体的最后一个函数指针init_machine会被初始化为Machine-Init的地址。系统中针对每一种CPU都会去定义一个该结构体变量,并在系统的启动过程中进行引用。

2. 对应当前开发板的结构体machine_des的初始化

这里以Samsung S3C6410的开发板的BSP为例来进行分析。

Samsung S3C6410machine_des在文件arch/arm/mach-s3c6410/mach-s3c6410.c中定义,定义方式如下:

MACHINE_START(SMDK6410"SMDK6410")

/* Maintainer: Ben Dooks <ben@fluff.org> */

.phys_ioS3C_PA_UART & 0xfff00000,

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

.boot_paramsS3C64XX_PA_SDRAM + 0x100,

.fixupsmdk6410_fixup,

.init_irqs3c6410_init_irq,

.map_iosmdk6410_map_io,

.init_machinesmdk6410_machine_init,

#ifndef CONFIG_HIGH_RES_TIMERS

.timer= &s3c64xx_timer,

#else

.timer= &sec_timer,

#endif /* CONFIG_HIGH_RES_TIMERS */

 

MACHINE_END

Linux中针对各个不同的CPU存在很多个类似于上面的定义,宏定义MACHINE_START的定义如下:

/*

* Set of macros to define architecture features.  This is built into

* a table by the linker.

*/

#define MACHINE_START(_type,_name)/

static const struct machine_desc __mach_desc_##_type/

__used/

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

.nrMACH_TYPE_##_type,/

.name_name,

 

#define MACHINE_END/

};

其实,宏定义替换后的就变成了如下的定义方式:

static const

抱歉!评论已关闭.