Linux_arm_启动_c语言部分详解,[原创]Linux arm 启动 c语言部分详解第六讲(终结篇,1号进程)...

这篇博客详细介绍了Linux内核启动过程中1号进程init的执行流程,包括锁机制、SMP初始化、文件系统挂载、设备驱动加载以及init进程如何启动用户空间程序。文章深入探讨了root设备的解析、initrd的使用以及如何根据不同的root参数挂载根文件系统。
摘要由CSDN通过智能技术生成

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

written by leeming

1号进程(init进程)

static int init(void * unused)

{

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

child_reaper = current;//child_reaper是1号进程

/***********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 = '!';

//除了nfs,ram外其他的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.");

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值