设备树编译器DTC中几个关于词法分析器和语法分析器中使用的数据结构
下面是DTS源文件布局的一个非常粗略的概述:
sourcefile : versioninfo plugindecl list_of_memreserve devicetree
memreserve: label ‘memreserve’ ADDR ADDR ‘;’
| label ‘memreserve’ ADDR ‘-’ ADDR ‘;’
devicetree: ‘/’nodedef
versioninfo: ‘/’ ‘dts-v1’ ‘/’ ‘;’
plugindecl: ‘/’ ‘plugin’ ‘/’ ‘;’
| /* empty */
nodedef: ‘{’ list_of_property list_of_subnode ‘}’ ‘;’
property: label PROPNAME ‘=’ propdata ‘;’
propdata: STRING
| ‘<’ list_of_cells ‘>’
| ‘[’ list_of_bytes ‘]’
subnode: label nodename nodedef
这种结构形成了一个以初始节点为根的节点和属性的层次布局:
/{
}
支持经典C和C++类型的注释。
源文件可以使用下面的语法包含:
/include/ “filename”
属性
属性是有名称的,可能是标签,值。每个值都是下面中的一个:
a、一个以null结尾的类似C的字符串
b、一个32位的数字值
c、一个32位值的列表
d、一个字节序列
下面是属性定义的一些示例:
a、一个包含0结尾的字符串属性
property1 = “string value”;
b、一个包含一个32位十六进制数字的属性
property2 = <1234abcd>;
c、一个包含3个32位十六进制数字的属性
property3 = <12345678 12345678 deadbeef>;
d、一个包含任意字节数组的属性
property4 = [0a 0b 0c 0d de ea ad be ef];
节点可以包含子节点以获取层次结构。
例如:
一个名为childnode的子节点,它的单位名字是childnode at address。它有一个名为childprop的字符串属性。
childnode@address{
childprop = “hello\n”;
};
默认情况下所有数字值是十六进制。可以使用前缀d#指示10进制,b#指示二进制,o#指示八进制。
字符串支持C中常见的转义序列:”\n”,”\t”,”\r”,”(octal value)”,”\x(hex value)”。
标签和引用
标签可以被应用到节点和属性。标签出现在一个节点名字之前,且使用&引用:&label。绝对节点路径名也允许节点的引用。
在下面的示例中,节点的标签名是”mpic”,且它被引用:
mpic: interrupt-controller@40000{
...
};
ethernet-pht@3{
interrupt-parent = <&mpic>;
...
};
在属性中,标签可以出现在任何值的之前或之后:
randomnode{
prop: string = data:”mystring\n”data_end:;
...
};
下面是设备树源文件的一段示例:
/dts-v1/;
#include "am4372.dtsi"
#include <dt-bindings/pinctrl/am43xx.h>
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/pwm/pwm.h>
#include <dt-bindings/sound/tlv320aic31xx-micbias.h>
/ {
model = "TI AM43x EPOS EVM";
compatible = "ti,am43x-epos-evm","ti,am438x","ti,am43";
aliases {
display0 = &lcd0;
};
chosen {
stdout-path = &uart0;
};
vmmcsd_fixed: fixedregulator-sd {
compatible = "regulator-fixed";
regulator-name = "vmmcsd_fixed";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
enable-active-high;
};
vbat: fixedregulator0 {
compatible = "regulator-fixed";
regulator-name = "vbat";
regulator-min-microvolt = <5000000>;
regulator-max-microvolt = <5000000>;
regulator-boot-on;
};
lcd0: display {
compatible = "osddisplays,osd070t1718-19ts", "panel-dpi";
label = "lcd";
backlight = <&lcd_bl>;
port {
lcd_in: endpoint {
remote-endpoint = <&dpi_out>;
};
};
};
};
上图中标识出了节点,属性和标签。
节点由节点的名称和单位地址,节点的属性,子节点,父节点和兄弟节点组成;属性有属性名和属性值;属性值可以是字符串,字节字符串,一个标签的引用或32位的值;标签以冒号结尾。
下面是DTC中关于这几种数据抽象出的数据结构:
数据类型枚举类:
enum markertype {
TYPE_NONE,
REF_PHANDLE,
REF_PATH,
LABEL,
TYPE_UINT8,
TYPE_UINT16,
TYPE_UINT32,
TYPE_UINT64,
TYPE_STRING,
};
标记结构体:
struct marker {
enum markertype type;
unsigned int offset;
char *ref;
struct marker *next;
};
数据结构体:
struct data {
unsigned int len;
char *val;
struct marker *markers;
};
标签结构体:
struct label {
bool deleted;
char *label;
struct label *next;
};
总线类型结构体:
struct bus_type {
const char *name;
};
属性结构体:
struct property {
bool deleted;
char *name;
struct data val;
struct property *next;
struct label *labels;
struct srcpos *srcpos;
};
节点结构体:
struct node {
bool deleted;
char *name;
struct property *proplist;
struct node *children;
struct node *parent;
struct node *next_sibling;
char *fullpath;
int basenamelen;
cell_t phandle;
int addr_cells, size_cells;
struct label *labels;
const struct bus_type *bus;
struct srcpos *srcpos;
bool omit_if_unused, is_referenced;
};
保留内存信息结构体:
struct reserve_info {
uint64_t address, size;
struct reserve_info *next;
struct label *labels;
};
设备树结构体:
struct dt_info {
unsigned int dtsflags;
struct reserve_info *reservelist;
uint32_t boot_cpuid_phys;
struct node *dt; /* the device tree */
const char *outname; /* filename being written to, "-" for stdout */
};
在词法分析和语法分析中,匹配到规则时会调用上面这些相关结构体的操作函数,最后将dts文件解析为dt_info的信息结构。
/************************************************************************************************************/
对DTC的分析还在学习中,后续继续分享