busybox制作最小根文件系统制作(保姆式教学)
1.busybox 编译编译环境:Ubuntu16.04 + gcc 5.4.0busybox版本:busybox 1.7.0busybox 官网链接1.1 解压tar xjf busybox1.7.0.tar.bz21.2 配置busybox编译之前需要先进行配置,如设置选择连接方式(动态或静态)、是否设置Tab补全功能等。cd busybox-1.7.0/make menuconfig1.2.
1.busybox 编译
- 编译环境:Ubuntu16.04 + gcc 5.4.0
- busybox版本:busybox 1.7.0 busybox 官网链接
1.1 解压
tar xjvf busybox1.7.0.tar.bz2
1.2 配置
busybox编译之前需要先进行配置,如设置选择链接方式(动态或静态)、是否设置Tab补全功能等。主要配置选项的含义如下图所示:
图形化配置命令:
cd busybox-1.7.0/
make menuconfig
1.2.1可能遇到的问题1
Makefile:405: *** mixed implicit and normal rules: deprecated syntax
Makefile:1242: *** mixed implicit and normal rules: deprecated syntax
make: *** No rule to make target 'menuconfig'。 停止。
-
原因:版本过久
-
解决方法:
a.修改busybox-1.7.0 顶层Makefile 405行:config%config: scripts_basic outputmakefile FORCE
改为:
%config:scripts_basic outputmakefile FORCE
b.修改busybox-1.7.0 顶层Makefile 1242行:/%/: prepare scripts FORCE
改为:
%/:prepare scripts FORCE
1.2.2 可能遇到的问题2
In file included from scripts/kconfig/lxdialog/checklist.c:24:0:
scripts/kconfig/lxdialog/dialog.h:31:20: fatal error: curses.h: 没有那个文件或目录
compilation terminated.
scripts/Makefile.host:120: recipe for target 'scripts/kconfig/lxdialog/checklist.o' failed
make[2]: *** [scripts/kconfig/lxdialog/checklist.o] Error 1
~/busybox-1.7.0/scripts/kconfig/Makefile:14: recipe for target 'menuconfig' failed
make[1]: *** [menuconfig] Error 2
Makefile:406: recipe for target 'menuconfig' failed
make: *** [menuconfig] Error 2
-
原因:ubuntu系统中缺少一个套件 ncurses devel
-
解决方法:安装此套件安装下即可:
sudo apt-get install libncurses5-dev
正在读取软件包列表... 完成
正在分析软件包的依赖关系树
正在读取状态信息... 完成
建议安装:
ncurses-doc
下列【新】软件包将被安装:
libncurses5-dev libtinfo-dev
升级了 0 个软件包,新安装了 2 个软件包,要卸载 0 个软件包,有 25 个软件包未被升级。
需要下载 252 kB 的归档。
解压缩后会消耗 1,461 kB 的额外空间。
您希望继续执行吗? [Y/n] y
获取:1 https://mirrors.tuna.tsinghua.edu.cn/ubuntu xenial/main amd64 libtinfo-dev amd64 6.0+20160213-1ubuntu1 [77.4 kB]
获取:2 https://mirrors.tuna.tsinghua.edu.cn/ubuntu xenial/main amd64 libncurses5-dev amd64 6.0+20160213-1ubuntu1 [175 kB]
已下载 252 kB,耗时 0秒 (254 kB/s)
正在选中未选择的软件包 libtinfo-dev:amd64。
(正在读取数据库 ... 系统当前共安装有 249748 个文件和目录。)
正准备解包 .../libtinfo-dev_6.0+20160213-1ubuntu1_amd64.deb ...
正在解包 libtinfo-dev:amd64 (6.0+20160213-1ubuntu1) ...
正在选中未选择的软件包 libncurses5-dev:amd64。
正准备解包 .../libncurses5-dev_6.0+20160213-1ubuntu1_amd64.deb ...
正在解包 libncurses5-dev:amd64 (6.0+20160213-1ubuntu1) ...
正在处理用于 man-db (2.7.5-1) 的触发器 ...
正在设置 libtinfo-dev:amd64 (6.0+20160213-1ubuntu1) ...
正在设置 libncurses5-dev:amd64 (6.0+20160213-1ubuntu1) ...
1.2.3 设置交叉编译器前缀为“arm-linux-”
- 依次进入Busybox Settings ——> Build Options,找到Cross compiler prefix选项,并将其修改为“arm-linux-”。
- 一些老版本的busybox不一定有此选项,此时可以选择修改Makefile文件:
原来的代码:
175 ARCH ?= $(SUBARCH)
176 CROSS_COMPILE ?=
修改后的代码:
175 ARCH ?= arm
176 CROSS_COMPILE ?= arm-linux-
1.2.4 设置init程序自动读取inittab配置文件
- 依次选择“Init Utilities” -> “Support reading an inittab file” 。
1.2.5 设置Tab键命令补全
- 依次选择“Busybox Setting”-> “Busybox library tuning”-> “Tab completion”。
1.2.6 设置为静态链接
- 依次选择“Busybox Setting”-> “Building options”-> “Build busybox as a static binary(no shared libs)”。
1.3 编译
make
- 可能遇到的问题
/arm-none-linux-gnueabi/libc/usr/include/linux/netfilter.h:44: error: field ‘in’ has incomplete type
/arm-none-linux-gnueabi/libc/usr/include/linux/netfilter.h:45: error: field ‘in6’ has incomplete type
ipsvd/tcpudp.c: In function ‘tcpudpsvd_main’:
ipsvd/tcpudp.c:314: warning: ignoring return value of ‘write’, declared with attribute warn_unused_result
scripts/Makefile.build:192: recipe for target ‘ipsvd/tcpudp.o’ failed
make[1]: *** [ipsvd/tcpudp.o] Error 1
Makefile:701: recipe for target ‘ipsvd’ failed
make: *** [ipsvd] Error 2
-
原因:使用的交叉编译库中有个头文件中的 in 和 in6 类型不对。
-
解决方法:在 …/arm-none-linux-gnueabi/libc/usr/include/linux/netfilter.h 的开头添加缺少的头文件
#include <netinet/in.h>
-
编译成功后显示:
util-linux/umount.c: In function 'umount_main':
util-linux/umount.c:96: warning: ignoring return value of 'realpath', declared with attribute warn_unused_result
AR util-linux/lib.a
LINK busybox_unstripped
Trying libraries: crypt m
Library crypt is needed
Library m is needed
Final link with: crypt m
1.4.busybox 安装
制作根文件系统映像文件,其实就是将我们制作好的目录及其所有内容,按照一定的文件格式存放到一个文件中,这个文件可以直接烧写到存储器上,当系统启动后挂接这个设备,就可以读取到与原来目录一样的内容。
- 新建一个安装目录 fs_mini_mdev_test 用于安装busybox,然后使用
CONFIG_PREFIX
环境变量指定该目录进行安装:
mkdir ./fs_mini_mdev_leon
make install CONFIG_PREFIX=./fs_mini_mdev_leon
- 可能遇到的错误1:创建链接文件失败
ln: failed to create symbolic link '/mnt/hgfs/virtual_shared/jz2440/busybox1.7/fs_mini_mdev_leon/bin/addgroup': Operation not supported
-
原因:busybox放在linux虚拟机与windows共享的文件下,由于在安装busybox文件的时候需要建立一些软连接,而在windows下不支持此操作。
-
解决方法:
- 方法一:将busybox复制到linux的非共享文件夹下,然后再执行安装操作。
- 方法二:在Linux中,建立Samba服务,然后新创建新samba用户和文件夹,这样在windows中就可以访问到该文件夹了。然后在Linux中,从共享目录拷贝到你所要共享的samba目录中,这样,也可以实现我们所要的文件共享。
-
可能遇到的错误2
make: *** No rule to make target 'install'。 停止。
- 原因:make install命令没在解压后的busybox目录下执行,所以找不到make的target。
- 解决方法:在解压后的busybox目录下执行
make install
命令。
安装成功后显示:
- 查看目录fs_mini_mdev_leon中生成的最小文件系统内容:
leon@ubuntu:~$ cd fs_mini_mdev_leon/
leon@ubuntu:~/fs_mini_mdev_leon$ ls
bin linuxrc sbin usr
leon@ubuntu:~/fs_mini_mdev_leon$ cd bin
leon@ubuntu:~/fs_mini_mdev_leon/bin$ ls
addgroup chgrp delgroup egrep gzip iprule ls mountpoint ping6 rpm stty uname
adduser chmod deluser false hostname iptunnel lsattr mt pipe_progress run-parts su uncompress
ash chown df fdflush ip kill mkdir mv printenv sed sync usleep
busybox cp dmesg fgrep ipaddr linux32 mknod netstat ps setarch tar vi
cat cpio dumpkmap getopt ipcalc linux64 mktemp nice pwd sh touch watch
catv date echo grep iplink ln more pidof rm sleep true zcat
chattr dd ed gunzip iproute login mount ping rmdir stat umount
- 查看最小文件系统中的命令本质都是指向busybox的链接。
leon@ubuntu:~/fs_mini_mdev_leon$ ls -l
总用量 12
drwxrwxr-x 2 leon leon 4096 Jun 7 21:27 bin
lrwxrwxrwx 1 leon leon 11 Jun 7 21:27 linuxrc -> bin/busybox
drwxrwxr-x 2 leon leon 4096 Jun 7 21:27 sbin
drwxrwxr-x 4 leon leon 4096 Jun 7 21:27 usr
leon@ubuntu:~/fs_mini_mdev_leon$ ls -l ./bin/ls
lrwxrwxrwx 1 leon leon 7 Jun 7 21:27 ./bin/ls -> busybox
2.安装glibc库
2.1 确定交叉编译器路径
leon@ubuntu:~/fs_mini_mdev_leon$ echo $PATH
/home/leon/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/usr/local/arm/4.3.2/bin:/snap/bin
2.2 确定交叉编译器使用的库文件
leon@ubuntu:~/fs_mini_mdev_leon$ cd /usr/local/arm/4.3.2/bin
leon@ubuntu:/usr/local/arm/4.3.2/bin$ cd ../
leon@ubuntu:/usr/local/arm/4.3.2$ ls
arm-none-linux-gnueabi bin lib libexec share
leon@ubuntu:/usr/local/arm/4.3.2$ find -name lib
./lib
./arm-none-linux-gnueabi/lib
./arm-none-linux-gnueabi/libc/lib
./arm-none-linux-gnueabi/libc/thumb2/lib
./arm-none-linux-gnueabi/libc/thumb2/usr/lib
./arm-none-linux-gnueabi/libc/armv4t/lib
./arm-none-linux-gnueabi/libc/armv4t/usr/lib
./arm-none-linux-gnueabi/libc/usr/lib
2.3 复制lib库文件到最小根文件目录中
- 在最小根文件目录中新建
/lib
和/usr/lib
文件夹 - 将
./arm-none-linux-gnueabi/libc/lib
中的动态库文件拷贝到/lib
文件夹中; - 将
./arm-none-linux-gnueabi/libc/usr/lib
中的动态库文件拷贝到/usr/lib
文件夹中;
leon@ubuntu:/usr/local/arm/4.3.2/arm-none-linux-gnueabi/libc/lib$ mkdir ~/fs_mini_mdev_leon/lib
leon@ubuntu:/usr/local/arm/4.3.2/arm-none-linux-gnueabi/libc/lib$ mkdir ~/fs_mini_mdev_leon/usr/lib
leon@ubuntu:/usr/local/arm/4.3.2/arm-none-linux-gnueabi/libc/lib$ cp *.so* -d ~/fs_mini_mdev_leon/lib
leon@ubuntu:/usr/local/arm/4.3.2/arm-none-linux-gnueabi/libc/usr/lib$ cp *.so* -d ~/fs_mini_mdev_leon/usr/lib
3.构建基本目录
3.1 构建etc目录
mkdir etc
cd etc
touch inittab
touch fstab
touch profile
touch passwd
touch group
touch shadow
touch resolv.conf
touch mdev.conf
touch inetd.conf
mkdir rc.d
mkdir init.d
touch init.d/rcS
chmod +x init.d/rcS
mkdir sysconfig
touch sysconfig/HOSTNAME
etc目录下的内容取决于要运行的程序,但至少会创建三个文件:
etc/inittab
: 系统在各种时机(启动、关闭及各种组合键)下自动执行的程序。etc/init.d/rcS
: 系统启动时自动执行的脚本;etc/fstab
: 系统启动后执行mount -a
命令时,自动挂载的文件系统。
3.1.1 编辑etc/inittab文件
内核启动init进程时已经打开/dev/console
设备作为控制台,但若内核启动时设置了环境变量CONSOLE
,则以环境变量制定的控制设备为准,若制定的控制设备不可用,则默认使用/dev/null
设备。
init进程启动后会解析/etc/inittab
文件,然后按照它的指示在各时间节点创建子进程。
该文件的格式为:<id>:<runlebels>:<action>:<process>
id:表示该子进程使用的控制台(标准输入、输出、错误设备)
runlevel:对于init程序,该字段无意义,一般省略为空就好
action:表示init进程何时会启动该子进程。其取值为sysinit、wait、once、respawn、askfirst、shutdown、restart、ctrlaltdel
process:要执行的程序或脚本。该字段前加
-
表示该程序为交互的。
-
init进程各action的执行顺序或时机为:
- sysinit执行完后执行wait,wait执行完后同时执行once、respawn、askfirst。
- shutdown在重启或关机时执行;
- restart在init进程接收到SIGHUP信号时执行(busybox需配置了CONFIG_FEATURE_USE_INITTAB);
- ctrlaltdel在按下Ctrl+ALT+Del3个组合键时执行。
-
仿照Busybox中example下的inittab文件内容,在fs_mini_mdev_leon/目录下创建etc目录,进入etc目录创建一个inittab文件,并编辑以下内容:
# /etc/inittab
::sysinit:/etc/init.d/rcS
ttySAC0::askfirst:-/bin/sh
console::askfirst:-/bin/sh
::ctrlaltdel:/sbin/reboot
::shutdown:/bin/umount -a -r
::restart:/sbin/init
- 当使用mdev自动生成/dev目录时,S3C2410和S3C2440的串口0的名称是
s3c2410_serial0
,而不是ttySAC0
。所以当使用mdev时,要修改以上文件的相应行为s3c2410_serial0::askfirst:-/bin/sh
。
3.1.2 编辑etc/init.d/rcS文件
这是一个脚本文件,可以在里面添加你希望系统启动后自动执行的命令。例如希望系统启动后自动配置ip地址和挂载/etc/fstab指定的文件系统时,可以如下编写:
#!/bin/sh
PATH=/sbin:/bin:/usr/sbin:/usr/bin
runlevel=S
prevlevel=N
umask 022
export PATH runlevel prevlevel
mount -a
/bin/hostname -F /etc/sysconfig/HOSTNAME
ifconfig eth0 192.168.1.17
但若你使用mdev自动创建/dev目录时,还需要添加mdev的几个命令:
mkdir /dev/pts
mount -t devpts devpts /dev/pts
echo /sbin/mdev > /proc/sys/kernel/hotplug
mdev -s
3.1.3 创建etc/fstab文件
该文件用来指示执行mount -a
命令后要挂接的文件系统,其格式如下:
挂载设备 挂载点 文件系统类型 挂接参数 是否备份 是否磁盘检查
挂接参数说明:
auto/noauto:执行mount -a时是否自动挂载;
user/nouser:是否允许普通用户挂载;
exec/noexec:是否允许挂载设备上的程序;
Ro/rw:以只读/读写方式挂接文件系统;
sync/async:修改文件时是否同步写入设备中;
default:rw、suid、dev、exec、auto、nouser、async的组合。
一般,需要自动挂载proc、sysfs、tmpfs、var文件系统:
#device mount-point type option dump fsckorder
proc /proc proc defaults 0 0
tmpfs /tmp tmpfs defaults 0 0
tmpfs /var tmpfs defaults 0 0
但当使用mdev命令时,需要另外挂载sysfs和/dev:
#device mount-point type option dump fsckorder
proc /proc proc defaults 0 0
sysfs /sys sysfs defaults 0 0
tmpfs /tmp tmpfs defaults 0 0
tmpfs /var tmpfs defaults 0 0
tmpfs /dev tmpfs defaults 0 0
3.2 创建dev目录
init 进程至少要用到两个设备文件:console和null,按如下方法建立:
leon@ubuntu:~/fs_mini_mdev_leon$ mkdir dev
leon@ubuntu:~/fs_mini_mdev_leon$ cd dev
leon@ubuntu:~/fs_mini_mdev_leon/dev$ sudo mknod console c 5 1
[sudo] leon 的密码:
leon@ubuntu:~/fs_mini_mdev_leon/dev$ chmod 777 console
leon@ubuntu:~/fs_mini_mdev_leon/dev$ sudo mknod null c 1 3
leon@ubuntu:~/fs_mini_mdev_leon/dev$ chmod 777 null
leon@ubuntu:~/fs_mini_mdev_leon/dev$ ls
console null
其它设备文件可以在系统启动后,使用cat /proc/devices
命令查看内核已经注册的设备,然后手动方式一个一个创建相应的设备文件。当然,也可以直接从其它已经建立好的根文件系统下的dev目录下复制过来。
3.3 构建其它目录
其它目录可以是空目录:
leon@ubuntu:~/fs_mini_mdev_leon$ mkdir proc mnt tmp sys root var opt home media
leon@ubuntu:~/fs_mini_mdev_leon$ ls
bin dev etc lib linuxrc mnt proc root sbin sys tmp usr var opt home media
4. 制作jffs2映像文件
接下来需要将制作好的根文件系统目录 fs_mini_mdev_leon 制作为一个文件系统映像,以jffs2为例来介绍,一是因为它是压缩文件系统,占用空间相对yaffs较小。二是因为Linux内核目前还没有配置支持yaffs2。但一般来说jffs2文件格式更适合NOR Flash,若是NAND Flash,一般需要制作成yaffs文件格式。
4.1 安装mtd-utils工具
leon@ubuntu:~/fs_mini_mdev_leon/etc/init.d$ sudo apt-get install mtd-utils
正在读取软件包列表... 完成
正在分析软件包的依赖关系树
正在读取状态信息... 完成
下列【新】软件包将被安装:
mtd-utils
升级了 0 个软件包,新安装了 1 个软件包,要卸载 0 个软件包,有 25 个软件包未被升级。
需要下载 183 kB 的归档。
解压缩后会消耗 900 kB 的额外空间。
获取:1 https://mirrors.tuna.tsinghua.edu.cn/ubuntu xenial/universe amd64 mtd-utils amd64 1:1.5.2-1 [183 kB]
已下载 183 kB,耗时 1秒 (167 kB/s)
正在选中未选择的软件包 mtd-utils。
(正在读取数据库 ... 系统当前共安装有 217144 个文件和目录。)
正准备解包 .../mtd-utils_1%3a1.5.2-1_amd64.deb ...
正在解包 mtd-utils (1:1.5.2-1) ...
正在处理用于 man-db (2.7.5-1) 的触发器 ...
正在设置 mtd-utils (1:1.5.2-1) ...
4.2 制作jffs2文件系统
执行制作命令:
leon@ubuntu:~$ ls
busybox-1.7.0 fs_mini_mdev_leon
leon@ubuntu:~$ mkfs.jffs2 -n -s 2048 -e 128KiB -d fs_mini_mdev_leon -o fs_mini_mdev_leon.jffs2
leon@ubuntu:~$ ls
busybox-1.7.0 fs_mini_mdev_leon.jffs2 fs_mini_mdev_leon
- mkfs.jffs2命令参数的意思为:
- -n:不要在每个擦除块上都加上清除标志;
- -s 2048:指明一页大小为2048字节;
- -e 128KiB:指明一个擦除扇区大小为128KB;
- -d fs_mini_mdev_test:指定要打包的根文件系统目录;
- -o fs_mini_mdev_test.jffs2:指明输出的映像文件名称;
5. 烧写与测试
将该文件系统映像下载到windows主机中,存放到TFTP服务器目录,然后在开发板中使用uboot烧录nand flash中:
tftp 30000000 fs_mini_mdev_leon.jffs2
nand erase.part rootfs //可使用mtdparts命令查看你板子的分区信息,此例中rootfs是根文件系统分区名
nand write.jffs2 30000000 260000 678c24 //其大小678c24可根据tftp下载命令执行完毕后的提示获得,烧写文件系统时最好避免使用分区别名,而是直接使用地址
然后设置环境变量:
set bootargs console=ttySAC0,115200 root=/dev/mtdblock3 rootfstype=jffs2
saveenv
利用tftp将内核镜像文件传到内存的0x30000000地址处,而后执行bootm 30000000
直接从内存中启动内核。
这个问题是因为编译器编译时使用了eabi接口(Embedded Application Binary Interface,嵌入式应用二进制接口),但是内核中没有开启配置,所以内核提示这是非法指令。
解决方案就是:在linux内核中配置支持该接口。
进入Linux3.4.2内核目录,执行make menuconfig
命令,进入 图形化配置界面。选择Kernel Features 菜单项,选择Use the ARM EABI to compile the kernel
:
然后退出,保存设置,重新编译内核。编译成功后,内核大小为2361KB,超过划分的2MB分区,所以不能烧写到nand flash中,直接使用tftp下载到内存中运行,后续文章中裁剪内核<2MB之后才能烧写到nand flash中!
重新烧写内核,启动进行测试:
tftp 30000000 uImage
bootm 30000000
启动之后,可以看到Linux内核启动成功,根文件系统挂载成功,成功进入Linux命令行:
6、yaffs2文件系统移植
6.1、yaffs2文件系统介绍
-
YAFFS全称为 Yet Another Flash File System 是第一个在GPL协议下发布的、基于日志的、专门为NAND Flash存储器设计的、适用于大容量的存储设备的嵌入式文件系统。
AFFS文件系统目前已经发展到YAFFS2,它向前兼容YAFFS1,主要特点是支持每页容量大于512字节的Nand Flash,相较于YAFFS1,YAFFS2的性能大幅提升。
一般而来,在Nor Flash上使用JFFS2文件系统,在Nand Flash上使用YAFFS2文件系统。
-
yaffs2源码获取,命令行执行:
git clone git://www.aleph1.co.uk/yaffs2
6.2、打补丁
打开yaffs2源码目录下的README-linux-patch
文件即可看到打补丁的方法:
首先在yaffs源码目录下,运行打补丁的脚本patch-ker.sh
,其中:
- c 参数表示copy,复制yaffs2源码文件到Linux内核源码中;
- m 参数表示使用多版本代码,官方推荐;
- 最后一个参数表示Linux源码路径
所以这里我执行的命令如下:
cd yaffs2/
./patch-ker.sh c m ../linux-3.4.2
这条命令会将yaffs2源码拷贝到Linux内核源码中的fs/yaffs2
文件夹下:
6.3、制作yaffs2映像文件
6.3.1 编译工具mkyaffs2image
yaffs2源码的utils文件夹下自带的工具源码没有修改,无法使用,这里使用JZ2440官方提供的工具。
可以在微信公众号mculover666,回复“yaffs“获取下载链接。
下载工具包之后,首先解压:
tar -jxvf yaffs_source_util_larger_small_page_nand.tar.bz2
解压之后进入Development_util_ok/yaffs2/utils
目录,执行make命令编译,编译之后产生的两个可执行文件(绿色)如下:
接着将这需要的可执行文件mkyaffs2image
复制到/usr/local/bin
下面去,这样就可以直接在命令行使用这个命令了。
sudo cp mkyaffs2image /usr/local/bin/
6.3.2 制作映像文件
首先进入到存放有根目录fs_mini_mdev_leon
的目录:
然后执行制作命令:
mkyaffs2image fs_mini_mdev fs_mini_mdev.yaffs2
制作完成:
将生成的映像文件下载到TFTP服务器目录,再下载到开发板的nand falsh对应分区rootfs中:
tftp 30000000 fs_mini_mdev.yaffs2
nand erase.part rootfs
nand write.yaffs 30000000 260000 <tftp传输的文件大小>
接着设置uboot的环境变量,指定文件系统类型为yaffs2:
set bootargs noinitrd console=ttySAC0,115200 root=/dev/mtdblock3 rootfstype=yaffs
saveenv
6.4、配置内核,开启yaffs2支持
进入Linux内核目录,打开图形配置界面,进入 File systems -> Miscellaneous filesystems ,开启yaffs2文件系统支持:
退出并保存,然后编译内核:
make uImage
6.5、启动内核,挂载文件系统
将arch/arm/boot/uImage
内核文件下载到TFTP服务器目录中并启动内核,查看是否支持:
tftp 30000000 uImage
bootm 30000000
注意:uImage大小超过2MB,不能烧写到nand flash的kernel分区中,经过裁剪到<2MB才能烧录到nand flash中,所以此处我们选择直接在内存中启动。
成功启动内核,挂载文件系统,进入Linux命令行:
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)