Linux启动流程
从链接脚本vmlinux.lds入手,找到入口函数stex位于head.S中
vmlinux.lds ---> Entry(stext) /arch/arm/kernel/vmlinux.lds
stext位于arch/arm/kernel/head.S
->stext
->__safe_svcmode_maskall
->__lookup_processor_type
->__vet_atags
->__create_page_tables
->将函数__mmap_switched保存在r13寄存器中
->__enable_mmu
->__turn_mmu_on
-> __mmap_switched(最后会执行r13里面保存的 __mmap_switched函数,位于arch/arm/kernel/head-common.S)
->start_kernel(位于init/main.c中,内核启动的C语言阶段)
->lockdep_init
->set_task_stack_end_magic
->smp_setup_processor_id
->debug_objects_early_init
->boot_init_stack_canary
->cgroup_init_early
->local_irq_disable
->boot_cpu_init
->page_address_init
->pr_notice /*打印出linux的版本信息*/
->setup_arch
/*此函数会解析传递进来的ATAGS或者设备树(DTB)文件。
会根据设备树里面的model和compatible这两个属性值来查找Linux是否支持这个单板。
此函数也会获取设备树中chosen节点下的bootargs属性值来得到命令行参数,也就是uboot中的bootargs环境变量的值,
获取到的命令行参数会保存到command_line中。*/
->mm_init_cpumask
->setup_command_line
->setup_nr_cpu_ids
->setup_per_cpu_areas
->smp_prepare_boot_cpu
->build_all_zonelists
->page_alloc_init
->parse_early_param /*解析命令行中的console参数*/
->setup_log_buf
->pidhash_init
->vfs_caches_init_early
->sort_main_extable
->trap_init
->mm_init
->sched_init
->preempt_disable
->idr_init_cache
->rcu_init
->trace_init
->context_tracking_init
->radix_tree_init
->early_irq_init
->init_IRQ
->tick_init
->init_timers
->hrtimers_init
->softirq_init
->time_init
->local_irq_enable
->kmem_cache_init_late
->console_init /*初始化控制台,之前printk打印的信息都存放缓冲区中,并没有打印出来。
只有调用此函数初始化控制台以后才能在控制台上打印信息。*/
->locking_selftest
->kmemleak_init
->calibrate_delay
->pidmap_init
->anon_vma_init
->cred_init
->fork_init
->proc_caches_init
->buffer_init
->key_init
->security_init
->vfs_caches_init
->signals_init
->page_writeback_init
->proc_root_init
->nsfs_init
->cpuset_init
->cgroup_init
->check_bugs
->rest_init /*建立init进程在此*/
->kernel_thread(kernel_init, NULL, CLONE_FS); /*建立init进程,进程号为1*/
->kernel_init
->kernel_init_freeable
->do_basic_setup /*do_basic_setup函数用于Linux设备驱动初始化工作!非常重要。会调用driver_init函数完成函数完成 Linux下驱动模型子系统的初始化.
->sys_open /*打开/dev/console 此文件描述符为0,是标准输入文件描述符0*/
->sys_dup /*sys_dup函数将标准输入文件描述符复制了2次一个作为标准输出 (1),一个作为标准错误 (2)*/
->prepare_namespace /*挂载根文件系统*/
->kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES); /*建立内核线程,进程号为2*/
->cpu_startup_entry
->cpu_idle_loop /*空闲0号进程*/