嵌入式 Linux 开发入门,第 3 部分
在本系列文章的第二篇文章末尾,该系列概述了嵌入式 Linux 开发的逐步过程,我们已经启动并运行了 LBox,可以用于应用程序开发。 然而,在某些情况下,开发人员需要修改底层系统。 任何 Linux 系统都可以被认为由三个部分组成:根文件系统、内核镜像和引导加载程序(BIOS 在桌面系统中扮演这个角色)。 通常,我们不改动引导加载程序——至少我们希望如此——而是修改根文件系统、内核镜像或两者都修改。
考虑到这种修改需求,本系列文章的第 3 部分包含四个部分
内存组织和文件系统布局
替换内核和根文件系统
替换 JFFS2 文件系统
替换引导加载程序
其中一些操作可能很危险,并可能导致系统无法正常运行。 如何从该状态恢复将在本入门系列的第四篇也是最后一篇文章中讨论。
我们继续使用本系列第 1 部分和第 2 部分中使用的 SBC(单板计算机),即 Engineering Technologies Canada Ltd. 公司的 LBox。 然而,大部分材料具有更广泛的应用,并且应该对各种目标平台有用。
为了智能地替换根文件系统和/或内核镜像,全面了解启动过程并掌握内存组织非常有用。 可以从 SBC 供应商处获得有用的详细信息; 如果 Linux 已驻留,则操作系统本身可以成为信息来源。 特别是,当连接到 LBox 时,我们发现以下 Linux 命令很有用:dmesg、df、cat /proc/mtd、cat /proc/meminfo 和 cat /proc/mounts。
内存和文件系统布局的详细信息因 SBC 而异。 使用上述命令和来自供应商的信息,可以获得以下信息。 我们的 LBox 内存由 4MB 闪存和 8MB SDRAM 组成。 在启动过程开始时,RAM 尚未部署,闪存组织如下
引导加载程序 (colilo)
设备是 /dev/mtd0
提供的空间 = 0x0000E000
位置:0x00000000 -> 0x0000E000
配置
设备是 /dev/mtd1
提供的空间 = 0x00002000
位置:0x0000E000 -> 0x00010000
镜像(根文件系统和内核镜像,均已压缩)
设备是 /dev/mtd2
提供的空间 = 0x00100000
位置:0x00010000 -> 0x00110000
JFSS2(日志文件系统,将在启动期间挂载)
设备是 /dev/mtd3
提供的空间 = 0x002F0000
位置:0x00110000 -> 0x00400000
在启动时,具有 Linux 驻留的典型 SBC 具有一个引导加载程序,该程序在闪存中查找压缩的内核镜像和根文件系统,将它们解压缩到 RAM 中,并将控制权转移到 RAM 中解压缩的内核。 然后,内核完成系统的初始化。
LBox 提供了上述内容的具体示例。 当它启动时,闪存中的引导加载程序开始执行。 它解压缩根文件系统和内核镜像,并将它们移动到 8MB 的 SDRAM 中。 此外,SDRAM 的一部分用于根文件系统,该文件系统设置为 ROM 文件系统。 然后,将 ramdisk /dev/ram1 挂载到 /var。 最后,将 JFFS2 文件系统 /dev/mtdblock3 挂载到 /etc/config。 因此,根文件系统最初是一个完全 ROM 文件系统,但已被挂载事件修改为包含读/写区域——ramdisk 和 JFFS2 区域。 需要注意的事项
ROM 文件系统本质上是只读的,其内容将在下一次启动序列中重新构建。
ramdisk 是易失性的,其内容将在断电时丢失。
JFFS2 文件系统位于闪存上,其内容将在断电事件中保持不变,因此它可以模拟硬盘驱动器。
启动后,原始系统的文件系统组织如下所示
RAM 中的根文件系统 (romfs),只读
/dev/root 挂载在 /
大小 = 1113 千字节
RAM 中的 ramdisk(ext2 文件系统),读/写
/dev/ram1 挂载在 /var
大小 = 115 千字节
闪存中的模拟硬盘驱动器(JFFS2 文件系统),读/写
/dev/mtdblock3 挂载在 /etc/config
大小 = 3008 千字节
存在各种更改内核和/或根文件系统的原因。 例如,编译新的硬件支持、更新现有驱动程序模块或向根文件系统添加新功能。
正如您可能在上面注意到的,在启动之前,内核镜像和根文件系统(均已压缩)位于同一分区 /dev/mtd2 上。 在发货之前,供应商将内核镜像和根文件系统的 romfs 放入同一个压缩文件 image.gz 中,然后将其刷入闪存中的 /dev/mtd2 分区。 我们保留这种方法,因此更新内核镜像或根文件系统都需要重新刷写两者。
让我们看看这些软件组件是如何放置在 LBox 上的。 为了更新软件,LBox 使用名为 netflash 的 uClinux 实用程序。 为了使用此实用程序,内核必须在 LBox 上运行。 此外,工作站必须运行 tftp(简单 FTP)守护程序,因为 netflash 依赖于它。 本文不讨论 tftp 的安装,但大多数发行版都有某种包管理工具,允许您安装 tftp,它是更大的 netkit 包的一部分。 截至撰写本文时,当前版本是 netkit-tftp-0.17,可以在这里找到。 近年来,安全问题导致我们避免使用 FTP 及其变体,而倾向于使用 sftp。 您可能还需要更改防火墙规则或关闭工作站上的防火墙。 因此,我们强烈建议谨慎偏执; 也就是说,tftp 应该仅在您连接到 LBox 而不是 Internet 本身时使用。 (有关更多详细信息,请参阅本系列第 2 部分中名为“NFS 挂载”的部分。)
netflash 实用程序允许我们通过网络连接从主机传输文件,并将其保存在目标设备上的闪存中。 该命令在 LBox 上输入。 例如,要检索其参数和选项的概要,请输入netflash -h以获取帮助屏幕。
我们使用的一个选项是 -b 选项,它可以防止在刷写操作完成后自动重启; 否则,LBox 会在 netflash 完成时重启。 因此,-b 选项提供了一层保护,以防止我们突然意识到我们刚刚刷写的软件组件是错误的或无法工作的组件。 我们还注意到,如果您尝试加载大于您尝试刷写的分区的文件,netflash 实用程序会报错。 但是,错误消息并不总是提供信息。 例如,当它因某些底层原因而失败时,它可能只会提供用法概要,即使语法没问题。
那么,我们从哪里获得 image.gz 文件呢? 这是在工作站上完成的,我们在工作站上使用 LBox 附带的工具链。 回想一下,这些工具链使用 uClinux 进行内核和根文件系统配置。 uClinux 目录层次结构从我们在本系列第 2 部分中安装在工作站上的 uClinux-dist 目录节点开始。 当给出相对路径名时,我们假设这是我们的工作目录。 如有必要,我们还使用绝对路径名。
要更改内核和/或根文件系统,我们必须从 uClinux-dist 目录以 root 身份运行make menuconfig或make xconfig。 此命令会显示一个高级 GUI,从中我们可以选择“Target Platform Selection”(目标平台选择)以打开一个新的低级 GUI。 然后,低级 GUI 允许我们配置内核、供应商设置或两者都配置。 此级别的 GUI 有些不直观。 特别是,在进行选择后,“Next”(下一步)按钮不会变为活动状态。 相反,在进行选择后,我们必须关闭低级 GUI,返回到原始高级 GUI。 然后,我们选择“Save and Exit”(保存并退出)按钮,此时会显示一个新的 GUI,用于进行内核和/或供应商设置修改。
我们建议第一次运行时,不要进行任何更改。 然后,在make xconfig步骤完成后,输入make dep和make all。 这些操作会将新的 image.gz 文件写入 images 子目录和 tftpboot 目录。 LBox 使用 netflash 访问后者。
当我们确信一切都已正确完成时,我们可以在 LBox 上输入以下命令——例如,通过 minicom——来更新内核镜像
netflash -knrb /dev/mtd2 tftp_server /tftpboot/image.gz
netflash -b -r tftp_server:/tftpboot/images/image.gz /dev/mtd2其中tftp_server
替换为您的工作站的 IP 地址。
回想一下,/dev/mtd2 设备对应于联合内核/根文件系统分区。 此外,如上所述,我们使用 -b 选项来防止在完成闪存更新后自动重启。
如果您在使用 netflash 实用程序时遇到问题,请检查以下事项
确保您要刷写的文件实际存在于 /tftpboot 中。 然后,确认 /tftpboot 目录权限为 777,image.gz 文件权限为 666。检查 tftp 守护程序是否正在运行。 在工作站上,输入命令.
netstat -a | grep tftp
确保 LBox 和主机之间的网络接口正常工作。
当然,我们可以在 LBox 运行时修改 JFFS2 文件系统——毕竟,它充当我们的硬盘驱动器。 但是,如果我们想要进行彻底的改造,我们可以重新组织并重新刷写整个文件系统。 确切地执行此操作是本节的主题。 我们将再次使用 netflash 刷写整个 /dev/mtd3 分区,使用 JFFS2 镜像。 这样做会使 JFFS2 闪存分区元数据与内核先前带入内存的文件系统信息(例如,inode 数据)不同步。 因此,建议在 netflash 操作看起来正常后重新启动。
在准备好用户文件系统以使用 netflash 刷写到 LBox 之前,必须考虑一些事项。 首先,我们需要在工作站上构建一个目录,其中包含最终将成为 LBox 上 JFFS2 目录的内容。 此目录已存在于供应商提供的 CD 上,我们之前已将其复制到工作站。 它的名称是 etc_config/。 我们建议将其保持原样以进行后续的试运行。
mkfs.jffs2 -b --pad=0x002f0000 --root=etc_config/ --output=config.jffs2
接下来,我们使用以下命令创建一个输出文件,并将其命名为 config.jffs2
make jffs2 ROOTFS_DIR=etc_config/ OUTPUT_FILE=config.jffs2 PADSIZE=0x002F0000 BIG_ENDIAN=1
netflash -knrb /dev/mtd3 tftp_server /tftpboot/config.jffs2
netflash -b -r tftp_server:/tftpboot/images/image.gz /dev/mtd2其中--root 选项指定 etc_config/ 目录用于提供 JFFS2 文件系统的预期内容。 --output 选项标识将要创建的文件的名称 config.jffs2,该文件包含所需的 JFFS2 文件系统。 --pad 选项将结果填充到与闪存上的 /dev/mtd3 分区相同的大小。 需要 -b 选项才能将文件系统创建为大端字节序,这适用于嵌入式 Motorola 架构。
文件系统准备就绪后,我们将其移动到主机上的 /tftpboot 目录中。 然后,我们通过 minicom 从 LBox 运行以下命令来刷写文件系统
被您的工作站的 IP 地址替换。
netflash -bknr /dev/mtd0 tftp_server /tftpboot/colilo.bin
netflash -b -r tftp_server:/tftpboot/images/image.gz /dev/mtd2其中请注意,设备是 /dev/mtd3,这对应于 JFFS2 文件系统的内存位置。 重新启动 LBox 后,您应该会在 LBox 上的 /etc/config 中看到新的文件系统。
netflash -r tftp_server:/tftpboot/colilo.bin /dev/mtd0
“嵌入式 Linux 开发入门,第 2 部分”
“嵌入式 Linux 开发入门,第 1 部分”