如何在U-Boot中添加自定义环境变量并从Linux内核模块访问
当然可行!下面我会一步步给你讲清楚怎么实现,还有其他可选方案:
在U-Boot中添加自定义环境变量
你有三种常见方式添加,满足不同需求:
- 临时添加(重启失效):直接在U-Boot命令行执行
setenv my_custom_var "hello_from_uboot",然后敲printenv就能看到这个变量出现在列表里了——这正是你想要的效果。不过这种方式下,重启开发板后变量会消失。 - 永久保存:如果想让变量重启后还存在,执行完
setenv后再敲saveenv,U-Boot会把环境变量写入到指定的存储区域(比如SPI Flash、eMMC的专属分区),下次启动就自动加载了。 - 编译时内置:如果希望这个变量是U-Boot的默认配置,不需要每次手动添加,可以修改U-Boot的板级配置文件(比如
include/configs/你的开发板.h),添加一行:
然后重新编译U-Boot,烧录到板子后,默认就有这个变量了。#define CONFIG_EXTRA_ENV_SETTINGS "my_custom_var=hello_from_uboot\0"
将U-Boot变量传递给Linux内核模块
U-Boot里的变量不能直接被Linux内核模块访问,必须通过中间通道传递,常用的有两种方法:
方法1:通过内核启动参数(bootargs)传递
这是最常用的简单方法:
- 在U-Boot里把自定义变量拼到
bootargs里:
这样Linux启动时,这个变量会被包含在内核的启动命令行里。setenv bootargs ${bootargs} my_custom_var=${my_custom_var} saveenv - 在内核模块里,你可以通过
__setup宏直接捕获这个参数,或者解析/proc/cmdline文件。示例代码:#include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> static char my_custom_val[256]; // 捕获启动参数中的my_custom_var=xxx static int __init my_custom_var_setup(char *str) { strncpy(my_custom_val, str, sizeof(my_custom_val)-1); my_custom_val[sizeof(my_custom_val)-1] = '\0'; // 确保字符串结束 return 1; } __setup("my_custom_var=", my_custom_var_setup); static int __init my_module_init(void) { printk(KERN_INFO "从U-Boot传递来的自定义变量:%s\n", my_custom_val); return 0; } static void __exit my_module_exit(void) { printk(KERN_INFO "模块卸载\n"); } module_init(my_module_init); module_exit(my_module_exit); MODULE_LICENSE("GPL");
方法2:通过设备树(DT)传递
如果你的系统使用设备树,这种方式更符合嵌入式Linux的标准做法:
- 在U-Boot里修改设备树的
/chosen节点,添加自定义属性:
然后正常启动内核即可。fdt set /chosen my-custom-var string "${my_custom_var}" - 在内核模块里通过设备树接口读取这个属性:
#include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/of.h> static int __init my_module_init(void) { struct device_node *chosen_node; const char *custom_val; int ret; // 找到设备树中的/chosen节点 chosen_node = of_find_node_by_path("/chosen"); if (!chosen_node) { printk(KERN_ERR "找不到/chosen节点\n"); return -ENOENT; } // 读取自定义属性的值 ret = of_property_read_string(chosen_node, "my-custom-var", &custom_val); if (ret) { printk(KERN_ERR "读取自定义变量失败\n"); return ret; } printk(KERN_INFO "通过设备树从U-Boot获取的变量:%s\n", custom_val); return 0; } static void __exit my_module_exit(void) { printk(KERN_INFO "模块卸载\n"); } module_init(my_module_init); module_exit(my_module_exit); MODULE_LICENSE("GPL");
关于
printenv显示变量的方式是否合适? 完全合适!printenv是U-Boot官方提供的查看环境变量的标准命令,你的自定义变量会和U-Boot内置的变量一起显示,这正是验证变量是否成功添加的最直接方式,没有任何问题。
其他可选实现方案
除了上面两种主流方法,还有一些场景化的方案:
- 直接读取U-Boot环境分区:如果Linux内核能访问存储U-Boot环境的分区(比如SPI Flash的某个分区),可以在模块里直接解析这个分区的格式(U-Boot环境通常带CRC校验,然后是键值对列表),读取变量。不过这种方法需要了解U-Boot环境的存储细节,实现起来比较繁琐,适合特殊场景。
- 通过安全固件传递:如果你的系统有安全监控固件(比如OP-TEE),可以让U-Boot把变量传给安全固件,然后内核模块通过SMC(安全监控调用)从固件中获取。这种方法适合需要安全隔离的场景,但复杂度较高。
内容的提问来源于stack exchange,提问作者TamiL
相关产品推荐
相关产品推荐

