linux4.1内核分析,Linux4.1.15 内核内核启动函数分析rest_init、kernel_init、kernel_init_freeable...

首先看一下该函数整体

static noinline void __init_refok rest_init(void)

{

int pid;

rcu_scheduler_starting(); //启动内核的RCU调度机制

smpboot_thread_init(); //多核心启动线程初始化

/*

* We need to spawn init first so that it obtains pid 1, however

* the init task will end up wanting to create kthreads, which, if

* we schedule it before we create kthreadd, will OOPS.

/

kernel_thread(kernel_init, NULL, CLONE_FS);

/PID=1,创建内核线程,该线程的回调函数为kernel_init(),设备驱动程序的初始化工作以及用户空间init进程的创建工作在kernel_init()函数中完成。/

numa_default_policy();

/ 设置numa内存管理的默认策略*/

pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);

/PID=2,创建kthreadd内核线程,并始终运行在内核空间, 负责所有内核线程的调度和管理。/

rcu_read_lock();

kthreadd_task = find_task_by_pid_ns(pid, &init_pid_ns);

/通过pid获取kthreadd的task_struct结构体/

rcu_read_unlock();

complete(&kthreadd_done);

/通过complete函数通知kernel_init函数kthreadd调度线程已经创建成功,

对应kernel_init_freeable()函数中的wait_for_completion(&kthreadd_done),接收到该信号之后才进行下一步的设置和初始化工作/

/*

* The boot idle thread must execute schedule()

* at least once to get things moving:

*/

init_idle_bootup_task(current);

/*current进程即为内核当前进程,并设置当前进程为idle进程类*/

schedule_preempt_disabled();

/*

sched_preempt_enable_no_resched(); 使能抢占但是不进行调度

schedule();执行调度,切换进程

preempt_disable();进程调度完成,禁用抢占

*/

/* Call into cpu_idle with preempt disabled */

cpu_startup_entry(CPUHP_ONLINE);

/*

arch_cpu_idle_prepare();

cpu_idle_loop();

内核本体进入idle状态,用循环消耗空闲的CPU时间

*/

}

在这个函数中重点关注kernel_init()函数,函数具体如下:

static int __ref kernel_init(void unused)

{

int ret;

kernel_init_freeable();

/该函数完成设备初始化以及模块加载等工作,后面分析/

/ need to finish all async __init code before freeing the memory */

async_synchronize_full();

free_initmem();

/*释放所有init.段中的内存/

mark_rodata_ro();

system_state = SYSTEM_RUNNING;

/设置系统状态为系统运行状态/

numa_default_policy();

flush_delayed_fput();

if (ramdisk_execute_command) {

ret = run_init_process(ramdisk_execute_command);

if (!ret)

return 0;

pr_err(“Failed to execute %s (error %d)\n”,

ramdisk_execute_command, ret);

}

/如果ramdisk_execute_command指定了要运行的程序,就运行

如果命令行中指定了"rdinit=…",则就去执行该指定的程序;

如果/init程序存在,ramdisk_execute_command=/init;

如果以上两种情况都不存在,则ramdisk_execute_command为空/

/*同上ramdisk_execute_command

* We try each of these until one succeeds.

* The Bourne shell can be used instead of init if we are

* trying to recover a really broken machine.

*/

if (execute_command) {

ret = run_init_process(execute_command);

if (!ret)

return 0;

panic(“Requested init %s failed (error %d).”,

execute_command, ret);

}

if (!try_to_run_init_process("/sbin/init") ||

!try_to_run_init_process("/etc/init") ||

!try_to_run_init_process("/bin/init") ||

!try_to_run_init_process("/bin/sh"))

return 0;

/*检查到ramdisk_execute_command和execute_command为空的情况下,顺序 执行以上四个函数。创建用户空间的第一个进程 */

panic("No working init found. Try passing init= option to kernel. "

“See Linux Documentation/init.txt for guidance.”);

/*如果出现错误,则可能是由于以下原因引起的

【1】启动参数配置有问题,指定了init进程,但是没有找到,在文件系统中找不到默认的四个应用程序;

【2】文件系统挂载出错

【3】以上四个程序均没有执行权限 */

}

继续分析kernel_init_freeable()函数

static noinline void __init kernel_init_freeable(void)

{

/*上文中已经提到过,需要等待内核kthreadd线程设置完毕后,才能进行下一步工作。kthreadd主要用于内核线程的调度等工作

* Wait until kthreadd is all set-up.

/

wait_for_completion(&kthreadd_done);

/ Now the scheduler is fully set up and can do blocking allocations /

gfp_allowed_mask = __GFP_BITS_MASK;

/

* init can allocate pages on any node

/

set_mems_allowed(node_states[N_MEMORY]);

/

* init can run on any cpu.

*/

set_cpus_allowed_ptr(current, cpu_all_mask);

cad_pid = task_pid(current);

smp_prepare_cpus(setup_max_cpus);

do_pre_smp_initcalls();

lockup_detector_init();

smp_init(); //初始化多核处理器

sched_init_smp(); //多核处理器调度初始化

do_basic_setup();

//后续继续深入分析这个函数,在这个函数中完成设备初始化工作

/* Open the /dev/console on the rootfs, this should never fail */

if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0)

pr_err("Warning: unable to open an initial console.\n");

//打开/dev/console设备

//将文件描述符0 赋值给文件描述符1、2,所以标准输入、输出、错误都对应用于 console

(void) sys_dup(0);

(void) sys_dup(0);

/*

* check if there is an early userspace init. If yes, let it do all

* the work

*/

if (!ramdisk_execute_command)

ramdisk_execute_command = "/init";

if (sys_access((const char __user *) ramdisk_execute_command, 0) != 0) {

ramdisk_execute_command = NULL;

prepare_namespace();

}

/*

* Ok, we have completed the initial bootup, and

* we're essentially up and running. Get rid of the

* initmem segments and start the user-mode stuff..

*

* rootfs is available now, try loading the public keys

* and default modules

*/

integrity_load_keys(); //加载系统信任链,IMA可信验证相关key

load_default_modules(); //加载默认模块

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值