构建根文件系统:
创建根文件系统主目录/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
#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
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