1. 程式人生 > >linux2.6.32系統移植過程總結

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/