Chinaunix首页 | 论坛 | 博客
  • 博客访问: 466314
  • 博文数量: 263
  • 博客积分: 9025
  • 博客等级: 中将
  • 技术积分: 2557
  • 用 户 组: 普通用户
  • 注册时间: 2007-11-01 17:42
文章分类

全部博文(263)

文章存档

2012年(4)

2011年(64)

2010年(47)

2009年(44)

2008年(99)

2007年(5)

我的朋友

分类:

2008-04-23 17:33:23

QQ2440
kernel2.6.13

VIVI传递给Kernel的命令行
noinitrd root=/dev/mtdblock2 init=/linuxrc console=ttySAC0

kernel启动
...
yaffs: dev is 32505858 name is "mtdblock2"
yaffs: Attempting MTD mount on 31.2, "mtdblock2"
VFS: Mounted root (yaffs filesystem).
...
表明rootfs是yaffs,启动命令行上又没有指定rootfstype=yaffs
一直有kernel如何以yaffs来mount的/dev/mtdblock2的问题。
今天认真看了kernel源码,并打印出rootfs搜索过程,总算是清楚了一些。

init/main.c:start_kernel
...
    printk(KERN_NOTICE "Kernel command line: %s\n", saved_command_line);
    parse_early_param();
    parse_args("Booting kernel", command_line, __start___param,
           __stop___param - __start___param,
           &unknown_bootoption);
...

parse_early_param()主要是解析cmdline并搜索vmlinux.lds.S的early_param段,调用对应函数
        __early_begin = .;
            *(__early_param)
        __early_end = .;


init/do_mounts.c
__setup("root=", root_dev_setup);

”root=“不在early_param段中。
故会调用unknown_bootoption

unknow_bootoption()会调用
static int __init obsolete_checksetup(char *line)
{
    struct obs_kernel_param *p;

    p = __setup_start;
    do {
        int n = strlen(p->str);
        if (!strncmp(line, p->str, n)) {
            if (p->early) {
                /* Already done in parse_early_param?  (Needs
                 * exact match on param part) */
                if (line[n] == '\0' || line[n] == '=')
                    return 1;
            } else if (!p->setup_func) {
                printk(KERN_WARNING "Parameter %s is obsolete,"
                       " ignored\n", p->str);
                return 1;
            } else if (p->setup_func(line + n))
                return 1;
        }
        p++;
    } while (p < __setup_end);
    return 0;
}

很简单,对启动命令行进行解析,调用对应函数。

所以就会调用root_dev_setup(char *line)
static int __init root_dev_setup(char *line)
{
    strlcpy(saved_root_name, line, sizeof(saved_root_name));
    return 1;
}

这就是把/dev/mtdblock2保持到saved_root_name中。

回到start_kernel(void),在start_kernel最后会调用rest_init(void)

rest_init(void)会create一个kernel thread,在thread中做初始化
...
    kernel_thread(init, NULL, CLONE_FS | CLONE_SIGHAND);
    numa_default_policy();
...

init(void * unused)中调用prepare_namespace()
...
    /*
     * check if there is an early userspace init.  If yes, let it do all
     * the work
     */
    if (sys_access((const char __user *) "/init", 0) == 0)
        execute_command = "/init";
    else
        prepare_namespace();
...

prepare_namespace()中用到前面提到的saved_root_name,找到对应的ROOT_DEV,调用mount_root()
void __init prepare_namespace(void)
{
    int is_floppy;

    mount_devfs();

    if (root_delay) {
        printk(KERN_INFO "Waiting %dsec before mounting root device...\n",
               root_delay);
        ssleep(root_delay);
    }

    md_run_setup();

    if (saved_root_name[0]) {
        root_device_name = saved_root_name;
        ROOT_DEV = name_to_dev_t(root_device_name);
        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 ();
}

mount_root没什么东西,主要是调用void __init mount_block_root(char *name, int flags)

mount_block_root()先获取系统文件类型,放在fs_names中,在for循环中根据不同文件类型do_mount_root(),直到找到对应的rootfs。
void __init mount_block_root(char *name, int flags)
{
    char *fs_names = __getname();
    char *p;
    char b[BDEVNAME_SIZE];

    get_fs_names(fs_names);
retry:
    for (p = fs_names; *p; p += strlen(p)+1) {
        int err = do_mount_root(name, p, flags, root_mount_data);
        switch (err) {
            case 0:
                goto out;
            case -EACCES:
                flags |= MS_RDONLY;
                goto retry;
            case -EINVAL:
                continue;
        }
            /*
         * Allow the user to distinguish between failed sys_open
         * and bad superblock on root device.
         */
        __bdevname(ROOT_DEV, b);
        printk("VFS: Cannot open root device \"%s\" or %s\n",
                root_device_name, b);
        printk("Please append a correct \"root=\" boot option\n");

        panic("VFS: Unable to mount root fs on %s", b);
    }
    panic("VFS: Unable to mount root fs on %s", __bdevname(ROOT_DEV, b));
out:
    putname(fs_names);
}

在for循环中do_mount_root前加了printk,输出如下信息:
Kernel : try fs ext2
Kernel : try fs msdos
Kernel : try fs vfat
Kernel : try fs yaffs


VIVI中linux cmd line加上rootfstype=yaffs后,输出如下信息:
MMC: sd_app_op_cond locked busy. Probably have broken SD-Card.
Kernel : try fs yaffs
yaffs: dev is 32505858 name is "mtdblock2"
yaffs: Attempting MTD mount on 31.2, "mtdblock2"


阅读(410) | 评论(0) | 转发(0) |
0

上一篇:Nand FLASH

下一篇:人生

给主人留下些什么吧!~~