浅析linux2.6.24内核initrd传递给rootfs进行系统加载流程
1.解析有loader传递过来的initrd参数
start_kernel()->
setup_arch()->
parse_tags()->
使用下面这个函数进行解析:
static int __init parse_tag_initrd(const struct tag *tag)
{
printk(KERN_WARNING "ATAG_INITRD is deprecated; "
"please update your bootloader.\n");
phys_initrd_start = __virt_to_phys(tag->u.initrd.start);
phys_initrd_size = tag->u.initrd.size;
return 0;
}
__tagtable(ATAG_INITRD, parse_tag_initrd);
2.进一步初始化initrd_start变量
start_kernel()->
setup_arch()->
paging_init()->
bootmem_init()->
bootmem_init_node()->
在该函数中使用下面2个语句将物理地址转为虚拟地址
#ifdef CONFIG_BLK_DEV_INITRD
...
initrd_start = __phys_to_virt(phys_initrd_start);
initrd_end = initrd_start + phys_initrd_size;
...
#endif
3.建立rootfs文件系统,并mount到根目录
start_kernel()->
vfs_caches_init()->
mnt_init()->
init_rootfs()->位于fs/ramfs/inode.c中,调用register_filesystem(&rootfs_fs_type);注册rootfs
接下来
init_mount_tree()函数将调用mnt = do_kern_mount("rootfs", 0, "rootfs", NULL);将rootfs挂在到/根目录下
然后使用如下两个函数,将后边建立线程的根目录指向rootfs,
set_fs_pwd(current->fs, ns->root, ns->root->mnt_root);
set_fs_root(current->fs, ns->root, ns->root->mnt_root);
4.将initrd(的ramdisk加载到rootfs
start_kernel()->
rest_init()->
kernel_init()->内核线程
do_basic_setup()->
do_initcalls()->调用所有arch/arm/kernel/vmlinux.lds.S中定义的INITCALLS模块,比如:使用module_init内建到zImage中的所有驱动模块
#define pure_initcall(fn) __define_initcall("0",fn,0)
#define core_initcall(fn) __define_initcall("1",fn,1)
#define core_initcall_sync(fn) __define_initcall("1s",fn,1s)
#define postcore_initcall(fn) __define_initcall("2",fn,2)
#define postcore_initcall_sync(fn) __define_initcall("2s",fn,2s)
#define arch_initcall(fn) __define_initcall("3",fn,3)
#define arch_initcall_sync(fn) __define_initcall("3s",fn,3s)
#define subsys_initcall(fn) __define_initcall("4",fn,4)
#define subsys_initcall_sync(fn) __define_initcall("4s",fn,4s)
#define fs_initcall(fn) __define_initcall("5",fn,5)
#define fs_initcall_sync(fn) __define_initcall("5s",fn,5s)
#define rootfs_initcall(fn) __define_initcall("rootfs",fn,rootfs)
#define device_initcall(fn) __define_initcall("6",fn,6)
#define device_initcall_sync(fn) __define_initcall("6s",fn,6s)
#define late_initcall(fn) __define_initcall("7",fn,7)
#define late_initcall_sync(fn) __define_initcall("7s",fn,7s)
上面我们关心的是rootfs_initcall定义,
在init/initramfs.c中具体实现如下:
rootfs_initcall(populate_rootfs);
populate_rootfs()会调用下面这个函数将initrd的内容释放到rootfs文件系统下
unpack_to_rootfs((char *)initrd_start,initrd_end - initrd_start, 0);
这样initrd的ramdisk的内容全部释放到了rootfs文件系统中,所以ramdisk下的所有目录结构将全部被克隆到rootfs文件系统下,具体unpack_to_rootfs函数的实现流程,以后有时间再研究。
上面的是从网上摘下来的内容,在实际应用中这一块的代码不需要任何更改,内核已经支持的比较完善了。
我们需要注意的地方是 initrd_start 和 initrd_size 。 这两个变量是内核根据bootloader 传递过来的参数决定的。 例如在u-boot里的bootargs环境变量:
setenv bootargs console=ttyS1,115200n8 initrd=0x2000000,0x3f2dc2 root=/dev/ram0 rw init=/linuxrc rootfstype=ext2
这里要注意:
1. initrd_size 是指你制作的initrd.img的大小如(0x3f2dc2),而不是内核里定义的
CONFIG_BLK_DEV_RAM_SIZE .
2 initrd_start 指的是你将initrd.img下载到内存的内存起始地址如(0x2000000)。
3. 如果你制作的initrd.img,使用的mkimage命令加了头以后。相应传递给内核的
initrd_start 要相应的加上0x40.initrd_size要相应的减去0x40. 以去掉0x40的文件头。否则挂载不了。
阅读(1820) | 评论(0) | 转发(0) |