资料来源:正点原子嵌入式Linux
目录
Linux启动第一阶段
Linux启动第二阶段
kernel_init(init)
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 启动内核。
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 进程具体做的工作,定义在文件 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
可以看出,最终引出根文件系统。