嵌入式系统移植之根文件系统制作

根文件系统的基本概念

什么是根文件系统

根文件系统(root filesystem)是存放运行、维护系统所必须的各种工具软件、库文件、脚本、配置文件和其他特殊文件的地方,也可以安装各种软件包。

根文件系统主要目录结构

程序文件的放置

程序文件目录
    /bin: 普通用户和root用户都能执行的基本程序
    ping, mknod, mount, tar, grep, gzip, etc
    /sbin: root用户能执行的基本程序
    int, insmod, route, mkfs, rmmod, ifconfig
    /usr/bin: 更多非必须的用户程序
    autorun, bibtex, latex, biff, ftp, wc, whereis, whoami
    /usr/sbin: 更多非必须的root工具程序
    automount, httpd, in.telnetd, in.talkd, sendmail

定制应用程序

配置基本的linux命令(嵌入式linux通过busybox制作)
cat, chmod, chown, cp, chroot, copi, date, dd, df, dmesg, dos2unix, du, echo, env, 
expr, find, grep, gunzip, gzip, halt, id, ifconfig, init, insmod等等
配置用户自己的应用
桌面管理器等等

库文件的放置

/lib: 系统和运行基本命令时需要的动态库文件
/usr/lib:所有的其他库
/usr/lib/xxx: 一些工具包的私有库
如:/usr/lib/perl5

根文件系统设备访问

Linux 设备文件

Linux 系统中所有的对象(包括设备)都是以文件的形式体现的
Linux系统中,所有的设备文件(如:设备节点),通常放到 /dev下
嵌入式系统中只需要创建必须的设备节点即可

字符设备

字符设备是指在I/O传输过程中以字符为单位进行传输的设备,应用程序可以顺序读取,通常不支持随机存取。
典型设备
keyboards, mice, parallel port, IrDA, Bluetooth port, consoles, terminals, sound, video...

ls –l  /dev/  “c” 指明该设备节点是字符设备
crw-rw---- 1 root uucp  4,    64 Feb 23 2004 /dev/ttyS0     
    //c-字符设备 rw-可读可写 4-主设备号 64-次设备号 ttyS0-0号串口
crw--w---- 1 jdoe tty    136, 1   Feb 23 2004 /dev/pts/1
crw-------- 1 root root   13,   32 Feb 23 2004 /dev/input/mouse0
crw-rw-rw 1 root root   1,    3    Feb 23 2004 /dev/null

块设备

块设备是i/o设备中的一类,是将信息存储在固定大小的块中,每个块都有自己的地址,
应用程序可以随机访问设备数据,程序可自行确定读取数据的位置。

典型块设备
磁盘, ramdisk,SD,U盘等等

设备的主设备号次设备号

Linux系统是通过主设备号和次设备号来区分设备的

内核中的相关文档 Documentation/admin-guide/devices.txt
(不同版本内核存储位置略有不同,搜devices.txt即可)

字符设备 块设备的区分

每一个字符设备或者块设备都在/dev目录下对应一个设备文件。

[root@tom /]# cd /dev                           /*进入/dev目录*/  
[root@tom dev]# ls -l                           /*列出/dev中文件的信息*/、 
 /*第1字段       2  3   4      5     6         7      8  */  
crw-rw----+     1 root root    14,  12  12-21 22:56 adsp  
crw-------      1 root root    10, 175  12-21 22:56 agpgart  
crw-rw----+     1 root root    14,   4  12-21 22:56 audio  
brw-r-----      1 root disk   253,   0  12-21 22:56 dm-0  
brw-r-----      1 root disk   253,   1  12-21 22:56 dm-1  
crw-rw----      1 root root    14,   9  12-21 22:56 dmmidi 

ls -l命令的第一字段中的第一个字符c表示设备是字符设备,b表示设备是块设备。第234字段对驱动程序开发来说没有关系。第5,6字段分别表示设备的主设备号和次设备号。第7字段表示文件的最后修改时间。第8字段表示设备的名字。
由第1和8字段可知,adsp是字符设备,dm-0是块设备。其中adsp设备的主设备号是14,次设备号是12。

根文件系统创建设备节点

设备文件不能在加载驱动程序时自动创建,要通过指令创建
创建设备文件的一般语法:

$ mknod /dev/<device> [c|b] <major> <minor>
例如:
$ mknod  /dev/ttySAC0  c  4  64
$ mknod  /dev/hda1  b  3  1

基本的设备节点

根文件系统内容制作

文件系统制作步骤

  1. 制作根文件系统的内容
    采用Busybox创建基本命令
    创建基本的目录 /lib /etc /var /tmp /dev /sys /proc等
    添加glibc基本动态库
    创建基本的设备节点
    添加启动配置和脚本程序 /etc/inittab /etc/fstab /etc/init.d/rcS
  2. 测试rootfs内容正确性
  3. 制作需要的rootfs类型的格式

BusyBox项目构建系统命令

Busybox是一个UNIX系统工具集,它将很多普通的UNIX工具集成到一个很小的可执行文件中,为普通用户提供大多数常用的命令;
BusyBox常用于制作linux命令 主要指令包括
cat, chmod, chown, cp, chroot, copi, date, dd, df, dmesg, dos2unix, du, echo, env, expr, find, grep, gunzip, gzip, halt, id, ifconfig, init, insmod, etc

创建根文件系统示例

  1. https://busybox.net/ 下载最新稳定版本的BusyBox

  2. 解压文件

    tar -vxf busybox-1.31.1.tar.bz2 
  1. 配置文件
    make -j6 menuconfig

  1. 编译并安装Busybox
    make -j6
    make install -j6        //在install之前,如果/_install目录下有rootfs目录,先删除。

安装成功后,生成以下目录。

linux@ubuntu:~/Level10/day8/busybox-1.31.1/_install$ ls
bin  linuxrc  sbin  usr
  1. 拷贝共享库文件。
linux@ubuntu:~/Level10/day8/busybox-1.31.1/_install$ sudo cp -a /home/linux/gcc-4.6.4/arm-arm1176jzfssf-linux-gnueabi/lib/ .
linux@ubuntu:~/Level10/day8/busybox-1.31.1/_install$ du -h lib
284K	lib/ldscripts
15M	lib
linux@ubuntu:~/Level10/day8/busybox-1.31.1/_install$ sudo rm lib/*.a   #删除静态文件库,缩减体积
linux@ubuntu:~/Level10/day8/busybox-1.31.1/_install$ du -h lib
284K	lib/ldscripts
7.0M	lib

arm-none-linux-gnueabi-strip lib/*.so  # 如有必要还可以用此命令 裁剪共享库文件,减小体积
  1. 添加其他目录。重新进入到rootfs目录,生成相应的目录。
linux@ubuntu:~/Level10/day8/busybox-1.31.1/_install$ mkdir dev etc home mnt proc root sys tmp var
linux@ubuntu:~/Level10/day8/busybox-1.31.1/_install$ mkdir etc/init.d
  1. 添加/etc/inittab文件,文件内容如下。
::sysinit:/etc/init.d/rcS       #指定系统开始运行后,最开始运行的脚本,可修改但不建议
::askfirst:-/bin/login
::ctrlaltdel:/sbin/reboot
::shutdown:/sbin/swapoff -a
::shutdown:/bin/umount -a -r
::restart:/sbin/init
ps:
/etc 目录下都是配置文件。这里配置的inittab 是linuxrc执行后最先执行的配置脚本文件之一
  1. 添加/etc/ init.d/rcS文件,文件内容如下。
#!/bin/sh

mount -a                                #挂载一切可以挂载的根文件系统
mkdir /dev/pts                          #挂载pts文件,可以让开发板启动后可以看到提示符[root@fs4412 ]#
mount -t devpts devpts /dev/pts         
echo /sbin/mdev > /proc/sys/kernel/hotplug #支持热插拔
mdev -s
#此处可添加一些个性化的内容 如insmod led.ko ./a.out 驱动的加载命令或程序的执行命令等等
hostname -F /etc/hostname

接下来添加该文件的可执行权限。

$ chmod +x etc/init.d/rcS
  1. 添加/etc/fstab文件,文件内容如下。 (指定挂载的根文件系统)
proc    /proc   proc    defaults        0       0
none    /tmp    tmpfs   defaults        0       0
none    /dev    tmpfs   defaults        0       0
sysfs   /sys    sysfs   defaults        0       0
  1. 添加/etc/group文件,文件内容如下。
root:x:0:root
  1. 添加/etc/passwd文件,文件内容如下。
root:x:0:0:root:/root:/bin/sh
  1. 添加/etc/shadow文件,文件内容如下。
root:BcPgSBqZz80dw:0:0:99999:7:::
  1. 添加/etc/hostname文件,文件内容如下。
fs4412
  1. 添加/etc/profile文件,文件内容如下。
LD_LIBRARY_PATH=/lib:/usr/lib
export LD_LIBRARY_PAHT                      

PATH=/bin:/sbin:/usr/bin:/usr:/sbin         # 配置环境变量
export PATH
export PS1=\\e[32m[\\u@\\h \\W\\a]\\$\\e[00;37m     # PS1后面的是终端显示的内容 如[root@fs4412 ]  可修改
  1. console设备节点
linux@ubuntu:~/Level10/day8/busybox-1.31.1/_install$ sudo mknod   dev/console  c  5  1     // 必须要有  console设备节点  
  1. 如仍不能正常NFS挂载根文件系统,尝试修改权限
chmod 777 /挂载的文件地址/rootfs

制作需要的rootfs类型的格式

制作ramdisk镜像文件 (ext2文件格式)

  1. 进入到/nfs目录,使用下面的命令制作镜像
linux@ubuntu:~/nfs$ dd if=/dev/zero of=ramdisk bs=1k count=16384        
    //dd命令用来制作镜像文件,if=input file 输入文件 /dev/zero是一个虚拟设备 里面数据全部为0
    //of =output file 输出文件 文件名为ramdisk 这个随意写。bs 是一个单位所占的空间,count是单位的数量。

linux@ubuntu:~/nfs$ mkfs.ext2 -F ramdisk                //将ramdisk制作成ext2的文件格式
linux@ubuntu:~/nfs$ sudo mount -t ext2 ramdisk /mnt    //因为无法直接将文件复制进ramdisk,所以需要通过挂载来实现
linux@ubuntu:~/nfs$ sudo cp -a /home/linux/Level10/day8/busybox-1.31.1/_install/* /mnt
linux@ubuntu:~/nfs$ sudo umount /mnt
linux@ubuntu:~/nfs$ gzip --best -c ramdisk>ramdisk.gz   //压缩ramdisk为ramdisk.gz 
linux@ubuntu:~/nfs$ mkimage -n "ramdisk" -A arm -O linux -T ramdisk -C gzip -d ramdisk.gz ramdisk.img
    //将格式转化为uboot识别的模式
  1. 拷贝制作好的.img镜像文件到TFTP服务器指定的目录。

  2. 接下来,重新配置内核,选择ramdisk的支持并指定大小。

File systems  --->
		<*> Second extended fs support
Device Drivers
		SCSI device support  --->
			<*> SCSI disk support
		Block devices  --->
			<*>RAM  block  device  support   
			(16)Default number of RAM disks  
			(16384) Default RAM disk size (kbytes)
General setup  --->
		[*] Initial RAM filesystem and RAM disk (initramfs/initrd) support

上面的配置项多数都已配置,主要是修改了ramdisk的大小为16384,这个值必须要和ramdisk镜像文件的大小保持一致。保存配置后,重新编译内核,再将uImage文件拷贝到tftp服务器指定的目录下。

  1. 开发板上电,在U-Boot中设置bootcmd环境变量如下。
setenv bootcmd tftp 41000000 uImage\; tftp 42000000 exynos4412-origen.dtb\; tftp 43000000 ramdisk.img\; bootm 41000000 43000000 42000000
bootargs console=ttySAC2,115200         //修改bootargs,这步可以省略,对最后结果没影响。
saveenv

烧写内核镜像文件

【实验目的】
掌握内核镜像文件的烧写方法。
说明:在实验中命令行提示符为“$”表示在主机上运行,“#”表示在目标板上运行。
【实验环境】

  1. Ubuntu 12.04发行版
  2. FS4412平台
    【实验步骤】
  3. 从SD卡启动。
  4. 下载uImage到开发板的内存中,并烧写至SD卡。
FS4412 # tftpboot 40000000 uImage
FS4412 # mmc write 40000000 400 3400
  1. 下载设备树到开发板的内存中,并烧写至SD卡。
FS4412 # tftpboot 40000000 exynos4412-fs4412.dtb
FS4412 # mmc write 40000000 3800 800
  1. 设置环境变量,验证内核镜像烧写成功。
FS4412 # setenv bootcmd mmc read 41000000 400 3400\; mmc read 42000000 3800 800\; bootm 41000000 - 42000000
FS4412 # setenv bootargs noinitrd root=/dev/nfs nfsroot=192.168.10.100:/nfs/rootfs rw console=ttySAC2,115200 init=/linuxrc ip=192.168.10.200
FS4412 # saveenv
FS4412 # boot
  1. 重启开发板,从eMMC启动。重复上面的步骤2-步骤4,将内核镜像烧写到eMMC中。

固化根文件系统到SD/eMMC

【实验目的】
掌握内核镜像文件的烧写方法。
说明:在实验中命令行提示符为“$”表示在主机上运行,“#”表示在目标板上运行。
【实验环境】

  1. Ubuntu 12.04发行版
  2. FS4412平台
    【实验步骤】
  3. 在上一实验的基础上从SD卡启动,直至系统最终启动成功。
  4. 对SD卡进行分区。
[root@fs4412 ~]# fdisk /dev/mmcblk0

注意,如果已有分区,请删除分区。可以用p命令确认。

Command (m for help): p

Disk /dev/mmcblk0: 8010 MB, 8010072064 bytes
4 heads, 16 sectors/track, 244448 cylinders
Units = cylinders of 64 * 512 = 32768 bytes

        Device Boot      Start         End      Blocks  Id System

接下来新建一个分区。

Command (m for help): n
Command action
   e   extended
   p   primary partition (1-4)
p
Partition number (1-4): 1
First cylinder (1-244448, default 1): 512
Last cylinder or +size or +sizeM or +sizeK (512-244448, default 244448): Using default value 244448

Command (m for help): w
The partition table has been altered.
Calling ioctl() to re-read partition table
[   34.470000]  mmcblk0: p1

上面分区从第512个柱面开始(命令显示每个柱面为32KB),跳过了内核镜像的烧写区域。
3. 格式化SD卡的新建分区。

[root@fs4412 ~]# mkfs.ext2 /dev/mmcblk0p1
  1. 拷贝根文件系统到SD卡的新建分区。
[root@fs4412 ~]# mkdir mmc
[root@fs4412 ~]# mount -t ext2 /dev/mmcblk0p1 mmc/
[root@fs4412 ~]# mount -t nfs -o nolock 192.168.10.100:/nfs/rootfs/mnt
[root@fs4412 ~]# cp -a /mnt/* mmc/
[root@fs4412 ~]# rm -rf mmc/root/mmc/
[root@fs4412 ~]# sync
[root@fs4412 ~]# umount mmc
[root@fs4412 ~]# umount /mnt
[root@fs4412 ~]# rm -rf mmc
  1. 重新启动开发板,设置环境变量。
FS4412 # setenv bootargs root=/dev/mmcblk0p1 rw noinitrd console=ttySAC2,115200 init=/linuxrc
FS4412 # saveenv
FS4412 # boot

内核启动后从SD卡挂载根文件系统。

[    1.780000] VFS: Mounted root (ext2 filesystem) on device 179:1.
[    1.785000] devtmpfs: mounted
[    1.790000] Freeing unused kernel memory: 232K (c05a7000 - c05e1000)
[    1.990000] usb 1-3: new high-speed USB device number 2 using exynos-ehci
[    2.125000] hub 1-3:1.0: USB hub found
[    2.130000] hub 1-3:1.0: 3 ports detected

Please press Enter to activate this console. 
fs4412 login: root
Password: 
login[1233]: root login on 'console'
[root@fs4412 ~]#
  1. 从eMMC启动。重复步骤2-5,将根文件系统固化在eMMC上。