為linux建立最小的根檔案系統__linux

來源:互聯網
上載者:User
為linux建立最小的根檔案系統

在編譯核心時候,可以指定一個檔案夾作為核心啟動時候的根檔案系統,linux中管這個檔案系統叫做initramfs。

具體做法如下(以i386為例)

1.下載核心檔案

  wget http://www.kernel.org/pub/linux/kernel/v2.6/linux-2.6.26.tar.bz2

2.解壓核心

   bzip2 -d linux-2.6.26.tar.bz2  產生一個linux-2.6.26.tar檔案,然後

   tar xvf linux-2.6.26.tar 

   解壓後,將有個linux-2.6.26檔案夾存在

3.準備一個iniramfs檔案系統的檔案夾

  在linux-2.6.26檔案夾下建立一個檔案夾 myinitramfs

   寫一個測試用的hello world,起名為hello.c,如下:

  #include <stdio.h>

  #include <unistd.h>

  int main(int argc,char *argv[])

  {

     int i = 0;

     while (1) {

      printf("hello world (%d)\n",i);

     }

    return 0;

   }

  編譯  gcc -static -o init hello.c

  把init拷貝到myinitramfs檔案夾下。

  cp init myinitramfs/

  由於需要顯示文字,還需要在檔案夾下準備console裝置檔案。

  mkdir myinitramfs/dev

  cp -a /dev/console myinitramfs/

4.編譯核心

   在linux-2.6.26檔案下下,執行make help。

   將看到很多協助資訊,其中有一項是 i386_defconfig

   執行 make i386_defconfig,將產生一個.config檔案。

   為了把之前準備好的檔案夾添加到核心設定檔中,還需要重新設定下config檔案

   make config

    在 General Setup --->

    Initial RAM filesystem and RAM disk (initramfs/initrd) support (BLK_DEV_INITRD) [Y/n/?]

     Initramfs source file(s) (INITRAMFS_SOURCE) [myinitramfs]

   處,輸入準備好的檔案夾.

    配置好後,在.config檔案中會有如下一條定義

   CONFIG_INITRAMFS_SOURCE="myinitramfs"

   儲存.config

   make 編譯核心

5.用qemu測試核心和initramfs

   qemu -kernel  linux-2.6.26/arch/i386/boot/bzImage  -initrd linux-2.6.26/usr/initramfs_data.cpio.gz  /dev/zero

   initramfs_data.cpio.gz 這個檔案是核心自動產生的,具體名字可能不同的系統或者核心有差異,但是尾碼應該是.cpio.gz

開工啦。

為了不看起來那麼乏味,我們嘗試通過一個看的著的例子來展示這個過程。

唔,我們還是把“hello world”作為第一個要放到initramfs中去的程式。事實上,rootfs和其它的root filesystem並沒有什麼區別,如果你喜歡,你可以放/etc和/usr和/tmp和。。。然後還可以mount /proc 和/sysfs過去。但是這裡我們只需要放/init過去。程式的最後我們使用sleeping而不是exiting,這主要是考慮如果PID 1的程式退出,kernel會panic,這會干擾我們的視線。

#include int main(int argc, char *argv[]){  printf("Hello world\n");  sleep(999999999);}

然後呢,靜態編譯,然後我們就不用考慮拷貝需要的庫過去了~

gcc -static hello.c -o hello

如果在命令列執行這個小程式,它會列印hello world,讓後停在那裡。你可以用ctrl-x讓它退出。如果是initramfs執行這個程式,我們會看到在boot messages的最後,有個“hello world”被列印。

注意:如果是要放到你的開發板上去執行,記得使用你的交叉編譯工具。打包的過程是和平台無關的,但是二進位檔案需要用目標系統的compiler。

那麼,我們該怎樣把這個程式給kernel用內。好吧,有四種基本方法:第一種是把cpio.gz作為一個獨立的包,然後告訴bootloader它在哪裡;或者你可以用下面三種方法之一,把initramfs直接編譯進kernel裡去。

 

把cipo.gz作為獨立的檔案

很多人喜歡把它編譯進核心裡面去,如果你樂意,你也可以這麼做。但是我們現在要用另一種方式。我們可以使能核心的initrd支援,然後用cpio.gz來代替ramdisk(initrd)。聰明的核心會為我們自動檢測檔案的類型,然後把我們的壓縮包解壓放進rootfs;它不是建立一個ram disk,這不會影響initramfs記憶體效率高這一優勢。

因為external initramfs是在built-in initramfs之後執行的,所以如果兩個檔案內包含有同名的內容,獨立檔案會覆蓋掉built-in填進去去的東西。這意味著,你不用修改kernel,就可以update或者是ucstomize你的rootfs而不用換掉你的核心。

另外一個好訊息是,這樣做你可以不用顧慮license的問題。你可以在rootfs裡面運行non-GPL的程式,或者是給你的驅動提供non-GPL的firmware...額,編譯進核心的話,算是核心的修改吧。製作自己的initramfs,只是算是使用,你不用公布你的原始碼哦親。

那麼,怎麼製作cpio.gz檔案呢。一種方法是你用cpio和gzip命令自己來壓縮。當然,你也可以用kernel build來做這個,如果你覺得不是那麼麻煩的話。原意自己做的,只需要敲下面這些代碼進去...

mkdir subcp hello sub/initcd subfind . | cpio -o -H newc | gzip > ../initramfs_data.cpio.gzcd ..rm -rf sub

按照傳統的使用initrd的方法,把上面產生的initramfs_data.cpio.gz放到該放的地方去(別問我要放哪裡,我也還不知道),它就會在boot結束的地方為你列印一朵漂亮的“hello world”,然後等待一段時間並重啟。

試試吧。

如果它沒有工作,照例的你該查查initial ramdisk支援是不是有被選中,然後看看你的init 程式是不是靜態連結的,再看看它是不是又執行許可權,或者是名字是不是對的。你可以用下面的命令來解壓任何的initramfs檔案到當前檔案夾: zcat initramfs_data.cpio.gz | cpio -i -d -H newc --no-absolute-filenames  

把initramfs編譯到核心裡面去

使用initramfs最簡單的方式,莫過於用已經做好的cpio.gz把kernel裡面那個空的給換掉。這是2.6 kernel天生支援的,所以,你不用做什麼特殊的設定。

kernel的config option裡面有一項CONFIG_INITRAMFS_SOURCE(I.E. General setup--->Initramfs source file(s) in menuconfig)。這個選項指向放著核心打包initramfs需要的所有檔案。預設情況下,這個選項是留空的,所以核心編譯出來之後initramfs也就是空的,也就是前面提到的rootfs什麼都不做的情形。

CONFIG_INITRAMFS_SOURCE 可以是一個絕對路徑,也可以是一個從kernel’s top build dir(你敲入build或者是make的地方)開始的相對路徑。而指向的目標可以有以下三種:一個已經做好的cpio.gz,或者一個已經為製作cpio.gz準備好所有內容的檔案夾,或者是一個text的設定檔。第三種方式是最靈活的,我們先依次來介紹這三種方法。

1)使用一個已經做好的cpio.gz檔案

If you already have your own initramfs_data.cpio.gz file (because you created it yourself, or saved the cpio.gz file produced by a previous kernel build), you can point CONFIG_INITRAMFS_SOURCE at it and the kernel build will autodetect the file type and link it into the resulting kernel image.

You can also leave CONFIG_INITRAMFS_SOURCE empty, and instead copy your cpio.gz file to usr/initramfs_data.cpio.gz in your kernel's build directory. The kernel's makefile won't generate a new archive if it doesn't need to.

Either way, if you build a kernel like this you can boot it without supplying an external initrd image, and it'll still finish its boot by running your init program out of rootfs. This is packaging method #2, if you'd like to try it now.

2)指定給核心一個檔案或者檔案夾

If CONFIG_INITRAMFS_SOURCE points to a directory, the kernel will archive it up for you. This is a very easy way to create an initramfs archive, and is method #3.

Interestingly, the kernel build doesn't use the standard cpio command to create initramfs archives. You don't even need to have any cpio tools installed on your build system. Instead the kernel build (in usr/Makefile) generates a text file describing the directory with the script "gen_initramfs_list.sh", and then feeds that descript to a program called "gen_init_cpio" (built from C source in the kernel's usr directory), which create the cpio archive. This looks something like the following:

scripts/gen_initramfs_list.sh $CONFIG_INITRAMFS_SOURCE > usr/initramfs_listusr/gen_init_cpio usr/initramfs_list > usr/initramfs_data.cpiogzip usr/initramfs_data.cpio

To package up our hello world program, you could simply copy it into its own directory, name it "init", point CONFIG_INITRAMFS_SOURCE at that directory, and rebuild the kernel. The resulting kernel should end its boot by printing "hello world". And if you need to tweak the contents of that directory, rebuilding the kernel will re-package the contents of that directory if anything has changed.

The downside of this method is that it if your initramfs has device nodes, or cares about file ownership and permissions, you need to be able to create those things in a directory for it to copy. This is hard to do if you haven't got root access, or are using a cross-compile environment like cygwin. That's where the fourth and final method comes in.

3)使用configuration檔案initramfs_list來告訴核心initramfs在哪裡

This is the most flexible method. The kernel's gen_initramfs_list.sh script creates a text description file listing the contents of initramfs, and gen_init_cpio uses this file to produce an archive. This file is a standard text file, easily editable, containing one line per file. Each line starts with a keyword indicating what type of entry it describes.

The config file to create our "hello world" initramfs only needs a single line:

file /init usr/hello 500 0 0

This takes the file "hello" and packages it so it shows up as /init in rootfs, with permissions 500, with uid and gid 0. It expects to find the source file "hello" in a "usr" subdirectory under the kernel's build directory. (If you're building the kernel in a different directory than the source directory, this path would be relative to the build directory, not the source directory.)

To try it yourself, copy "hello" into usr in the kernel's build directory, copy the above configuration line to its own file, use "make menuconfig" to point CONFIG_INITRAMFS_SOURCE to that file, run the kernel build, and test boot the new kernel. Alternately, you can put the "hello" file in its own directory and use "scripts/gen_initramfs_list.sh dirname" to create a configuration file (where dirname is the path to your directory, from the kernel's build directory). For large projects, you may want to generate a starting configuration with the script, and then customize it with any text editor.

This configuration file can also specify device nodes (with the "nod" keyword), directories ("dir"), symbolic links ("slink"), named FIFO pipes ("pipe"), and unix domain sockets ("sock"). Full documentation on this file's format is available by running "usr/gen_init_cpio" (with no arguments) after a kernel build.

A more complicated example containing device nodes and symlinks could look like this:

  dir /dev 755 0 0  nod /dev/console 644 0 0 c 5 1  nod /dev/loop0 644 0 0 b 7 0  dir /bin 755 1000 1000  slink /bin/sh busybox 777 0 0  file /bin/busybox initramfs/busybox 755 0 0  dir /proc 755 0 0  dir /sys 755 0 0  dir /mnt 755 0 0  file /init initramfs/init.sh 755 0 0

One significant advantage of the configuration file method is that any regular user can create one, specifying ownership and permissions and the creation of device nodes in initramfs, without any special permissions on the build system. Creating a cpio archive using the cpio command line tool, or pointing the kernel build at a directory, requires a directory that contains everything initramfs will contain. The configuration file method merely requires a few source files to get data from, and a description file.

This also comes in handy cross-compiling from other environments such as cygwin, where the local filesystem may not even be capable of reproducing everything initramfs should have in it.

 

總結一下

這四種給rootfs提供內容的方式都有一個共同點:在kernel啟動時,一系列的檔案被解壓到rootfs,如果kernel能在其中找到可執行檔檔案“/init”,kernel就會運行它;這意味著,kernel不會再去理會“root=”是指向哪裡的。

此外,一旦initramfs裡面的init 進程運行起來,kernel就會認為啟動已經完成。接下來,init將掌控整個宇宙。它擁有霹靂無敵的專門為它預留的Process ID #1,整個系統接下來的所有都將由它來創造。還有,它的地位將是不可剝奪的,嗯哼,PID 1 退出的話,系統會panic的。

接下來我會介紹其他一些,在rootfs中,init程式可以做的事。


UBOOT已經燒錄成功,LINUX核心也燒錄了,根檔案系統也可以這麼打包燒錄進去。但如果每改一下核心或程式檔案都要這麼打包燒錄是比較麻煩的,接下來就是如何利用TFTP和NFS讓UBOOT自動從ubuntu的檔案系統中載入核心和掛載根檔案系統。

 

首先安裝tftp:
TFTP和NFS是為了方便調試,開發板接上網線可以連到PC的TFTP,下載編譯好的Linux核心uImage,掛接PC機上的NFS網路檔案系統作為根檔案系統,這樣你編譯好的程式可以程式檔案可以直接發布到NFS檔案夾中,然後直接就可以在開發板載入運行了。

 

 (xinetd是網路服務主程式,一般是要與TFTP一起安裝)
root@ubuntu:/# apt-get install xinetd tftpd tftp
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following packages were automatically installed and are no longer required:
  ssl-cert
Use 'apt-get autoremove' to remove them.
The following NEW packages will be installed:
  tftp tftpd xinetd
0 upgraded, 3 newly installed, 0 to remove and 61 not upgraded.
Need to get 0B/185kB of archives.
After this operation, 578kB of additional disk space will be used.
Selecting previously deselected package tftp.
(Reading database ... 40278 files and directories currently installed.)
Unpacking tftp (from .../tftp_0.17-17ubuntu1_i386.deb) ...
Selecting previously deselected package xinetd.
Unpacking xinetd (from .../xinetd_1%3a2.3.14-7ubuntu2_i386.deb) ...
Selecting previously deselected package tftpd.
Unpacking tftpd (from .../tftpd_0.17-17ubuntu1_i386.deb) ...
Processing triggers for man-db ...
Setting up tftp (0.17-17ubuntu1) ...
Setting up xinetd (1:2.3.14-7ubuntu2) ...
 * Stopping internet superserver xinetd                                  [ OK ]
 * Starting internet superserver xinetd                                  [ OK ]

Setting up tftpd (0.17-17ubuntu1) ...
--------- IMPORTANT INFORMATION FOR XINETD USERS ----------
The following line will be added to your /etc/inetd.conf file:

tftp            dgram   udp     wait    nobody  /usr/sbin/tcpd  /usr/sbin/in.tftpd /srv/tftp

If you are indeed using xinetd, you will have to convert the
above into /etc/xinetd.conf format, and add it manually. See
/usr/share/doc/xinetd/README.Debian for more information.
Suggested entry (automatically converted using itox):

service tftp
{
        socket_type     = dgram
        protocol        = udp
        wait            = yes
        user            = nobody
You must use option -daemon_dir if you use tcpd
-----------------------------------------------------------

建立目錄:
root@ubuntu:/# mkdir tftpboot
root@ubuntu:~# chmod o+w /tftpboot
root@ubuntu:~# chown -R nobody /tftpboot

編輯TFTP設定檔:
root@ubuntu:/# vi /etc/xinetd.d/tftp
按i進入編輯模式,輸入以下內容:
service tftp
{
       socket_type     = dgram
       protocol        = udp   
       wait            = yes
       user            = root
       server          = /usr/sbin/in.tftpd
       server_args     = -s /tftpboot
       disable         = no
       per_source      = 11
       cps             = 100 2
       flags           = IPv4
}
按ESC,輸入:wq指令儲存退出。

重新啟動xinetd:
root@ubuntu:/# /etc/init.d/xinetd reload
 * Reloading internet superserver configuration xinetd                   [ OK ]
root@ubuntu:/# /etc/init.d/xinetd restart
 * Stopping internet superserver xinetd                                  [ OK ]
 * Starting internet superserver xinetd                                  [ OK ]

尋找並測試一下tftp:
root@ubuntu:/

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.