構建根文件系統(一)

接着前邊內核移植的文章,記錄根文件系統的構建。


這裏要用到強大的busybox,我選擇的版本是busybox-1.18.5.tar.bz2 ,1.17的也可以;之所以選擇這個版本是因爲基於現在的交叉編譯環境,可以正常靜態編譯busybox的版本貌似就是1.17之後的了(之前測試的是這樣),當然用動態的也可以。


這裏我講述兩種構建(靜態和動態)形式都記錄一下。正好這兩種構建模式分別與TQ2440開發板手冊和嵌入式Linux開發完全手冊是對應的,所以整個流程都是參照這兩份材料進行的。


根文件系統的構建到底是做什麼的呢?說白了就是製作好一個文件目錄,按照OS正常啓動的必要需求,在對應的位置放上對應的需要的文件和應用程序(比如經常用到的一些命令[不過命令並不是製作文件系統所必須的,只是爲了後邊維護時用着方便,這也是busybox的實際存在意義,它集成了很多可用於嵌入式的管理命令和系統命令,還有系統啓動所必須的一些東西,如init])。另一方面也說明了根文件系統的某些特性,它對應着內核的接口,按照一定的規範,實現了用戶和內核的交互(shell,和目錄樹),這也是爲什麼有句話說“掛載根文件系統”。其實文件系統也並不是所有工程所必須的。一切都由需求而定。


首先進行的是動態編譯的簡單構建,比較簡單。並沒有配置很多很多用戶和一些預期要用到的文件,只是實現了可以掛載以及busybox集成的命令工具,可以用於arm Linux的驅動開發和測試。


1、 編譯busybox 

這裏,在busybox解壓後的目錄裏,運行make menuconfig 會看到和kernel一樣的配置菜單,可以對其進行配置,大多配置項都是對一些命令支持的選擇。有一點用到了必須說一下,就是是否靜態編譯的選項:

Busybox Settings  --->

Build Options  --->

[ ] Build BusyBox as a static binary (no shared libs)

這裏我們先用動態編譯。動態編譯的話,在配置好文件系統後,要把編譯時動態連接到的庫手動的拷貝到對應的目錄中。


這裏就用默認的了(其實默認的配置基本上是所有功能都選上了,圖個懶麼,萬一將來用到選項沒有配上,還得回來重新配上,重新編譯,重新制作鏡像,重新燒寫。。。)

編譯時改Makefile

ARCH ?=arm #1.18版的busybox190(我也糾結着倆哥們怎麼分開了)

CROSS_COMPILE ?=arm-linux- #1.18版本的在164


然後我們在工程目錄中建一個目錄fs1,來存放我們的這個文件系統,即/home/jun/arm/fs1.

弄好以後,執行命令:(ps:busybox目錄下)

$ make CONFIG_PREFIX=/home/jun/arm/fs1 install


待到編譯完成以後,會在fs1目錄下生產bin  linuxrc  sbin  usr,證明我們已經有了強大功能的命令和工具集,接下來就可以構建我們的根文件系統了。


因爲編譯是動態鏈接的,所以我們要把動態鏈接庫準備好,我們是用的arm-linux-gcc編譯的,當然用的就是glibc的庫嘍,去交叉編譯器的目錄下找一下。


busybox目錄下執行:

$ arm-linux-readelf -a ./busybox|grep "Shared"


會列出sharedlib,我的列出來的是:

0x00000001 (NEEDED)                     Shared library: [libm.so.6]

 0x00000001 (NEEDED)                     Shared library: [libc.so.6]


然後我們就把這兩個依賴到的鏈接庫拷貝到fs1/lib(沒有這個目錄就創建一個,我們本來就是在構建根文件系統),另外動態鏈接還要用到加載器,這裏只會看到依賴的庫,要手動的複製加載器過來,就是 ld-linux.so.3


我的所以庫都在交叉編譯工具目錄下的 /home/jun/arm/4.3.3/arm-none-linux-gnueabi/libc/lib 下邊,你ls –l 一下發現有玄機,就是我們需要用到的幾個文件libm.so.6、 libm.so.6、ld-linux.so.3都是鏈接文件,實際指向的是:

lrwxrwxrwx   1 jun jun      11 2011-09-20 17:32 libc.so.6 -> libc-2.8.so

lrwxrwxrwx   1 jun jun      11 2011-09-20 17:31 libm.so.6 -> libm-2.8.so

lrwxrwxrwx   1 jun jun       9 2011-09-20 17:31 ld-linux.so.3 -> ld-2.8.so

所以我們不但要把鏈接文件cpfs1/lib中,還要把連接到的文件cp過去:

$ cp libc.so.6 libm.so.6 ld-linux.so.3 libc-2.8.so libm-2.8.so ld-2.8.so /home/jun/arm/fs1/lib


2、 構建根文件系統。


主要構件的目錄爲/etc/dev 。其他的目錄一條命令就OK了。

這裏的/dev要用busybox提供的mdev來實現。

mdev busybox 自帶的一個簡化版的udev, 適合於嵌入式的應用埸合。 其具有使用簡 單的特點。它的作用,就是在系統啓動和熱插拔或動態加載驅動程序時,自動產生驅動程序 所需的節點文件。 在以busybox爲基礎構建嵌入式linux 的根文件系統時,使用它是最優的選擇。默認的配置單中已經加入了mdev的支持。優秀的mdev不但可以動態更新dev目錄,還支持熱插拔。

不但busybox要添加對mdev的支持,內核也要添加,因爲這個必須有內核的底層支持纔可以動態識別設備變更、動態創建設備文件。主要是通過添加內核對sysfstmpfs文件系統的支持,因爲udev其實是通過讀取sysfs信息來動態構建的設備文件:所以在內核中設置CONFIG_SYSFSCONFIG_TMPFS配置項:


找不到可以在配置項裏搜索一下:

| Symbol: SYSFS [=y]                                                                |

  | Prompt: sysfs file system support                                                 |

  |   Defined at fs/sysfs/Kconfig:1                                                   |

  |   Depends on: EMBEDDED                                                            |

  |   Location:                                                                       |

  |     -> File systems                                                               |

  |       -> Pseudo filesystems                                                       |

  |   Selected by: GFS2_FS && BLOCK && EXPERIMENTAL && (64BIT || LBD) && GFS2_FS_LOCK |

  |                                                                                   |

  +--------------------------------- Search Results ----------------------------------+

  | Symbol: TMPFS [=y]                                                                |

  | Prompt: Virtual memory file system support (former shm fs)                        |

  |   Defined at fs/Kconfig:99                                                        |

  |   Location:                                                                       |

  |     -> File systems                                                               |

  |       -> Pseudo filesystems                                                       |

  |                                                                                   |

  |                                                                                   |

  | Symbol: TMPFS_POSIX_ACL [=y]                                                      |

  | Prompt: Tmpfs POSIX Access Control Lists                                          |

  |   Defined at fs/Kconfig:111                                                       |

  |   Depends on: TMPFS                                                               |

  |   Location:                                                                       |

  |     -> File systems                                                               |

  |       -> Pseudo filesystems                                                       |

  |         -> Virtual memory file system support (former shm fs) (TMPFS [=y])        |

  |   Selects: GENERIC_ACL                                                            |

  +---------------------------------------------------------------------------(100%)--+


搜索結果可以看出,兩個都主要依賴於下邊選項,都選上,重新編譯我們的內核鏡像就好了。

-> File systems 

  -> Pseudo filesystems

其實上述選項也是默認的都選好的。

好的,開始嘍……


a.構建/etc    /*這裏的/—根目錄指的是fs1,這就是我們構建的根目錄,製作鏡像時就是把fs1的整個目錄及子目錄打包成鏡像的*/

$ mkdir etc

$ touch etc/inittab

$ chmod 777 inittab

$ vi etc/inittab       #vi編輯器打開並加入如下內容

#/etc/inittab

::sysinit:/etc/init.d/rcS

s3c2410_serial0::askfirst:-/bin/sh

::ctrlaltdel:/sbin/reboot

::shutdown:/bin/umount -a -r

$ cd etc

$ mkdir init.d

$ touch init.d/rcS

$ chmod 777 rcS

$ vi init.d/rcS      #vi編輯器打開並加入如下內容

#!/bin/sh

ifconfig eth0 192.168.1.111

mount -a

mkdir /dev/pts

mount -t devpts devpts /dev/pts

echo /sbin/mdev > /proc/sys/kernel/hotplug

mdev –s

$ touch fstab

$ vi fstab #vi編輯器打開並加入如下內容

proc    /proc   proc    defaults        0       0

tmpfs   /tmp    tmpfs   defaults        0       0

sysfs   /sys    sysfs   defaults        0       0

tmpfs   /dev    tmpfs   devaults        0       0


OK,基本上差不多了,接下來是創建幾個必要的設備文件,和其他目錄:


因爲mdev是一個程序,程序的運行就要創建進程,而linux的第一個進程是init進程,init進程至少要用到設備文件:/dev/console /dev/null 。所以先創建這兩個設備文件:

$ cd /home/jun/arm/fs1/ #確保當前是在fs1目錄下

$ mkdir dev

$ cd dev

$ sudo mknod console c 5 1

$ sudo mknod null c 1 3


然後是創建其他必要的目錄:

$ mkdir proc mnt tmp sys root

Ok,構建完成。可以用來製作鏡像。

$ mkyaffs2image fs1 fs1.bin #/home/jun/arm/


燒入板子測試一下先。。。。。。。。。。。。


額,報錯如下:

……

yaffs_read_super: isCheckpointed 0

VFS: Mounted root (yaffs filesystem) on device 31:2.

Freeing init memory: 120K

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

……

解決方法: /*估計是創建的設備節點的權限問題,所以刪掉重新創建*/

$ cd /home/jun/arm/fs1/dev

$ rm –f  *

$ sudo mknod -m 660 null c 1 3

$ sudo mknod -m 660 console c 5 1

然後重新制作文件系統鏡像,並燒寫測試。。。。。。。。。。。。。。。。。。

不行,由此看來不單單是權限的而問題了,我查看了一下Uboot(這裏是TQ自帶的Uboot)的啓動命令參數:

bootargs=noinitrd root=/dev/mtdblock2 init=/linuxrc console=ttySAC0


因爲我們用的是mdev自動生成的設備文件,所以他默認的是s3c240_serial0s3c240_serial1s3c240_serial2……我們把啓動參數改一下試試:

輸入q可以進入uboot的命令模式。然後輸入help或者?可以列出所以的可用命令。


原來的啓動參數是:bootargs=noinitrd root=/dev/mtdblock2 init=/linuxrc console=ttySAC0;我們重新設置爲:bootargs=noinitrd root=/dev/mtdblock2 init=/linuxrc console=s3c2410_serial0 

設置命令是:

> setenv bootargs 'noinitrd root=/dev/mtdblock2 init=/linuxrc console=s3c2410_serial0' 

> saveenv

然後啓動內核就沒有輸出了:

Start Linux ...

Copy linux kernel from 0x00200000 to 0x30008000, size = 0x00200000 ... Copy Kernel to SDRAM done,NOW, Booting Linux......

Uncompressing Linux.......................................................................................................................... done, booting the kernel.

然後就沒有下文了,顯然是沒有輸出了。看來還是console得問題。我們爲了還原回去,證明是改爲console=s3c2410_serial0造成的,我們重新設置回去:

> setenv bootargs 'noinitrd root=/dev/mtdblock2 init=/linuxrc console=ttySAC0' 

> saveenv

看來還是理解不到位造成的。因爲這一換原來的輸出也沒有了,這證明不是串口加載對接的問題,比較沒有對接好的話是沒有輸出的。回覆後報錯依舊是:

yaffs_read_super: isCheckpointed 0

VFS: Mounted root (yaffs filesystem) on device 31:2.

Freeing init memory: 120K

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.

[<c002c700>] (unwind_backtrace+0x0/0xdc) from [<c02b69d0>] (panic+0x40/0x110)

[<c02b69d0>] (panic+0x40/0x110) from [<c00264c0>] (init_post+0xcc/0xf4)

[<c00264c0>] (init_post+0xcc/0xf4) from [<c000859c>] (kernel_init+0xb8/0xe0)

[<c000859c>] (kernel_init+0xb8/0xe0) from [<c004812c>] (do_exit+0x0/0x578)

[<c004812c>] (do_exit+0x0/0x578) from [<00000001>] (0x1)


+++++++++++++++++++++++++++美麗的分割線++++++++++++++++++++++++++++


中間因爲換電腦,臺式機換筆記本,再回來做開發確實挺糾結的,另外還是win7的系統,驅動問題很糾結。有同樣問題的朋友可以看我的另一篇文章,《 》,有介紹相關問題的解決辦法。

Well ,大多數網上給的上邊問題的解決辦法都是說你沒有創建consolenull設備文件,顯然不是這樣,那是爲什麼呢?我也查了一番資料,確實良久無果,最後,就是今天一不小心調好了。因爲之前不知道編好的程序沒法燒到板子裏,所以改好東西后隔了一天才驗證了其正確性,努力的回想我的改動,應該還是源於這篇文章的:WARNING: Unable to open an initial console ,我主要只改了一下內核配置:

內核選擇如下選項:

Device Drivers  --->

Character devices  --->

     [*] Virtual terminal

 Serial drivers  --->

          <*> 8250/16550 and compatible serial support 

    [*]   Console on 8250/16550 and compatible serial port

  (2) Maximum number of 8250/16550 serial ports 

  (2) Number of 8250/16550 serial ports to register at runtime  

     [*] Unix98 PTY support


原來默認的應該是84(上邊的Maximum number...和 Number of...);改過後重新編譯內核;又到之前構建的根文件系統下的/dev下,把原來的consolenull刪除了,重新構建一下。就好了:




(雖然掛載成功,但還是有兩個小問題的,ifconfigtmpfs有問題。)




        /dev下有大量的設備文件:一方面說明我們的mdev工作正常;另一方面也說明我們的內核只是簡單的移植,沒有進一步做優化和裁剪,才使得有這麼多實際無用的設備文件。

       

        OK,根文件系統移植的第一階段就在此畫上完美的句號吧。現在可以用於驅動開發了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章