一次失败的实验:让我知道了U-Boot的重要性
目录一、QEMU与真实开发板的不同无pinctl节点、设备树节点极为简单二、修改内核编译选项开启GPIO子系统三、验证GPIO子系统只开启了前8位,并修改成32位四、问题分析在学习GPIO子系统的时候发现我的Linux无法正常体现子系统目录文件也就无法正常使用子系统经过分析得知是没有使用U-Boot启动文件而是用简易的命令行直接在QEMU开启的Linux。本文最初是为了记录GPIO子系统的编写但遇到了各种各样的问题索性记录下来。一、QEMU与真实开发板的不同无pinctl节点、设备树节点极为简单首先将GPIO的初始化静态配置写到设备树中让子系统可以正常初始化寄存器。最开始我试图将教程中的pinctl节点照猫画虎copy下来于是我去.dtsi文件中看了看发现并没有pinctl节点后来查询了相关资料得知由于QEMU是软件模拟的vexpress-a9开发板他并不会有真实开发板的引脚复用、冲突等问题而是直接给每个外设一个或一组GPIO引脚虚拟的就是豪气比如下图是我从当开开发板的.dtsi文件中截取出来的一部分路径/home/hmy/linux-mini/linux-6.8/arch/arm/boot/dts/arm。我们主要关注gpio8这个节点他是本开发板的GPIO控制寄存器相较于父节点sysreg基地址base的偏移量是0x08通过偏移量可以让GPIO子系统对设备树节点解析并执行寄存器级别的初始化。不过值得注意的是这里的名字虽然是gpio-controller。初学者可能认为他是用来配置GPIO引脚的寄存器但它其实就是暴露出去的引脚你可以直接对每一位进行读写就是在控制LED的亮灭不需要类似STM32中的其他寄存器来间接配置。它就是一个纯粹的数据状态寄存器如果你想要使用这个GPIO则需要在.dts文件中继承该节点并对使用引脚编号、电平有效性进行配置。好比他是QEMU开发板提供的32口插座而LED灯则是使用这些插座接口的人。只不过内核限制了你最多只能使用8个接口多出来的24个接口我宁愿浪费也不给你用。补充说明真实硬件是「先配置引脚 → 再配置 GPIO 模式 → 最后写数据」的三层流程QEMU 虚拟 LED GPIO 直接把前两层砍了只剩最后一层「直接写数据」所以你感觉像 “直接操作引脚”。二、修改内核编译选项开启GPIO子系统我本来打算直接重写刚刚的v2m_led_gpios节点并对其下方所属的某个引脚设置成我的LED引脚但是我接着往下看发现0-7号这8个引脚都已经被开发板使用了。这一点是上网查资料的我本身并不清楚是不是只能用32位的前8位于是我尝试按照往上的资料执行查询命令cd ~/linux-mini/linux-6.8 #不过这个是老版本的命名方式必定查询不到 find . -name gpio-vexpress.c # 正确的用compatible字符串精准定位不受版本影响100%能搜到 grep -r arm,vexpress-sysreg,sys_led . --include*.c然后我回顾了一下当初在裁剪Linux内核时候的命令把他喂给AI帮我分析得到的结论是我并没有把GPIO子系统裁剪到内核里面来于是所有在设备树中配置的节点都成了废纸不仅是我不能用GPIO子系统内核本身也无法使用。在VScode命令行中输入一下编译命令仅仅修改了GPIO子系统的开启状态其余的子系统我们学到的时候即用即开# 1. 清空 make ARCHarm clean make ARCHarm mrproper # 2. 官方配置 make ARCHarm vexpress_defconfig # 3. 基础功能 ./scripts/config -e MODULES ./scripts/config -e MODULE_UNLOAD ./scripts/config -e PRINTK ./scripts/config -e EARLY_PRINTK # 4. 串口 ./scripts/config -e SERIAL_AMBA ./scripts/config -e SERIAL_AMBA_CONSOLE # 5. SD卡/MMC (必须开保证能启动) ./scripts/config -e MMC ./scripts/config -e MMC_ARM ./scripts/config -e MMCI_PL180 ./scripts/config -e EXT2_FS # 6. 文件系统 ./scripts/config -e PROC_FS ./scripts/config -e TMPFS # # ✅ 【修正后的】GPIO 依赖配置针对你的 vexpress-sysreg.c # ./scripts/config -e GPIO_DEVICES # 核心框架 ./scripts/config -e MFD_SYSCON # 加载 sysreg 模块 ./scripts/config -e GPIO_BIG_GENERIC # 支持 bgpio_pdata ./scripts/config -e GPIO_SYSFS # 生成 /sys/class/gpio # 7. 关闭其他无用 ./scripts/config -d I2C ./scripts/config -d SPI ./scripts/config -d USB ./scripts/config -d NET ./scripts/config -d FB ./scripts/config -d SOUND ./scripts/config -d INPUT ./scripts/config -d WATCHDOG # 8. 编译 make ARCHarm olddefconfig make ARCHarm CROSS_COMPILEarm-linux-gnueabihf- -j$(nproc) make ARCHarm CROSS_COMPILEarm-linux-gnueabihf- dtbs三、验证GPIO子系统只开启了前8位,并修改成32位#全局搜索这个文件在开启GPIO子系统重新编译内核之前是找不到该文件的 find . -name vexpress-sysreg.c我们现在只需要把这里的8改成32并重新编译内核因为GPIO子系统属于内核驱动代码后续就可以使用9-31共24位了扩展性提高了。当然也有人会问我直接使用PIN0-7可以吗其实是可以的不过0-7引脚已经在dtsi文件中被其他LED占用了不清楚和他们抢同一个PIN会发生什么问题。保守起见我还是重新编译一下内核吧。四、问题分析尽管我们已经编译很多次内核了但发现仍然无法找到GPIO子系统。经过查阅资料后得知可能是我的QEMU没有经过Uboot启动而是手动简略命令行启动的可能跳过了一系列对子系统的初始化操作导致的。关于裁剪、编译、挂载根文件系统这一块我也云里雾里、一知半解。但没办法如果不能正常用U-Boot启动Linux内核的话很可能后续还会遇到各种奇怪的问题所以我打算先暂停更新GPIO子系统而先把环境搭好。