iTOP4412制作最小根文件系统使用NFS挂载、烧写至EMMC两种方式
目录介绍
根文件系统是存放运行、维护系统所必须的各种工具、软件、库文件、脚本,配置文件和其他特殊文件的地方,也可以是安装各种软件的地方
/bin
可执行程序
/dev
块 , 字符设备节点文件
/lib
基本的库文件 如C库和内核模块 (modules)
/etc
主要配置文件和初始化文件
/linuxrc
init=/linuxrc 根文件系统挂载后运行的第一个程序
/proc
虚拟文件系统,用于内核和进程通讯
/sys
虚拟文件系统SYSFS挂载点
/usr
更多的用户程序
/mnt
挂载点,临时挂载文件系统
/sbin
基本的系统管理程序
/tmp
临时目录文件
/var
可变信息存储,如log等
制作根文件系统 使用busybox工具
一、前期准备
下载并解压busybox
https://busybox.net/
我使用的是busybox-1.22.1版本的
二、指定交叉编译器
修改Makefile 指定交叉编译器
三、配置busybox
busybox采用了和内核相同的菜单式选配方式,相当友好
make menuconfig
修改生成的根文件安装路径 也可以不修改
Busybox Settings –>
Installation Options (“make install” behavior) —>
四 、编译 安装
make
编译完成 安装
make install
五、创建相关目录
mkdir mnt dev sys proc etc var boot
六、创建配置文件
由于init=/linuxrc,因此,在文件系统挂载后,运行的第一个程序就是根目录下的linuxrc,而这是一个指向/bin/busybox 的链接,也就是说,系统起来后运行的第一个程序就是busybox本身。
busybox首先将试图解析/etc/inittab来获取进一步的初始化配置信息(参考busybox源代码init/init.c中的parse_inittab()函数)。而事实上,root_qtopia中并没有/etc/inittab这个配置文件,根据busybox的裸机,它将生成默认的配置。其中最重要的一个,就是new_init_action(SYSINIT,INIT_SCRIPT,””),也就决定了接下来初始化的脚本是INIT_SCRIPT所定义的值,这个宏的默认值是”etc/init.d/rcS”。
所以首先创建/etc/init.d/rcS文件,这里重点分析一下rcS文件
1、/etc/init.d/rcS
#! /bin/sh:
PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin:
runlevel=S
#运行级别
prevlevel=N
umask 022
#权限掩码 创建文件默认为 777-022 =755
export PATH runlevel pervlevel
trap ":" INT QUIT TSTP
#捕捉信号 SIGINT SIGQUIT SIGTSTP 然后执行":" 相当于忽视这几个信号
#只在init 进程捕捉这几个信号 这样就可以终止子进程
/bin/hostname yuan
#none:取消使用mount命令回显"xxx on /proc type proc (rw,noexec,nosuid,nodev)
#挂载文件系统
mount -t sysfs none /sys
#挂载proc 文件系统 为内核和内核模块将信息发送给进程
mount -t proc none /proc
#挂载 ramfs, 相当于把原本nandflash上的只读的/dev目录"覆盖上"一块可写的空的SDRAM
mount -t ramfs none /dev
#/sys 和挂载了ramfs的/dev是正确创建设备节点的关键 对于如今的内核已经没有devfs的支持,创建设备节点只有通过两种办法由文件系统完成:
1)制作文件系统镜像前用mknod手动创建好系统所有的(包括可能有的)设备节点,
并把这些节点文件一起做进文件系统镜像中;
2)在文件系统初始化过程中,通过/sys目录所输出的信息,
在/dev目录下动态的创建系统中当前实际有的设备节点。
显然,方法1)有很大的局限性,仅限于没有设备动态增加或减少的情况,
不适用于很多设备热插拔的情况,比如U盘,SD卡等等。
方法2)是目前大多数PC上的linux的做法(基于udev实现)。
这种方法有2个前提:/sys目录挂载和一个可写的/dev目录。这也就是为什么我们这里需要挂载/sys和ramfs在/dev目录上,事实上,这种方法最早就是为热插拔设计的,你可以理解为当系统启动时,所有设备一下子全部"插入"了进来。
这里有一点要说明的是,在文件系统初始化跑到这里之前,原来的/dev目录下必须有一个设备节点:/dev/console。
其实,要搞清楚"程序"这种东西,没有什么好的办法,无非2个东西,源码和脚本
echo /sbin/mdev > /proc/sys/kernel/hotplug
#热插拔 把/sbin/mdev写到/proc/sys/kernel/hotplug,内核会读取里面的内容,当有热插拔时间时,会调用这个函数
/sbin/mdev -s
/bin/hotplug
##这几个就是用来完成上面所说的两个东西:1)通过mdev -s在/dev目录下创建必要的设备节点;2)设置内核的hotplug handler 为mdev,即当设备热插拔时,由mdev接受来自内核的消息并作出相应的回应,比如挂载U盘。
mkdir -p /dev/pts
mkdir -p /dev/shm
/bin/mount -n -t devpts none /dev/pts -o mode=0622
/bin/mount -n -t tmpfs tmpfs /dev/shm
#作用可以了解目前虚拟终端(telent,ssh等)的基本情况
mkdir -p /var/empty
mkdir -p /var/log
mkdir -p /var/log/boa
mkdir -p /var/lock
mkdir -p /var/run
mkdir -p /var/tmp
/etc/rc.d/init.d/netd start
#启动网卡
/sbin/ifconfig lo 127.0.0.1
/etc/init.d/ifconfig-eth0
#对网卡进行配置
2、profile
USER="`id -un`"
LOGNAME=$USER
PS1='[$USER@$HOSTNAME]# '
#终端前面的提示符
HOSTNAME=`/bin/hostname`
PATH=$PATH
export USER LOGNAME PS1 PATH
3、password(可以直接copy虚拟机上的root用户)
root::0:0:root:/:/bin/sh
bin:*:1:1:bin:/bin:
daemon:*:2:2:daemon:/sbin:
nobody:*:99:99:Nobody:/:
~
4、eth0-setting
IP=192.168.12.166
Mask=255.255.255.0
Geteway=192.168.1.1
DNS=192.168.1.1
MAC=08:90:90:90:90:90
5、/etc/rc.d/init.d/netd
#! /bin/sh
base=inetd
case "$1" in
start)
/usr/sbin/$base
;;
stop)
pid='/bin/pidof %base'
if [ -n "$pid" ]; then
kill -9 $pid
fi
;;
esac
6、/etc/init.d/ifconfig-eth0
#!/bin/sh
source /etc/eth0-setting
ifconfig eth0 down
ifconfig eth0 hw ether $MAC
ifconfig eth0 $IP netmask $Mask up
route add default gw $Geteway
echo eth0 interface done > /dev/ttySAC2
七、生成ext4文件格式镜像 并烧写至EMMC
执行以下命令
make_ext4fs -s -l 314572800 -a root -L Linux system.img system
使用fastboot烧写至emmc
结果出错了!!
Kernel panic – not syncing: Requested init /linuxrc failed (error -13)
错误在这里定义:在Linux源码目录/include/uapi/asm-generic的errno-base.h中
#define EPERM 1 /* Operation not permitted */
#define ENOENT 2 /* No such file or directory */
#define ESRCH 3 /* No such process */
#define EINTR 4 /* Interrupted system call */
#define EIO 5 /* I/O error */
#define ENXIO 6 /* No such device or address */
#define E2BIG 7 /* Argument list too long */
#define ENOEXEC 8 /* Exec format error */
#define EBADF 9 /* Bad file number */
#define ECHILD 10 /* No child processes */
#define EAGAIN 11 /* Try again */
#define ENOMEM 12 /* Out of memory */
#define EACCES 13 /* Permission denied */
#define EFAULT 14 /* Bad address */
#define ENOTBLK 15 /* Block device required */
#define EBUSY 16 /* Device or resource busy */
#define EEXIST 17 /* File exists */
#define EXDEV 18 /* Cross-device link */
#define ENODEV 19 /* No such device */
#define ENOTDIR 20 /* Not a directory */
#define EISDIR 21 /* Is a directory */
#define EINVAL 22 /* Invalid argument */
#define ENFILE 23 /* File table overflow */
#define EMFILE 24 /* Too many open files */
#define ENOTTY 25 /* Not a typewriter */
#define ETXTBSY 26 /* Text file busy */
#define EFBIG 27 /* File too large */
#define ENOSPC 28 /* No space left on device */
#define ESPIPE 29 /* Illegal seek */
#define EROFS 30 /* Read-only file system */
#define EMLINK 31 /* Too many links */
#define EPIPE 32 /* Broken pipe */
#define EDOM 33 /* Math argument out of domain of func */
#define ERANGE 34 /* Math result not representable */
原因是显示没有权限
有一个问题是,使用这样制作的镜像,system分区文件的权限都是预定的,即使先修改system目录文件权限后在制作镜像,烧入设备后,其权限仍未改变。关键问题在make_ext4fs工具,在制作ext4fs时更改了权限,其依据为system/core/private/android_ilesystem_config.h所定义的权限。
“-a system”,是指这个img用于android系统,挂载点是/system,使用这个参数,make_ext4fs会根据private/android_filesystem_config.h里定义好的权限来给文件夹里的所有文件重新设置权限,如果你刷机以后发现有文件权限不对,可以手工修改android_filesystem_config.h来添加权限,重新编译make_ext4fs,也可以不使用 “-a system”参数,这样就会使用文件的默认权限。
去掉-a选项即可
重新制作system.img
make_ext4fs -s -l 314572800 -L Linux system.img system
烧写、启动 ——-成功!
为了这个根文件系统来回烧写了好多次,实在是麻烦,因而使用一种更加方便高效的方式使用nfs挂载根文件系统
八、使用NFS服务挂载根文件系统
1、准备工作
在主机上安装并配置NFS服务
apt-get install nfs-kernel-server
配置nfs服务 进入/etc/exports
其中/home/nfs/system放的是最小文件系统不是img镜像,我当时挂载时挂载成了system.img,然后死活挂载不上
[ 7.413837] VFS: Mounted root (nfs filesystem) on device 0:16.
[ 7.421726] devtmpfs: error mounting -2
[ 7.426034] Freeing unused kernel memory: 1024K
[ 7.460197] Run /linuxrc as init process
[ 7.467259] Kernel panic - not syncing: Requested init /linuxrc failed (error -2).
[ 7.883171] ---[ end Kernel panic - not syncing: Requested init /linuxrc failed (error -2). ]---
#define ENOENT 2 /* No such file or directory */
启动nfs服务
/etc/init.d/nfs-kernel-server start
2、修改uboot的bootargs参数
Setenv bootargs ‘root=/dev/nfs rw nfsroot=192.168.12.144:/home/nfs/system,proto=tcp ip=192.168.12.166:192.168.12.144::255.255.255.0:itop:eth0:off init=/linuxrc console=ttySAC2,115200’
设置为以nfs方式启动
参数详解
root=/dev/nfs nfsroot=server-ip:root-dir,nfs-options ip=client-ip:server-ip:gwip:netmask:hostname:device:autoconf:dns0-ip:dns1-ip
server-ip:服务器 IP 地址,也就是存放根文件系统主机的 IP 地址,那就是 Ubuntu 的 IP
地址,比如我的 Ubuntu 主机 IP 地址为 192.168.12.144
root-dir: 根文件系统的存放路径,比如我的就是/home/nfs/system。
nfs-options: NFS 的其他可选选项 例如proto=tcp,使用tcp传输
client-ip: 客户端 IP 地址,也就是我们开发板的 IP 地址, Linux 内核启动以后就会使用
此 IP 地址来配置开发板。此地址一定要和 Ubuntu 主机在同一个网段内,并且没有被其他的设
备使用,在 Ubuntu 中使用 ping 命令 ping 一下就知道要设置的 IP 地址有没有被使用,如果不能
ping 通就说明没有被使用,那么就可以设置为开发板的 IP 地址,比如我就可以设置为
192.168.12.166。
server-ip: 服务器 IP 地址,即ubuntu的IP地址。
gw-ip: 网关地址,我的就是 192.168.1.1。
netmask:子网掩码,我的就是 255.255.255.0。
hostname:客户机的名字,一般不设置,此值可以空着,但是“:”不能少。
device: 设备名,也就是网卡名,一般是 eth0, eth1….
autoconf: 自动配置,一般不使用,所以设置为 off。
dns0-ip: DNS0 服务器 IP 地址,不使用。
dns1-ip: DNS1 服务器 IP 地址,不使用。
3、修改最小根文件系统/home/nfs/system/etc/init.d/rcS
因为我们已经在bootargs中设置了IP 这几个脚本是用来设置网卡信息的,会重启网卡那样nfs便会断开无法进入根文件系统
如果出现挂载不上的话,首先看看客户机有没有启动nfs服务,然后检查参数是否正确
极大可能是参数问题