uboot常用的函数
http://blog.csdn.net/ooonebook/article/details/53206623
以下例子都以project X项目tiny210(s5pv210平台,armv7架构)为例
[uboot] uboot流程系列:
[project X] tiny210(s5pv210)上电启动流程(BL0-BL2)
[project X] tiny210(s5pv210)从存储设备加载代码到DDR
[uboot] (第一章)uboot流程——概述
[uboot] (第二章)uboot流程——uboot-spl编译流程
[uboot] (第三章)uboot流程——uboot-spl代码流程
[uboot] (第四章)uboot流程——uboot编译流程
[uboot] (第五章)uboot流程——uboot启动流程
[uboot] (番外篇)global_data介绍
[uboot] (番外篇)uboot relocation介绍
建议先看《[[uboot] (番外篇)uboot relocation介绍》和《[uboot] (第四章)uboot流程——uboot编译流程》
=================================================================================
因为在学习uboot的driver module,发现有必要先把uboot的fdt整明白点。所以这里就先学习一下fdt咯。
一、介绍
FDT,flatted device tree,扁平设备树。熟悉Linux的人对这个概念应该不陌生。
简单理解为将部分设备信息结构存放到device tree文件中。
uboot最终将其device tree编译成dtb文件,使用过程中通过解析该dtb来获取板级设备信息。
uboot的dtb和kernel中的dtb是一致的。这部分建议直接参考wowo的dtb的文章
Device Tree(一):背景介绍
Device Tree(二):基本概念
Device Tree(三):代码分析
关于uboot的fdt,可以参考doc/README.fdt-control。
二、dtb介绍
1、dtb结构介绍
结构体如下 |
---|
DTB header |
alignment gap |
memory reserve map |
alignment gap |
device-tree structure |
alignment gap |
device-tree string |
dtb header结构如下:
结构体如下 |
---|
magic |
totalsize |
off_dt_struct |
off_dt_strings |
off_mem_rsvmap |
version |
…… |
其中,magic是一个固定的值,0xd00dfeed(大端)或者0xedfe0dd0(小端)。
以s5pv210-tiny210.dtb为例:
执行”hexdump -C s5pv210-tiny210.dtb | more”命令
@:dts$ hexdump -C s5pv210-tiny210.dtb | more
00000000 d0 0d fe ed 00 00 5a cc 00 00 00 38 00 00 58 14 |......Z....8..X.|
00000010 00 00 00 28 00 00 00 11 00 00 00 10 00 00 00 00 |...(............|
可以看到dtb的前面4个字节就是0xd00dfeed,也就是magic。
综上,我们只要提取待验证dtb的地址上的数据的前四个字节,与0xd00dfeed(大端)或者0xedfe0dd0(小端)进行比较,如果匹配的话,就说明对应待验证dtb就是一个合法的dtb。
2、dtb在uboot中的位置
dtb可以以两种形式编译到uboot的镜像中。
dtb和uboot的bin文件分离
- 如何使能
需要打开CONFIG_OF_SEPARATE宏来使能。 - 编译说明
在这种方式下,uboot的编译和dtb的编译是分开的,先生成uboot的bin文件,然后再另外生成dtb文件。
具体参考《[uboot] (第四章)uboot流程——uboot编译流程》。 - 最终位置
dtb最终会追加到uboot的bin文件的最后面。也就是uboot.img的最后一部分。
因此,可以通过uboot的结束地址符号,也就是_end符号来获取dtb的地址。
具体参考《[uboot] (第四章)uboot流程——uboot编译流程》。
- 如何使能
dtb集成到uboot的bin文件内部
- 如何使能
需要打开CONFIG_OF_EMBED宏来使能。 - 编译说明
在这种方式下,在编译uboot的过程中,也会编译dtb。 - 最终位置
注意:最终dtb是包含到了uboot的bin文件内部的。
dtb会位于uboot的.dtb.init.rodata段中,并且在代码中可以通过__dtb_dt_begin符号获取其符号。
因为这种方式不够灵活,文档上也不推荐,所以后续也不具体研究,简单了解一下即可。
- 如何使能
另外,也可以通过fdtcontroladdr环境变量来指定dtb的地址
可以通过直接把dtb加载到内存的某个位置,并在环境变量中设置fdtcontroladdr为这个地址,达到动态指定dtb的目的。
在调试中使用。
三、uboot中如何支持fdt
1、相关的宏
CONFIG_OF_CONTROL
用于配置是否使能FDT。
./source/configs/tiny210_defconfig:312:CONFIG_OF_CONTROL=yCONFIG_OF_SEPARATE、CONFIG_OF_EMBED
配置dtb是否集成到uboot的bin文件中。具体参考上述。一般都是使用分离的方式。
2、如何添加一个dtb
以tiny210为例,具体可以参考project X项目中uboot的Git记录:8a371676710cc0572a0a863255e25c35c82bb928
(1)在Makefile中添加对应的目标dtb
arch/arm/dts/Makefile
dtb-$(CONFIG_TARGET_TINY210) += \
s5pv210-tiny210.dtb
(2)创建对应的dts文件
arch/arm/dts/s5pv210-tiny210.dts,注意文件名要和Makefile中的dtb名一致
/dts-v1/;
/{
};
(3)打开对应的宏
configs/tiny210_defconfig
CONFIG_OF_CONTROL=y
CONFIG_OF_SEPARATE=y ##其实这里不用配,arm默认就是指定这种方式
(4)因为最终的编译出来的dtb可能会多个,这里需要为tiny210指定一个dtb
configs/tiny210_defconfig
CONFIG_DEFAULT_DEVICE_TREE="s5pv210-tiny210"
编译,解决一些编译错误,就可以发现最终生成了u-boot.dtb文件。
通过如下“hexdump -C u-boot.dtb | more”命令可以查看我们的dtb文件,得到部分内容如下:
hlos@node4:u-boot$ hexdump -C u-boot.dtb | more
00000000 d0 0d fe ed 00 00 01 a4 00 00 00 38 00 00 01 58 |...........8...X|
00000010 00 00 00 28 00 00 00 11 00 00 00 10 00 00 00 00 |...(............|
00000020 00 00 00 4c 00 00 01 20 00 00 00 00 00 00 00 00 |...L... ........|
00000030 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 |................|
四、uboot中如何获取dtb
1、整体说明
在uboot初始化过程中,需要对dtb做两个操作:
- 获取dtb的地址,并且验证dtb的合法性
- 因为我们使用的dtb并没有集成到uboot的bin文件中,也就是使用的CONFIG_OF_SEPARATE方式。因此,在relocate uboot的过程中并不会去relocate dtb。因此,这里我们还需要自行为dtb预留内存空间并进行relocate。关于uboot relocate的内容请参考《[uboot] (番外篇)uboot relocation介绍》。
- relocate之后,还需要重新获取一次dtb的地址。
这部分过程是在init_board_f中实现,参考《[uboot] (第五章)uboot流程——uboot启动流程》。
对应代码common/board_f.c
static init_fnc_t init_sequence_f[] = {
...
#ifdef CONFIG_OF_CONTROL
fdtdec_setup, // 获取dtb的地址,并且验证dtb的合法性
#endif
...
reserve_fdt, // 为dtb分配新的内存地址空间
...
reloc_fdt, // relocate dtb
...
}
后面进行具体函数的分析。
2、获取dtb的地址,并且验证dtb的合法性(fdtdec_setup)
对应代码如下:
lib/fdtdec.c
int fdtdec_setup(void)
{
#if CONFIG_IS_ENABLED(OF_CONTROL) // 确保CONFIG_OF_CONTROL宏是打开的
# ifdef CONFIG_OF_EMBED
/* Get a pointer to the FDT */
gd->fdt_blob = __dtb_dt_begin;
// 当使用CONFIG_OF_EMBED的方式时,也就是dtb集成到uboot的bin文件中时,通过__dtb_dt_begin符号来获取dtb地址。
# elif defined CONFIG_OF_SEPARATE
/* FDT is at end of image */
gd->fdt_blob = (ulong *)&_end;
//当使用CONFIG_OF_SEPARATE的方式时,也就是dtb追加到uboot的bin文件后面时,通过_end符号来获取dtb地址。
# endif
/* Allow the early environment to override the fdt address */
gd->fdt_blob = (void *)getenv_ulong("fdtcontroladdr", 16,
(uintptr_t)gd->fdt_blob);
// 可以通过环境变量fdtcontroladdr来指定gd->fdt_blob,也就是指定fdt的地址。
#endif
// 最终都把dtb的地址存储在gd->fdt_blob中
return fdtdec_prepare_fdt();
// 在fdtdec_prepare_fdt中检查fdt的合法性
}
/* fdtdec_prepare_fdt实现如下 */
int fdtdec_prepare_fdt(void)
{
if (!gd->fdt_blob || ((uintptr_t)gd->fdt_blob & 3) ||
fdt_check_header(gd->fdt_blob)) {
puts("No valid device tree binary found - please append one to U-Boot binary, use u-boot-dtb.bin or define CONFIG_OF_EMBED. For sandbox, use -d <file.dtb>\n");
return -1;
// 判断dtb是否存在,以及是否有四个字节对齐。
// 然后再调用fdt_check_header看看头部是否正常。fdt_check_header主要是检查dtb的magic是否正确。
}
return 0;
}
验证dtb的部分可以参考《[kernel 启动流程] (第四章)第一阶段之——dtb的验证》。
3、为dtb分配新的内存地址空间(reserve_fdt)
relocate的内容请参考《[uboot] (番外篇)uboot relocation介绍》。
common/board_f.c中
static int reserve_fdt(void)
{
#ifndef CONFIG_OF_EMBED
// 当使用CONFIG_OF_EMBED方式时,也就是dtb集成在uboot中的时候,relocate uboot过程中也会把dtb一起relocate,所以这里就不需要处理。
// 当使用CONFIG_OF_SEPARATE方式时,就需要在这里地方进行relocate
if (gd->fdt_blob) {
gd->fdt_size = ALIGN(fdt_totalsize(gd->fdt_blob) + 0x1000, 32);
// 获取dtb的size
gd->start_addr_sp -= gd->fdt_size;
gd->new_fdt = map_sysmem(gd->start_addr_sp, gd->fdt_size);
// 为dtb分配新的内存空间
debug("Reserving %lu Bytes for FDT at: %08lx\n",
gd->fdt_size, gd->start_addr_sp);
}
#endif
return 0;
}
4、relocate dtb(reloc_fdt)
relocate的内容请参考《[uboot] (番外篇)uboot relocation介绍》。
common/board_f.c中
static int reloc_fdt(void)
{
#ifndef CONFIG_OF_EMBED
// 当使用CONFIG_OF_EMBED方式时,也就是dtb集成在uboot中的时候,relocate uboot过程中也会把dtb一起relocate,所以这里就不需要处理。
// 当使用CONFIG_OF_SEPARATE方式时,就需要在这里地方进行relocate
if (gd->flags & GD_FLG_SKIP_RELOC)
// 检查GD_FLG_SKIP_RELOC标识
return 0;
if (gd->new_fdt) {
memcpy(gd->new_fdt, gd->fdt_blob, gd->fdt_size);
// relocate dtb空间
gd->fdt_blob = gd->new_fdt;
// 切换gd->fdt_blob到dtb的新的地址空间上
}
#endif
return 0;
}
五、uboot中dtb解析的常用接口
gd->fdt_blob已经设置成了dtb的地址了。
注意,fdt提供的接口都是以gd->fdt_blob(dtb的地址)为参数的。
1、接口功能
以下只简单说明几个接口的功能,没有深究到实现原理。先说明几个,后续继续补充。
另外,用节点在dtb中的偏移地址来表示一个节点。也就是节点变量node中,存放的是节点的偏移地址
lib/fdtdec.c中
fdt_path_offset
int fdt_path_offset(const void *fdt, const char *path)
eg:node = fdt_path_offset(gd->fdt_blob, “/aliases”);
功能:获得dtb下某个节点的路径path的偏移。这个偏移就代表了这个节点。fdt_getprop
const void *fdt_getprop(const void *fdt, int nodeoffset, const char *name, int *lenp)
eg: mac = fdt_getprop(gd->fdt_blob, node, “mac-address”, &len);
功能:获得节点node的某个字符串属性值。fdtdec_get_int_array(const void *blob, int node, const char *prop_name, u32 *array, int count)
eg: ret = fdtdec_get_int_array(blob, node, “interrupts”, cell, ARRAY_SIZE(cell));
功能:获得节点node的某个整形数组属性值。fdtdec_get_addr
fdt_addr_t fdtdec_get_addr(const void *blob, int node, const char *prop_name)
eg:fdtdec_get_addr(blob, node, “reg”);
功能:获得节点node的地址属性值。fdtdec_get_config_int、fdtdec_get_config_bool、fdtdec_get_config_string
功能:获得config节点下的整形属性、bool属性、字符串等等。fdtdec_get_chosen_node
int fdtdec_get_chosen_node(const void *blob, const char *name)
功能:获得chosen下的name节点的偏移fdtdec_get_chosen_prop
const char *fdtdec_get_chosen_prop(const void *blob, const char *name)
功能:获得chosen下name属性的值
lib/fdtdec_common.c中
fdtdec_get_int(const void *blob, int node, const char *prop_name, int default_val)
eg: bus->udelay = fdtdec_get_int(blob, node, “i2c-gpio,delay-us”, DEFAULT_UDELAY);
功能:获得节点node的某个整形属性值。fdtdec_get_uint
功能:获得节点node的某个无符号整形属性值。
uboot常用的函数的更多相关文章
- UBoot常用命令手册
UBoot常用命令手册 U-Boot还提供了更加详细的命令帮助,可以通过”?”显示支持的命令列表,通过help [CommandName]命令还可以查看每个命令的参数说明. 1.bootm bootm ...
- oracle(sql)基础篇系列(一)——基础select语句、常用sql函数、组函数、分组函数
花点时间整理下sql基础,温故而知新.文章的demo来自oracle自带的dept,emp,salgrade三张表.解锁scott用户,使用scott用户登录就可以看到自带的表. #使用ora ...
- php常用字符串函数小结
php内置了98个字符串函数(除了基于正则表达式的函数,正则表达式在此不在讨论范围),能够处理字符串中能遇到的每一个方面内容,本文对常用字符串函数进行简单的小结,主要包含以下8部分:1.确定字符串长度 ...
- php常用数组函数回顾一
数组对于程序开发来说是一个必不可少的工具,我根据网上的常用数组函数,结合个人的使用情况,进行数组系列的总结复习.里面当然不只是数组的基本用法,还有相似函数的不同用法的简单实例,力求用最简单的实例,记住 ...
- byte数据的常用操作函数[转发]
/// <summary> /// 本类提供了对byte数据的常用操作函数 /// </summary> public class ByteUtil { ','A','B',' ...
- WordPress主题模板层次和常用模板函数
首页: home.php index.php 文章页: single-{post_type}.php – 如果文章类型是videos(即视频),WordPress就会去查找single-videos. ...
- Python 常用string函数
Python 常用string函数 字符串中字符大小写的变换 1. str.lower() //小写>>> 'SkatE'.lower()'skate' 2. str.upper ...
- MySQL之MySQL常用的函数方法
MySQL常用函数 本篇主要总结了一些在使用MySQL数据库中常用的函数,本篇大部分都是以实例作为讲解,如果有什么建议或者意见欢迎前来打扰. limit Select * from table ord ...
- Delphi常用系统函数总结
Delphi常用系统函数总结 字符串处理函数 Unit System 函数原型 function Concat(s1 [, s2,..., sn]: string): string; 说明 与 S : ...
随机推荐
- Spring再接触 Annotation part1
使用annotation首先得加这两条代码 beans.xml <?xml version="1.0" encoding="UTF-8"?> < ...
- 代码详解:TensorFlow Core带你探索深度神经网络“黑匣子”
来源商业新知网,原标题:代码详解:TensorFlow Core带你探索深度神经网络“黑匣子” 想学TensorFlow?先从低阶API开始吧~某种程度而言,它能够帮助我们更好地理解Tensorflo ...
- Taro开发微信小程序之利用腾讯地图sdk标记
首先要下载腾讯地图提供的sdk,放在项目的对应目录下,引用. import QQMapWX from '../../sdks/qqmap-wx-jssdk' 设置好后,就可以开始使用了. let qq ...
- python之集合及其方法---整理集
集合的定义: 由不同元素组成.一组无序排列的可hash值.集合中元素必须是不可变类型 集合的定义方式: 由大括号组成: 每个元素用逗号分隔: 元素书写不是key-value形式: 集合是由不同元素组成 ...
- 【MYSQL】MYSQLの環境構築
ダウンロード:https://dev.mysql.com/downloads/mysql/ 手順① 手順② mysql.iniの設定について [mysql]default-character-set= ...
- SpringCloud Zuul网关超时
最近在使用SpringCloudZuul网关时,报错"NUMBEROF_RETRIES_NEXTSERVER_EXCEEDED", 查询资料后,发现: ribbon.Connect ...
- Polar Code(1)极化码SC译码迭代公式的理解
采用对数似然比求解的迭代公式推导: 考虑 如上图,将L的部分看为一个整体,用 exp(a)和exp(b)代替,并对式子左右都取对数,则公式变为如下所示: 对数似然比 上述公式等效一下公式: 进一步可等 ...
- spring-framework源码编译及导入
环境说明: 时间:2017-09-26 OS name: "mac os x", version: "10.12.4", arch: "x86_64& ...
- Python学习笔记4基本数据类型
start:16:00 1.Python基本数据类型 (1)数字类型及其操作 整数类型 浮点数类型 浮点数间运算存在不确定尾数,不是bug 复数类型 数值运算操作符 (2)数值运算函数 . 2. ...
- 贪吃蛇(简易版)Leslie5205912著
# include <stdio.h># include <string.h># include <windows.h># include <stdlib.h ...