设备树的根目录下的chosen节点是一个特殊的节点, 它用作uboot 像内核传递参数.这里简单介绍如何使用bootargs参数从uboot传递参数到内核.
1. 如何查看bootargs的值?
cat /sys/firmware/devicetree/base/chosen/bootargs 命令可以查看最终的bootargs值.
bootargs会作为linux内核启动时的命令行参数,在内核启动过程中也会打印bootargs参数,关键字"Kernel command line:"
2. uboot中如何添加传递到内核的参数.
uboot传递参数到内核的实现原理:uboot启动内核时会先加载设备树. uboot加载设备树后就可以读取设备树里的内容,这里就是读取chose节点的bootargs属性, 然后在bootargs属性中追加要传递到内核的属性,最后写回到设备树即可.
uboot提供了一组fdt_xxx()函数,定义在lib/libfdt 目录下, 使用库里面提供的API即可修改,添加设备树节点的属性.例如下面是一个封装好的,用于向bootargs追加属性的函数实现:
/**
* @brief 向 bootargs 添加属性
*
* @param fdt 加载到内存中的设备树起始地址
* @param append_args 要添加的属性字符串,例如"lcd_id=0x98"
* @param force 强制写,这是自定义的.
* @return int
*/
int fdt_chosen_bootargs_append(void *fdt, char *append_args, int force)
{
int nodeoffset;
int err;
const char *path;
char *strargs;
int size;
if (!append_args)
return -1;
/**
* @brief fdt 是加载的设备树在内存中的起始地址.
* fdt_check_header函数可以检查这个地址是不是一个有效的设备树
*/
err = fdt_check_header(fdt);
if (err < 0) {
errorf("fdt_chosen_bootargs_append: %s\n", fdt_strerror(err));
return err;
}
/*
* 查找 "chosen" 节点.
* 成功返回节点的偏移地址,失败返回负数.
*/
nodeoffset = fdt_path_offset(fdt, "/chosen");
/*
* If the property exists, update it only if the "force" parameter
* is true.
* 如果设备树里bootargs属性存在 fdt_getprop 返回属性字符串,否则返回0
*/
path = fdt_getprop(fdt, nodeoffset, "bootargs", NULL);
if ((path == NULL) || force) {
strargs = malloc(MAX_BOOTARG_LEN+1);
if (!strargs)
return -1;
/**
* @brief 这里bootargs 属性的最大限制是4K
*
*/
memset(strargs, 0, MAX_BOOTARG_LEN+1);
if(path != NULL)
{
size = strlen(path) + strlen(append_args);
if (size > (MAX_BOOTARG_LEN - 1)) {
errorf("bootargs len:%d overflow (MAX_BOOTARG_LEN-1)\n", size);
free(strargs);
return -1;
}
sprintf(strargs, "%s %s", path, append_args);
}
else
{
size = strlen(append_args);
if (size > MAX_BOOTARG_LEN) {
errorf("bootargs len:%d overflow MAX_BOOTARG_LEN\n", size);
free(strargs);
return -1;
}
sprintf(strargs, "%s", append_args);
}
/**
* @brief 设置好bootargs后就写回去.
*
*/
err = fdt_setprop(fdt, nodeoffset, "bootargs", strargs, strlen(strargs) + 1);
if (err < 0)
errorf("could not set bootargs %s.\n", fdt_strerror(err));
free(strargs);
}
return err;
}
追加的属性是形如"lcd_id=0x96" xxx=xxx的字符串.这和linux内核设备树中的设置是一致的.
3. linux驱动中是否如何获取uboot传递过来的参数?
linux驱动中可以使用内核提供的宏定义直接得到uboot传递过来的参数如下:
static int __init chipid_base_get(char *str)
{
printk(KERN_ERR "chipid_base_get = %s",str);
return 0;
}
__setup("msocid=", chipid_base_get);
例如在uboot里使用函数fdt_chosen_bootargs_append(xxx,"msocid=hello\0",1); 添加了属性. 驱动里就可以按照上方的定义,linux内核启动后就会执行chipid_base_get 函数. 宏定义__setup() 介绍可以参考"linux kernel中__setup()函数介绍_setup linux kernel-优快云博客"
文章参考: