微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > Arm linux kernel 启动之start_kernel

Arm linux kernel 启动之start_kernel

时间:11-09 来源:互联网 点击:
了解完kernel启动以前的汇编之后我们来看看正式的c语言启动代码,也就是我们的start_kernel函数了。start_kernel相当大,里面每一个调用到的函数都足够我们伤脑筋了,我这里只是浅尝辄止的描述一下函数的功能,从而对kernel启动的过程有一个比较直观的了解。很多函数真正理解需要对linux相关体系有很深的了解,暂时没有时间深入,留待以后了。

说实话启动的代码看到现在唯一的感觉就是kernel的全局变量实在太多了,要了解一个过程跟踪一个变量的值的变化相当痛苦啊,不过耐心看下来,收获还是比较丰富的,对很多概念都有了一个比较直观的理解。闲话就不多说了,直接来上代码~~


smp_setup_processor_id();

//这个函数现在是空的;


lockdep_init();

//Runtime locking correctness validator, see Documentation/lockdep_design.txt

debug_objects_early_init();

cgroup_init_early();

//Control group, read Documentation/cgroup.txt

local_irq_disable();

//使用armcpsid i指令来禁止IRQ

early_boot_irqs_off();

early_init_irq_lock_class();

/* 基本上面几个函数就是初始化lockdep和cgroup,然后禁止IRQ,为后续的运行创造条件 */


lock_kernel();

/* 看这个函数的之前我们首先来了解一段知识,linux kernel默认是支持preemption(抢占)的。在SMP环境下为了实现kernel的锁定,kernel使用了一个BKL(big kernel lock)的概念,在初始化的过程中先锁定这个BKL,然后再继续进行其他启动或者初始化过程,这样就可以防止启动过程中被中断,执行到res_init以后,kernel会释放这个锁,这样就确保了整个start_kernel过程都不会被抢占或者中断。由此我们可以看到这主要是针对多处理器而言的,实际上如果只有一个处理器的话它也不会被中断或者被抢占。 */

/* 下面我们来看看这个函数的执行过程,在这里面能学到很多东西的:

int depth = current->lock_depth+1;

这个current实际上是一个宏,定义在arch/arm/include/asm/current.h里面,它实际是一个task_struct的结构体,这个结构体描述了这个task的一系列信息(task应该是linux进程调度的一个基本单位?)。linux下每个进程都有一个相对应的task_struct,这个task_struct有几个我们经常能看到的信息,一个就是PID,然后就是comm进程的名字,然后就是mm_struct,它定义了跟这个进程相关的所有申请的memory的管理。这个curren_thread_info()也是个很有意思的函数,直接读取SP来获得当前线程的结构体信息thread_info。thread_info和task_struct这两个结构体应该就代表了当前线程的所有信息。

初始化的lock_depth是-1,只有init task的lock_depth是0。

if (likely(!depth))

__lock_kernel();

这里判断是不是init task,如果是就会执行__lock_kernel();这个__lock_kernel首先禁止抢占,然后试着获得BKL,如果成功则直接返回,如果不成功首先判断是否禁止抢占成功了,如果成功了就用自旋锁去锁BKL。如果禁止抢占没有成功则在抢占有效的情况下去等待BKL,直到获得BKL。因为QC的片子不是SMP,所有这里第一次try的时候就直接成功了。

current->lock_depth = depth;

这个就没什么好说的了 */

/* 基本上来说这个lock_kernel就是禁止抢占,然后获得BKL,干了这么件事 */


tick_init();

//和时钟相关的初始化,好像是注册notify事件,没有仔细研究过


boot_cpu_init();

//这个实际上是在SMP环境下选择CPU,这里直接CPUID选择的是0号cpu


page_address_init();

//初始化high memory,在arm环境下实际上这个函数是空的,也就是说arm不支持high memory


printk(KERN_NOTICE);

printk(linux_banner);

//这里的KER_NOTICE是字符串<5>,不太明白它的意思。。。后面的linux_banner定义在kernel/init/version.c里面,这里的printk是门高深的学问,以后看console的时候会仔细分析


setup_arch(&command_line);

/* 这是一个重量级的函数了,会比较仔细地分析一下,主要完成了4个方面的工作,一个就是取得MACHINE和PROCESSOR的信息然或将他们赋值给kernel相应的全局变量,然后呢是对boot_command_line和tags接行解析,再然后呢就是memory、cach的初始化,最后是为kernel的后续运行请求资源。 */

/* 我们来仔细看看这个函数的实现:

setup_processor();

这个函数首先从arm寄存器里面取得cpu ID,然后调用lookup_processor_t

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top