Chinaunix首页 | 论坛 | 博客
  • 博客访问: 932768
  • 博文数量: 153
  • 博客积分: 4195
  • 博客等级: 上校
  • 技术积分: 2631
  • 用 户 组: 普通用户
  • 注册时间: 2009-06-22 11:32
文章存档

2012年(7)

2010年(35)

2009年(111)

分类: LINUX

2010-04-06 15:55:34

【原创】Linux arm 启动 c语言部分详解第六讲(终结篇,1号进程)

written by leeming

1号进程(init进程)

static int init(void * unused)

{

       lock_kernel();//这是1号进程的lock

 

       child_reaper = current;//child_reaper1号进程

       /***********smp的一些操作*****************/

       smp_prepare_cpus(max_cpus);

 

       do_pre_smp_initcalls();

 

       fixup_cpu_present_map();

       smp_init();

       sched_init_smp();

 

       cpuset_init_smp();

       /*********************************/

 

      

       /*initcalls之前安装文件系统,因为有些驱动可能会

       访问,这部分主要针对initrd,在我们一般使用的系统

       是不用用到的*/

       /*第一种方式已经用过了,比如直接在mtdblock3上挂载

       jffs2根文件系统。第二种方式要分为两种情况,一种是

       image-initrd一种是cpio-initrd。在host上普遍采用cpio-initrd

       是在嵌入式系统上还是采用image-initrd多。本来想探讨

       一下如何使用cpio-initrd没有结果暂时放弃。第三

       种方式实际上就是把fs作到kernel中,实际的映像就是

       kernel+fs了。不过第三种方式对小系统来说合适,一

       旦这个映像比较大,那么更多的时间会消耗在解压

       缩上,反而得不偿失了。*/

       populate_rootfs();

 

       do_basic_setup();

{

       /* drivers will send hotplug events */

       init_workqueues();

       //启动了用户态的khelper进程

       usermodehelper_init();

       driver_init();

 

#ifdef CONFIG_SYSCTL

       sysctl_init();

#endif

 

//Do_initcalls()用来启动所有在__initcall_start__initcall_end段的函

//数,而静态编译进内核的modules也会将其入口放置在这段区间里。

       do_initcalls();

}

       /*

        * 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();

{

       int is_floppy;

 

       //我们没有使用devfs

       mount_devfs();

 

       if (root_delay) {

              printk(KERN_INFO "Waiting %dsec before mounting root device...\n",

                     root_delay);

              ssleep(root_delay);

       }

 

       //这是定义CONFIG_BLK_DEV_MD才会用到

       md_run_setup();

 

       if (saved_root_name[0]) {

              root_device_name = saved_root_name;

              //这一步很重要,解析了参数中的root选项,获得要挂载的设备号

              ROOT_DEV = name_to_dev_t(root_device_name);

{

       char s[32];

       char *p;

       dev_t res = 0;

       int part;

 

#ifdef CONFIG_SYSFS

       int mkdir_err = sys_mkdir("/sys", 0700);

       if (sys_mount("sysfs", "/sys", "sysfs", 0, NULL) < 0)

              goto out;

#endif

 

//如果bootargs不是以root=/dev/**开始,则进入循环

//我们也可以通过设备号,例root=31:03等价于/dev/mtdblock3

       if (strncmp(name, "/dev/", 5) != 0) {

              unsigned maj, min;

              if (sscanf(name, "%u:%u", &maj, &min) == 2) {

                     res = MKDEV(maj, min);

                     if (maj != MAJOR(res) || min != MINOR(res))

                            goto fail;

              } else {

                     res = new_decode_dev(simple_strtoul(name, &p, 16));

                     if (*p)

                            goto fail;

              }

              goto done;

       }

       name += 5;

       res = Root_NFS;

       if (strcmp(name, "nfs") == 0)

              goto done;

       res = Root_RAM0;

       if (strcmp(name, "ram") == 0)

              goto done;

 

       //root参数的名字不能过长,即/dev/后面的个数不能超过31

       if (strlen(name) > 31)

              goto fail;

       strcpy(s, name);

 

       //将参数中的/换为!

       for (p = s; *p; p++)

              if (*p == '/')

                     *p = '!';

 

       //除了nfsram外其他的root参数通过/sys/block/%s/dev找到设备号

       res = try_name(s, 0);

       if (res)

              goto done;

 

       while (p > s && isdigit(p[-1]))

              p--;

       if (p == s || !*p || *p == '0')

              goto fail;

       part = simple_strtoul(p, NULL, 10);

       *p = '\0';

       res = try_name(s, part);

       if (res)

              goto done;

 

       if (p < s + 2 || !isdigit(p[-2]) || p[-1] != 'p')

              goto fail;

       p[-1] = '\0';

       res = try_name(s, part);

done:

#ifdef CONFIG_SYSFS

       sys_umount("/sys", 0);

out:

       if (!mkdir_err)

              sys_rmdir("/sys");

#endif

       return res;

fail:

       res = 0;

       goto done;

}

              if (strncmp(root_device_name, "/dev/", 5) == 0)

                     root_device_name += 5;

       }

 

       is_floppy = MAJOR(ROOT_DEV) == FLOPPY_MAJOR;

 

       if (initrd_load())

              goto out;

 

       if (is_floppy && rd_doload && rd_load_disk(0))

              ROOT_DEV = Root_RAM0;

       //挂载设备

       mount_root();

out:

       umount_devfs("/dev");

       sys_mount(".", "/", NULL, MS_MOVE, NULL);

       sys_chroot(".");

       security_sb_post_mountroot();

       mount_devfs_fs ();

}

       }

 

       /*

        * 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..

        */

       //将以init标示的函数空间释放,也就是我们启动的时候

       //经常会冒出来:Freeing init memory: 116K

       free_initmem();

       unlock_kernel();

      

       mark_rodata_ro();

       system_state = SYSTEM_RUNNING;

       numa_default_policy();

 

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

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

 

       (void) sys_dup(0);

       (void) sys_dup(0);

 

       if (ramdisk_execute_command) {

              run_init_process(ramdisk_execute_command);

              printk(KERN_WARNING "Failed to execute %s\n",

                            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) {

              run_init_process(execute_command);

              printk(KERN_WARNING "Failed to execute %s.  Attempting "

                                   "defaults...\n", execute_command);

       }

       //一个个查找init进程

       run_init_process("/sbin/init");

       run_init_process("/etc/init");

       run_init_process("/bin/init");

       run_init_process("/bin/sh");

 

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

}

阅读(2014) | 评论(0) | 转发(4) |
给主人留下些什么吧!~~