本文章来源于正点原子资料,记录下来,以后参考。
1、根文件系统介绍
linux系统里面有很多目录,这些目录的大致内容如下:
1 、/bin 目录
bin 文件就是可执行文件。此目录下存放着系统需要的可执行文件,一般都是一些常用的命令
2 、/dev 目录
dev 是 device 的缩写,所以此目录下的文件都是和设备有关的,此目录下的文件都是设备文件。在Linux 下一切皆文件。
3 、/etc 目录
此目录下存放着各种配置文件
4 、/lib 目录
lib 是 library 的简称,也就是库的意思,因此此目录下存放着 Linux 所必须的库文件。这些库文件是共享库,命令和用户编写的应用程序要使用这些库文件。
5 、/mnt 目录
临时挂载目录,一般是空目录,可以在此目录下创建空的子目录,比如/mnt/sd、/mnt/usb,这样就可以将 SD 卡或者 U 盘挂载到/mnt/sd 或者/mnt/usb 目录中。
6 、/proc 目录
此目录一般是空的,当 Linux 系统启动以后会将此目录作为 proc 文件系统的挂载点,proc是个虚拟文件系统,没有实际的存储设备。proc 里面的文件都是临时存在的,一般用来存储系统运行信息文件。
7 、/usr 目录
要注意,usr 不是 user 的缩写,而是 Unix Software Resource 的缩写,也就是 Unix 操作系统软件资源目录。既然是软件资源目录,因此/usr 目录下也存放着很多软件,一般系统安装完成以后此目录占用的空间最多。
8 、/var 目录
此目录存放一些可以改变的数据。
9 、/sbin 目录
此目录用户存放一些可执行文件,但是此目录下的文件或者说命令只有管理员才能使用,主要用户系统管理。
10 、/sys 目录
系统启动以后此目录作为 sysfs 文件系统的挂载点,sysfs 是一个类似于 proc 文件系统的特殊文件系统,sysfs 也是基于 ram 的文件系统,也就是说它也没有实际的存储设备。此目录是系统设备管理的重要目录,此目录通过一定的组织结构向用户提供详细的内核数据结构信息。
11 、/opt
可选的文件、软件存放区,由用户选择将哪些文件或软件放到此目录中。
我们构建根文件系统就是要创建上面这些子目录以及子目录中的文件。
2、busybox移植
2.1 busybox介绍
BusyBox是一个集成了大量linux命令和工具的软件。
BusyBox 官网下载地址为:https://busybox.net/
在左边“Get BusyBox”下,点击“Download Source”进入busybox源码下载页面https://busybox.net/downloads/里面有各个版本的busyboxy源码
这里下载busybox-1.29.0.tar.bz2来移植
2.2 busybox配置及编译
在ubuntu中解压源码
tar jxvf busybox-1.29.0.tar.bz2
1 、添加编译器
进入源码根目录,修改顶层 Makefile ,添加编译器(CROSS_COMPILE为编译器的绝对路径),修改 ARCH 和 CROSS_COMPILE
164 CROSS_COMPILE ?= /usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf-
190 #ARCH ?= $(SUBARCH)
191 ARCH ?= arm
2 、busybox 中文字符支持
如果默认直接编译 busybox 的话,在使用 SecureCRT 的时候中文字符是显示不正常的,中文字
符会显示为“?”,比如你的中文目录,中文文件都显示为“?”。
所以我们需要修改 busybox 源码,取消 busybox 对中文显示的限制,打开文件 busybox-
1.29.0/libbb/printable_string.c,找到函数 printable_string,缩减后的函数内容如下:
const char* FAST_FUNC printable_string(uni_stat_t *stats, const char *str)
{
char *dst;
const char *s;
s = str;
while (1) {
unsigned char c = *s;
if (c == '\0') {
/* 99+% of inputs do not need conversion */
if (stats) {
stats->byte_count = (s - str);
stats->unicode_count = (s - str);
stats->unicode_width = (s - str);
}
return str;
}
if (c < ' ')
break;
/*注释这两行*/
/*if (c >= 0x7f)
break;*/
s++;
}
#if ENABLE_UNICODE_SUPPORT
dst = unicode_conv_to_printable(stats, str);
#else
{
char *d = dst = xstrdup(str);
while (1) {
unsigned char c = *d;
if (c == '\0')
break;
/*修改*/
//if (c < ' ' || c >= 0x7f)
if (c < ' ')
*d = '?';
d++;
}
if (stats) {
stats->byte_count = (d - dst);
stats->unicode_count = (d - dst);
stats->unicode_width = (d - dst);
}
}
#endif
return auto_string(dst);
}
注 释 20 − 21 行 , 修 改 34 − 35 行 \color{#FF0000}{注释20-21行,修改34-35行} 注释20−21行,修改34−35行,
打开文件 busybox-1.29.0/libbb/unicode.c 修改如下:
static char* FAST_FUNC unicode_conv_to_printable2(uni_stat_t *stats, const char *src, unsigned width, int flags)
{
char *dst;
unsigned dst_len;
unsigned uni_count;
unsigned uni_width;
if (unicode_status != UNICODE_ON) {
char *d;
if (flags & UNI_FLAG_PAD) {
d = dst = xmalloc(width + 1);
while ((int)--width >= 0) {
unsigned char c = *src;
if (c == '\0') {
do
*d++ = ' ';
while ((int)--width >= 0);
break;
}
/*修改下面的这行代码*/
/**d++ = (c >= ' ' && c < 0x7f) ? c : '?';*/
*d++ = (c >= ' ') ? c : '?';
src++;
}
*d = '\0';
} else {
d = dst = xstrndup(src, width);
while (*d) {
unsigned char c = *d;
/*修改下面的一行代码*/
/*if (c < ' ' || c >= 0x7f)*/
if (c < ' ')
*d = '?';
d++;
}
}
if (stats) {
stats->byte_count = (d - dst);
stats->unicode_count = (d - dst);
stats->unicode_width = (d - dst);
}
return dst;
}
......
return dst;
}
3 、配置 busybox
默认配置 make defconfig
全选配置 make allyesconfig
最小配置 make allnoconfig 一般使用这个
输入上面三个命令中的其中一个后,就会在根目录生成 .config 文件。
make menuconfig 打开图形话配置界面
a.不选用静态编译
->Settings
->Build static binary (no shared libs)
不 能 勾 选 这 个 选 项 \color{#FF0000}{不能勾选这个选项} 不能勾选这个选项
b.vi风格的编辑
-> Settings
│ -> vi-style line editing commands
勾 选 这 个 \color{#00FF00}{勾选这个} 勾选这个
c.Simplified modutils
-> Linux Module Utilities
-> Simplified modutils
不 勾 选 这 个 选 项 \color{#FF0000}{不勾选这个选项} 不勾选这个选项
d.其他配置(usb热插拔)
-> Linux System Utilities
->mdev (16 kb)
如
图
所
示
全
部
选
中
\color{#00FF00}{如图所示全部选中}
如图所示全部选中
e.使能 busybox 的 unicode 编码以支持中文
-> Settings
-> Support Unicode
-> Check $LC_ALL, $LC_CTYPE and $LANG environment variables
选 中 上 面 的 两 个 \color{#00FF00}{选中上面的两个} 选中上面的两个
4 、编译 busybox
编译命令:
make install CONFIG_PREFIX=/home/XXX/nfsroot/rootfs
COFIG_PREFIX指定编译结果的存放目录 ,如果不指定目录 , 编译结果在 _install 目录中
此时,rootfs 目录下有 bin、sbin 和 usr 这三个目录,以及 linuxrc 这个文件。如果 bootargs 设置init=/linuxrc,那么 linuxrc 就是可以作为用户空间的 init 程序,所以用户态空间的 init 程序是 busybox 来生成的。此时的根文件系统还不能使用,还需要一些其他的文件。
2.3 向根文件系统添加 lib
a.将交叉编译环境下lib库拷贝到/rootfs/lib
进入rootfs中,创建lib目录 make lib
cp /usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/arm-linux-gnueabihf/libc/lib/*.a lib/ -d
cp /usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/arm-linux-gnueabihf/libc/lib/*so* lib/ -d
“-d” 表示符号链接拷贝
先将 rootfs/lib 中的 ld-linux-armhf.so.3 文件删除掉,命令
如下:
rm ld-linux-armhf.so.3
从编译器中拷贝 ld-linux-armhf.so.3
cd /usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/arm-linux-gnueabihf/libc/lib
cp ld-linux-armhf.so.3 ~/imx-share/nfsroot/rootfs/lib/
进入下目录:
/usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/arm-linux-gnueabihf/lib
此目录下也有很多的的so和.a 库文件,我们将其也拷贝到 rootfs/lib 目录中
cd /usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/arm-linux-gnueabihf/lib
cp *so* *.a ~/imx-share/nfsroot/rootfs/lib/ -d
a.将交叉编译环境下lib库拷贝到 rootfs/usr/lib
在rootfs中的usr目录建lib目录 mkdir usr/lib
进入/usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/arm-linux-gnueabihf/libc/usr/lib目录
cd /usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/arm-linux-gnueabihf/libc/usr/lib
cp *so* *.a ~/imx-share/nfsroot/rootfs/usr/lib/ -d
2.4 创建其他文件夹
在根文件系统中创建其他文件夹,如 dev、proc、mnt、sys、tmp 和 root
三、测试
NFS挂载根文件系统
root=/dev/nfs nfsroot=[<server-ip>:]<root-dir>[,<nfs-options>] ip=<client-ip>:<server-ip>:<gw-ip:<hostname>:<device>:<autoconf>:<dns0-ip>:<\dns1-ip>
<server-ip>:服务器 IP 地址,也就是存放根文件系统主机的 IP 地址,那就是 Ubuntu 的 IP地址,比如我的 Ubuntu 主机 IP 地址为 192.168.1.250。
<root-dir> :根文件系统的存放路径,比如我的就是/home/zuozhongkai/linux/nfs/rootfs。
<nfs-options>:NFS 的其他可选选项,一般不设置。
<client-ip> :客户端 IP 地址,也就是我们开发板的 IP 地址,Linux 内核启动以后就会使用此 IP 地址来配置开发板。此地址一定要和 Ubuntu 主机在同一个网段内,并且没有被其他的设备使用
<server-ip> :服务器 IP 地址,前面已经说了。
<gw-ip> :网关地址,我的就是 192.168.1.1。
<netmask>:子网掩码,我的就是 255.255.255.0。
<hostname>:客户机的名字,一般不设置,此值可以空着。
<device> :设备名,也就是网卡名,一般是 eth0,eth1….,正点原子的 I.MX6U-ALPHA 开
发板的 ENET2 为 eth0,ENET1 为 eth1。如果你的电脑只有一个网卡,那么基本只能是 eth0。
这里我们使用 ENET2,所以网卡名就是 eth0。
<autoconf> :自动配置,一般不使用,所以设置为 off。
<dns0-ip> :DNS0 服务器 IP 地址,不使用。
<dns1-ip> :DNS1 服务器 IP 地址,不使用。
设置上面的格式 bootargs 环境变量的 root 值如下:
root=/dev/nfs rw nfsroot=192.168.1.172:/home/xxxxx/nfsroot/rootfs ip=192.168.1.187:192.168.1.172:192.168.1.1:255.255.255.0::eth0:off
设置bootargs
setenv bootargs 'console=ttymxc0,115200 root=/dev/nfs rw nfsroot=192.168.1.172:/home/xxxxx/nfsroot/rootfs ip=192.168.1.187:192.168.1.172:192.168.1.1:255.255.255.0::eth0:off'
saveenv
boot启动内核
报错:
can’t run ‘/etc/init.d/rcS’: No such file or directory
四、完善根文件系统
a.创建/etc/init.d/rcS
rcS 是个 shell 脚本,Linux 内核启动以后需要启动一些服务,而 rcS 就是规定启动哪些文件
的脚本文件。在 rootfs 中创建/etc/init.d/rcS 文件,然后在 rcS 中输入如下所示内容:
1 #!/bin/sh
2
3 PATH=/sbin:/bin:/usr/sbin:/usr/bin:$PATH
4 LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/lib:/usr/lib
5 export PATH LD_LIBRARY_PATH
6
7 mount -a
8 mkdir /dev/pts
9 mount -t devpts devpts /dev/pts
10
11 echo /sbin/mdev > /proc/sys/kernel/hotplug
12 mdev -s
第 1 行,表示这是一个 shell 脚本。
第 3 行,PATH 环境变量保存着可执行文件可能存在的目录,这样我们在执行一些命令或
者可执行文件的时候就不会提示找不到文件这样的错误。
第 4 行,LD_LIBRARY_PATH 环境变量保存着库文件所在的目录。
第 5 行,使用 export 来导出上面这些环境变量,相当于声明一些“全局变量”。
第 7 行,使用 mount 命令来挂载所有的文件系统,这些文件系统由文件/etc/fstab 来指定,
所以我们一会还要创建/etc/fstab 文件。
第 8 和 9 行,创建目录/dev/pts,然后将 devpts 挂载到/dev/pts 目录中。
第 11 和 12 行,使用 mdev 来管理热插拔设备,通过这两行,Linux 内核就可以在/dev 目录
下自动创建设备节点。关于 mdev 的详细内容可以参考 busybox 中的 docs/mdev.txt 文档。
示例代码 38.4.1.1 中的 rcS 文件内容是最精简的,大家如果去看 Ubuntu 或者其他大型 Linux
操作系统中的 rcS 文件,就会发现其非常复杂。因为我们是初次学习,所以不用搞这么复杂的,
而且这么复杂的 rcS 文件也是借助其他工具创建的,比如 buildroot 等。
创建好文件/etc/init.d/rcS 以后一定要给其可执行权限!否则有can’t run ‘/etc/init.d/rcS’: Permission denied报错
使用如下命令给予/ec/init.d/rcS 可执行权限:
chmod 777 rcS
继续启动内核 有报错:
Freeing unused kernel memory: 400K (80910000 - 80974000)
mount: can’t read ‘/etc/fstab’: No such file or directory
/etc/init.d/rcS: line 11: can’t create /proc/sys/kernel/hotplug: nonexistent directory
mdev: /sys/dev: No such file or directory
“mount -a”挂载所有根文件系统的时候需要读取/etc/fstab,因为/etc/fstab 里面定义了该挂载哪些文件
b.创建/etc/fstab
在 rootfs中创建/etc/fstab 文件,fstab在Linux开机以后自动配置哪些需要自动挂载的分区,格式如下:
<file system> <mount point> <type> <options> <dump> <pass>
<file system>:要挂载的特殊的设备,也可以是块设备,比如/dev/sda 等等。
<mount point>:挂载点。
<type>:文件系统类型,比如 ext2、ext3、proc、romfs、tmpfs 等等。
<options>:挂载选项,在 Ubuntu 中输入“man mount”命令可以查看具体的选项。一般使用defaults,也就是默认选项defaults 包含了 rw、suid、 dev、 exec、 auto、 nouser 和 async。
<dump>:为 1 的话表示允许备份,为 0 不备份,一般不备份,因此设置为 0。
<pass>:磁盘检查设置,为 0 表示不检查。根目录‘/’设置为 1,其他的都不能设置为 1,
其他的分区从 2 开始。一般不在 fstab 中挂载根目录,因此这里一般设置为 0。
fstab文件内容如下:
1 #
2 proc /proc proc defaults 0 0
3 tmpfs /tmp tmpfs defaults 0 0
4 sysfs /sys sysfs defaults 0 0
c.创建/etc/inittab
参考https://www.cnblogs.com/uestc-mm/p/11985696.html
当内核初始化后,就会启动第一个进程 init,init进程 会读取/etc/inittab文件,执行里面的内容来进行初始化工作
/etc/inittab文件中每个登记项的结构都是一样的,共分为以冒号“:”分隔的4个字段.具体如下:
<id>:<runlevels>:<action>:<process>
<id>:每个指令的标识符,不能重复。但是对于 busybox 的 init 来说,有着特殊意义。对于 busybox 而言用来指定启动进程的控制 tty,一般我们将串口或者 LCD 屏幕设置为控制 tty。
<runlevels> :对 busybox 来说此项完全没用,所以空着。
<action>:动作,用于指定可能用到的动作。busybox 支持的动作如所示:
sysinit 在系统初始化的时候 process 才会执行一次。
respawn 当 process 终止以后马上启动一个新的。
askfirst
和 respawn类似,在运行 process 之前在控制台上显示“Please press Enter to activate
this console.”。只要用户按下“Enter”键以后才会执行 process。
wait 告诉 init,要等待相应的进程执行完以后才能继续执行。
once 仅执行一次,而且不会等待 process 执行完成。
restart 当 init 重启的时候才会执行 procee。
ctrlaltdel 当按下 ctrl+alt+del 组合键才会执行 process。
shutdown 关机的时候执行 process。
<process> :具体的动作,比如程序、脚本或命令等。
参考 busybox 的 examples/inittab 文件,我们也创建一个/etc/inittab,在里面输入如下内容:
1 #etc/inittab
2 ::sysinit:/etc/init.d/rcS
3 console::askfirst:-/bin/sh
4 ::restart:/sbin/init
5 ::ctrlaltdel:/sbin/reboot
6 ::shutdown:/bin/umount -a -r
7 ::shutdown:/sbin/swapoff -a
第 2 行,系统启动以后运行/etc/init.d/rcS 这个脚本文件。
第 3 行,将 console 作为控制台终端,也就是 ttymxc0。
第 4 行,重启的话运行/sbin/init。
第 5 行,按下 ctrl+alt+del 组合键的话就运行/sbin/reboot,看来 ctrl+alt+del 组合键用于重
启系统。
第 6 行,关机的时候执行/bin/umount,也就是卸载各个文件系统。
第 7 行,关机的时候执行/sbin/swapoff,也就是关闭交换分区。
/etc/inittab 文件创建好以后就可以重启开发板即可,至此!根文件系统要创建的文件就已经
全部完成了。
五、根文件系统其他功能测试
1、软件运行测试
在rootfs中,写一个hello.c 程序,用交叉编译器编译,开机后,测试是否能运行
2、中文字符测试
在rootfs 中,新建一个中文目录和中文文件,测试能否正常显示
3、程序开机自动测试
l
i
n
u
x
启
动
后
,
自
动
执
行
程
序
\color{#00FF00}{linux启动后,自动执行程序}
linux启动后,自动执行程序
修改/etc/init.d/rcS ,增加以下内容
14 #开机自启动程序
15 cd /drivers
16 ./hello &
17 cd /
开机,看hello程序能否自动运行
4、外网连接测试
ping www.baidu.com
测试失败 / # ping www.baidu.com
ping: bad address ‘www.baidu.com’
需要设置域名服务器
在 rootfs 中新建文件/etc/resolv.conf 内容如下:
1 nameserver 114.114.114.114
2 nameserver 192.168.1.1
红
色
\color{#FF0000}{红色}
红色
橙
色
\color{#FF7D00}{橙色}
橙色
黄
色
\color{#FFFF00}{黄色}
黄色
绿
色
\color{#00FF00}{绿色}
绿色
蓝
色
\color{#0000FF}{蓝色}
蓝色
靛
色
\color{#00FFFF}{靛色}
靛色
紫
色
\color{#FF00FF}{紫色}
紫色