Tuesday, September 09, 2008

Build Ramdisk for ARM


目標

  • 建置一個基本的 Ramdisk for arm,以便了解整個 file system 的開機流程。
  • ramdisk 主要程式由 busybox 提供,並包含基本的設定檔。
  • 建置平台為 Qemu: ARM Integrator/CP board 的模擬平台上。

Preview

  • 參考之前 Linux 2.6 的 initramfs 機制,了解 initramfs 的觀念。
  • Linux 2.6 核心將一個小的 ram-based initial root filesystem(initramfs) 包進核心,且若這個檔案系統包含一隻程式 /init,核心會將它當作第一隻程式執行。此時,找尋其他檔案系統並執行其他程式已不再是核心的問題,而是新程式的工作。

開機及初步 ramdisk

  • 由於Linux 2.6 核心已將一個小的 ram-based initial root filesystem(initramfs) 包進核心,所以我們可以先建立一個假的 ramdisk,只包含 init 來測試是否 kernel boot 成功與否。Ref: Jserv's blog: 深入理解 Linux 2.6 的 initramfs 機制 (上)
    mkdir hello-initramfs
    cd hello-initramfs
    vi init.c
    arm-none-linux-gnueabi-gcc -static -o init init.c # 編成 static 省麻煩
    file init # 確認編譯完成的檔案格式是否正確
    #init: ELF 32-bit LSB executable, ARM, version 1 (SYSV), for GNU/Linux 2.6.14, statically linked, not stripped
    mkdir dev
    cd dev
    mknod -m 600 console c 5 1
    cd ..

    • init.c, 將開機停在執行 /init 時,以驗証我們的動作是否成功
      #include 
      int main()
      {
      printf("Hello World!\n");
      sleep(9999);
      return 0;
      }

  • Build Kernel
    • 取得最近的 kernel source,linux-2.6.26.3
    • 嚐試用 kernel source 裡的 integrator_defconfig 編譯 kernel,但在測試時發現沒有任何反應,所以先從 qemu 網站上可以下載的 arm-test-0.2.tar.gz 裡取出 .config 來編譯。
    • 修改 Makefile 以符合我們用的 cross compile
      ARCH            ?= arm
      CROSS_COMPILE ?= arm-none-linux-gnueabi-
    • make menuconfig,記得選取 initramfs 並填上 path
      [*] Initial RAM filesystem and RAM disk (initramfs/initrd) support
      (/home/ryan/qemu/hello-initramfs) Initramfs source file(s)
    • make zImage
    • 測試: qemu-system-arm -kernel linux-2.6.26.3/arch/arm/boot/zImage。可以看見開機時有成功執行 Hello World! 這個 fake init
      TCP cubic registered
      NET: Registered protocol family 17
      RPC: Registered udp transport module.
      RPC: Registered tcp transport module.
      802.1Q VLAN Support v1.8 Ben Greear
      All bugs added by David S. Miller
      VFP support v0.3: implementor 41 architecture 1 part 10 variant 9 rev 0
      Hello World!

  • 以 busybox 建置 ramdisk,將 busybox 編譯為 static。
    • 取得最新 soruce BusyBox 1.11.2
    • 修改 Makefile
      CROSS_COMPILE ?= arm-none-linux-gnueabi-
      ARCH ?= arm
    • make menuconfig。記得選取 static libnary
      [*] Build BusyBox as a static binary (no shared libs)
    • make install。會在目錄下產生 _install 目錄,這也是待會我們要移進 ramdisk 的內容
    • 檢查檔案格式
      file _install/bin/busybox
      #_install/bin/busybox: ELF 32-bit LSB executable, ARM, version 1 (SYSV), for GNU/Linux 2.6.14, statically linked, stripped
  • 建置初步 ramdisk
    mkdir busybox-initramfs
    cd busybox-initramfs/
    cp -av ../busybox-1.11.2/_install/* .
    ln -s sbin/init init
    find ./ | cpio -o -H newc | gzip > ../busybox.initramfs.cpio.gz
    cd ..
  • 啟動
    qemu-system-arm -kernel linux-2.6.26.3/arch/arm/boot/zImage -initrd busybox.initramfs.cpio.gz
    • 此時會一直 argue 缺少 device 。此時可是自建相關的 device node,則可正常啟動。
    • 但我希望能由系統自行建立,所以先 copy arm_test 裡 file system 的 etc 目錄 來用,待之後再來分析流程。成功開機。
      cd busybox-initramfs
      cp ../arm-test/arm_root.img arm_root.img.gz
      gunzip arm_root.img.gz
      mkdir tmp
      cd tmp
      cpio -i -F ../arm_root.img
      cp -av etc ../
      touch mdev.conf # 這是因為開機時 complain 沒有這個檔,所以先做個假的。這是因為開始時有執行 mdev,而 mdev.conf 為它的設定檔。
      mkdir root
      cd ..
      rm -rf arm_root.img tmp
      find ./ | cpio -o -H newc | gzip > ../busybox.initramfs.cpio.gz
      qemu-system-arm -kernel linux-2.6.26.3/arch/arm/boot/zImage -initrd busybox.initramfs.cpio.gz

開機流程剖析

  • Linux kernel 在掛載 ramdisk 後,預設會尋找 /init 這隻程式,除非在内核傳遞参數裡有設置 init=/linuxrc 來指定要找的第一個程式。
  • 目前 /init 是由 busybox 所提供的,其預設行為可以參考 init (重要,read it)。
  • 建立 /etc/inittab,/init 預設會先分析此 script
    ::sysinit:/etc/init.d/rcS

    ::respawn:/sbin/getty -L 38400 tty1
    ::respawn:/sbin/getty -L 38400 tty2
    ::respawn:/sbin/getty -L 38400 tty3
    ::respawn:/sbin/getty -L 38400 tty4

    ::respawn:/sbin/getty -L ttyAMA0 115200 xterm
  • 由 /etc/inittab 所指定 (或 /etc/inittab 不存在時,init 的預設行為),會去執行 /etc/init.d/rcS。
    • 其執行的內容為
      • 掛載 virtual file system,參考Magic Linux开发入门指南(五),基本說明的蠻清楚的。
      • mdev: 初始 device node 及自動更新,參考 busybox 附帶的文檔 busybox-1.11.2/docs/mdev.txt
      • 其除為網路設定部份,這就先不處理了。
    • #! /bin/sh

      mkdir -p /proc
      mount -t proc proc /proc
      mkdir -p /sys
      mount -t sysfs sysfs /sys
      mkdir -p /dev/pts
      mount -t devpts devpts /dev/pts
      echo /sbin/mdev > /proc/sys/kernel/hotplug
      mdev -s
      hostname qemu
      ifconfig lo 127.0.0.1 up
      # This board doesn't have a hardware clock, so system time is way off.
      # The bugsybox dhcp client doesn't work when the clock is wrong.
      # Oh well.
      ifconfig eth0 10.0.2.15 up
      rdate 10.0.2.2
      ip route add default via 10.0.2.2
  • inittab 其餘的部份為本機端終端機啟動的個數,參考 Util-linux (getty 和login) 及 man getty。
    • 允許登錄系統(log in)和得到命令行提示符(bash prompt)。
    • 准備一個密碼文件/etc/passwd.login 登錄程序正是通過查詢該文件來確認您是否允許登錄的。我們可以只設置根系統用戶就夠了,而且不需要任何密碼!! 只需要在目標系統的密碼文件/etc/passwd加上此行 "root::0:0:root:/root:/bin/bash"即可。(/etc/group 也要加入 "root:x:0:")
  • /etc/issue: 在終端機介面登入的時,顯示提示的字串。(如果想要讓使用者登入後取得一些訊息,可以寫在 /etc/motd)
  • /etc/nsswitch.conf: name-server switch,用來控制名稱資訊轉換,例如,當系統要取得 password、group、host 等資訊時,會參考這個檔案以決定要從哪裡得到資訊。參考 man nsswitch.conf。
    # /etc/nsswitch.conf
    #
    # Example configuration of GNU Name Service Switch functionality.
    # If you have the `glibc-doc' and `info' packages installed, try:
    # `info libc "Name Service Switch"' for information about this file.

    passwd: compat
    group: compat
    shadow: compat

    hosts: files dns
    networks: files

    protocols: db files
    services: db files
    ethers: db files
    rpc: db files

    netgroup: nis
  • /etc/resolv.con: 參考簡介,man resolv.conf
    nameserver 10.0.2.3

No comments: