根文件系统制作
uboot进入命令行终端,一定得需要根文件系统,否则会一直等待终端启动然后卡住,而根文件系统的制作基本上都是busybox来实现的
下载地址:https://busybox.net/

根据交叉编译器版本:选择1.23.2.tar.bz2
chris@sys_geek:src_pack$ tar -xvf /mnt/hgfs/chris/busybox-1.23.2.tar.bz2 #解压到本地目录
chris@sys_geek:src_pack$ cd ./busybox-1.23.2/
chris@sys_geek:busybox-1.23.2$ make menuconfig
#路径:busybox settings---->Build options ---->cross compiler prefix

#设置好后选择 OK--->EXIT--->Installation options
选择设置安装路径

chris@sys_geek:busybox-1.23.2$ make && make install #编译

报错了,检查了下,交叉编译器写的是arm-linx-gcc,改成arm-linux-gcc就好了,再次编译,安装,完成之后查看制作的根文件系统

可以看到,,但是此时制作的根目录是不完全的
- bin:这个目录包含了用户在单用户模式下以及系统启动时所需的基本命令和程序,如
ls、cp、mv、grep等。 linuxrc是一个特殊的脚本或可执行文件,它在 Linux 系统启动过程中被内核执行。它通常负责初始化硬件设备、挂载根文件系统以及启动用户空间的 init 进程。在使用 BusyBox 构建的最小化系统中,linuxrc可能被用来执行一些早期的启动任务。- sbin: 同理bin目录,s = super
usr目录是一个用户级别的软件层次结构,它包含了不属于系统基本运行所需的额外的程序、库和文档。在 BusyBox 的最小化 rootfs 中,usr目录可能包含了一些额外的实用程序和库
回到电脑的ubuntu的根目录下:查看虚拟机的根目录结构,做相应修改,ubuntu这里有些文件夹不需要

chris@sys_geek:busybox-1.23.2$ cd ~/rootfs/
chris@sys_geek:rootfs$ mkdir cgroup etc lib misc net proc srv var boot dev home lost+found media mnt root selinux sys
查看目录结构:

chris@sys_geek:rootfs$ touch etc/profile #profile 用来保存相关环境变量
chris@sys_geek:rootfs$ mkdir etc/init.d #初始化文件
chris@sys_geek:rootfs$ touch etc/init.d/rcS #开机启动脚本文件
chris@sys_geek:rootfs$ chmod +x etc/init.d/rcS #赋予脚本执行权限
chris@sys_geek:rootfs$ cp /etc/passwd etc/ #存放登录密码(可有可无)
chris@sys_geek:rootfs$ cp /etc/group etc/ #分组文件
chris@sys_geek:rootfs$ cp /etc/fstab etc/ #存放磁盘挂载信息
chris@sys_geek:rootfs$ cp ~/src_pack/busybox-1.23.2/examples/inittab etc/ #启动文件
修改 inittab 文件内容 gedit etc/inittab,只保留下面内容
::sysinit:/etc/init.d/rcS #设置初始化执行的文件
console::askfirst:-/bin/sh #需要加上 console askfirst 表示需要按下回车才可以进入系统
#respawn 表示开机直接进入系统
::ctrlaltdel:/sbin/reboot #指定重启命令
::shutdown:/bin/umount -a -r #指定关机时执行的命令
编写 rcS 启动脚本文件 gedit etc/init.d/rcS
mount -a #挂载所有在 /etc/fstab 文件中定义的文件系统
mkdir /dev/pts #/dev/pts 目录,POSIX终端(伪终端)设备的挂载点。存放伪终端设备文件/dev/pts/0、/dev/pts/1 等
mount -a #确保所有文件系统已经正确挂载
mkdir /dev/pts #dev/pts 文件在特殊目录中存储与通过 Linux 连接的设备相关的信息
mount -t devpts devpts /dev/pts #挂载伪终端文件系统
echo /sbin/mdev > /proc/sys/kernel/hotplug #配置内核的热插拔功能,指定 /sbin/mdev 作为处理热插拔事件的程序
mdev -s #启动 mdev守护进程
/bin/hostname chris #设置主机名称
mkdir /dev/pts
/dev/pts 是远程登陆(telnet,ssh 等)后创建的控制台设备文件所在的目录。由于可能有好
几千个用户登陆,所以/dev/pts 其实是动态生成的,不象其他设备文件是构建系统时就已经
产生的硬盘节点
mount -t devpts devpts /dev/pts
内核虚拟文件。和 proc 一样。Linux 提供给管理员通过文件系统和内核进行沟通(读\
写)的一种渠道。pts 是远程虚拟终端。devpts 即远程虚拟终端文件设备。通过/dev/pts 可
以了解目前远程虚拟终端的基本情况。
echo /sbin/mdev > /proc/sys/kernel/hotplug
linux 系统对于热插拔事件的产生默认都是调用/sbin/hotplug,该程序通过加载驱动程
序,创建设备节点,挂载分区等。如果系统中不是/sbin/hotplug 来执行,而是 mdev,那么用
户应当在早期启动的时候将改执行档(包含绝对位置)设置进去,于是有了上面的 echo
/sbin/mdev> /proc/sys/kernel/hotplug 我们可以在脚本中注释掉该命令行,重新开机后 cat
/proc/sys/kernel/hotplug 就会发现返回来的是/sbin/hotplug 说明系统默认都是调用这个。这
个的配置在内核编译的时候写好的在内核目录下的.config 可以看到有个配置叫做
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
mdev -s #生成设备节点
编写 profile 文件 gedit etc/profile
USER="id-un" #id -un 是获得当前登陆的用户名称,USER="`id -un`" 则是将 id -un 的返
#回值赋值给变量 USER
LOGNAME=$USER #用于显示用户名称
PS1='[\u@\h \W]\$ ' #命令行样式环境变量,查看系统命令行样式 echo $PS1
PATH=$PATH
HOSTNAME='/bin/hostname'
export USER LOGNAME PS1 PATH HOSTNAME
将官方提供的交叉编译动态库拷贝到lib目录下
chris@sys_geek:rootfs$ cp ~/arm-linux-gcc/opt/FriendlyARM/toolschain/4.5.1/arm-none-linux-gnueabi/lib/* ./lib/ -rfdv
chris@sys_geek:rootfs$ cp ~/arm-linux-gcc/opt/FriendlyARM/toolschain/4.5.1/arm-none-linux-gnueabi/sys-root/lib/* ./lib -rfdv
chris@sys_geek:rootfs$ cp ../arm-linux-gcc/opt/FriendlyARM/toolschain/4.5.1/arm-none-linux-gnueabi/sys-root/usr/lib* ./lib -rfdv
#-rf 强制递归(有些是文件夹)
#d (保留动态库的链接属性,有些库可能有版本之分,在运行的时候如果没有链接信息会随机找一个同名的进行链接或者内核崩溃)
#v 输出过程
完善/dev/目录,创建设备空节点与控制台节点
chris@sys_geek:rootfs$ sudo mknod dev/null c 1 3
chris@sys_geek:rootfs$ sudo mknod /dev/console c 5 1
NFS挂载
通过NFS挂载共享文件夹的方式,可以更方便的进行与低端设备进行文件交互
在NFS协议共享的文件夹最好不要放到虚拟机的共享目录下,以防冲突,
chris@sys_geek:chris$ sudo apt-get install nfs-kernel-server #下载NFS环境和指令集
chris@sys_geek:~$ cd ./nfs_shared/ #在user目录下创建共享文件夹
chris@sys_geek:nfs_shared$ pwd #获取当前环境路径
/home/chris/nfs_shared
chris@sys_geek:nfs_shared$ sudo vim /etc/exports #NFS配置文件为/etc/exports 如果/etc目录下没有,则需要自己创建
/home/chris/nfs_shared *(rw,sync,no_root_squash,no_subtree_check,insecure)

关闭防火墙
chris@sys_geek:nfs_shared$ sudo ufw disable # 防火墙在系统启动时自动禁用
chris@sys_geek:nfs_shared$ sudo exportfs -arv #配置共享目录重新生效 a:全部 r:重新挂载 v:输出共享文件夹路径以及规则
exporting *:/home/chris/nfs_shared
chris@sys_geek:nfs_shared$ showmount -e localhost #查看当前ip的挂载信息
Export list for localhost:
/home/chris/nfs_shared *
如果没有挂载成功,重启nfs服务,然后再挂载:
chris@sys_geek:sudo /etc/init.d/nfs-kernel-server restart
如果不需要NFS服务,取消挂载再重新打开防火墙就好了
chris@sys_geek:nfs_shared$ sudo exportfs -auv #全部取消挂载
chris@sys_geek:nfs_shared$ sudo ufw enable
chris@sys_geek:sudo mount -t nfs 192.168.2.101:/home/chris/rootfs/ /mnt/ #将rootfs挂载到共享目录下
chris@sys_geek:umount /mnt/ #取消挂载共享目录
将开发板通过NFS挂载的方式访问虚拟机ubuntu提供的共享文件夹
直接将开发板的网口与虚拟机相连接,虚拟机继承主机网口配置,然后再由ubuntu手动分配IP,通过开发板uboot配置主机和开启加载的文件夹为NFS共享文件夹,此时就能正常进入命令行
由于本人需要使用vmware上网,又不想更改上网的网卡设置,这里需要添加新的虚拟网卡,上网的网卡配置为桥接模式,虚拟机网络设置里面修改为对应的桥接模式
开发板通过USB网口和主机相连接
- 先将主机的网卡设置为与虚拟机桥接模式,修改电脑上网的网卡为桥接模式,保存虚拟机网络设置
- 添加给板子使用的虚拟网卡,创建为Vmnet2,配置为自定义虚拟网络,再使用vmware虚拟网络编辑器,修改Vmnet2虚拟机网络设置,我这里使用的是USB网卡,配置为桥接模式



可以看到,这里多了一个以太网连接方式,其中ens33默认为vmware最先设置的那个,也就是能上网的那个网卡,以防IP冲突,在使用开发板的时候需要将ens33关闭
接下来配置板子通信的网卡,设置虚拟机ens34作为NFS主机的静态IP地址

chris@sys_geek:rootfs$ ifconfig #查看网络信息
ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.xx.xx netmask 255.255.255.0 broadcast 192.168.1.255
inet6 fe80::xxxx:953b:9c2d:xxxx prefixlen 64 scopeid 0x20<link>
ether 00:0c:29:8b:bb:6d txqueuelen 1000 (以太网)
RX packets 1964 bytes 1138609 (1.1 MB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 4020 bytes 495739 (495.7 KB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
ens34: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.2.101 netmask 255.255.255.0 broadcast 192.168.2.255
inet6 fe80::c0c3:ef6c:f90e:30b9 prefixlen 64 scopeid 0x20<link>
ether 00:0c:29:8b:bb:77 txqueuelen 1000 (以太网)
RX packets 3027 bytes 1729611 (1.7 MB)
RX errors 0 dropped 19 overruns 0 frame 0
TX packets 286 bytes 33625 (33.6 KB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (本地环回)
RX packets 1213 bytes 123117 (123.1 KB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 1213 bytes 123117 (123.1 KB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
静态IP生效!
通过uboot print命令查看环境变量,对其进行修改

TINY4412 # setenv bootargs root=/dev/nfs nfsroot=192.168.2.101:/home/chris/rootfs ip=192.168.2.123:192.168.2.101:192.168.2.1:255.255.255.0::eth0:off init=/linuxrc console=ttySAC0 lcd=S702
TINY4412 # save
TINY4412 # reset
#命令解析:root=/dev/nfs :以NFS的方式启动和挂载
# nfsroot=192.168.2.101:/home/chris/rootfs :根目录在服务器为192.168.2.101下的/home/chris/rootfs
# ip=192.168.2.123(开发板IP)
# 192.168.2.101:192.168.2.1:255.255.255.0 NFS服务器IP(也就是虚拟机配置的静态IP)、192.168.2.1(NFS服务器网关)、255.255.255.0子网掩码
# init=/linuxrc:linux内核启动完成后第一个要执行的用户空间
# ttySAC0:特定的设备文件(主板开发商这里在uboot中指定的是COM1)
# lcd=S702 使用的屏幕,由厂商的uboot适配,并且告诉内核以及启动脚本如何正确使用屏幕

此时,IP地址发生改变

启动linux内核,通过虚拟机ping开发板,得到回应,

但是此时一直没有出现NFS挂载的字样,VFS也并未启动,猜测可能是因为开发板的NFS支持的版本比较老,毕竟linux内核时3.5,uboot是十多年前的了,busybox使用的也是对应的1.23.2版本,虚拟机环境为64为ubuntu18.04
指定NFS的版本:
chris@sys_geek: sudo vim /etc/default/nfs-kernel-server +20 #增加指定NFS的版本
#在末尾插入以下:
RPCNFSDOPTS="--nfs-version 2,3,4 --debug --syslog" #指定兼容的NFS版本为2,3,4
开发板成功启动内核,通过挂载主机的NFS进入到主机的根文件系统,成功进入命令行终端!
(这里修改了上位机的字体和颜色–linux ANSI格式)

过程分析:
- windows主机通过网线连接电脑主板的网口对运营商进行拨号上网
- windows与虚拟机ubuntu桥接,并且使用的是虚拟的网口地址
- 开发板通过USB网口接入到windows
- 将开发板网卡桥接到ubuntu
- 将ubuntu来自windows的网络分配设置为桥接
- 将与开发板相连接的以太网IP分配为静态IP,并且将开发板的IP设置为ubuntu相同网关的不同网段
注意:此时windows下桥接来自运营商的网络是能够上网的,但是开发板是不能上网的,可能存在IP冲突,所以两者无法一同使用,需要在使用其一的时候关闭对方网络,不然有概率会出现IP冲突
测试开发板上面是否能正常运行编译后的可执行文件:
chris@sys_geek:rootfs$ mkdir code
chris@sys_geek:rootfs$ cd ./code/
chris@sys_geek:code$ touch hello_world.c
chris@sys_geek:code$ vim ./hello_world.c
chris@sys_geek:code$ gcc ./hello_world.c -o test1
hello_world!
#include <stdio.h>
int main(int argc, char *argv[], char *envp[])
{
printf("hello world!\n");
return 0;
}

报错,因为使用的是GCC编译,而不是交叉编译器,因为GCC本质上是适配了我们虚拟机ubuntu64位的环境,使用file命令在ubuntu下查看文件详细信息
chris@sys_geek:code$ file ./test1
#输出结果:
./test1: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=69e12de53f6ef075f14052c891a367c516c432bc, not stripped
此时应该指定编译器来实现
chris@sys_geek:code$ arm-linux-gcc ./hello_world.c -o test2
再使用file命令查看test2
chris@sys_geek:code$ file ./test2
#输出结果:
./test2: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.3, for GNU/Linux 2.6.27, not stripped

成功执行第一个hello world程序!大win特win!!!
此时还没有结束,只是成功挂载到了虚拟机提供的rootfs文件系统,SD卡还没有自己的文件系统
rootfs本地挂载
从此刻开始,可以使用官方提供的EMMC来接替SD卡的任务
1.在ubuntu上操作,回退到rootfs上一级目录下进行操作,将rootfs目录进行打包和其他操作
chris@sys_geek:~$ rm ./rootfs/dev/* -rf #清空dev目录下的所有设备节点,如果一边删不掉,再删一边
chris@sys_geek:~$ sudo tar -cvf rootfs.tar.gz ./rootfs/
chris@sys_geek:~$ cp ./rootfs.tar.gz ./rootfs #将打包的rootfs放到挂载的rootfs的根目录下
2.从SD卡启动uboot,对EMMC磁盘进行格式化,并制作启动盘
#使用fdisk对磁盘进行操作 -c:创建一个新的临时文件系统 1:此时从SD卡启动,SD卡设备号为0 EMMC为设备号1 #三星提供的这个uboot分区指令最小是1MB 系统磁盘1024MB 用户数据分区1024MB 缓存分区1024MB
fdisk -c 1 1024 1024 1024

partion1:剩余容量、partion2:系统分区、partion3:用户数据区、partion4:缓冲分区
1.剩余容量
2.系统分区(/):
这是 Linux 系统中的主分区,也称为根分区。它包含了操作系统的核心文件和程序,以及用户程序和配置文件
3.用户数据分区(/home):
这个分区专门用于存储用户数据,如文档、图片、视频和个人设置等
4.缓存分区(/tmp 或 /var/tmp):
这个分区用于存储临时文件,如系统运行时产生的临时数据和用户程序的临时文件
#将系统分区、用户分区、缓存分区格式化为ext3格式
TINY4412 # ext3format mmc 1:2
TINY4412 # ext3format mmc 1:3
TINY4412 # ext3format mmc 1:4
4.重启开发板进入uboot ,将bl1、bl2、uboot、tzsw、以及linux内核镜像写入到EMMC中
movi r f 0 40008000;emmc open 1;movi w z f 1 40008000;emmc close 1;
movi r b 0 40008000;emmc open 1;movi w z b 1 40008000;emmc close 1;
movi r u 0 40008000;emmc open 1;movi w z u 1 40008000;emmc close 1;
movi r t 0 40008000;emmc open 1;movi w z t 1 40008000;emmc close 1;
movi r k 0 40008000;movi w k 1 40008000;
3.重新从SD卡启动linux内核
使用mount命令进行挂载,将EMMC的系统盘挂载到NFS共享的根文件系统目录下
(注意,此时使用的是SD卡作为启动盘,mmc设备0是SD卡,mmc设备1是EMMC)

#将EMMC的系统盘分区挂载到当前NFS共享的/mnt/目录下
[root@192 ]# mount /dev/mmcblk1p2 /mnt/
挂载成功会出现lost + found目录

将rootfs的打包文件解压到挂载的mnt共享目录中
tar -xvf /rootfs.tar.gz

删除掉rootfs.tar.gz,将解压后的rootfs目录下的所有文件都解压到/mnt/目录下

回退到根目录,卸载EMMC的磁盘
[root@192 ]# /
[root@192 ]# umount /mnt/
5.关闭重启开发板,选择EMMC启动,进入uboot,修改环境变量
setenv bootargs root=/dev/mmcblk0p2 rootfstype=ext3 rw ip=192.168.2.123:192.168.2.101:192.168.2.1:255.255.255.0::eth0:off init=/linuxrc console=ttySAC0 lcd=S702
save
reset
此时就不需要NFS挂载可以直接进入命令行终端
将SD卡启动也脱离NFS网络挂载
同样的步骤,只需要将SD卡分区,然后将系统磁盘分格式化为ext3格式,通过EMMC启动NFS挂载,将SD卡的系统磁盘扇区挂载到/mnt/目录,最后用同样的操作,理论上是可以的
首先分析SD卡启动时的内存块:
- 第一部分读取从块 1057 开始,读取了 12288 个块,所以结束块号是: 1057+12288−1=133441057+12288−1=13344
- 第二部分读取从块 13345 开始,读取了 8192 个块,所以结束块号是: 13345+8192−1=2153613345+8192−1=21536
总共读取块为(21536 + 1 -1057) * 512 = 10485760,差不多10MB左右,所以当给SD卡分区的时候并不会被覆盖掉,32GB内存卡远远够了

通过SD卡启动uboot,将SD卡做4个分区,并且格式化第二个分区为ext32
TINY4412 # fdisk -c 0 4096 4096 4096
通过EMMC启动uboot,将EMMC恢复为NFS挂载的方式
setenv bootargs root=/dev/nfs nfsroot=192.168.2.101:/home/chris/rootfs ip=192.168.2.123:192.168.2.101:192.168.2.1:255.255.255.0::eth0:off init=/linuxrc console=ttySAC0 lcd=S702
save
reset
进入到EMMC启动的控制台的命令行
#将SD卡的第二个分区挂载到/mnt/目录下 成功后查看mnt目录下
[root@192 ]# mount /dev/mmcblk1p2 /mnt/
[root@192 ]# ls /mnt/

lost+found目录存在,挂载成功,此时再进入mnt,将rootfs目录下的根文件系统解压到mnt目录下
[root@192 mnt]# tar -xvf /rootfs.tar.gz #解压
[root@192 mnt]# ./rootfs/* ./ #移动
[root@192 mnt]# rm ./rootfs/ -rf #删除没用的rootfs文件夹
[root@192 mnt]# reboot #重启进入uboot
重新进入uboot修改其环境变量
setenv bootargs root=/dev/mmcblk0p2 rootfstype=ext3 rw ip=192.168.2.123:192.168.2.101:192.168.2.1:255.255.255.0::eth0:off init=/linuxrc console=ttySAC0 lcd=S702
save
reset

成功加载!但是此时还没能将主机的共享文件夹挂载进来
[root@192 ]# cd ./home/ #创建code目录
[root@192 home]# mkdir code
[root@192 home]# mount -t nfs 192.168.2.101:/home/chris/nfs_shared ./code/#手动挂载主机的NFS目录

挂载失败,解决方案:
nfs mount 默认选项包括文件锁,依赖于portmap提供的动态端口分配功能。
解决方法:kill 文件锁(lockd)或者mount -o nolock
[root@192 home]# mount -t nfs -o nolock 192.168.2.101:/home/chris/nfs_shared ./code/
[root@192 home]# touch nfs_mount.sh
[root@192 home]# chmod +x ./nfs_mount.sh
但是每一次都要手动挂载就太麻烦了,这里可以编写脚本来实现,在开机的时候让Linux自己运行这个脚本,就省去了挂载
编写挂载脚本:
ifconfig eth0 192.168.2.123 #set ipaddr
mount -t nfs -o nolock 192.168.2.101:/home/chris/nfs_shared /home/code/ #mount nfs_dictory
将脚本执行放在/etc/init.d/rcS里面执行

[root@192 home]# reboot #重新启动
[root@192 ]# cd /home/code/
[root@192 code]# ls #成功查看到共享文件,挂载成功!
test2
[root@192 code]#

最后再来解决host名字乱码的问题,查看hostname文件,发现并没有这个文件
[root@192 ]# file /etc/hostname
-/bin/sh: file: not found
[root@192 ]# vi ./etc/hostname
[root@192 ]# reboot
hostname
sys-geek
重启后发现还是一样的现象,使用hostname查看
[root@192 ]#hostname
192.168.2.123
这里的hostname为板子的ip,直接通过/bin/hostname修改hostname, 发现名字可以成功更改,问题应该出在/etc/profile 或者时/etc/init.d/rcS文件内设置hostname那一步
[root@192 ]#/bin/hostname sys-geek
[root@sys-geek ]#
发现rcS脚本并没有修改主机名称,前面移植rootfs的时候可能操作失误了,这里添加上



修改成功!
name文件,发现并没有这个文件
[root@192 ]# file /etc/hostname
-/bin/sh: file: not found
[root@192 ]# vi ./etc/hostname
[root@192 ]# reboot
hostname
sys-geek
重启后发现还是一样的现象,使用hostname查看
[root@192 ]#hostname
192.168.2.123
这里的hostname为板子的ip,直接通过/bin/hostname修改hostname, 发现名字可以成功更改,问题应该出在/etc/profile 或者时/etc/init.d/rcS文件内设置hostname那一步
[root@192 ]#/bin/hostname sys-geek
[root@sys-geek ]#
发现rcS脚本并没有修改主机名称,前面移植rootfs的时候可能操作失误了,这里添加上



修改成功!
1万+

被折叠的 条评论
为什么被折叠?



