[置顶] 泰晓 RISC-V 实验箱,配套 30+ 讲嵌入式 Linux 系统开发公开课
为 LicheePi 4A 开发板构建运行 Linux v6.5-rc1
Corrector: TinyCorrect v0.2-rc1 - [tounix spaces header tables refs pangu autocorrect] Author: 王杰迅 wangjiexun@foxmail.com Date: 2023/07/26 Revisor: falcon falcon@tinylab.org Project: RISC-V Linux 内核剖析 Sponsor: PLCT Lab, ISCAS
前言
LicheePi 4A 是 Sipeed 公司推出的高性能 RISC-V Linux 开发板,是截止目前(2023Q2)为止最强的 RISC-V SBC。目前 Sipeed 官方基于 Linux v5.10.113 开发了官方 SDK —— RevyOS,对该开发板提供了较为完整的驱动支持。
Linux 主线在 v6.5-rc1 版本加入了 部分补丁,以提供对该开发板的支持。
本文介绍了为 LicheePi 4A 开发板构建并运行 Linux v6.5-rc1 的过程,实现的效果为:内核可以成功启动并进入 initramfs 命令行界面。
软件版本
Software | Version |
---|---|
Linux | 6.5-rc1 |
U-Boot | 2020.01 |
OpenSBI | 0.9 |
Buildroot | 2023.02.2 |
构建 U-Boot、OpenSBI
U-Boot 和 OpenSBI 主要使用了 Sipeed 官方提供的版本, 见 RevyOS 文档 中构建 U-Boot 和 OpenSBI 的相关部分。
构建设备树
在尝试使用 Linux v6.5-rc1 自带的设备树进行启动时,系统会在初始化 PLIC 时报错:
[ 0.000000] Oops - load access fault [#1]
[ 0.000000] epc : __plic_toggle+0x6a/0x72
由于无法验证该设备树是否存在 Bug,所以使用了 Sipeed 官方 SDK 编译的设备树。
根据 RevyOS 文档 构建内核后,设备树文件为:
arch/riscv/boot/dts/thead/light-lpi4a.dtb
。
构建 initramfs
使用 Buildroot 构建 initramfs 较为简单,只需进行简单的配置,即可自动编译生成。
配置处理器架构
在 Buildroot 目录下输入:
$ make menuconfig
选择架构为 RISC-V:
Target options --->
Target Architecture () --->
(X) RISCV
配置文件系统类型
选择文件系统类型为 CPIO:
Filesystem images --->
[*] cpio the root file system(for use as an initial RAM filesystem)
配置内核
构建好 initramfs 后,需要在内核配置中使能 initramfs,并指定生成的 CPIO 文件的位置。
General Setup --->
[*] Initial RAM filesystem and RAM disk (initramfs/initrd) support
() Initramfs source file(s)
构建内核
构建 Linux v6.5-rc1 内核的过程与 RevyOS 文档 中构建内核的过程基本一致,只是需要在配置内核时更改为使用 RISC-V 架构下的 defconfig:
$ make CROSS_COMPILE=riscv64-unknown-linux-gnu- ARCH=riscv defconfig
串口无法工作
在尝试使用直接编译的 Linux v6.5-rc1 内核在开发板上启动时,串口输出会卡住,不再继续显示,相关日志如下:
[ 0.876673] Warning: unable to open an initial console.
[ 0.884088] Freeing unused kernel image (initmem) memory: 3744K
[ 0.895429] Run /init as init process
下面将介绍该问题的解决思路和解决方法。
解决思路
下面依次从根文件系统、内核启动参数、设备树、内核驱动这几个方面考虑可能出现问题的原因,并依次进行了排查。
根文件系统
针对该问题,网上最普遍的原因为:根文件系统中缺少 console 文件。因此需要在根文件系统的 /dev 目录下输入以下命令进行创建:
$ mknod -m 660 console c 5 1
$ mknod -m 660 null c 1 3
笔者打开 /dev 目录下发现并不缺少 console 文件,问题没能解决。
进行测试时发现:使用构建好的内核文件和 initramfs 在 QEMU 模拟器上运行时,QEMU 模拟器可以正常启动,进入到 initramfs 的命令行界面,因此推断构建的 initramfs 可以正常使用。
内核启动参数
在内核启动时,需要由 Bootloader 为其传递一些命令行参数。其中 console 参数指定了内核启动后使用的输出端口,通常设置为 console=ttyS0,115200
。如果开发板串口提供的波特率不为 115200,则需要进行更改。
在使用了 U-Boot 作为 Bootloader 时,可以在启动倒计时按下回车键,进入 U-Boot 命令行界面,
输入 printenv
指令可以看到内核启动参数 bootargs
,并可以通过 setenv
指令修改该参数。
在内核的启动日志中也会打印出启动参数,如:
[ 0.000000] Kernel command line: console=ttyS0,115200 rootwait rw earlycon init=/lib/systemd/systemd
同时需要注意,在内核启动时使用的 bootconsole 并不受启动参数 console 的影响。
[ 0.000000] earlycon: uart0 at MMIO32 0x000000ffe7014000 (options '115200n8')
[ 0.000000] printk: bootconsole [uart0] enabled
经过检查,相关配置没有问题,问题没能解决。
设备树
随后考虑了设备树是否有问题,但使用的设备树为开发板厂家 Sipeed 提供的,并且可以成功启动厂家提供的 RevyOS(基于 Linux v5.10.113)。因此推断设备树可以正常使用。
内核驱动
其他因素已经排除的差不多,只剩内核相关的因素可能存在问题。而使用 QEMU 可以成功启动构建好的内核,因此基本将问题锁定在与开发板相关的因素。主要怀疑内核驱动与设备树的对应可能存在问题,最怀疑的是串口驱动。
重新分析启动日志后发现,存在下述输出:
[ 0.674296] Serial: 8250/16550 driver, 4 ports, IRQ sharing disabled
这句输出可以证明串口驱动被内核正常加载。而下述输出:
[ 11.098262] platform ffe7014000.serial: deferred probe pending
基本宣告了问题出现的真正原因:串口设备加载失败。
Linux 内核驱动采用平台设备驱动模型,驱动和设备分别被加载进内核,再进行匹配。 因此驱动被成功加载,而串口加载失败,这种情况是可能的。
随后阅读了一篇 具有类似报错信息的文章,发现导致 deferred probe pending
的原因可能为:该设备依赖的驱动没有被内核正确加载。
随后分析设备树文件中串口相关部分:
uart0: serial@ffe7014000 { /* Normal serial, for C910 log */
compatible = "snps,dw-apb-uart";
……
interrupt-parent = <&intc>;
……
clocks = <&clk CLKGEN_UART0_SCLK>;
……
};
intc: interrupt-controller@ffd8000000 {
compatible = "riscv,plic0";
……
};
clk: clock-controller@ffef010000 {
compatible = "thead,light-fm-ree-clk";
……
};
通过在代码仓库中搜索 compatible 属性的值,来判断内核中是否存在驱动缺失的情况。
- 串口使用的驱动为:“snps,dw-apb-uart”
- 串口依赖的中断控制器 intc 使用的驱动为:“riscv,plic0”
- 串口依赖的时钟 clk 使用的驱动为:“thead,light-fm-ree-clk”
通过搜索发现串口依赖的时钟 clk 使用的驱动 “thead,light-fm-ree-clk” 缺失。 从 Sipeed 提供的内核中将相关驱动移植到 Linux v6.5-rc1 后,终于可以正常启动。
解决方法(驱动移植)
- 在 Sipeed 提供的内核中找到 drivers/clk/thead 文件夹,添加到 Linux v6.5-rc1 的 drivers/clk 文件夹下
- 将 thead 文件夹中的 Kconfig 文件进行修改:将其中所有 SOC_THEAD 替换为 ARCH_THEAD
- 修改 drivers/clk 下的 Kconfig 和 Makefile 文件,使之包含 thead 文件夹
- 在 Sipeed 提供的内核中找到 include/dt-bindings/clock 文件夹,添加以下头文件到 Linux v6.5-rc1 的相同文件夹下:
- light-dspsys.h
- light-fm-ap-clock.h
- light-mpw-clock.h
- light-visys.h
- light-vosys.h
- light-vpsys.h
- 修改 Linux v6.5-rc1 的 arch/riscv/configs/defconfig 文件,在最后添加
CONFIG_THEAD_CLK=y
CONFIG_CLK_LIGHT_FM=y
驱动移植完成后,再对内核重新编译即可在开发板上正常启动。 烧录的具体步骤见 Sipeed 官方提供的烧录文档。
总结
本文介绍了为 LicheePi 4A 开发板构建并运行 Linux v6.5-rc1 的过程,并分析了在内核启动过程中无法得到串口输出的问题,提供了相应的分析思路和解决措施。
参考资料
猜你喜欢:
- 我要投稿:发表原创技术文章,收获福利、挚友与行业影响力
- 知识星球:独家 Linux 实战经验与技巧,订阅「Linux知识星球」
- 视频频道:泰晓学院,B 站,发布各类 Linux 视频课
- 开源小店:欢迎光临泰晓科技自营店,购物支持泰晓原创
- 技术交流:Linux 用户技术交流微信群,联系微信号:tinylab
支付宝打赏 ¥9.68元 | 微信打赏 ¥9.68元 | |
请作者喝杯咖啡吧 |
Read Album:
- TinyBPT 和面向 buildroot 的二进制包管理服务(1):设计简介与框架
- RISC-V Linux 内核及周边技术动态第 118 期
- RISC-V Linux 内核及周边技术动态第 117 期
- 实时分析工具 rtla timerlat 介绍(二):延迟测试原理
- 实时分析工具 rtla timerlat 介绍(一):交叉编译及使用