(Linux内核) 2-内核启动

资料来源:正点原子嵌入式Linux

目录

Linux启动第一阶段

Linux启动第二阶段

kernel_init(init)

 

 

Linux启动第一阶段

image和zImage是经过压缩的,Linux内核会先进行解压缩,解压缩完成以后就要运行Linux内核。要求:

       1、MMU关闭

       2、D cache关闭

       3、I cache无所谓

       4、r0 = 0。  

       5、r1 = machine nr

       6、r2=atags 或设备树

以上要求完成后,进入stext入口函数,arch/arm/kernel/head.S,完成的以下工作:

      __vet_atags 函数验证atags或dtb是否有效,如果使用设备树的话就是dtb。

      __create_page_tables 创建页表。

       ldr   r13, =__mmap_switched 也就是r13保存__mmap_switched。

       __enable_mmu  使能MMU

              -> __turn_mmu_on

                     ->_mmap_switched

                            ->start_kernel  启动内核。

 

Linux启动第二阶段

start_kernel 通过调用众多的子函数来完成 Linux 启动之前的一些初始化工作(P911)。start_kernel 函数最后调用了 rest_init,接下来简单看一下 rest_init函数,init/main.c

static noinline void __init_refok rest_init(void)
{
	int pid;

	rcu_scheduler_starting();
	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);
	numa_default_policy();
	pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);
	rcu_read_lock();
	kthreadd_task = find_task_by_pid_ns(pid, &init_pid_ns);
	rcu_read_unlock();
	complete(&kthreadd_done);

	/*
	 * The boot idle thread must execute schedule()
	 * at least once to get things moving:
	 */
	init_idle_bootup_task(current);
	schedule_preempt_disabled();
	/* Call into cpu_idle with preempt disabled */
	cpu_startup_entry(CPUHP_ONLINE);
}

kernel_thread 函数用来创建进程,首先是kernel_init进程,也就是init内核进程,PID=1。

接着创建kthreadd进程,PID=2,负责所有内核进程的调度和管理。

cpu_startup_entry会调用cpu_idle_loop,也就是空闲进程,PID=0,当CPU没有任务时就执行这个空闲进程。

所以第二阶段可以总结为:

start_kernel

              -> rest_init

                     -> kernel_thread(kernel_init, NULL, CLONE_FS);  创建kernel_init进程。也就是init进程,PID=1

                     -> kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);  创建kthreadd进程,进程PID为2。

                     -> cpu_startup_entry 进入空闲进程,也就是主进程退化为空闲进程,idle。

 

kernel_init(init)

kernel_init 函数就是 init 进程具体做的工作,定义在文件 init/main.c

kernel_init

              -> kernel_init_freeable

                     -> 设置标准输入、标准输出、标准错误使用console控制台,比如ttymxc0(串口)

                     -> ramdisk_execute_command = "/init";

 

              -> 检查/init是否存在,存在的话就运行。

              -> uboot传递给Linux内核的bootargs可以自定init=xxx,或者叫命令行参数。

有一些开发板会设置init=linuxrc。

              -> 试着运行/sbin/init。

              -> /etc/init

              -> /bin/init

              -> /bin/sh

 

       可以看出,最终引出根文件系统。

你可能感兴趣的:(嵌入式)