Linux/嵌入式 Linux - 了解内核和其他 BSP 特定组件

Linux/嵌入式 Linux - 了解内核和其他 BSP 特定组件

*太长了;我想大致了解 Linux/嵌入式 Linux 的世界是如何运作的。我需要做什么才能从头开始使用 Linux 主线并将其编译/部署到具有不同处理器和外设的主板上。

我目前如何看待它的工作原理:

让 Linux 在任意板上运行的步骤:

  • 获取 uBoot(嵌入式)或 GRUB(桌面/x86 SOM)的源代码
  • 针对特定系统修改uBoot或GRUB,编写代码来初始化特定芯片并获得内存和控制台启动和运行所需的接口
  • 修改uBoot/GRUB config.txt来配置上面写的代码
  • 编译这些并部署到主板,验证引导加载程序控制台是否出现并可以与其交互
  • 获取内核主线源
  • “make config”来选择可用的驱动程序和模块(此时,这些选择将更改源 - 无论这些设置存储在何处,都将不再与主线中的 git 克隆匹配)(在源代码管理中跟踪此 .config 文件以后的参考)
  • 获取 Busybox 等工具或桌面替代品?安装在源目录中
  • 获取 ucLibc 或其他库并安装在源目录中
  • 使用交叉编译工具链针对特定芯片编译内核源代码
  • 为板创建设备树文件.dtb(嵌入式/桌面?或桌面不使用?)这将驱动程序连接到物理引脚
  • 使用Uboot/GRUB和TFTP/串口控制台或存储卡等加载编译后的内核映像。
  • 根据驱动程序和设备树配置,通过串行/SSH 等启动并验证 shell 访问
  • 修改 uEnv.txt(嵌入式)或 mymyfile.txt(桌面)以进行主板特定配置?这本质上是一个阻止或添加内核启动步骤的脚本?桌面等效项是什么?
  • apt-get 所需的软件包和驱动程序
  • 编写驱动程序和应用程序代码并测试(手动加载驱动程序)
  • 添加设备树文件以说明上面实现的硬件和驱动程序(这些文件与创建的初始 BSP 是分开的)
  • 要将这些内容包含在内核映像中,请构建内核并在文件夹结构中包含所有这些源和配置文件修改的文件结构(Linux 主线的添加/修改)
  • 可以为 Linux 主线和 mods 建立一个单独的文件夹,直接将 mods 复制到第三个暂存文件夹中的主线中。这将允许所有添加内容和非主线模组进行单独的源控制。

如果您可以获得一个可以通过 SSH 连接的基本系统,并且此时您拥有所有常见组件(视频、USB、鼠标等)的驱动程序,那么此时您几乎可以做任何事情(安装 X11 服务器、LXDE、网络等)?哪些驱动程序需要由引导加载程序/BIOS 处理,哪些驱动程序纯粹在内核域中?

有用于配置内核构建的 Kconfig 文件。这是有道理的,我见过的内核模块开发文档似乎很好地描述了这一点。

还有像 uEnv.txt 和 config.txt 这样的文件处理运行时配置以及应该加载哪些设备。还有设备树 blob 也确定应加载哪些设备?

这些文件中的魔法字符串如何与内核联系起来,这些修改是否针对特定板的主线进行了?必须读取这些内容才能确定是否应启用 HDMI,并且这不可能与 Linux 桌面版本上的代码完全相同。

一旦驱动程序进入主线,它们仍然独立于主线开发吗?例如,我一直在使用几个驱动程序,但有注释说它们现在包含在主线中,这是否意味着不再可以直接自行下载?我遵循的步骤下载了我的主板的标头、源代码,然后编译并安装它。如果它在主线中,我现在需要从那里提取它吗?

背景和具体想法

我是一名 EE,有微控制器和 Windows 开发经验,但没有太多 Linux 经验。我的问题的框架是“如果我开始使用这个任意(具有可用的 Linux 编译器)处理器,以及这些外围设备,我如何(以及我的选择是什么)来构建 Linux 版本”

引导加载程序:

我已经能够找到 RPI2 和 BBB (Beaglebone Black) 的特定文档和操作方法,但是当您进入引导加载程序等更高级的主题时,只有一些碎屑可以模糊地描述正在发生的事情。例如,RPI2 有一个 3 阶段引导加载程序(从阅读来看,它听起来并不完全基于 uBoot),而 BBB 有一个更“传统”的基于 uBoot 的引导加载程序。现在,新的 BBx15 具有跳线,您可以在其中选择要从哪里启动。

桌面系统使用 GRUB (IIRC),嵌入式系统通常使用 uBoot。我读到 RPI 在启动期间使用 GPU 并从单独的 ROM 读取第一阶段引导加载程序。这就是所有可用的信息。如果您想旋转您自己的开发板版本(出于讨论目的,这并不实际)那么除了 uBoot 之外还发生了什么? BBx15 的 uBoot 没有额外的修改来允许跳线启动选择吗?

Linux 是否知道有关引导阶段的任何信息,或者一旦运行就忘记了这一点? BBB 使用 uBoot 将映像从 eMMC 加载到 RAM 中,RPI2 使用 3 阶段引导加载程序。我猜测 BBB 使用 ARM 处理器来执行此操作,但 RPI2 使用 GPU。我想在加电时,ARM 处理器开始执行,他们需要修改什么来暂存这些加载过程? GPU 是否会将 ARM 保持在复位状态,直到完成其 ROM 代码为止?由于 GPU 是启动过程的一部分,这是否意味着它执行的代码是从 uBoot 代码中取出的,没有该 GPU 的其他系统必须在 uBoot 代码中运行?这整个过程对我来说意味着,如果您修改第二阶段或第三阶段引导加载程序,您可以完全独立于 GPU 运行 Linux(如果内核是使用 GPU 工具链编译的)?

第三阶段bootloader和config.txt实际上只是uBoot吗?

关于正在使用的板的标头。这些只是来自主线的标头,其中包含已覆盖的驱动程序,还是还有其他内容。如果您已经开始运行,那么“标题”只是主线标题?

对于嵌入式微控制器开发,我习惯于使用 HAL 层。 HAL 具有函数存根,您可以在其中设置外设,然后将驱动程序指向这些资源。板支持包通常已经为相关板编码了这些 HAL 存根。我确信这与 Linux 开发有一些相似之处,但我不太明白这些区别在哪里。

有 Buildroot 和 Yocto 等软件包。这些只是具有自动选择要包含的 ARM 处理器和驱动程序的界面的 Linux 主线吗?

答案1

根据我使用路由器硬件的小经验,我可以说这是一个愚蠢的小硬件,只是为了做一件事而拿起。

在硬件层面,很简单:

U-Boot 不仅是引导加载程序,而且是 PC 术语中的 BIOS。所以这不是仅有的引导加载程序,而且它还初始化所有硬件。启动时,CPU 直接执行它(例如从 FLASH),并决定下一步做什么,但通常它会将自身重新定位到内存中。然后它执行所需的操作:从闪存读取配置,然后在指定地址加载图像并将控制权转移到那里。没什么特别的,但了解这一点很重要。

U-Boot(嵌入在路由器硬件上)根本不访问根文件系统。相反,有一个用于整个内核映像的专用空间(通常是压缩的)。因此,至少在路由器上 - 没有 /boot/vmlinuz 文件。

RPI 确实使用它自己的、专有的启动顺序。他们有闭源二进制文件,用户可以将其放在 SD 闪存上。第一阶段初始化代码被硬编码到 CPU 或板上的某个位置。他们在GPU之后启动ARM核心,整个代码都是为GPU完成的。有关更多信息,也许您已经找到了,但如果没有:https://raspberrypi.stackexchange.com/questions/10489/how-does-raspberry-pi-boot

因此,因为我对路由器做了一些有趣的事情,并且完全从源代码将它们重建到我的小型服务器中,所以我可以列出我自己的构建顺序:

  • 获取并构建平台的u-boot
  • 构建Linux内核
  • 构建用户空间(内核和用户空间通常是分开的,即使在闪存上也是如此)
  • 将u-boot烧写到编程器上的flash中
  • 将闪光焊料焊接到板上
  • 通过 UART 连接到开发板
  • 启动它,验证 u-boot 是否正确初始化所有硬件
  • tftp内核,写入板内闪存
  • tftp rootfs,写入板内闪存
  • 重置,验证一切正常
  • 微调 rootfs:设置权限,通过 tftp 预加载默认配置
  • 转储整个图像,在许多设备上刷新它

Linux 内核可以支持也可以不支持您的主板。请确认一下。例如,您将无法仅采用最新的内核并为您的路由器构建它。 RPi 也是如此:它们有自己的内核树。这种情况在嵌入式世界中经常发生,只有少数(通常是通用)平台由 Linux 内核直接支持。为此做好准备。

至于用户空间,您可以选择您需要的任何内容,在您需要的内容和剩余空间之间平衡您的需求。通常在嵌入式中,您要么压缩任何内容,要么删除不需要的内容,或两者兼而有之。

我希望这能有所启发。如果您还有其他问题——欢迎评论! :-)

相关内容