ARM busybox 的移植实战2

news/2024/5/4 13:12:32/文章来源:https://blog.csdn.net/weixin_42109053/article/details/130277492

一、busybox 源码分析1

1、源码目录梳理

在这里插入图片描述


2、整个程序入口的确认

(1) 分析一个程序,不管多庞大还是小,最好的路线都是 按照程序运行时的逻辑顺序来。所以找到一个程序的入口至关重要。


(2) 学 C 语言的时候都知道,程序的主函数 main 函数就是整个程序的入口。这种情况适应于操作系统下工作的应用程序 的情况。


(3) 在 uboot 和 linux kernel 这两个大的 C 语言的项目中,main 函数都没有,都不是入口。在我们这种裸机程序中,入口不是 main 函数,而是由链接脚本来指定的。


(4) busybox 是 linux 启动起来后工作的一个应用程序,因此其中必然有 main 函数,而且 main 就是入口。


3、busybox 中 main 函数全解析

(1) busybox 入口就是 main 函数,其中有很多个 main,但是只有一个起作用了,其他的是没起作用的。真正的 busybox 工作时的入口是 libbb/appletlib.c 中的 main 函数。

在这里插入图片描述


(2) busubox 中有很多 xxx_main 的函数,这些 main 函数每一个都是 busybox 支持的一个命令的真正入口。

譬如 ls_main 函数,就是 busybox 当作 ls 函数使用时的入口程序。

在这里插入图片描述


(3) ls 或者 cd 等命令,其实都是 busybox 一个程序,但是实际执行时的效果却是各自的效果。busybox 是如何实现一个程序化身万千还能各自工作的?答案就是 main 转 xxx_main。

在这里插入图片描述

也就是说,busybox 每次执行时,都是先执行其 main,在 main 函数中识别(靠 main 函数的传参 argv[0] 来识别)我们真正要执行的函数(譬如 ls),然后去调用相应的 xxx_main(譬如 ls_main)来具体实现这个命令。

在这里插入图片描述


二、busybox源码分析2

1、inittab 解析与执行

(1) inittab 的解析是在 busybox/init/init.c/init_main 函数中。

在这里插入图片描述


(2) 执行逻辑是:先通过 parse_inittab 函数解析 /etc/inittab(解析的重点是,将 inittab 中的各个 action 和 process 解析出来),然后后面先直接执行 sysinit 和 wait 和 once(注意这里只执行一遍),然后在 while(1) 死循环中去执行 respwan 和 askfirst。

在这里插入图片描述

在这里插入图片描述


2、pwd 命令执行路径分析

(1) 根据上节讲的,我们在 busybox 命令行下执行 pwd 命令时,实际执行的是 pwd_main 这个函数。

在这里插入图片描述


3、busybox 的体积优势原理

(1) busybox 实际上就是把 ls、cd、mkdir 等很多个 linux 中常用的 shell 命令集成在一起了。集成在一起后有一个体积优势:就是 busybox 程序的大小,比 busybox 中实现的那些命令的大小加起来 要小很多。


(2) busybox 体积变小的原因主要有 2 个:

第一个是 busybox 本身提供的 shell 命令是阉割版的(busybox 中的命令支持的参数选项比发行版中要少,譬如 ls 在发行版中可以有几十个 -x 选项,但是在 busybox 中只保留了几个常用的选项,不常用的都删除掉了);

第二个是 busybox 中因为所有的命令的实现代码都在一个程序中实现,而各个命令中有很多代码函数都是通用的(譬如 ls 和 cd、 mkdir 等命令都会需要去操作目录,因此在 busybox 中实现目录操作的函数,就可以被这些命令共用),共用会降低重复代码出现的次数,从而减少总的代码量和体积。


(3) 经过分析,busybox 的体积优势 是嵌入式系统本身的要求和特点造成的。


三、rcS 文件介绍1

0、/etc/init.d/rcS

/etc/init.d/rcS 文件,是 linux 的运行时配置文件中最重要的一个,其他的一些配置都是由这个文件引出来的。这个文件可以很复杂,也可以很简单,里面可以有很多的配置项。

这是 ubuntu 发行版的 rcS 文件:

root@ubuntu:# cat /etc/init.d/rcS
#! /bin/sh
#
# rcS
#
# Call all S??* scripts in /etc/rcS.d/ in numerical/alphabetical order
#exec /etc/init.d/rc S
root@ubuntu:# vim /etc/init.d/rc

在这里插入图片描述


这是 busybox 最简单的 rcS 文件:

在这里插入图片描述


1、PATH=xxx

在这里插入图片描述

(1) 首先从 shell 脚本的语法角度分析,这一行定义了一个变量PATH,值等于后面的字符串。


(2) 后面用 export 导出了这个 PATH,那么 PATH 就变成了一个环境变量。


(3) PATH 这个环境变量,是 linux 系统内部定义的一个环境变量,含义是操作系统去执行程序时,会默认到 PATH 指定的各个目录下去寻找。

如果找不到,就认定这个程序不存在,如果找到了就去执行它。将一个可执行程序的目录导出到 PATH,可以让我们不带路径 来执行这个程序。


(4) rcS 中为什么要先导出 PATH?就是因为我们希望一旦进入命令行时,PATH 环境变量中就有默认的 /bin /sbin /usr/bin /usr/sbin 这几个常见的可执行程序的路径,这样我们进入命令行后就可以 ls、 cd 等直接使用了。


(5) 为什么我们的 rcS 文件还没添加,系统启动就有了 PATH 中的值?原因在于 busybox 自己用代码硬编码,为我们导出了一些环境变量,其中就有 PATH。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


2、runlevel=

在这里插入图片描述

(1) runlevel 也是一个 shell 变量,并且被导出为环境变量。


(2) runlevel 这个环境变量到底有什么用?

在这里插入图片描述


(3) runlevel=S 表示将系统设置为单用户模式。


3、umask=

在这里插入图片描述

(1) umask 是 linux 的一个命令,作用是设置 linux 系统的 umask 值。

(2) umask 值决定当前用户在创建文件时的默认权限。


4、mount -a

在这里插入图片描述

(1) mount 命令是用来挂载文件系统的。


(2) mount -a 是挂载所有的应该被挂载的文件系统,在 busybox 中 mount -a 时,busybox 会去查找一个文件 /etc/fstab 文件,这个文件按照一定的格式列出来所有应该被挂载的文件系统(包括了虚拟文件系统)

ubuntu 发行版的 /etc/fstab:

在这里插入图片描述


busybox 的 fstab:

在这里插入图片描述


四、 rcS文件实战1

1、PATH&runlevel

在 rootfs 根文件系统创建 init.d 目录,然后拷贝 rcS 到 init.d 目录下:

在这里插入图片描述

root@ubuntu:/home/aston/workspace/porting_x210/rootfs/rootfs/etc# cd init.d/
root@ubuntu:/home/aston/workspace/porting_x210/rootfs/rootfs/etc/init.d# vim rcS 
root@ubuntu:/home/aston/workspace/porting_x210/rootfs/rootfs/etc/init.d# 
root@ubuntu:/home/aston/workspace/porting_x210/rootfs/rootfs/etc/init.d# cat rcS 
#!/bin/sh
PATH=/sbin:/bin:/usr/sbin:/usr/binrunlevel=S
prevlevel=Numask 022export PATH runlevel prevlevelmount -aroot@ubuntu:/home/aston/workspace/porting_x210/rootfs/rootfs/etc/init.d#  

拷贝 fstab 文件到 etc 目录下:

在这里插入图片描述

root@ubuntu:/home/aston/workspace/porting_x210/rootfs/rootfs/etc# ls
fstab  init.d  inittab
root@ubuntu:/home/aston/workspace/porting_x210/rootfs/rootfs/etc# vim fstab 
root@ubuntu:/home/aston/workspace/porting_x210/rootfs/rootfs/etc# cat fstab 
# /etc/fstab: static file system information.
#
# Use 'vol_id --uuid' to print the universally unique identifier for a
# device; this may be used with UUID= as a more robust way to name devices
# that works even if disks are added and removed. See fstab(5).
#
# 	<file system> 	<mount point> 	<type> 	<options> 	<dump> 	<pass>proc 			/proc 			proc 	defaults 	0 		0sysfs 			/sys 			sysfs 	defaults 	0 		0tmpfs 			/var 			tmpfs 	defaults 	0 		0tmpfs 			/tmp 			tmpfs 	defaults 	0 		0tmpfs 			/dev 			tmpfs 	defaults 	0 		0root@ubuntu:/home/aston/workspace/porting_x210/rootfs/rootfs/etc# 

(1) 我们实战发现,rcS 文件明明存在,但是却提示不存在。问题原因就是,rcS 文件在 windows 下创建的,行尾换行符为 ‘\r\n’,多了点东西。但是因为 ubuntu 中的 vi 对行尾做了优化,所以在 ubuntu 中是看不出来多了东西的。但是在 securecrt 下一看就发现,每一行末尾多出来了一个^M。

在这里插入图片描述

在这里插入图片描述


手动修改删除多余的 ^M。

重新启动,不再报错 rcS 找不到。

在这里插入图片描述


(2) 这个故事告诉我们:shell 脚本文件如果格式不对,运行时可能会被提示文件不存在。


(3) 扩展讲一个:有时候一个应用程序执行时,也会提示文件不存在,问题可能是这个程序所调用的一个动态链接库找不到。


开发板的 runlevel 无效:

在这里插入图片描述

正常的 ubuntu 发行版的 runlevel 命令能正常工作:

在这里插入图片描述


在这里插入图片描述


(4) 测试结果:PATH 本来在 busybox 中就已经用代码导出过了,所以 rcS 中再次导出没有任何明显的现象,因此看不出什么差别;runlevel 实际执行结果一直是 unknown,问题在于 busybox 并不支持 runlevel 这个特性


2、umask 测试

在这里插入图片描述

(1) umask是022的时候,默认touch创建一个文件的权限是644。

(2) umask是044的时候,默认touch创建一个文件的权限是622。

(3) umask是444的时候,默认touch创建一个文件的权限是222。

总结:umask 的规律就是:umask 值和默认创建文件的权限值加起来,是666.


3、mount 测试

在这里插入图片描述

(1) 挂载时全部出错:

mount: mounting proc on /proc failed: No such file or directory
mount: mounting sysfs on /sys failed: No such file or directory
mount: mounting tmpfs on /var failed: No such file or directory
mount: mounting tmpfs on /tmp failed: No such file or directory
mount: mounting tmpfs on /dev failed: No such file or directory

(2) 原因是因为,根文件系统中找不到挂载点。

所谓挂载点, 就是我们要将目标文件系统(当然这里都是虚拟文件系统)挂载到当前文件系统中的某一个目录中,这个目录就是挂载点。


(3) 解决方案就是,自己在制作的 rootfs 根目录下 创建这些挂载点目录即可。

root@ubuntu:/home/aston/workspace/porting_x210/rootfs/rootfs# mkdir proc sys tmp var dev
root@ubuntu:/home/aston/workspace/porting_x210/rootfs/rootfs# ls
bin  dev  etc  linuxrc  proc  sbin  sys  tmp  usr  var
root@ubuntu:/home/aston/workspace/porting_x210/rootfs/rootfs# 

在这里插入图片描述


(4) 验证是否挂载成功,可以看挂载时输出信息;还可以启动后去看 proc 和 sys 文件夹,如果有文件出现则证明挂载成功了,如果没东西就证明失败了。

在这里插入图片描述

在这里插入图片描述


五、rcS文件介绍2

1、mdev

(1) mdev 是 udev 的嵌入式简化版本,udev/mdev 是用来配合 linux 驱动工作的一个应用层的软件,udev/mdev 的工作就是配合 linux 驱动生成相应的 /dev 目录下的设备文件。


(2) 因为这个问题涉及到驱动,因此详细讲解要等到驱动部分。这里我们只是通过一些直观的现象来初步理解 udev/mdev 的工作效果。


(3) 在 rcS 文件中没有启动 mdev 的时候,/dev 目录下启动后是空的;在 rcS 文件中添加上 mdev 有关的 2 行配置项后,再次启动系统后发现,/dev 目录下生成了很多的设备驱动文件。

在这里插入图片描述


(4) /dev 目录下的设备驱动文件就是 mdev 生成的,这就是 mdev 的效果和意义。

在这里插入图片描述

在这里插入图片描述


2、hostname

(1) hostname 是 linux 中的一个 shell 命令。命令(hostname xxx)执行后,可以用来设置当前系统的主机名为 xxx,直接 hostname 不加参数,可以显示当前系统的主机名。


(2)

/bin/hostname -F /etc/sysconfig/HOSTNAME

-F 来指定一个主机名配置文件(这个文件一般文件名叫 hostname 或者 HOSTNAME)

在这里插入图片描述


在这里插入图片描述


3、ifconfig

(1) 有时候我们希望开机后进入命令行时,ip 地址就是一个指定的 ip 地址(譬如192.168.1.30),这时候就可以在 rcS 文件中:

ifconfig eth0 192.168.1.30

在这里插入图片描述

在这里插入图片描述


六、profile 文件和用户登录理论

1、profile 文件添加

(1) 之前添加了 /bin/hostname/etc/sysconfig/HOSTNAME 文件中定义了一个 hostname(aston210),实际效果是:命令行下 hostname 命令查到的 host 名字确实是 aston210。但是问题就是,命令行的提示符是没有显示的。


(2) 这个问题的解决就要靠 profile 文件。将提供的 profile 文件放入 /etc/ 目录下即可。

root@ubuntu:/home/aston/workspace/porting_x210/rootfs/rootfs# cd etc/
root@ubuntu:/home/aston/workspace/porting_x210/rootfs/rootfs/etc# 
root@ubuntu:/home/aston/workspace/porting_x210/rootfs/rootfs/etc# cp /mnt/hgfs/linux_win_shared/etc/profile .
root@ubuntu:/home/aston/workspace/porting_x210/rootfs/rootfs/etc# ls
fstab  init.d  inittab  profile  sysconfig
root@ubuntu:/home/aston/workspace/porting_x210/rootfs/rootfs/etc# cat profile 
# Ash profile
# vim: syntax=sh# No core files by default
ulimit -S -c 0 > /dev/null 2>&1USER="`id -un`"
LOGNAME=$USER
PS1='[\u@\h \W]\# '
PATH=$PATHHOSTNAME=`/bin/hostname`export USER LOGNAME PS1 PATHroot@ubuntu:/home/aston/workspace/porting_x210/rootfs/rootfs/etc# 

在这里插入图片描述


(3) 添加了 profile 之后的实验现象:命令行提示符前面显示:[@aston210 ]#

在这里插入图片描述

结论是:

第一,profile 文件起了作用,hostname 显示出来了。

第二,还有个问题,登录用户名没显示出来。

原因就是我们直接进入了命令行,而没有做登录。等我们添加了用户登录功能,并且成功登陆后这个问题就能解决。


(4) profile 文件工作原理是:profile 文件也是被 busybox(init 进程)自动调用的,所以是认名字的。


2、如何看到用户登录界面

(1) linux 中有一个原则就是:用一个小程序来完成一个功能。如果我们产品确实需要很复杂的综合型的功能,我们倾向于先使用很多个小程序完成其中的一个功能,然后再将这些小程序集成起来完成整个大功能的产品。


(2) 这种集成很多个小程序来完成一个大的功能,有很多种技术实现。譬如 shell 脚本,还有一些别的技术,譬如 linux 启动中的 inittab。


(3) 因为我们之前 intttab 中有一个配置项 ::askfirst:-/bin/sh,这个配置项作用就是:当系统启动后,就去执行 /bin/sh,执行这个就会出现命令行。
因此我们这样的安排就会直接进入命令行,而不会出现登录界面。


(4) 我们要出现登录界面, 就不能直接执行 /bin/sh,而应该执行一个负责出现登录界面,并且负责管理用户名和密码的一个程序,busybox 中也集成了这个程序(就是 /bin/login 和 /sbin/gettty),因此我们要在 inittab 中用 /bin/login 或者 /sbin/getty ,去替代 /bin/sh。


3、用户名和密码的设置

(1) 用户名和密码的设置,是和登录程序有关联的,但是 /bin/login和 /sbin/getty 在用户名和密码的管理上是一样的。 其实常见的所有的 linux 系统的用户名和密码的管理几乎都是一样的。


(2) 密码一般都是用加密文字的,而不是用明文。意思就是系统中的密码肯定是在系统中的一个专门用来存密码的文件中存储的,用明文存密码有风险,因此 linux 系统都是用密文来存储密码的。关于密文密码的使用下节课实践时会详细讲。


七、用户登录实战

1、添加 /bin/login 到 sysinit

(1) 在 inittab 中修改,去掉 /bin/sh,换上 /bin/login,则系统启动后出现登录界面。可以输入用户名和密码。

root@ubuntu:/home/aston/workspace/porting_x210/rootfs/rootfs/etc# vim inittab 
root@ubuntu:/home/aston/workspace/porting_x210/rootfs/rootfs/etc# cat inittab 
#first:run the system script file
::sysinit:/etc/init.d/rcS
#::askfirst:-/bin/sh
::sysinit:/bin/login
::ctrlaltdel:-/sbin/reboot
#umount all filesystem
::shutdown:/bin/umount -a -r
#restart init process
::restart:/sbin/initroot@ubuntu:/home/aston/workspace/porting_x210/rootfs/rootfs/etc# 

在这里插入图片描述


(2) 实验现象:成功出现用户登录界面,但是死活密码不对。

成功出现登陆界面:

在这里插入图片描述


2、添加 passwd 和 shadow 文件

(1) 为什么用户名和密码不对?因为我们根本没有为 root 用户设置密码。


(2) linux 系统中用来描述用户名和密码的文件是 passwd 和 shadow 文件,这两个文件都在 etc 目录下。passwd 文件中存储的是用户的密码设置,shadow 文件中存储的是加密后的密码。


(3) 我们直接复制 ubuntu 系统中的 /etc/passwd 和 /etc/shadow 文件到当前制作的 rootfs 目录下,然后再做修改即可。

在这里插入图片描述


同理,删除 shadow 文件除了 root 之外的 其他用户密码:

在这里插入图片描述


(4) /etc/passwd 和 /etc/shadow 修改好后,shadow 中默认有一个加密的密码口令,这个口令和你拷贝的shadow本身有关,像我的 ubuntu 中, root 用户的密码就是 root,因此复制过来后登陆时的密码还是 root。

在这里插入图片描述


3、重置密码实践

(1) ubuntu 刚装好的时候,默认登录是用普通用户登录的,默认 root 用户是关闭的。普通用户的密码是在装系统的时候设置的,普通用户登陆后可以使用 su passwd root 给 root 用户设置密码,设置了密码后,root 用户才可以登录。


(2) 其实这个原因就是,root 用户在 /etc/shadow 文件中加密口令是空白的。所以是不能登录的。


(3) busybox 中因为没有普通用户,所以做法是:默认 root 用户如果加密口令是空的,则默认无密码直接登录。

等我们登陆了之后,还是可以用 passwd root 给 root 用户设置密码。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述


解决报错:-sh:can’t access tty; job control turned off

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述


(4) 平时有时候我们忘记了自己的操作系统的密码,怎么办?

有一种解决方法就是,用其他系统(WindowsPE 系统或者 ubuntu 的单用户模式等···)来引导启动,启动后挂载到我们的硬盘上,然后找到 /etc/shadow 文件,去掉密文密码后保存。然后再重启系统后密码就没了。


4、getty 实战

(1) 大家后面做项目会发现,inittab 中最常见的用于登录的程序不是 /bin/login,反而是 /sbin/getty。


(2) 这两个的差别不详,但是在 busybox 中这两个是一样的。这两个其实都是 busybox 的符号链接而已。因此不用严格区分这两个。


(3) 我们可以在 inittab 中,用 getty 替换 login 程序来实现同样的效果。

在这里插入图片描述

重启登录效果没有差别:

在这里插入图片描述


八、动态链接库的拷贝

1、静态编译链接 helloworld 程序并执行

(1) 任务:自己写一个 helloworld 程序,然后交叉编译连接,然后丢到开发板根文件系统中,开机后去运行。


(2) C 程序如果使用 gcc 来编译,则可以在主机 ubuntu 中运行,但是不能在开发板运行;

要在开发板运行,需要用 arm-linux-gcc 来交叉编译,但是这时候就不能在主机 ubuntu 中运行了。

我们可以用 file xx 命令来查看一个 elf 可执行程序是哪个架构的。

在这里插入图片描述


(3) 静态链接:

arm-linux-gcc hello.c -o hello_satic -static

在这里插入图片描述

制作 Makefile 进行程序编译:

在这里插入图片描述


(4) 实验结果:静态编译连接后生成的 hello_satic 已经可以成功运行。

在这里插入图片描述


2、动态编译连接helloworld程序并执行

(1) 动态链接:

arm-linux-gcc hello.c -o hello_dynamic

(2) 实验结果:-sh: ./hello_dynamic: not found 。运行时提示找不到程序。

在这里插入图片描述


(3) 错误分析:动态链接的 hello 程序中调用到了 printf 函数,而 printf 函数在动态连接时,要在运行时环境(开发板的 rootfs)中,去寻找对应的库文件(开发板 rootfs 中部署的动态链接库中,包含了 printf 函数的那个库文件)。如果找到了,则 printf 函数就会被成功解析,然 后hello_dynamic 程序就会被执行;如果找不到,则程序就不能被执行,命令行会提示错误信息 -sh: ./hello_dynamic: not found。


(4) 解决方案:将 arm-linux-gcc 的动态链接库文件,复制到开发板 rootfs 的 /lib 目录下即可解决。


3、找到并复制动态链接库文件到rootfs中

(1) 我们用的 arm-2009q3 这个交叉编译工具链的动态链接库,在 /usr/local/arm/arm-2009q3/arm-none-linux-gnueabi/libc/lib 目录下。

其他的一些交叉编译工具链中动态链接库的目录不一定在这里,要去找一下。找的方法就是 find。

在这里插入图片描述


(2) 复制动态链接库,到 roots/lib 目录下。复制时要注意参数用 -rdf,主要目的就是符号链接复制过来还是符号链接。
复制命令:

cp ../lib/ /home/aston/workspace/porting_x210/rootfs/rootfs/. -rfd

在这里插入图片描述

在这里插入图片描述

动态库的大小总共 3.8M:

在这里插入图片描述


(3) 现在再去测试 ./hello_dynamic 看看是否可以运行,实验结果是可以运行。

在这里插入图片描述


4、使用strip工具去掉库中符号信息

动态链接库 so 文件中,包含了调试符号信息,这些符号信息在运行时是没用的(调试时用的),这些符号会占用一定空间。

在传统的嵌入式系统中,flash 空间是有限的,为了节省空间常常把这些符号信息去掉。这样节省空间并且不影响运行。

去掉符号命令:

arm-linux-strip *so*

实际操作后发现库文件由 3.8M 变成了 3.0M,节省了 0.8M 的空间。

在这里插入图片描述


九、开机自启动与主流rcS格式介绍

1、修改 rcS 实现开机自启动

(1) 开机自启动指的是,让一些应用程序能够开机后自动执行。


(2) 开机自启动的实现原理就是,在开机会自动执行的脚本 rcS 中,添加上执行某个程序的语句代码即可。

在这里插入图片描述


2、前台运行与后台运行

(1) 程序运行时占用了当前的控制台,因此这个程序不结束我们都无法使用控制台,这就叫前台运行。默认执行程序就是前台运行的。


(2) 后台运行就是让这个程序运行,并且同时让出控制台。这时候运行的程序还能照常运行,而且还能够不影响当前控制台的使用。


(3) 让一个程序后台运行的方法就是 ./xxx &


3、实际开发中 rootfs 的 rcS 是怎样的

(1) 我们以 X210 开发板九鼎科技做的 rootfs 中 rcS 部分来分析。


(2) 分析 inittab 发现:sysinit 时执行 rcS,shutdown 时执行 rcK。

在这里插入图片描述


(3) 分析 /etc/init.d/rcS 和 rcK 文件发现,rcS 和 rcK 都是去遍历执行 /etc/init.d/ 目录下的 S 开头的脚本文件,区别是 rcS 传参是 start,rcK 传参是 stop。


(4) 由此可以分析出来,正式产品中的 rcS 和 rcK 都是一个引入,而不是真正干活的。真正干活的配置脚本是 /etc/init.d/S??*。这些文件中肯定有一个判断参数是 start 还是 stop,然后 start 时去做一些初始化,stop 时做一些清理工作。


十、制作 ext2 格式的镜像并烧录启动

1、确定文件夹格式的rootfs可用

(1) 设置 bootargs 为 nfs 启动方式,然后从主机 ubuntu 中做好的文件夹格式的 rootfs 去启动,然后看启动效果,作为将来的参照物。


2、动手制作ext2格式的镜像

在这里插入图片描述


(1)

# bs=1024 count=10240   相乘就是 10MB.
dd if=/dev/zero of=rootfs.ext2 bs=1024 count=10240
losetup  /dev/loop1 rootfs.ext2
mke2fs -m 0 /dev/loop1 10240
mount -t ext2 /dev/loop1 ./ext2_rootfs/

在这里插入图片描述


(2) 向 ./rootfs 中复制内容

root@ubuntu:/home/aston/workspace/porting_x210/rootfs#cd ext2_rootfs/
root@ubuntu:/home/aston/workspace/porting_x210/rootfs/ext2_rootfs# ls
lost+found
root@ubuntu:/home/aston/workspace/porting_x210/rootfs/ext2_rootfs# 
root@ubuntu:/home/aston/workspace/porting_x210/rootfs/ext2_rootfs# 
root@ubuntu:/home/aston/workspace/porting_x210/rootfs/ext2_rootfs# cp ../rootfs/* . -rf
root@ubuntu:/home/aston/workspace/porting_x210/rootfs/ext2_rootfs# ls

在这里插入图片描述


(3) 回到 ext2_rootfs 的上级路径,卸载 ext2_rootfs 根文件系统:

umount /dev/loop1
losetup -d /dev/loop1

在这里插入图片描述


(4)完成后得到的rootfs.ext2就是我们做好的rootfs镜像。拿去烧录即可。

cp rootfs.ext2   /mnt/hgfs/linux_win_shared/. -rf

拷贝 rootfs.ext2 文件,到 Windows 主机:

在这里插入图片描述

将 rootfs.ext2 文件拷贝到 Windows 的 fastboot 软件目录中:

在这里插入图片描述


3、烧录镜像并设置合适的bootargs

(1) 使用 fastboot 烧录制作好的 rootfs.ext2 到开发板 inand 中

fastboot flash system rootfs.ext2

烧录完成后重启系统

  1. 开发板进入 fastboot 模式:
    在这里插入图片描述

  2. 在 Windows fastboot 这边输入命令:
    在这里插入图片描述


(2) 设置bootargs为:

set bootargs console=ttySAC2,115200 root=/dev/mmcblk0p2 rw init=/linuxrc rootfstype=ext2

在这里插入图片描述


(3) 启动后发现,现象和之前 nfs 方式启动挂载 rootfs 后一样的,至此 rootfs 制作实验圆满完成。

在这里插入图片描述


源自朱有鹏老师.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_102345.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【JUC高并发编程】—— 初见JUC

一、JUC 概述 什么是JUC JUC 是 Java并发编程的缩写&#xff0c;指的是 Java.util.concurrent 即Java工具集下的并发编程库 【说白了就是处理线程的工具包】 JUC提供了一套并发编程工具&#xff0c;这些工具是Java 5以后引入的&#xff0c;使得Java开发者可以更加方便地编写…

【系统集成项目管理工程师】项目干系人管理

&#x1f4a5;十大知识领域&#xff1a;项目干系人管理 项目干系人管理包括以下 4 个过程: 识别干系人规划干系人管理管理干系人参与控制干系人参与 一、识别干系人 输入工具与技术输出项目章程采购文件事业环境因素组织过程资产组织相关会议专家判断干系人分析干系人登记册 …

ansible自动运维——ansible使用临时命令通过模块来执行任务

大家好&#xff0c;这里是天亮之前ict&#xff0c;本人网络工程大三在读小学生&#xff0c;拥有锐捷的ie和红帽的ce认证。每天更新一个linux进阶的小知识&#xff0c;希望能提高自己的技术的同时&#xff0c;也可以帮助到大家 另外其它专栏请关注&#xff1a; 锐捷数通实验&…

为什么使用了索引,查询还是慢?

&#x1f3c6;今日学习目标&#xff1a; &#x1f340;为什么使用了索引&#xff0c;查询还是慢&#xff1f; ✅创作者&#xff1a;林在闪闪发光 ⏰预计时间&#xff1a;30分钟 &#x1f389;个人主页&#xff1a;林在闪闪发光的个人主页 &#x1f341;林在闪闪发光的个人社区&…

linux 安装 oracle 11g

linux 安装 oracle 11g 1、下载oracle 11g (11.2.0.1.0)1.1、Oracle Database 11.2.0.1.01.2、Oracle Database Grid Infrastructure 11.2.0.1.01.3、客户端 2、安装文档3、安装前准备3.1、建立用户和用户组3.2、sysctl3.3、security limits3.4、其他设置3.5、创建安装目录3.6、…

校招又临近了,怎么在面试中应对设计模式相关问题呢?

夏天开始了&#xff0c;那么夏天结束时的毕业季也不远了。毕业是个伤感、期待而又略带残酷的时节&#xff0c;就像蜜桃无论成熟与否都会在这个时间被采摘&#xff0c;如果毫无准备就踏入社会&#xff0c;就会……马上变成低级社畜。所以说还是要早点为了毕业找工作做点准备&…

Jetson nano B01学习笔记 -- 系统环境配置以及ROS安装

文章目录 一、Jetson nano 简介二、 系统环境配置1、系统镜像烧录2、CUDA环境配置 三、 ROS安装和环境配置总结 一、Jetson nano 简介 Jetson Nano是一款体积小巧、功能强大的人工智能嵌入式开发板&#xff0c;于2019年3月由英伟达推出。它预装Ubuntu 18.04LTS系统&#xff0c;…

LeafLet加载自定义Legend的设计与实现

背景 众所周知&#xff0c;在GIS的世界里&#xff0c;图例和地图永远是一对一起出现的对象。在地图上表示地理环境各要素&#xff0c;比如山脉、河流、城市、铁路等所用的符号叫做图例。这些符号所表示的意义&#xff0c;常注明在地图的边角上。图例是表达地图内容的基本形式和…

小六壬学习笔记

小六壬学习笔记 简介前置知识:十二地支和十二时辰适用范围起课&#xff1a;月令日时卦象 疑问&#xff1a;遇到闰月怎么办&#xff1f;禁忌数字起课法手机计算器取余数 简单解卦 简介 马前课&#xff0c;又名&#xff1a;小六壬。 小六壬历史渊源&#xff1a;https://m.sohu.c…

统信UOS 20 安装达梦数据库V8

统信UOS 20 安装达梦数据库V8 1、安装教程2、启动数据库实例服务失败解决方法3、使用dm管理工具连接数据库 1、安装教程 https://blog.csdn.net/OceanWaves1993/article/details/129936878 此教程进行到启动数据库实例步骤时 使用下面命令启动数据库实例服务时&#xff0c;报…

大数据技术之集群数据迁移

在大数据集群数据迁移的项目中涉及到很多技术细节&#xff0c;本博客记录了迁移的大致的操作步骤。 迁移借用Hadoop自带的插件&#xff1a;distcp。 一、Hadoop集群数据迁移 **DistCp&#xff08;分布式拷贝&#xff09;**是用于大规模集群内部和集群之间拷贝的工具。它使用M…

DHCP笔记

目录 DHCP动态主机配置协议——UDP67/68端口 DHCP获取IP地址 客户端首次获取IP地址 客户端再次获取IP地址 租期/续租 DHCP的工作报文 DHCP的配置 案例 DHCP动态主机配置协议——UDP67/68端口 DHCP是应用层协议&#xff0c;采用C/S服务模式&#xff0c;只能在一个广播域…

数据科学与机器学习在软件开发中的应用

数据科学和机器学习是现代软件开发的重要组成部分&#xff0c;可以帮助开发人员更好地理解和分析数据&#xff0c;从而提高软件的质量和性能。在本篇博客中&#xff0c;我将深入探讨数据科学和机器学习在软件开发中的应用&#xff0c;并讨论它们如何帮助我们创建更好的软件。 …

Xshell中的基本命令

whoami 当我们刚登录上Xshell的时候&#xff0c;我们应该做什么呢&#xff1f;&#xff1f; 我们上次说了如何增加使用者&#xff0c;和删除使用者&#xff0c;今天我们说一下其他的基本命令。 我们刚开始登录的时候可以用root登录 那么我们怎么看自己事谁呢&#xff1f; …

Android 一个获取网址时间的Demo

Android 一个获取网址时间的Demo 文章目录 Android 一个获取网址时间的Demo通过一个网址获取时间的代码关于Android NTP 时间Android 同步时间代码 前段时间有个客户想用局域网同步Android 设备的时间&#xff0c;开发后把这个demo分享一下。 效果&#xff1a; 这里也获取了阿…

VUE3子组件-业务代码优化

Vue3子组件 1.简介 Vue 3组件的主要优势之一就是它们可以帮助你将你的应用程序分解成可维护和可重用的部分。当你在应用程序中多次使用相同的代码时&#xff0c;你可以将它们抽象成一个组件&#xff0c;然后在应用程序中的多个地方使用该组件&#xff0c;而不必每次都编写相同…

User Diverse Preference Modeling by Multimodal Attentive Metric Learning

BACKGROUND 现有模型通常采用一个固定向量去表示用户偏好&#xff0c;在假设——特征向量每一个维度都代表了用户的一种特性或者一个方面&#xff0c;这种方式似乎不妥&#xff0c;因为用户对于不同物品的偏好是不一样的&#xff0c;例如因演员喜欢一部电影&#xff0c;而因特…

Linux 静态库的制作与使用

目录 静态库1、 什么是库2、 静态库的制作2.1 命名规则与制作规则 3、 静态库的使用 静态库 1、 什么是库 库文件是计算机上的一类文件&#xff0c;可以简单的把库文件看成一种代码仓库&#xff0c;它提供使用者可以直接拿来用的变量、函数或类。库是一种特殊的程序&#xff…

多兴趣推荐召回模型:ComiRec

前言 多兴趣向量召回系列&#xff1a; 通过Youtube DNN推荐模型来理解推荐流程 多兴趣召回模型&#xff1a;MIND 推荐系统可以表达为序列推荐问题的形式&#xff0c;序列推荐任务是通过用户的历史行为来预测用户下一个感兴趣的item&#xff0c;这也与真实场景的推荐场景是符…

ERROR org.springframework.web.context.ContextLoader

项目启动时报错&#xff1a; ERROR org.springframework.web.context.ContextLoader - Context initialization failed java.lang.NoSuchMethodError: org.springframework.core.annotation.AnnotationUtils.clearCache() 原因分析 这个错误的原因可能是因为 Spring 的不同…