微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > arm Linux系统启动之start_kernel函数

arm Linux系统启动之start_kernel函数

时间:11-09 来源:互联网 点击:
head-common.S

---具体做了哪些动作

---跳转到init/main.c

---b start_kernel

//关于start_kernel的强文深入理解linux内核,第八章

main.c

asmlinkage void __init start_kernel(void)

{

char * command_line;

extern struct kernel_param __start___param[], __stop___param[];

//来设置smp process id,当然目前看到的代码里面这里是空的

smp_setup_processor_id();

/*

* Need to run as early as possible, to initialize the

* lockdep hash:

*/

//lockdep是linux内核的一个调试模块,用来检查内核互斥机制尤其是自旋锁潜在的死锁问题。

//自旋锁由于是查询方式等待,不释放处理器,比一般的互斥机制更容易死锁,

//故引入lockdep检查以下几种情况可能的死锁(lockdep将有专门的文章详细介绍,在此只是简单列举):

//

//·同一个进程递归地加锁同一把锁;

//

//·一把锁既在中断(或中断下半部)使能的情况下执行过加锁操作,

// 又在中断(或中断下半部)里执行过加锁操作。这样该锁有可能在锁定时由于中断发生又试图在同一处理器上加锁;

//

//·加锁后导致依赖图产生成闭环,这是典型的死锁现象。

lockdep_init();

debug_objects_early_init();

/*

* Set up the the initial canary ASAP:

*/

//初始化stack_canary栈3

//stack_canary的是带防止栈溢出攻击保护的堆栈。

// 当user space的程序通过int 0x80进入内核空间的时候,CPU自动完成一次堆栈切换,

//从user space的stack切换到kernel space的stack。

// 在这个进程exit之前所发生的所有系统调用所使用的kernel stack都是同一个。

//kernel stack的大小一般为4096/8192,

//内核堆栈示意图帮助大家理解:

//

// 内存低址 内存高址

// | |<-----------------------------esp|

// +-----------------------------------4096-------------------------------+

// | 72 | 4 | x < 4016 | 4 |

// +------------------+-----------------+---------------------------------+

// |thread_info | | STACK_END_MAGIC | var/call chain |stack_canary |

// +------------------+-----------------+---------------------------------+

// | 28 | 44 | | |

// V | |

// restart_block V

//

//esp+0x0 +0x40

// +---------------------------------------------------------------------------+

// |ebx|ecx|edx|esi|edi|ebp|eax|ds|es|fs|gs|orig_eax|eip|cs|eflags|oldesp|oldss|

// +---------------------------------------------------------------------------+

// | kernel完成 | cpu自动完成 |

//http://hi.baidu.com/wzt85/blog/item/112a37132f6116c2f6039e44.html

boot_init_stack_canary();

// cgroup: 它的全称为control group.即一组进程的行为控制.

// 比如,我们限制进程/bin/sh的CPU使用为20%.我们就可以建一个cpu占用为20%的cgroup.

// 然后将/bin/sh进程添加到这个cgroup中.当然,一个cgroup可以有多个进程.

//http://blogold.chinaunix.net/u1/51562/showart_1736813.html

cgroup_init_early();

//更新kernel中的所有的立即数值,但是包括哪些需要再看?

core_imv_update();

//关闭当前CUP中断

local_irq_disable();

//修改标记early_boot_irqs_enabled;

//通过一个静态全局变量 early_boot_irqs_enabled来帮助我们调试代码,

//通过这个标记可以帮助我们知道是否在”early bootup code”,也可以通过这个标志警告是有无效的终端打开

early_boot_irqs_off();

//每一个中断都有一个IRQ描述符(struct irq_desc)来进行描述。

//这个函数的主要作用是设置所有的 IRQ描述符(struct irq_desc)的锁是统一的锁,

//还是每一个IRQ描述符(struct irq_desc)都有一个小锁。

early_init_irq_lock_class();

/*

* Interrupts are still disabled. Do necessary setups, then

* enable them

*/

// 大内核锁(BKL--Big Kernel Lock)

//大内核锁本质上也是自旋锁,但是它又不同于自旋锁,自旋锁是不可以递归获得锁的,因为那样会导致死锁。

//但大内核锁可以递归获得锁。大内核锁用于保护整个内核,而自旋锁用于保护非常特定的某一共享资源。

//进程保持大内核锁时可以发生调度,具体实现是:

//在执行schedule时,schedule将检查进程是否拥有大内

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

网站地图

Top