嵌入式 FreeBSD:打造自己的镜像
作者:Christopher R. Bowman
在上一卷中,我粗略提及了我用的开发板,Digilent 的 ARTYZ7。在本卷,我将讨论如何制作自己的镜像。到某个时候,你可能会需要一个与现有镜像略有差异的镜像,因此你可能想从源代码开始构建、创建镜像来写入 SD 卡。
首先,让我们了解一下 ARTYZ7 如何启动。 Zynq-7000 SoC 技术参考手册 是一本宝贵的技术信息来源,第 6 章讲述了芯片及所有 Zynq 主板的启动过程。这里有很多技术细节,但根据默认配置的跳线设置,ARTYZ7 是从 SD 卡启动的。你可能已经下载看了我在上一卷中提供的镜像。如果查看过,你会发现它是以 MBR 模式格式化的,首先是 FAT 分区,第二个 MBR 分区上是一个带有 UFS 的 FreeBSD 切片。处理器将查找 MBR,并寻找 FAT16/FAT32 分区。它会在 FAT 分区中查找文件 boot.bin
。若找到,它会将其加载到内存中,开始执行。如果你想要直接编程到裸机,可以将你的应用程序写入,命名为 boot.bin
。对我来说这有些复杂。因此,当启动 FreeBSD 时,我们使用了一个第一阶段引导加载程序,像许多嵌入式开发板一样,我们使用 Das U-Boot。U-Boot 是一款由社区维护的开源引导加载程序。在我们的用例中,使用了两回 U-Boot。首先,U-Boot 被编译为最小的第一阶段引导加载程序(FSBL),它设置硬件查找第二阶段引导加载程序,第二阶段引导加载程序也是 U-Boot,但功能更加丰富。在我们的使用中,第二阶段的 U-Boot 位于 FAT 分区中的名为 U-boot.img
的文件中。这个 U-Boot 第二阶段加载程序会从 FAT 分区中的 EFI/BOOT/bootarm.efi
文件加载 lua 加载器。然后,lua 加载器会将内核等文件加载到内存中再执行。
所以,如果我们要构建镜像,我们需要创建分区,再把 U-Boot 和 FreeBSD 安装到 SD 卡上。
构建 U-Boot 相对直接。虽然有许多 U-Boot 的移植版本用于各种板子,但 ARTYZ7 并没有现成的移植版本。我已经创建了一个移植版本,你能在这里找到。虽然我还没有把它纳入 FreeBSD 的 ports 中,但你可以直接将其放入最新的 ports 目录 /usr/ports/sysutils
下。 FreeBSD 手册第 4.5 章提供了非常详细的安装和构建 ports 的说明。你将该 port 添加到你的 ports 中后,在 sysinstall/u-boot-artyz7
目录下简单地运行 make
,应该就能自动下载构建 U-Boot。运行 make install
后,文件 boot.bin
和 U-boot.img
应该会出现在目录 /usr/local/share/U-boot/U-boot-artyz7
下。注意:我以前可以使用较大的 “-j
” 值来让 make
使用多个核心进行构建,但在最新的 ports(2024Q3)中,似乎无法正常工作。
从源代码构建也在 FreeBSD 手册中有很好的文档。在第 26.6 章:从源代码更新 FreeBSD 中,你将找到有关下载 FreeBSD 源代码和从中构建的详细信息。如果你已经在 /usr/src
安装了 FreeBSD 源代码,你可以直接进入该目录并运行以下命令:
虽然这些命令应该能在 ARTYZ7 板上正常工作,毕竟它有完整的 FreeBSD 安装,但你应该做好准备,它会花费很长时间。由于 PC 硬件变得非常强大且价格低廉,我使用一台 AMD64 系统来托管所有文件、开发环境,并进行所有构建。FreeBSD 对交叉编译和构建提供了内置支持。在我的 PC 上,我使用以下命令让我的 PC 为基于 ARM 的 ARTYZ7 卡板进行源代码构建:
这将从 AMD64 构建一个交叉编译器到 ARMv7,并使用这个编译器来构建所有内容。
对于内核配置文件,我已将 src/sys/arm/conf/ZEDBOARD
中的 ZEDBOARD 配置文件复制到 src/sys/arm/conf/ARTYZ7
并在其中修改了名称以匹配。参数 -j32
使得编译过程可以使用最多 32 个进程来进行构建。在一台搭载高速固态硬盘的 AMD 5950x PC 上,构建世界大约需要 10 分钟,构建内核大约需要 60 秒。我无法想象在 ARTYZ7 上需要多少天来完成这个过程。
若你从源代码构建了所有内容,过程可能会有所不同,具体有以下几种方式:
你可以将 SD 卡挂载到主机开发系统,并直接从主机安装到 SD 卡上。
接下来,我们更详细地考察方法 3。我通常会创建 msdos
目录和 ufs
目录,来表示我需要在 SD 卡上的两个分区:
接下来,我在 ufs
目录上进行安装:
你还需要运行分发目标,该目标会在 /etc
中创建所有默认的配置文件。当你对一个工作系统进行源代码升级时,通常不会运行这个命令,因为它会覆盖你的配置文件,但在从零开始构建系统时,你确实需要默认的配置文件:
此时,我已经在 ufs
目录下完成了完整的安装,并可以对镜像进行一些自定义。例如,我可以定制 ufs/etc/rc.conf
,以便自动启动以太网接口 cgem0
上的 DHCP 获取 IP 地址。我可以将 ssh
密钥安装到 ufs/etc/ssh
中,这样系统每次启动时都会使用相同的 ssh
密钥,而非在首次启动时生成新的密钥。由于我使用主机系统来进行所有构建并托管我的文件,我还喜欢配置 /etc/fstab
以通过 NFS 挂载我的主目录。
我发现创建一个用户账户非常方便,这样我可以立即登录:
pw
命令的参数 -R
使得 pw
会编辑 ufs/etc
中的密码文件,而不是我主机系统中的文件。参数 -H0
能让我使用 echo
将密码通过管道传输给 pw
,而无需交互式输入(你需要使用你主机系统中的编码密码替代 xxxx
)。你也可以觉得修改 root 账户的密码更加方便,避免没有密码的情况。
现在,既然我已经按照希望的方式定制了 ufs
目录,我们就来关注一下 FAT 分区。
我需要安装 boot.bin
和 U-boot.img
:
boot.bin
会加载 U-boot.img
,而 U-boot.img
模拟了 FreeBSD 加载器的 EFI 固件。EFI 系统会在 FAT 分区上查找一个名为 EFI/BOOT/bootarm.efi
的文件,因此我们需要将 FreeBSD 的 lua 加载器复制到该位置:
注意,我复制的是我们构建的 ARM 版本,而不是主机版本(后者是 AMD64 代码)。
现在,我们已经有了两个目录 msdos
和 ufs
,它们包含了我们想要写入 SD 卡的文件。接下来我们只需要创建镜像文件。这是一个 4 步的过程:
第一个命令从 msdos
目录构建文件系统镜像文件 (efi.part
)。第二个命令从 ufs
目录构建文件系统镜像文件 (rootfs.ufs
)。第三个命令将 rootfs.ufs
文件组合成一个包含 1GB 交换分区的 FreeBSD 切片。最后一个命令将我们的 efi.part
和 freebsd.part
文件打包成一个单一的镜像文件 (selfbuilt.img
)。
如果我将 SD 卡插入主机,我会看到一个 /dev/da0
设备,并使用简单的 dd
命令将镜像复制到 SD 卡:
到此为止,剩下的工作就是将 SD 卡插入 ARTYZ7 板卡,按下重置(reset)按钮,观察精彩的启动过程。由于我在 ufs
分区中的配置,我能够在启动完成后立即通过 ssh
登录到我的板卡,并且已经通过 NFS 挂载我的主目录。现在,要么征服世界,要么喝杯啤酒——反正啤酒什么时候都合适。
Christopher R. Bowman 自 1989 年开始使用 BSD,当时他在约翰斯·霍普金斯大学应用物理实验室的地下二层工作。后来,在 90 年代中期,他在马里兰大学使用 FreeBSD 设计了自己的第一款 2 微米 CMOS 芯片。从那时起,他一直是 FreeBSD 用户,并对硬件设计及其驱动软件非常感兴趣。他在过去 20 年里一直从事半导体设计自动化行业工作。
最后更新于
这有帮助吗?