You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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),添加一行:
    #define CONFIG_EXTRA_ENV_SETTINGS "my_custom_var=hello_from_uboot\0"
    
    然后重新编译U-Boot,烧录到板子后,默认就有这个变量了。
将U-Boot变量传递给Linux内核模块

U-Boot里的变量不能直接被Linux内核模块访问,必须通过中间通道传递,常用的有两种方法:

方法1:通过内核启动参数(bootargs)传递

这是最常用的简单方法:

  1. 在U-Boot里把自定义变量拼到bootargs里:
    setenv bootargs ${bootargs} my_custom_var=${my_custom_var}
    saveenv
    
    这样Linux启动时,这个变量会被包含在内核的启动命令行里。
  2. 在内核模块里,你可以通过__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的标准做法:

  1. 在U-Boot里修改设备树的/chosen节点,添加自定义属性:
    fdt set /chosen my-custom-var string "${my_custom_var}"
    
    然后正常启动内核即可。
  2. 在内核模块里通过设备树接口读取这个属性:
    #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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 07:13:39