uboot - kernel - 根文件系统 - 应用
根文件系统,它是内核启动时所挂载(mount)的第一个文件系统,内核代码的映像文件保存在根文件系统中,系统引导启动程序会在根文件系统挂载之后从中把一些初始化脚本(如rcS,inittab)和服务加载到内存中去运行。
1BootLoader
需要需要修改的:
bootcmd
网络参数
bootargs 内核参数
1.1 bootargs 内核参数
语法: < name > = < value >
常见:
配置Linux内核
- 从官网下载的源码解压之后有这些文件;
- 这里面都是一些Linux支持的官方开发板;
- 在arm/configs中是一些已经准备好的配置;这些配置是对内核的设置,什么编译进去内核等等。
5. Linux-4.9.88$ vi Makefile ,对CROSS_COMPILE和ARCH进行配置;
6. 图形化界面make menuconfig配置也就是以上步骤的图形化,最后都会生成一个隐藏的.config文件;用于编译镜像内核。
7. 进行配置,make config。这个是使用make menuconfig配置的内容;也可以使用make 100ask_imx6ull_defconfig,使用别人写好的配置;这些对镜像没有影响,但是影响设备树。
8. 编译镜像文件,make zImage -j6
9. 编译内核模块,make modules -j4
10. 编译设备树,make dtbs。
11.实际上生成的 zImage 是一个通用的内核文件,而dtbs可以表示特定的平台了。
最后生成如图,可以看到设备树和你用的配置相关。
3 根文件系统
3.1 根文件系统
1、Linux启动后;其他文件系统挂载的挂载点(也是一个目录)。
2、这是因为kernel的VFS机制支持很多文件系统。
3.2 根文件系统的组成
1、根文件存在的位置必须能让内核读取;内核必须支持根文件所在介质的驱动;
2、init=/linuxrc 指定了Linux第一个用户程序,该程序存在在根文件内;
3、基本的目录和配置文件。
举个栗子:
在启动内核之前,修改一下bootargs
setenv bootargs 'boot=/dev/nfs nfs=192.168.5.11:/home/lcx/mini_Linux_system ip=192.168.5.9 init=/linuxrc console=ttySAC0,115200'
由于已经实现使用busybox写好了linuxrc 所以能正常启动。
如果报错去/linux-4.xx.xx 下查看Documentation/init.r=txt
4 生成根文件
4.1 根文件系统定制 于busybox编译之前完成的
linuxrc是初始化程序,是一个链接
lrwxrwxrwx 1 lcx lcx 11 Oct 11 08:13 linuxrc -> bin/busybox
本质上busybox的elf文件,一个二进制文件。
4.1.1 理解初始化函数(inittab和rcS)
/home/lcx/source/busybox-1.27.0/init/init.c
--------------
/* Figure out where the default console should be */
console_init();
set_sane_term();
xchdir("/");
setsid();
....
parse_inittab(); //调用配置文件
static void parse_inittab(void)
{
#if ENABLE_FEATURE_USE_INITTAB
char *token[4];
parser_t *parser = config_open2("/etc/inittab", fopen_for_read);
if (parser == NULL)
#endif
{
/* No inittab file - set up some default behavior */
/* Sysinit */
new_init_action(SYSINIT, INIT_SCRIPT, "");
/* Askfirst shell on tty1-4 */
new_init_action(ASKFIRST, bb_default_login_shell, "");
//TODO: VC_1 instead of ""? "" is console -> ctty problems -> angry users
new_init_action(ASKFIRST, bb_default_login_shell, VC_2);
new_init_action(ASKFIRST, bb_default_login_shell, VC_3);
new_init_action(ASKFIRST, bb_default_login_shell, VC_4);
/* Reboot on Ctrl-Alt-Del */
new_init_action(CTRLALTDEL, "reboot", "");
/* Umount all filesystems on halt/reboot */
new_init_action(SHUTDOWN, "umount -a -r", "");
/* Swapoff on halt/reboot */
new_init_action(SHUTDOWN, "swapoff -a", "");
/* Restart init when a QUIT is received */
new_init_action(RESTART, "init", "");
return;
}
#if ENABLE_FEATURE_USE_INITTAB
/* optional_tty:ignored_runlevel:action:command
* Delims are not to be collapsed and need exactly 4 tokens
*/
while (config_read(parser, token, 4, 0, "#:",
PARSE_NORMAL & ~(PARSE_TRIM | PARSE_COLLAPSE))) {
/* order must correspond to SYSINIT..RESTART constants */
//支持的八种动作类型
static const char actions[] ALIGN1 =
"sysinit\0""wait\0""once\0""respawn\0""askfirst\0"
"ctrlaltdel\0""shutdown\0""restart\0";
int action;
char *tty = token[0];
if (!token[3]) /* less than 4 tokens */
goto bad_entry;
action = index_in_strings(actions, token[2]);
if (action < 0 || !token[3][0]) /* token[3]: command */
goto bad_entry;
/* turn .*TTY -> /dev/TTY */
if (tty[0]) {
tty = concat_path_file("/dev/", skip_dev_pfx(tty));
}
new_init_action(1 << action, token[3], tty);
if (tty[0])
free(tty);
continue;
bad_entry:
message(L_LOG | L_CONSOLE, "Bad inittab entry at line %d",
parser->lineno);
}
config_close(parser);
#endif
}
/如果有配置文件执行默认,其中最重要的是系统吃实话rcS
#ifndef INIT_SCRIPT
#define INIT_SCRIPT "/etc/init.d/rcS"
#endif
该init.c主要是/etc/inittab进行解析,其中也会调用一些配置;没有配置就调用默认。
parse_inittab就是解析/etc/inittab;new_init_action复制完成一些配置;
* Now run everything that needs to be run */
/* First run the sysinit command */
run_actions(SYSINIT);
check_delayed_sigs();
/* Next run anything that wants to block */
run_actions(WAIT);
check_delayed_sigs();
/* Next run anything to be run only once */
run_actions(ONCE);
之后在由run_actions运行。
总结:
1、初始化究竟完成了什么是由parse_inittab()调用配置/etc/inittab;
2、默认/etc/inittab为 INIT_SCRIPT “/etc/init.d/rcS”,由busybox创建的。
4.1.2 配置文件inittab:
./home/lcx/source/busybox-1.27.0/examples/inittab
./home/lcx/source/busybox-1.27.0/examples/bootfloppy/etc/inittab
./home/lcx/source/busybox-1.27.0/examples/bootfloppy/etc/inittab
::sysinit:/etc/init.d/rcS 用的也是rcS脚本
::respawn:-/bin/sh
tty2::askfirst:-/bin/sh
::ctrlaltdel:/bin/umount -a -r
用的也是rcS脚本
总结如何定制初始化过程?
1、修改自己的inittab文件,让init.c中的parse_inittab()解析我们的配置文件从而执行不同的命令动作;
2、不用inittab文件,修改启动脚本INIT_SCRIPT 也就是/etc/init.d/rcS。
4.1.3 编写rcS定制启动过程(重要)
#! /bin/sh
for scrpit in /etc/init.d/S[0-9][0-9]*
do
if [ -x $script ];then
ehco"rcS:$scrpit"
/bin/sh -c $scrpit
fi
done
echo "-----rcS endl-----"
通过for的循环去读取脚本文件,然后执行;
修改rcS负责启动其他脚本,其他脚本负责启动服务
4.1.4 总结
1、启动初始函数init() —— 读取inittab中的动作 —— 没有inittab启用/etc/init.d/rcS —— 应用
2、所以可以修改rcS(不仅仅是脚本也可以是C)定制系统。
4.2 busybox编译配置生成过程
在ubuntu上对busybox进行交叉编译,以生成可以执行的二进制文件
- 下载解压;
- 修改Makefile
ARCH = arm
CROSS_COMPILE = arm-linux-gnueabi-
- make deconfig
- 或者启动图形化直接make menuconfig;注意需要编译为静态库;并在busybox setting中设置交叉编译器前缀
- make && make install
一些常用命令软链接等等。
以上是在busybox中的配置
以下是对根文件系统中的文件配置
5 完善根文件系统 于busybox编译完成之后
5.1 解决动态库依赖
补全目录,并查看所依赖的动态库。
注意:由于是为ARM服务的,除了busybox之外还需要arm的库;这个库就是安装交叉编译器的库
查看动态库依赖
readelf -d busybox|grep NEEDED
ld-linux-armhf.so.3 ——> 实现动态库的链接
c库的选择:glibc ——> 更全面完善
echo 'main(){}'| arm-linux-gnueabihf-gcc -E -v -
用于查看当前编译模式下头文件和库文件的路径
进入/usr/arm-linux-gnueabihf中查看库文件
lcx@ubuntu:/usr/arm-linux-gnueabihf$ find -name libc.so.6
./lib/libc.so.6
lcx@ubuntu:/usr/arm-linux-gnueabihf$ find -name libm.so.6
./lib/libm.so.6
lcx@ubuntu:/usr/arm-linux-gnueabihf$ find -name ld-linux-armhf.so.3
./lib/ld-linux-armhf.so.3
或者直接拷了整个lib过去
将所有库拷贝到系统中。
5.2 补充配置和设备文件
mkdir dev
cd dev
mknod -m 666 tty1 c 4 1
mknod -m 666 tty2 c 4 2
mknod -m 666 tty3 c 4 3
mknod -m 666 tty4 c 4 4
mknod -m 666 console c 5 1
mknod -m 666 null c 1 3
配置文件:
将实例文件中的etc全部拷贝至根文件系统的etc中。
注意,这个inittab和init.d就是上面的rcS
到此为止,根文件系统已经完成,可以挂载使用
烧录过程(以MfgTool为例)
- BootStrap 阶段
打开mfgtool2-yocto-mx-evk-emmc.vbs
脚本会根据芯片型号选择怎么烧写,通过USB OTG 向DDR中下载uboot
- 启动Linux系统后才是烧写uboot、zImage、.dtb(设备树)和根文件系统。