900字范文,内容丰富有趣,生活中的好帮手!
900字范文 > <linux> busybox制作rootfs

<linux> busybox制作rootfs

时间:2023-11-20 23:09:17

相关推荐

<linux> busybox制作rootfs

busybox制作rootf

Ⅰ、下载busyboxⅡ、修改busybox支持中文字符Ⅲ、选择配置基于defconfig上选择一些基本配置1. 选择动态库编译busybox2. 选择vi支持命令行3.取消simplified modutils4. 选择mdev5.选择unicode,支持中文Ⅳ、交叉编译工具配置Ⅴ、编译busybox,输出到指定文件夹Ⅵ、uboot配置nfs挂载rootfsubuntu配置nfsuboot nfs挂载rootfsⅦ、处理linux启动机制1、linuxrc与/etc/init.d/rcS2、创建/etc/fstab3、/etc/inittab机制总结

Ⅰ、下载busybox

本次实验在ubuntu环境下进行。

busybox的官方链接/

找到某个版本的busybox,点击git

使用git clone将busybox源码复制到Ubuntu下

Ⅱ、修改busybox支持中文字符

默认的busybox源码,是不支持中文字符显示的

需要修改以下几个文件

1、libbb/printable_string.c文件

显示中文,需要解除对0x7f字符数值的限制,原来的代码是将超过0x7f的字符,重新赋值为?,所以看到的中文字符,全部会显示为?

const char* FAST_FUNC printable_string2(uni_stat_t *stats, const char *str){char *dst;const char *s;s = str;while (1) {unsigned char c = *s;if (c == '\0') {/* 99+% of inputs do not need conversion */if (stats) {stats->byte_count = (s - str);stats->unicode_count = (s - str);stats->unicode_width = (s - str);}return str;}if (c < ' ')break;/* if (c >= 0x7f) //解除中文字符限制break;*/s++;}#if ENABLE_UNICODE_SUPPORTdst = unicode_conv_to_printable(stats, str);#else{char *d = dst = xstrdup(str);while (1) {unsigned char c = *d;if (c == '\0')break;/* if (c < ' ' || c >= 0x7f) *d = '?';*/if (c < ' ') //解除中文字符限制*d = '?';d++;}if (stats) {stats->byte_count = (d - dst);stats->unicode_count = (d - dst);stats->unicode_width = (d - dst);}}#endifreturn auto_string(dst);}

2、libbb/unicode.c文件

unicode_conv_to_printable2函数下,解除对数值大于0x7f字符的限制。

//截取部分代码static char* FAST_FUNC unicode_conv_to_printable2(uni_stat_t *stats, const char *src, unsigned width, int flags){char *dst;unsigned dst_len;unsigned uni_count;unsigned uni_width;if (unicode_status != UNICODE_ON) {char *d;if (flags & UNI_FLAG_PAD) {d = dst = xmalloc(width + 1);while ((int)--width >= 0) {unsigned char c = *src;if (c == '\0') {do*d++ = ' ';while ((int)--width >= 0);break;}//*d++ = (c >= ' ' && c < 0x7f) ? c : '?';*d++ = (c >= ' ') ? c : '?';src++;}*d = '\0';} else {d = dst = xstrndup(src, width);while (*d) {unsigned char c = *d;//if (c < ' ' || c >= 0x7f)if (c < ' ')*d = '?';d++;}}if (stats) {stats->byte_count = (d - dst);stats->unicode_count = (d - dst);stats->unicode_width = (d - dst);}return dst;}dst = NULL;uni_count = uni_width = 0;dst_len = 0;while (1) {

Ⅲ、选择配置

busybox默认支持三种自动配置方式

默认配置

make defconfig

所有配置

make allyesconfig

最小配置

make allnoconfig

一般情况下,我们使用默认配置

当然也可以选择手动配置,与大部分的linux SDK一样,支持menuconfig图形配置界面

make menuconfig

可以通过配置选项来选择/取消一些应用工具。

比如linux下常见的编辑器,vi,可以通过Editors–>vi来选择/取消

基于defconfig上选择一些基本配置

1. 选择动态库编译busybox

取消选择静态库编译,即选择动态库, 静态库会有较大的文件生成。

Settings --->Build static binary (no shared libs)

2. 选择vi支持命令行

Settings --->vi-style line editing commands

3.取消simplified modutils

不知为何,大家都这么做,疑问暂时保存在这里。

Linux Module Utilities --->Simplified modutils

4. 选择mdev

支持mdev相关的内容,默认配置下,已经勾选。

Linux System Utilities --->mdevSupport /etc/mdev.conf......Support daemon mode

5.选择unicode,支持中文

Settings --->[*] Support Unicode[*] Check $LC_ALL, $LC_CTYPE and $LANG environment variables

Ⅳ、交叉编译工具配置

与uboot、linux kernel的编译类似,不同cpu架构下的rootfs需要对应的工具链来编译,才可以适用到对应架构下

可以通过修改busybox目录下的Makefile,指定编译工具链和架构。

以编译arm架构为例

vim Makefile

若没有指定arch,makefile会自带获取uname中的架构名称。也可以手动指定ARCH ?= arm

# 工具链需要对应ubuntu环境下安装的工具链,如果没有对应工具链,需要先安装工具链CROSS_COMPILE ?= arm-linux-gnueabihf-

ifneq ($(CROSS_COMPILE),)SUBARCH := $(shell echo $(CROSS_COMPILE) | cut -d- -f1 | sed 's:^.*/::g')elseSUBARCH := $(shell uname -m)endifSUBARCH := $(shell echo $(SUBARCH) | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \-e s/arm.*/arm/ -e s/sa110/arm/ \-e s/s390x/s390/ -e s/parisc64/parisc/ \-e s/ppc.*/powerpc/ -e s/mips.*/mips/ )ARCH ?= $(SUBARCH)

或者在编译的时候,传入指定工具链和架构

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf-

Ⅴ、编译busybox,输出到指定文件夹

测试rootfs,可以将开发板上的rootfs通过nfs挂载到ubuntu上,这样可以方便修改,不用重新制作镜像,烧录。

busybox编译,支持将编译的产物输出到指定的目录下。

CONFIG_PREFIX=<路径>的形式,需要先创建输出文件夹。

使用make install进行编译安装

make install ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- CONFIG_PREFIX=/home/xxx/rootfs/

编译完成后,可以看到rootfs目录下的文件,具备了基本的rootfs文件夹

ls /home/xxx/rootfs/bin linuxrc sbin usr

还需要添加一些c库,因为编译rootfs的时候选择了非静态编译。

C库是从交叉编译工具链中复制而来

# 首先创建 libmkdir lib# 复制交叉编译工具链中的C库到lib目录下,工具链下的libc/lib/*so*, *.a, -d表示带符号拷贝cp /opt/gcc-arm-linux-gnueabihf/arm-linux-gnueabihf/libc/lib/*so* /opt/gcc-arm-linux-gnueabihf/arm-linux-gnueabihf/libc/lib/*.a ./lib/ -d# 复制工具链下的lib/*so* ,*.a 到rootfs的lib/cp /opt/gcc-arm-linux-gnueabihf/arm-linux-gnueabihf/lib/*.so /opt/gcc-arm-linux-gnueabihf/lib/*.a ./lib -d# 删除linux armhf.so,是个软连接文件,需要复制实际文件到rootfs目录下ls -l ld-linux-armhf.so.3ld-linux-armhf.so.3 -> ld-2.19-.08-1-git.so* # 实际上是个软连接#拷贝真实的ld-linux-armhf.so.3, 暂时不知道为何rm ld-linux-armhf.so.3cp /opt/gcc-arm-linux-gnueabihf/arm-linux-gnueabihf/libc/lib/ld-2.19-.08-1-git.so ld-linux-armhf.so.3# 最后拷贝工具链的/usr/lib/*.so ,*.a到rootfs的/usr/lib目录下mkdir usr/libcp /opt/gcc-arm-linux-gnueabihf/arm-linux-gnueabihf/libc/usr/lib/*.so /opt/gcc-arm-linux-gnueabihf/arm-linux-gnueabihf/libc/usr/lib/*.a ./usr/lib/ -d

到这里rootfs就准备完成,查看一下rootfs的大小,总共127M,太大了

du -sh rootfs4.0K rootfs/sbin724K rootfs/bin60Mrootfs/lib4.0K rootfs/usr/sbin4.0K rootfs/usr/bin67Mrootfs/usr/lib67Mrootfs/usr127M rootfs/

还需要准备一些空文件夹,给rootfs挂载后使用

mkdir dev # 用于给kernel挂载设备mkdir etc # 用于装载一些配置mkdir tmp # 用于装载临时生成的文件mkdir proc # 用于进程相关存储mkdir sys # 用于device、class等驱动创建节点目录

Ⅵ、uboot配置nfs挂载rootfs

进入uboot,配置rootfs,通过nfs挂载rootfs。

uboot 里面的 bootargs 环境变量会设置“root”的值,所以我们将 root 的值改为 NFS 挂载即可。

在 Linux 内核源码里面有相应的文档讲解如何设置,文档为 Documentation/filesystems/nfs/

nfsroot.txt,格式如下:

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.31.90。root-dir:根文件系统的存放路径,比如我的就是/home/allen/Desktop/rootfs/nfs-options:NFS 的其他可选选项,一般不设置。client-ip:客户端 IP 地址,也就是我们开发板的 IP 地址,Linux 内核启动以后就会使用

此 IP 地址来配置开发板。此地址一定要和 Ubuntu 主机在同一个网段内,并且没有被其他的设

备使用,在 Ubuntu 中使用 ping 命令 ping 一下就知道要设置的 IP 地址有没有被使用,如果不能

ping 通就说明没有被使用,那么就可以设置为开发板的 IP 地址,比如我就可以设置为

192.168.1.248。server-ip:服务器 IP 地址,前面已经说了。gw-ip:网关地址,我的就是 192.168.1.1。netmask:子网掩码,我的就是 255.255.255.0。hostname:客户机的名字,一般不设置,此值可以空着。device:设备名,也就是网卡名,一般是 eth0,eth1….,正点原子的 I.MX6U-ALPHA 开

发板的 ENET2 为 eth0,ENET1 为 eth1。如果你的电脑只有一个网卡,那么基本只能是 eth0。

这里我们使用 ENET2,所以网卡名就是 eth0。autoconf:自动配置,一般不使用,所以设置为 off。dns0-ip:DNS0 服务器 IP 地址,不使用。dns1-ip:DNS1 服务器 IP 地址,不使用。

根据上面的格式 bootargs 环境变量的 root 值如下:

root=/dev/nfs nfsroot=192.168.1.250:/home/zuozhongkai/linux/nfs/rootfs,proto=tcp rwip=192.168.1.251:192.168.1.250:192.168.1.1:255.255.255.0::eth0:off

“proto=tcp”表示使用 TCP 协议,“rw”表示 nfs 挂载的根文件系统为可读可写。启动开发

板,进入 uboot 命令行模式,然后重新设置 bootargs 环境变量,命令如下:

setenv bootargs 'console=ttymxc0,115200 root=/dev/nfs nfsroot=192.168.1.250:/home/zuozhongkai/linux/nfs/rootfs,proto=tcp rw ip=192.168.1.251:192.168.1.250:192.168.1.1:255.255.255.0::eth0:off' //设置 bootargssaveenv //保存环境变量

ubuntu配置nfs

安装nfs

sudo apt-get install nfs-kernel-server

配置nfs目录

vim /etc/exports# /etc/exports: the access control list for filesystems which may be exported#to NFS clients. See exports(5).## Example for NFSv2 and NFSv3:# /srv/homes hostname1(rw,sync,no_subtree_check) hostname2(ro,sync,no_subtree_check)## Example for NFSv4:# /srv/nfs4 gss/krb5i(rw,sync,fsid=0,crossmnt,no_subtree_check)# /srv/nfs4/homes gss/krb5i(rw,sync,no_subtree_check)#/home/allen/Desktop/ *(rw,sync,no_root_squash) # 这里设置/home/allen/Desktop/作为nfs共享目录。

(rw,sync,no_root_squash)设置rw权限。

测试mount是否成功

showmount -e Export list for allen:/home/allen/Desktop *

windows尝试挂载nfs

打开电脑cmd

mount 192.168.xx.90:/home/allen/Desktop

挂载成功

打开我的电脑可以看到

到此nfs已经挂载成功,就可以尝试在uboot中通过nfs来挂载rootfs了。

uboot nfs挂载rootfs

设置bootargs,roofs属性

setenv bootargs 'console=ttymxc0,115200 root=/dev/nfs nfsroot=192.168.31.90:/home/allen/Desktop/rootfs,nfsvers=3,proto=tcp ip=192.168.31.25:192.168.31.90:192.168.31.1:255.255.255.0::eth0:off'

root=/dev/nfs ⇒ 指定roofs启动方式是nfsnfsroot=192.168.31.90:/home/allen/Desktop/rootfs,nfsvers=3,proto=tcp 。

亿个小细节:

重点是nfsvers=3,ubuntu20.04,如果不指定nfsvers=3会出现无法连接到nfs的问题。

启动内核检查是否挂载rootfs成功。

[ 3.604707] fec 20b4000.ethernet eth0: Freescale FEC PHY driver [SMSC LAN8710/LAN8720] (mii_bus:phy_addr=20b4000.ethernet:01, irq=-1)[ 3.644131] IPv6: ADDRCONF(NETDEV_UP): eth0: link is not ready[ 6.684452] fec 20b4000.ethernet eth0: Link is Up - 100Mbps/Full - flow control rx/tx[ 6.704091] IPv6: ADDRCONF(NETDEV_CHANGE): eth0: link becomes ready[ 6.724370] IP-Config: Complete:[ 6.727636]device=eth0, hwaddr=40:a9:22:34:68:68, ipaddr=192.168.31.25, mask=255.255.255.0, gw=192.168.31.1[ 6.738042]host=192.168.31.25, domain=, nis-domain=(none)[ 6.744063]bootserver=192.168.31.90, rootserver=192.168.31.90, rootpath=[ 6.751343] gpio_dvfs: disabling[ 6.754661] can-3v3: disabling[ 6.757988] ALSA device list:[ 6.760971] #0: wm8960-audio[ 6.805225] VFS: Mounted root (nfs filesystem) readonly on device 0:14.[ 6.814381] devtmpfs: mounted[ 6.818079] Freeing unused kernel memory: 532K (80b43000 - 80bc8000)can't run '/etc/init.d/rcS': No such file or directory

可以看到log上获取到了网络, IP地址设置正常,看到logVFS: Mounted root (nfs filesystem) readonly on device 0:14.说明rootfs挂载正常。

Ⅶ、处理linux启动机制

1、linuxrc与/etc/init.d/rcS

rootfs挂载后,会执行linuxrc

drwxrwxr-x 2 100010004096 May 16 bindrwxr-xr-x 6 0 0 2980 Jan 1 00:00 devdrwxrwxr-x 2 100010004096 May 16 etcdrwxrwxr-x 2 100010004096 May 16 liblrwxrwxrwx 1 10001000 11 May 16 linuxrc -> bin/busyboxdrwxrwxr-x 2 100010004096 May 16 procdrwxrwxr-x 2 100010004096 May 16 sbindrwxrwxr-x 2 100010004096 May 16 tmpdrwxrwxr-x 5 100010004096 May 16 usr

可以看到linuxrc -> bin/busybox,会执行/etc/inittab脚本,然后在调用/etc/init.d/rcS文件配置一些基本的shell变量环境

/etc/init.d/rcS示例:

1 #!/bin/sh2 3 PATH=/sbin:/bin:/usr/sbin:/usr/bin:$PATH4 LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/lib:/usr/lib5 export PATH LD_LIBRARY_PATH6 7 mount -a8 mkdir /dev/pts9 mount -t devpts devpts /dev/pts1011 echo /sbin/mdev > /proc/sys/kernel/hotplug12 mdev -s

第 1 行,表示这是一个 shell 脚本。

第 3 行,PATH 环境变量保存着可执行文件可能存在的目录,这样我们在执行一些命令或

者可执行文件的时候就不会提示找不到文件这样的错误。

第 4 行,LD_LIBRARY_PATH 环境变量保存着库文件所在的目录。

第 5 行,使用 export 来导出上面这些环境变量,相当于声明一些“全局变量”。

第 7 行,使用 mount 命令来挂载所有的文件系统,这些文件系统由文件/etc/fstab 来指定,

所以我们一会还要创建/etc/fstab 文件。

第 8 和 9 行,创建目录/dev/pts,然后将 devpts 挂载到/dev/pts 目录中。

第 11 和 12 行,使用 mdev 来管理热插拔设备,通过这两行,Linux 内核就可以在/dev 目录

下自动创建设备节点。关于 mdev 的详细内容可以参考 busybox 中的 docs/mdev.txt 文档。

2、创建/etc/fstab

/etc/fstab主要是配置一些基本的文件系统挂载信息

示例:

#<file system> <mount point> <type> <options> <dump> <pass>proc /proc proc defaults 0 0tmpfs /tmp tmpfs defaults 0 0sysfs /sys sysfs defaults 0 0

<file system>: 要挂载的特殊的设备,也可以是块设备,比如/dev/sda 等等。

<mount point>:挂载点。

<type>:文件系统类型,比如 ext2、ext3、proc、romfs、tmpfs 等等。

<options>:挂载选项,在 Ubuntu 中输入“man mount”命令可以查看具体的选项。一般使

用 defaults,也就是默认选项,defaults 包含了 rw、suid、 dev、 exec、 auto、 nouser 和 async。

<dump>:为 1 的话表示允许备份,为 0 不备份,一般不备份,因此设置为 0。

<pass>:磁盘检查设置,为 0 表示不检查。根目录‘/’设置为 1,其他的都不能设置为 1,

其他的分区从 2 开始。一般不在 fstab 中挂载根目录,因此这里一般设置为 0。

配置后,重新启动linux,报错就没有了

[ 6.737030]device=eth0, hwaddr=40:a9:22:34:68:68, ipaddr=192.168.31.25, mask=255.255.255.0, gw=192.168.31.1[ 6.747440]host=192.168.31.25, domain=, nis-domain=(none)[ 6.753457]bootserver=192.168.31.90, rootserver=192.168.31.90, rootpath=[ 6.760738] gpio_dvfs: disabling[ 6.764056] can-3v3: disabling[ 6.767381] ALSA device list:[ 6.770363] #0: wm8960-audio[ 6.819245] VFS: Mounted root (nfs filesystem) readonly on device 0:14.[ 6.834257] devtmpfs: mounted[ 6.837956] Freeing unused kernel memory: 532K (80b43000 - 80bc8000)

ls /sys也可以看到驱动device都挂载到sys下

/ # ls sys/block/class/devices/ fs/ kernel/ power/bus/ dev/ firmware/ fsl_otp/ module/

/proc目录下进程也正常。

/ # cat /proc/1/ 5/ 87/ driver/ net/10/ 6/ 88/ execdomains pagetypeinfo100/ 61/ 89/ fb partitions101/ 62/ 9/ filesystems self/102/ 67/ 90/ fs/ softirqs11/ 68/ 91/ interruptsstat12/ 69/ 92/ iomemswaps13/ 7/ 93/ ioports sys/14/ 70/ 99/ irq/ sysrq-trigger15/ 71/ asound/ kallsyms sysvipc/16/ 72/ buddyinfokey-usersthread-self/17/ 73/ bus/ keys timer_list18/ 74/ cgroups kmsg tty/19/ 75/ cmdline kpagecountuptime2/ 76/ config.gzkpageflagsversion20/ 77/ consoles loadavg vmallocinfo21/ 8/ cpu/ locksvmstat22/ 82/ cpuinfo meminfo zoneinfo23/ 83/ crypto misc24/ 84/ device-tree/ modules3/ 85/ devices mounts4/ 86/ diskstatsmtd

3、/etc/inittab机制

inittab 的详细内容可以参考 busybox 下的文件 examples/inittab。init 程序会读取/etc/inittab

这个文件,inittab 由若干条指令组成。每条指令的结构都是一样的,由以“:”分隔的 4 个段组

成,格式如下:

<id>:<runlevels>:<action>:<process>

简单来说,inittab可以理解为预设一些指令,执行指令时进而执行一些动作。

四个选项的说明如下:

<id>:每个指令的标识符,不能重复。但是对于 busybox 的 init 来说,<id>有着特殊意义。对于 busybox 而言<id>用来指定启动进程的控制 tty,一般我们将串口或者 LCD 屏幕设置为控制 tty。<runlevels>:对 busybox 来说此项完全没用,所以空着。<action>:动作,用于指定<process>可能用到的动作。<process>:具体的动作,比如程序、脚本或命令等。

/etc/inittab 示例:

::sysinit:/etc/init.d/rcSconsole::askfirst:-/bin/sh::restart:/sbin/init::ctrlaltdel:/sbin/reboot::shutdown:/bin/umount -a -r 7 ::shutdown:/sbin/swapoff -a

当执行shutdown时,就会执行命令/bin/umount -a -r 7 ::shutdown:/sbin/swapoff -a

至此整个rootfs就完成!完结撒花。

总结

1、rootfs是linux重要的一环,可以通过nfs挂载,或直接在存储空间挂载。

2、rootfs启动后,需要经历几个阶段,linuxrc、/etc/inittab、/etc/init.d/rcS、/etc/fstab。需要了解三个文件的作用,inittab保存一些<动作:执行>指令的绑定,rcS启动后自动执行,配置一些环境变量,或添加自定义启动程序,类似/etc/rc.local。 fstab是配置基本的文件系统、tmpfs、proc、sysfs等

3、制作rootfs可以通过busybox,或直接用buildroot制作。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。