zoukankan      html  css  js  c++  java
  • 制作根文件系统之内核如何启动init进程

    start_kernel其实也是内核的一个进程,它占用了进程号0,start_kernel的内容简写如下:

    asmlinkage void __init start_kernel(void)  //内核线程,0号进程idle进程
    {  
      ......  
      tick_init();
      boot_cpu_init();
      page_address_init();   //内存管理相关     kernel2.6.35.11/mm/highmem.c
      ......
      setup_arch(&command_line);  //内核解析uboot参数就在这步;内核页表  kernel2.6.35.11/arch/arm/kernel/setup.c
      mm_init_owner(&init_mm,&init_task);   //kernel2.6.35.11/kernel/fork.c
      mm_init_cpumask(&init_mm);
      ......
      page_alloc_init();    //内存页表相关  kernel2.6.35.11/mm/page_alloc.c
      ......
      vfs_caches_init(totalram_pages); //rootfs创建,并将rootfs设置为系统根文件系统、rootfs根目录设置为系统根目录;这部是决定驱动加载关键
      ......
      mm_init();  //构建整个页表 kernel2.6.35.11/kernel/fork.c 
      sched_init();    //进程管理相关  kernel2.6.35.11/kernel/sched.c
      ......
      init_timers();  //内核定时器   kernel2.6.35.11/kernel/timer.c
      hrtimers_init();  //内核定时器  kernel2.6.35.11/kernel/timer.c
      ......
      timekeeping_init();
      time_init();
      ......
      page_cgroup_init();  //内核页表相关 kernel2.6.35.11/mm/page_cgroup.c
      ......
      fork_init(totalram_pages);  //kernel2.6.35.11/kernel/fork.c
      proc_caches_init();  //kernel2.6.35.11/kernel/fork.c
      ......
      signals_init();  //信号量相关  kernel2.6.35.11/kernel/signal.c
      ......
      rest_init();
    }
    接着制作根文件系统之内核挂接文件系统步骤分析继续分析,rest_init函数创建了kernel_init线程,进程号为1,kernel_init线程主要做了两件事情
    1、调用prepare_namespace挂接根文件系统
    2、调用init_post函数启动init进程
    其中第一条已经分析过,接着分析第二条:调用init_post函数启动init进程,init_post位于init/Main.c中
    748    static int noinline init_post(void)
    749    {
    750        free_initmem();
    751        unlock_kernel();
    752        mark_rodata_ro();
    753        system_state = SYSTEM_RUNNING;
    754        numa_default_policy();
    755
    756        if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0)//尝试打开/dev/console设备,如果成功它就是stdin
    757            printk(KERN_WARNING "Warning: unable to open an initial console.
    ");
    758
    759        (void) sys_dup(0);//将文件描述符0复制给文件描述符1
    760        (void) sys_dup(0);//将文件描述符1复制给文件描述符2
    761
    762        if (ramdisk_execute_command) {//如果存在ramdisk_execute_command则执行ramdisk_execute_command不再返回
    763            run_init_process(ramdisk_execute_command);
    764            printk(KERN_WARNING "Failed to execute %s
    ",
    765                    ramdisk_execute_command);
    766        }
    767
    768        /*
    769         * We try each of these until one succeeds.
    770         *
    771         * The Bourne shell can be used instead of init if we are
    772         * trying to recover a really broken machine.
    773         */
    774        if (execute_command) {//如果存在execute_command则执行ramdisk_execute_command不再返回
    775            run_init_process(execute_command);//内核空间调用用户空间函数kernel_execve执行execute_command进程
    776
    777            printk(KERN_WARNING "Failed to execute %s.  Attempting "
    778                        "defaults...
    ", execute_command);
    779        }
    780        run_init_process("/sbin/init");//执行/sbin/init,不再返回
    781        run_init_process("/etc/init");//执行/etc/init,不再返回
    782        run_init_process("/bin/init");//执行/bin/init,不再返回
    783        run_init_process("/bin/sh");//执行/bin/sh,不再返回
    784    
    785        panic("No init found.  Try passing init= option to kernel.");//到了这里,说明出错了,没有找到init程序
    786    }

    它的主要意思就是打开控制台设备,然后找到init进程,然后执行。其中execute_command的值在Linux移植之tag参数列表解析过程分析已经分析过,它的值就是Uboot传入的init参数的值/linuxrc,所以内核执行的第一个用户态进程就是linuxrc。这个进程是由kernel_init进程直接转换的,所以它的进程号也为1。这个就是init进程的启动过程。从上面分析可以知道根文件系统是提前建立好的,里面至少有/linuxrc程序、/dev/console文件。后面继续分析他们。

    
    
  • 相关阅读:
    sql优化
    什么是泛型
    Http Status 400
    Hadoop搭建伪分布式 & 上传和下载文件
    Centos64 安装指南
    个人感悟
    zabbix4.0部署
    MySQL引擎
    mysql正则表达式
    k8s自动补全命令
  • 原文地址:https://www.cnblogs.com/andyfly/p/9418808.html
Copyright © 2011-2022 走看看