注:本文是学习朱老师课程整理的笔记,基于busybox_1.25.1版本移植
问题1:busybox的配置
Makefile修改:
ARCH = arm
CROSS_COMPILE = /usr/local/arm/arm-2009q3/bin/arm-none-linux-gnueabi- //这里是交叉编译工具链的安装路径和工具名的前缀。在高版本的busybox中,CROSS_COMPILE可以在menuconfig中配置。
menuconfig的配置:
Busybox Settings--->
Build Options--->
[*]Build BusyBox as a static binary(no shared libs)
Busybox Settings--->
Busybox Library Tuning--->
[*]vi-style line editing commands
[*]Fancy shell prompts
Linux Module Utilities--->
[ ]Simplified modutils
[*]insmod
[*]rmmod
[*]lsmod
[*]modprobe
[*]depmod
Linux System Utilities--->
[*]mdev
[*]Support /etc/mdev.conf
[*]Support subdirs/symlinks
[*]Support regular expressions substitutions when renaming dev
[*]Support command execution at device addition/removal
[*]Support loading of firmwares
Busybox Settings --->
Installation Options ("make install" behavior) --->
BusyBox installation prefix //选择安装的路径
如果使用nfs服务进行挂载根文件系统的还要修改uboot的bootargs,格式如下:
setenv bootargs root=/dev/nfs nfsroot=192.168.1.141:/root/porting_x210/rootfs ip=192.168.1.10:192.168.1.141:192.168.1.1:255.255.255.0::eth0:off init=/linuxrc console=ttySAC2,115200
问题2:VFS: Cannot open root device "nfs" or unknown-block(0,255)
配置内核支持nfs挂载根文件系统:
1、配置网络部分,主要是使能CONFIG_IP_PNP以在2中能够看到Root file system on NFS选项
Networking support
Networking options
[*]TCP/IP networking
[*]IP: kernel level autoconfiguration
[*] IP: DHCP support
[*] IP: BOOTP support
2、配置开启nfs服务
File systems --->
Network File Systems --->
<*> NFS client support
[*] NFS client support for NFS version 3
[*] NFS client support for the NFSv3 ACL protocol extension
[*] NFS client support for NFS version 4 (EXPERIMENTAL)
[*] NFS client support for NFSv4.1 (DEVELOPER ONLY)
[*] Root file system on NFS
问题3:miscutils/nandwrite.c:151: error: 'MTD_FILE_MODE_RAW' undeclared (first use in this function)
busybox1.25.1中没有定义这个宏,MTD_FILE_MODE_RAW在/usr/include/mtd/mtd-abi.h中定义,将/usr/include/mtd/mtd-abi.h拷贝到busybox的include文件中,然后包含该头文件,编译时就不会显示这个错误了。
为什么在busybox中没有包含这个文件,需要自己去添加呢?
在/usr/include/mtd/mtd-abi.h中定义,说明这应该是编译器提供的,但是编译器没有提供该文件,说明编译器库版本不合适,就需要移植第三方库。作为应用程序,busybox不会有这个文件,就像stdio.h,busybox就不会提供。不要尝试用一个编译器去编译遇到的所有源代码,你不会成功的。
问题4:
mount: mounting proc on /proc failed: No such file or directory
mount: mounting sysfs on /sys failed: No such file or directory
mount: mounting tmpfs on /var failed: No such file or directory
mount: mounting tmpfs on /tmp failed: No such file or directory
mount: mounting tmpfs on /dev failed: No such file or directory
因为根文件系统中找不到挂载点。所谓挂载点就是我们要将目标文件系统(在busybox中mount -a时busybox会去查找/etc/fstab文件,这个文件按照一定的格式列出来所有应该被挂载的文件系统,包括了虚拟文件系统)挂载到当前文件系统中的某一个目录中,这个目录就是挂载点。解决方案就是自己在制作的rootfs根目录下创建这些挂载点目录即可。验证是否挂载成功,可以看挂载时输出信息;还可以启动后去看proc和sys文件夹,如果有文件出现则证明挂载成功了,如果没东西就证明失败了。
问题5:指定开机后的IP地址
有时候我们希望开机后进入命令行时,ip地址就是一个指定的ip地址(譬如192.168.1.30),这时候就可以在rcS文件中添加:ifconfig eth0 192.168.1.30。如果在用nfs调试阶段时,uboot的IP地址和rcS中的设置的IP地址不同,则系统启动后会与宿主机上的根文件系统失去十几秒的失联,之后会正常运行。
问题6:login: can't execute '/bin/bash': No such file or directory
busybox支持ash、hush、msh三种shell,但是不支持bash。所以修改etc/init.d/rcS文件的shell解析器为sh或其他。
问题7:添加设备驱动文件
在etc/init.d/rcS文件中没有启动mdev的时候,/dev目录下启动后是空的;在rcS文件中添加上mdev有关的2行配置项:
echo /sbin/mdev > /proc/sys/kernel/hotplug
mdev -s
再次启动系统后发现/dev目录下生成了很多的设备驱动文件。/dev目录下的设备驱动文件就是mdev生成的。
问题8:显示主机名
etc/init.d/rcS中添加/bin/hostname -F /etc/sysconfig/HOSTNAME 来指定了一个主机名配置文件(这个文件一般文件名叫hostname或者HOSTNAME),在HOSTNAME文件中写入自己的主机名(x210)。命令行下hostname命令查到的host名字确实是x210。但是问题就是命令行的提示符是没有显示的。
在etc目录下创建profile文件,在文件中输入以下内容:
# Ash profile
# vim: syntax=sh
# No core files by default
ulimit -S -c 0 > /dev/null 2>&1
USER="`id -un`"
LOGNAME=$USER
PS1='[\u@\h \W]\# '
PATH=$PATH
HOSTNAME=`/bin/hostname`
export USER LOGNAME PS1 PATH
添加了之后的实验现象:命令行提示符前面显示:[@x210 ]#
问题9:显示用户登录界面:用户名和密码
intttab中有一个配置项 ::askfirst:-/bin/sh,这个配置项作用就是当系统启动后就去执行/bin/sh,执行这个就会出现命令行。因此我们这样的安排就会直接进入命令行而不会出现登录界面。我们要出现登录界面,就不能直接执行/bin/sh,而应该执行一个负责出现登录界面并且负责管理用户名和密码的一个程序,busybox中也集成了这个程序(就是/bin/login和/sbin/gettty),因此我们要在inittab中用/bin/login或者/sbin/getty去替代/bin/sh。
在inittab中添加/bin/login到sysinit,去掉/bin/sh,则系统启动后出现登录界面。可以输入用户名和密码。
实验现象:成功出现用户登录界面,但是密码不对。
linux系统中用来描述用户名和密码的文件是passwd和shadow文件,这两个文件都在etc目录下。passwd文件中存储的是用户的密码设置,shadow文件中存储的是加密后的密码。我们直接复制ubuntu系统中的/etc/passwd和/etc/shadow文件到当前制作的rootfs目录下,然后再做修改即可。/etc/passwd和/etc/shadow修理好后,shadow中默认有一个加密的密码口令,这个口令和你拷贝的shadow本身有关,像我的ubuntu中root用户的密码就是root,因此复制过来后登陆时的密码还是root。
ubuntu刚装好的时候默认登录是用普通用户登录的,root用户是关闭的。普通用户的密码是在装系统的时候设置的,普通用户登陆后可以使用su passwd root给root用户设置密码,设置了密码后root用户才可以登录。原因就是root用户在/etc/shadow文件中加密口令是空白的。所以是不能登录的。
busybox中因为没有普通用户,所以做法是:默认root用户如果加密口令是空的则默认无密码直接登录。等我们登陆了之后还是可以用passwd root给root用户设置密码。
问题10:login: can't change directory to '/root'
在根目录创建目录root作为用户root的目录
-sh: can't access tty; job control turned off
在/dev目录下有很多设备驱动文件(启动的时候才可以看到),找到开发板所用的控制台设备。这里我开发板用的是串口2,选择的是s3c2410_serial2,然后在etc/inittab文件中改成如下形式:s3c2410_serial2::sysinit:/bin/login。
问题12:-sh: ./xxxx: not found运行时提示找不到程序。
任务:自己写一个helloworld程序,然后交叉编译连接,然后丢到开发板根文件系统中,开机后去运行。
C程序如果使用gcc来编译则可以在宿主机中运行,但是不能在开发板运行;要在开发板运行需要用arm-linux-gcc来交叉编译,但是这时候就不能在宿主机中运行了。我们可以用file xx命令来查看一个elf可执行程序是哪个架构的。
如果是静态链接:arm-linux-gcc hello.c -o hello_satic -static,编译连接后生成的hello_satic已经可以成功运行。
如果是动态链接:arm-linux-gcc hello.c -o hello_dynamic,实验结果:-sh: ./hello_dynamic: not found运行时提示找不到程序。
错误分析:动态连接的hello程序中调用到了printf函数,而printf函数在动态连接时要在运行时环境(开发板的rootfs)中去寻找对应的库文件。如果找到了则printf函数就会被成功解析,然后hello_dynamic程序就会被执行;如果找不到则程序就不能被执行,命令行会提示错误信息-sh: ./hello_dynamic: not found
解决方案:将arm-linux-gcc的动态链接库文件复制到开发板rootfs的/lib目录下即可解决。
比如我用的arm-2009q3这个交叉编译工具链的动态链接库在/usr/local/arm/arm-2009q3/arm-none-linux-gnueabi/libc/lib目录下。其他的一些交叉编译工具链中动态链接库的目录不一定在这里,要去找一下。找的方法就是find。复制动态链接库到roots/lib目录下。复制时要注意参数用-rdf,主要目的就是符号链接复制过来还是符号链接。复制命令:cp lib/*so* /root/porting_x210/rootfs/rootfs/lib/ -rdf
问题13:使用strip工具去掉库中符号信息
动态链接库so文件中包含了调试符号信息,这些符号信息在运行时是没用的(调试时用的),这些符号会占用一定空间。在传统的嵌入式系统中flash空间是有限的,为了节省空间常常把这些符号信息去掉。这样节省空间并且不影响运行。
去掉符号命令:arm-linux-strip *so*
实际操作后发现库文件由3.8M变成了3.0M,节省了0.8M的空间。
问题14:如何实现开机程序自启动(前台或者后台运行)
开机自启动指的是让一些应用程序能够开机后自动执行,实现原理就是在开机会自动执行的脚本rcS中添加上执行某个程序的语句代码即可,比如:
cd xxx_dir./xxx
cd /
就是先进入某个目录,然后执行这个目录下的程序,接着退出到根目录下。
程序运行时占用了当前的控制台,因此这个程序不结束我们都无法使用控制台,这就叫前台运行。默认执行程序就是前台运行的。
后台运行就是让这个程序运行,并且同时让出控制台。这时候运行的程序还能照常运行而且还能够不影响当前控制台的使用。
让一个程序后台运行的方法就是 ./xxx &,加上&符号即可。
问题15:rcK是什么。和rcS有什么区别
分析inittab发现:sysinit执行rcS,shutdown时执行rcK。
分析/etc/init.d/rcS和rcK文件发现,rcS和rcK都是去遍历执行/etc/init.d/目录下的S开头的脚本文件,区别是rcS传参是start,rcK传参是stop。正式产品中的rcS和rcK都是一个引入,而不是真正干活的。真正干活的配置脚本是/etc/init.d/S??*。这些文件中肯定有一个判断参数是start还是stop,然后start时去做一些初始化,stop时做一些清理工作。:
问题16:制作ext2格式的镜像
(1)dd if=/dev/zero of=rootfs.ext2 bs=1024 count=10240
losetup /dev/loop1 rootfs.ext2
mke2fs -m 0 /dev/loop1 10240
mount -t ext2 /dev/loop1 ./ext2_rootfs/
(2)向./rootfs中复制内容,用cp ../rootfs/* ./ -rf
(3)umount /dev/loop1
losetup -d /dev/loop1
(4)完成后得到的rootfs.ext2就是做好的rootfs镜像。拿去烧录即可。
待续……