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_end; call < __initcall_end; call++) 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_debug, initcall_debug, bool, 0644);
int do_one_initcall(initcall_t fn) { int count = preempt_count(); ktime_t calltime, delta, rettime; 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", fn, call.caller); calltime = ktime_get(); trace_boot_call(&call, fn); enable_boot_trace(); }
ret.result = fn();
if (initcall_debug) { disable_boot_trace(); rettime = ktime_get(); delta = ktime_sub(rettime, calltime); ret.duration = (unsigned long long) ktime_to_ns(delta) >> 10; trace_boot_ret(&ret, fn); printk("initcall %pF returned %d after %Ld usecs/n", fn, ret.result, ret.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", fn, msgbuf); }
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 S3C6410的machine_des在文件arch/arm/mach-s3c6410/mach-s3c6410.c中定义,定义方式如下:
MACHINE_START(SMDK6410, "SMDK6410") /* Maintainer: Ben Dooks <ben@fluff.org> */ .phys_io= S3C_PA_UART & 0xfff00000, .io_pg_offst= (((u32)S3C_VA_UART) >> 18) & 0xfffc, .boot_params= S3C64XX_PA_SDRAM + 0x100, .fixup= smdk6410_fixup, .init_irq= s3c6410_init_irq, .map_io= smdk6410_map_io, .init_machine= smdk6410_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"))) = {/ .nr= MACH_TYPE_##_type,/ .name= _name,
#define MACHINE_END/ }; |
其实,宏定义替换后的就变成了如下的定义方式:
static const
|