构建根文件系统:
创建根文件系统主目录/nfsroot/rootfs (/nfsroot问nfs文件系统共享目录,开发板可将他作为网络根文件系统直接启动)
mkdir -p /nfsroot/rootfs (-p表示如果创建目录的父目录不存在,则创建父目录)
cd /nfsroot/rootfs
mkdir bin dev etc lib proc sbin sys usr mnt tmp var
mkdir usr/bin usr/sbin usr/lib lib/modules
创建设备文件(可自行创建,或者通过mdev生成)
内核在引导时,设备节点console,null必须存在(使用mdev的情况下,不使用mdev还要创建其他设备文件)
mknod -m 666 console c 5 1
mknod -m 555 null c 1 3
构建etc目录
init进程根据/etc/inittab文件来创建其他子进程。
仿照busybox的examples/inittab文件(ubuntu默认不创建,所以找不到这个文件,但可自行创建,系统还是首先搜索inittab进行配置)
#格式(<id>:<runlevels>:<action>:<process>)
#id:子进程要使用的控制台(标准输入、标准输出、标准错误设备),如果省略,则使用与init进程一样的控制台
#runlevels:对于busybox init无意义
#action:表示init进程如何控制这个子进程(sysinit\wait\once\respawn\askfirst\shutdown\restart\ctrlaltdel)
#process:要执行的程序,可执行程序或者脚本(如字段前有“-”字符,程序为”交互的“)
# /etc/inittab
#init进程启动的第一个子进程,是一个脚本,可以在里面指定用户想执行的操作,如挂接其他文件系统,配置网络等
#脚本文件,可在rcS中添加想自动执行的命令
::sysinit:/etc/init.d/rcS
#启动shell,已/dev/ttySAC0为控制台(如果通过mdev生成,则为s3c2440_serial0)
ttySAC0::askfirst:-/bin/sh
#按下ctrl+alt+del之后执行的程序
::ctrlaltdel:/sbin/reboot
#重启、关机前执行的程序
::shutdown:/bin/umount -a -r
创建etc/init.d/rcS文件
脚本文件,可在里面添加想自动执行的命令
#表示这是一个脚本文件,运行时用/bin/sh解析
#!/bin/sh
#用来配置ip地址
ifconfig eth0 192.168.1.17
#挂接/etc/fstab文件指定的所有文件系统
mount -a
创建etc/fstab文件
#device 要挂接的设备
#如/dev/hda2、/dev/mtdblock1等设备文件;对于proc文件系统。此字段无意义,可是任意值;对于NFS文件系统,此字段为<host>:<dir>
#proc文件系统为伪文件系统,存储内核当前运行状态的一系列特殊文件
#mount-point 挂接点
#type 文件系统类型
#option 挂接参数
#device mount-point type options dump fsck order
proc /proc proc defaults 0 0
tmpfs /tmp tmpfs defaults 0 0
也可参考busybox中的/docs/mdev.txt使用mdev创建设备文件。
解释语句:
#mdev需要内核支持sysfs文件系统,使用tmpfs减少对Flash的读写
mount -t tmpfs mdev /dev
#dev/pts用来支持外部网络连接的虚拟终端
mkdir /dev/pts
mount -t devpts devpts /dev/pts
#通过sysfs文件系统获得设备信息
mount -t sysfs sysfs /sys
#设置内核,当有设备拔插时调用/bin/mdev程序
echo /bin/mdev > /proc/sys/kernel/hotplug
#在/dev目录下生成内核支持的所有设备的节点
mdev -s
制作ysffs文件系统映像文件(Yet Another Flash File System)
make出现错误,暂不能解决
Linux启动init进程程序init/main.c介绍
/* This is a non __init function. Force it to be noinline otherwise gcc
* makes it inline to init() and it becomes part of init.text section
*/
static noinline int init_post(void)
{
/* need to finish all async __init code before freeing the memory */
async_synchronize_full();
free_initmem();
unlock_kernel();
mark_rodata_ro();
system_state = SYSTEM_RUNNING;
numa_default_policy();
//在这里打开/dev/console设备,如果成功则它就是init进程控制终端
if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0)
printk(KERN_WARNING "Warning: unable to open an initial console.\n");
//将文件描述符0赋给标准输出、标准错误,则标准输入,输出,错误,对应同一设备
(void) sys_dup(0);//1
(void) sys_dup(0);//2
current->signal->flags |= SIGNAL_UNKILLABLE;
if (ramdisk_execute_command) { //ramdisk_execute_command指定要运行的程序
//1、命令行参数指定了“rdinit=”,则ramdisk_execute_command等于参数指定程序
//2、如果/init程序存在,则XXX等于“/init”
//3、不满足上面2条件,XXX为空
run_init_process(ramdisk_execute_command);
printk(KERN_WARNING "Failed to execute %s\n",
ramdisk_execute_command);
}
/*
* We try each of these until one succeeds.
*
* The Bourne shell can be used instead of init if we are
* trying to recover a really broken machine.
*/
if (execute_command) {//如果命令行参数中指定了“init=...”,则execute_command等于这个参数指定的程序,否则为空
run_init_process(execute_command);
printk(KERN_WARNING "Failed to execute %s. Attempting "
"defaults...\n", execute_command);
}
//依次尝试执行/sbin/init、/etc/init、/bin/init、/bin/sh
run_init_process("/sbin/init");
run_init_process("/etc/init");
run_init_process("/bin/init");
run_init_process("/bin/sh");
panic("No init found. Try passing init= option to kernel.");
}
static static char * argv_init[MAX_INIT_ARGS+2] = { "init", NULL, };//程序名
char * envp_init[MAX_INIT_ENVS+2] = { "HOME=/", "TERM=linux", NULL, };//执行/sbin/init的环境参数
void run_init_process(char *init_filename)
{
argv_init[0] = init_filename;
kernel_execve(init_filename, argv_init, envp_init);
}
busybox init启动情况
static void console_init(void)
{
struct serial_struct sr;
char *s;
s = getenv("CONSOLE"); //如果有设置环境变量CONSOLE或者console则根据环境变量使用指定设备
if (!s) s = getenv("console");
if (s) {
int fd = open(s, O_RDWR | O_NONBLOCK | O_NOCTTY);
if (fd >= 0) {
dup2(fd, 0); //使标准输入输出错误联系到同一设备
dup2(fd, 1);
dup2(fd, 2);
while (fd > 2) close(fd--);//除上述句柄,关闭其他句柄
}
messageD(L_LOG, "console='%s'", s);
} else {
/* Make sure fd 0,1,2 are not closed */
bb_sanitize_stdio();
}
s = getenv("TERM");
if (ioctl(0, TIOCGSERIAL, &sr) == 0) {
/* Force the TERM setting to vt102 for serial console --
* if TERM is set to linux (the default) */
if (!s || strcmp(s, "linux") == 0)
putenv((char*)"TERM=vt102");
#if !ENABLE_FEATURE_INIT_SYSLOG
log_console = NULL;//如果上述设备不能打开,则使用/dev/null
#endif
} else if (!s)
putenv((char*)"TERM=linux");
}
编译busybox,执行
make CONFIG_PREFIX=/nfsroot/rootfs install
将busybox安装到/rootfs目录下
目标目录下sbin bin下的命令都是busybox的软连接
使用glibc库
在开发板上只需要加载器和动态库(基本含有so字符的都属于两者之一)
进入交叉编译器源目录中的lib将其中的加载器和动态库拷贝至根目录文件的lib中
使用mkyaffsimage制作yaffs映像文件
进入根文件目录
sudo mkyaffsimage rootfs rootfs.yaffs