如果要自己製作 linux 的檔案系統, 通常是一個小系統, 要不然官方提供的版本已經很好用了, 何必要自己做一個, 既然要小, 就會以 busybox 為主, 通常我都參考
build busybox and glic to root file system 來製作檔案系統。
busybox
wget http://busybox.net/downloads/busybox-1.23.2.tar.bz2
tar -xjf busybox-1.23.2.tar.bz2
cd busybox-1.23.2/
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- defconfig
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- menuconfig
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi-
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- install CONFIG_PREFIX=/home/export/rootfs
glibc
wget http://ftp.gnu.org/gnu/libc/glibc-2.21.tar.xz
tar -xJf glibc-2.21.tar.xz
mkdir glibc-build
cd glibc-build/
../glibc-2.21/configure arm-linux-gnueabi --target=arm-linux-gnueabi --build=i686-pc-linux-gnu --prefix= --enable-add-ons
在我使用的 toolchain 中, 要用以下的指令
../glibc-2.21/configure arm-linux-gnueabihf --target=arm-linux-gnueabihf --build=i686-pc-linux-gnu --prefix= --enable-add-ons
make
make install install_root=/home/export/rootfs
再安裝 glibc 後就會有一些工具可用, ldconfig, ldd 之類的, 對於查詢執行檔能不能正常運作很有用, 通常我會再安裝 bash。bash 的 cross compile 比較麻煩, 我用 native compile 搞定一個 static 版本。
然後再從 toolchain 複製 c++ library (libstdc++*) 到 root filesystem usr/lib, 其實這不是好方法, 比較正確的方式是從 source code 建立 toolchain, 再複製 toolchain 所需的 library 到 root filesystem, 可是因為太麻煩, 也不容易, 改用這樣的方式比較簡單。
刪除一些 glibc 多語系和 .a 的檔案。產生 /dev files (可能需要 root 權限), 從使用的 linux 複製過來即可。
wget https://matt.ucc.asn.au/dropbear/releases/dropbear-2015.68.tar.bz2
tar -xjf dropbear-2015.68.tar.bz2
cd dropbear-2015.68
./configure --host=arm-linux-gnueabi --prefix=/ --disable-zlib CC=arm-linux-gnueabi-gcc LD=arm-linux-gnueabi-ld
make
make install DESTDIR=/home/export/rootfs
我用 chroot 來做以下的 dropbear 相關設定 (x86), rfs 是 root file system 目錄:
chroot rfs/ /bin/sh
產生 ssh key, 需要 /dev/urandom
mkdir /etc/dropbear
dropbearkey -t dss -f /etc/dropbear/dropbear_dss_host_key
dropbearkey -t rsa -f /etc/dropbear/dropbear_rsa_host_key
Unless otherwise specified, root will be given a default home directory of /home/root. However as this doesn't exist, DropBear will close your connection immediately after successfully logging in. To address this, simply create a home directory for root:
mkdir /home /home/root
產生密碼檔
touch /etc/passwd # /bin/bash 改成 /bin/sh
touch /etc/group
adduser root -u 0
建立 pty device, ref: http://www.denx.de/wiki/view/DULG/TelnetServerNotWorking
# mkdir /dev/pts
# mknod c 5 2 /dev/ptmx
# mount -t devpts devpts /dev/pts
DropBear can now be started by running:
dropbear -E
同常都是用這個設定檔, 取消 busybox "Please press Enter to activate this console" 不需要按下 enter 即可進入 console
ref:
linux开机自启动,去掉“Please press Enter to activate this console“
busyboxy /etc/inittab
1 ::sysinit:/etc/init.d/rcS
2
3 # /bin/ash
4 #
5 # Start an "askfirst" shell on the serial port
6 console::respawn:-/bin/ash
7 #console::askfirst:-/bin/ash # Please press Enter to activate this console
8 #console::askfirst:-/bin/login
9
10 # Stuff to do when restarting the init process
11 ::restart:/sbin/init
12
13 # Stuff to do before rebooting
14 ::ctrlaltdel:/sbin/reboot
15 ::shutdown:/bin/umount -a -r
16 ::shutdown:/sbin/swapoff -a
我在幾個 arm cortex A9 平台上都很順利, 惟獨在 rpi2 上, 製作的檔案系統無法正常開到 login/shell 畫面。製作一個 linux 檔案系統的學問很大, 通常做完開不了機是很正常的, 至少有 10 種以上的原因會造成這個結果, 這次遇到一個我不知道的原因, 所以還要再加上一個。
錯誤訊息是這樣:
[ 3.052569] smsc95xx v1.0.4
[ 3.116771] smsc95xx 1-1.1:1.0: eth0: register 'smsc95xx' at usb-bcm2708_usb-1.1, smsc95xx USB 2.0 Ethernet, b8:27:eb:f7:69:6d
在開到網路這部份就 hang 住了, 把訊息拿去 google, 有一堆, 有的說要改 config.txt, 有的要改 cmdline.txt, 當然都無法解決我的問題, 我猜測了幾個原因:
init 是不是又放錯位置了 (/sbin/init 才對)
init 沒有編好, 無法正常執行
init 需要的 library 沒有安置好
/dev/ 沒有需要的 device file
kernel 開機參數是不是有問題
root filesystem 沒有正確 mount
root filesystem 製作有問題
kernel 沒有正確編譯
sd partition 是不是有問題
sd 檔案系統是不是有問題
/etc/ 的設定是不是有問題
真的有 10 種以上的可能, 沒一個中 ...
linux_src/init/main.c L966 ~ 969 告訴我們 linux 怎麼啟動 init。
linux_src/init/main.c
931 static int __ref kernel_init(void *unused)
932 {
933 int ret;
934
935 kernel_init_freeable();
936 /* need to finish all async __init code before freeing the memory */
937 async_synchronize_full();
938 free_initmem();
939 mark_rodata_ro();
940 system_state = SYSTEM_RUNNING;
941 numa_default_policy();
942
943 flush_delayed_fput();
944
945 if (ramdisk_execute_command) {
946 ret = run_init_process(ramdisk_execute_command);
947 if (!ret)
948 return 0;
949 pr_err("Failed to execute %s (error %d)\n",
950 ramdisk_execute_command, ret);
951 }
952
953 /*
954 * We try each of these until one succeeds.
955 *
956 * The Bourne shell can be used instead of init if we are
957 * trying to recover a really broken machine.
958 */
959 if (execute_command) {
960 ret = run_init_process(execute_command);
961 if (!ret)
962 return 0;
963 pr_err("Failed to execute %s (error %d). Attempting defaults...\n",
964 execute_command, ret);
965 }
966 if (!try_to_run_init_process("/sbin/init") ||
967 !try_to_run_init_process("/etc/init") ||
968 !try_to_run_init_process("/bin/init") ||
969 !try_to_run_init_process("/bin/sh"))
970 return 0;
971
972 panic("No working init found. Try passing init= option to kernel. "
973 "See Linux Documentation/init.txt for guidance.");
974 }
官方的檔案系統沒問題, 不過是 systemd 的設定, 不熟, 很難比對。
/etc/inittab L1 ~ L15 是原本的設定, 其結果是在 kernel 開機後就會直接進入 console, 不需要帳號/密碼。
/etc/inittab
1 ::sysinit:/etc/init.d/rcS
2
3 # /bin/ash
4 #
5 # Start an "askfirst" shell on the serial port
6 #console::askfirst:-/bin/ash
7 #console::askfirst:-/bin/login
8
9 # Stuff to do when restarting the init process
10 ::restart:/sbin/init
11
12 # Stuff to do before rebooting
13 #::ctrlaltdel:/sbin/reboot
14 #::shutdown:/bin/umount -a -r
15 #::shutdown:/sbin/swapoff -a
16
17 # /etc/inittab
18 #
19 # Copyright (C) 2001 Erik Andersen <andersen@codepoet.org>
20 #
21 # Note: BusyBox init doesn't support runlevels. The runlevels field is
22 # completely ignored by BusyBox init. If you want runlevels, use
23 # sysvinit.
24 #
25 # Format for each entry: <id>:<runlevels>:<action>:<process>
26 #
27 # id == tty to run on, or empty for /dev/console
28 # runlevels == ignored
29 # action == one of sysinit, respawn, askfirst, wait, and once
30 # process == program to run
31
32 # Startup the system
33 null::sysinit:/bin/mount -t proc proc /proc
34 null::sysinit:/bin/mount -o remount,rw / # REMOUNT_ROOTFS_RW
35 null::sysinit:/bin/mkdir -p /dev/pts
36 null::sysinit:/bin/mkdir -p /dev/shm
37 null::sysinit:/bin/mount -a
38 null::sysinit:/bin/hostname -F /etc/hostname
39 # now run any rc scripts
40 ::sysinit:/etc/init.d/rcS
41
42 # Put a getty on the serial port
43 tty1::respawn:/sbin/getty -L ttyAMA0 115200 # GENERIC_SERIAL
44
45 # Stuff to do for the 3-finger salute
46 ::ctrlaltdel:/sbin/reboot
47
48 # Stuff to do before rebooting
49 null::shutdown:/etc/init.d/rcK
50 null::shutdown:/bin/umount -a -r
51 null::shutdown:/sbin/swapoff -a
/etc/inir.d/rcS 可以加上:
mount -t proc none /proc
mount -t sysfs none /sys
不過最後卻需要/etc/inittab L43 的 ttyAMA0 這個設定才能正常以帳號/密碼的方式進入 console。所以還需要 /etc/passwd, /etc/group (從已經存在的 linux 系統複製即可) 記得把 root 密碼清除, 免得無法登入。
這花了我兩天才找到問題。
通常還可以複製 /dev/ 的裝置檔, 不用自己 mknod。
要製作 initfs 可以用以下指令:
cd rfs
find . | cpio -o -Hnewc |gzip -9 > ../rootfs.img
沒有留言:
張貼留言
使用 google 的 reCAPTCHA 驗證碼, 總算可以輕鬆留言了。
我實在受不了 spam 了, 又不想讓大家的眼睛花掉, 只好放棄匿名留言。這是沒辦法中的辦法了。留言的朋友需要有 google 帳號。