linux2.6.32系统移植过程总结

 经历了好长时间的折磨,终于搞定了一个移植的最简单的linux+根文件系统,过程很曲折,很痛苦,不过还是很有收获的…^_^

制作的整个过程中最折磨人的还是根文件系统的制作,在最终发现问题竟然在内核上,太弱了,最开始没发现问题在哪里。具体的移植过程,需要修改哪些参数,网上都有教程,很详细,本文中就不再赘述了。本文主要讨论一下在移植中遇到的问题。
环境:
Ubuntu 12.04
arm-linux-gcc4.4.3
busybox1.13
linux2.6.32
FL2440 512M SDRAM 、256M nand flash
整个过程是参照mini 2440的移植手册来做的(虽然我用的是飞凌的板子,但是不得不吐槽,飞凌的板子在文档方面做的太差了,根本就没有提供移植文档),arm-linux-gcc、busybox、yaffs2是用的mini2440的,linux2.6.32.2是自己配置的,至于具体内核中需要修改那些参数请参照《Mini2440_Linux移植开发实战指南.pdf》
在移植过程中串口打印的调试信息,也是我在调试中遇到的最大的问题。

VFS: Mounted root (yaffs filesystem) on device 31:3.// 这个并不说明yaffs文件系统就已经正确挂载了,
Freeing init memory: 124K
Warning: unable to open an initial console.         //bootloader 向内核中传参数的问题

Failed to execute /linuxrc.  Attempting defaults...
Kernel panic - not syncing: No init found.  Try passing init= option to kernel.
[<c002da24>] (unwind_backtrace+0x0/0xd8) from [<c02c0bd4>] (panic+0x40/0x110)
[<c02c0bd4>] (panic+0x40/0x110) from [<c00275b0>] (init_post+0xe8/0x118)
[<c00275b0>] (init_post+0xe8/0x118) from [<c00085b8>] (kernel_init+0xdc/0x10c)
[<c00085b8>] (kernel_init+0xdc/0x10c) from [<c0028e68>] (kernel_thread_exit+0x0/0x8)

(一)
在这个调试信息中,最重要的是Warning: unable to open an initial console,必须先解决这个问题才能继续解决一下的问题.调试信息从/init/main.c的init_post函数打印出调试信息。其流程主要是
1、该函数首先从文件系统中找到console文件,初始化控制台,
2、找到根文件系统的中linuxrc文件初始化文件,并执行。在嵌入式系统中,linuxrc是由busybox生成的。其指向bin/busybox文件,该文件执行一些初始化程序,调用etc/inittab文件来执行一些init初始化程序。若找到,则不返回init_post函数;若没找到,则继续找其它的初始化文件:/sbin/init、/etc/init、/bin/init、/bin/sh。

static int noinline init_post(void)
{
    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);
    current->signal->flags |= SIGNAL_UNKILLABLE;

    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);
    }
    run_init_process("/sbin/init");
    run_init_process("/etc/init");
    run_init_process("/bin/ini`这里写代码片`t");
    run_init_process("/bin/sh");

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

当打印出这个调试信息,说明内核没有找到根文件系统中的console设备文件,有三种可能导致这种情况的原因:
1.根文件系统制作正确,但是没有创建dev目录下的console设备文件。
虽然在使用过程中通过udev来管理设备,但是在系统启动的过程中就需要读取这个文件,还是先需要静态的创建这个ocnsole文件。因为udev是用户层设备管理程序,需要系统启动后才能执行,如果系统没有正确启动,是无法创建该设备文件。
2.根文件系统制作正确,但是内核没有找到文件系统的位置。
整个板子的启动顺序是:uboot/bootloader–>linux 内核–>文件系统,在遇到问题时,可以根据这条线来查找问题。根文件系统的位置是由bootloader/uboot决定的,要更改只能修改bootloader/uboot 。而内核是怎么知道文件系统的位置的呢?内核是通过uboot/bootloader的传递的参数来查找内核中的分区表找到文件系统的。如果参数和文件系统的所在的分区不一致,那么内核就找不到文件系统,更无法启动。我当时移植的时候,就是卡在了这个问题上,好长时间都没有解决,一直以为是文件系统的ecc校验的问题,直到最近才排除了所有可能将错误定在了bootloader传参的问题上。
3.文件系统制作的不正确,主要是ECC的设置的问题。
内核、yaffs2、硬件ECC,一般情况下,只有yaffs2的ecc校验,其余的不选。具体什么原因,自己查帖子,反正我是没搞懂。

Please select which region to write : Esc to abort
0 : offset 0x00000000, size 0x00020000 [boot]
1 : offset 0x00020000, size 0x00060000 [bootParam]
2 : offset 0x00080000, size 0x00100000 [pic]
3 : offset 0x00180000, size 0x00380000 [MyApp]
4 : offset 0x00500000, size 0x00300000 [kernel]
5 : offset 0x00800000, size 0x03c00000 [fs_yaffs]
6 : offset 0x04400000, size 0x00080000 [eboot]
7 : offset 0x04480000, size 0x03b80000 [wince]

Set boot params = root=/dev/mtdblock3 init=/linuxrc load_ramdisk=0 console=ttySAC0,115200 mem=65536K devfs=mount display=lcd480
Load Kernel...

上面是FL2440的启动信息,其中0~7是bootloader设置的启动分区(这个Bootloader是飞凌自己做的,其他的公司好像用的都是uboot ,二者是有区别的 ╮(╯▽╰)╭),我当时看到这个信息,就傻乎乎的将内核中分区信息设置为上面的分区形式,结果就悲剧了。因为bootloader传给内核的参数是/dev/mtdblock3 ,那么内核就在MyApp这个分区找文件系统,那肯定是找不到的啊。。
只有将内核中的分区改为下面的形式,就可以找到文件系统了。真想喊一句:TMD,坑爹啊,飞凌╮(╯▽╰)╭。

       [0] = {
                .name        = "boot",
                .size        = 0x00020000,
                .offset = 0
        },
        [1] = {
                .name        = "bootParam",
                .size        = 0x00060000,
                .offset = 0x00020000,
        },
        [2] = {
                .name        = "Kernel",
                .size        = 0x00300000,
                .offset = 0x00500000,
        },
        [3] = {
                .name        = "fs_yaffs",
                .size        = 0x03c00000, 
                .offset = 0x00800000,
        },        
        [4] = {
                .name        = "eboot",
                .size        = 0x00080000,
                .offset = 0x04400000,
        },
         [5] = {
                .name        = "WINCE",
                .size        = 0x03b80000,
                .offset = 0x04480000,
        }
总结一句话,就是内核中定义的文件系统的分区一定要在bootloader/uboot指定的文件系统的分区上,其他的分区可适当保留。

(二)
基本上解决了Warning: unable to open an initial console这个问题,其余的问题都只剩下动态编译的问题。串口信息中的

Failed to execute /linuxrc.  Attempting defaults...
Kernel panic - not syncing: No init found.  Try passing init= option to kernel.

这个两个问题就是动态链接库的问题。
Busybox中有两种编译方式:静态编译和动态编译。制作嵌入式根文件系统时可以先从静态编译入手,待成功后再采用动态编译。
在动态编译的问题主要是链接库的问题,就是需要哪些库,将相应的库文件拷贝到你制作的根文件系统中即可。在编译好的Busybox下有Busybox文件,用arm-linux-readelf -a busybox|grep “Shared”命令即可查看文件需要哪些库,然后从交叉编译器中拷贝该库即可,该命令显示的往往是链接文件,需要找到该链接库的实际的库文件也拷贝到根文件系统的lib文件夹下才可以。这个很重要!!!!
这里写图片描述
不然只拷贝链接文件,linuxrc还是不能链接到正确的文件,还是不能执行的。可以先将整个交叉编译器的lib文件拷贝到根文件系统中,在批量的删除,不然制作的文件系统会很大,我的大概有40M多。然后将所有与arm-linux-readelf -a busybox|grep “Shared”
下面是lib文件截图

这里写图片描述
(三)
咱整理库的过程中还遇到一个问题:invalid ELF header linux。这个是我删除了sys-root文件夹后产生的问题。其实问题还是库文件不全。
注:我的这个文件系统不是最简的文件系统,大概有18M多,诸君若有兴趣可以继续精简哈。

参考网址:
http://bbs.witech.com.cn/thread-468-1-1.html
http://blog.csdn.net/ssdsafsdsd/article/details/8768209
http://www.ibm.com/developerworks/cn/linux/l-linuxboot/

猜你喜欢

转载自blog.csdn.net/wwxxff28/article/details/45315391
今日推荐