<kernel v5.10>
디바이스 트리(FDT) -> Expanded 포맷으로 변환
- device_node와 property 구조체를 사용하여 트리 구조로 각 노드와 속성을 연결한다.
- 기존에 사용하던 DTB 바이너리들도 문자열등을 그대로 사용하므로 삭제되지 않고 유지된다.
노드 명
다음 디바이스 트리를 보고 3 가지 노드 명 분류를 알아본다.
- Full path 노드명
- Compact 노드명
- Alias 명
arch/arm64/boot/dts/broadcom/northstar2/ns2.dtsi
/ {
compatible = "brcm,ns2";
interrupt-parent = <&gic>;
#address-cells = <2>;
#size-cells = <2>;
cpus {
#address-cells = <2>;
#size-cells = <0>;
A57_0: cpu@0 {
device_type = "cpu";
compatible = "arm,cortex-a57", "arm,armv8";
reg = <0 0>;
enable-method = "psci";
next-level-cache = <&CLUSTER0_L2>;
};
Full path 노드명
- 디렉토리 구조로 표현한다.
- /cpus/cpu@0
Compact 노드명
- Device Tree 버전 0x10이되면서 full path 노드명 대신 compact 노드명을 널리 사용한다.
- cpu@0
- 참고: Device trees I: Are we having fun yet? | LWN.net
Alias 명
- Compact 노드명 앞에 alias 명을 둘 수 있다.
- A57_0
FDT -> Expanded Format으로 변환 수행
워드(4바이트) 단위로 정렬된 DTB를 unflatten_device_tree( ) 함수를 통해 unflatten 과정으로 변환하면 각 노드는 device_node 구조체로 변환된다. 전역 of_root 노드가 루트 노드를 가리킨다. 각 노드에 있는 속성들도 property 구조체로 변환되어 해당 노드에 등록된다. 이렇게 바이너리 형태로 존재하다가 device_node 구조체와 property 구조체를 할당받아 트리 형태로 구성된 것을 확장 포맷(expanded format)이라고 부른다.
노드와 속성은 of_로 시작되는 API에 의해 관리되어 사용한다. unflatten된 구조체들은 슬랩 캐시 할당자에서 할당받아 만들어진다.
unflatten_device_tree()
drivers/of/fdt.c
/** * unflatten_device_tree - create tree of device_nodes from flat blob * * unflattens the device-tree passed by the firmware, creating the * tree of struct device_node. It also fills the "name" and "type" * pointers of the nodes so the normal device-tree walking functions * can be used. */
void __init unflatten_device_tree(void)
{
__unflatten_device_tree(initial_boot_params, NULL, &of_root,
early_init_dt_alloc_memory_arch, false);
/* Get pointer to "/chosen" and "/aliases" nodes for use everywhere */
of_alias_scan(early_init_dt_alloc_memory_arch);
unittest_unflatten_overlay_base();
}
DTB를 확장 포맷으로 변환하고 관련 전역 변수가 적절한 노드를 가리키도록 초기화한다.
- 코드 라인 3~4에서 4바이트 단위의 바이너리로 구성된 DTB를 파싱하여 확장 포맷으로 변환한 후 of_root 전역 변수가 가리키게 한다.
- 코드 라인 7에서 전역 aliases_lookup 리스트에 alias_prop들을 추가한다.
- 전역 변수 of_aliases가 “/aliases” 노드를 가리키도록 설정한다.
- 전역 변수 of_chosen이 “/chosen” 노드를 가리키도록 설정한다.
- 전역 변수 of_stdout을 “/chosen” 노드의 “stdout-path” 속성 값에 대응하는 노드로 설정한다.
다음 그림과 같이 주요 노드들은 of_로 시작되는 전역 변수가 가리키는 것을 보여준다.
- of_stdout
- /soc/uart@7e201000 노드를 가리킨다.
- /chosen 노드의 stdout-path가 가리키는 노드가 출력 디바이스로 사용된다.
- of_aliases
- /aliases 노드를 가리킨다.
- aliases_lookup
- /aliases 노드에 담겨있는 모든 속성들을 alias_prop 구조체 형태로 변환한 후 그 들이 연결되어 있다.
- of_root
- 루트 노드를 가리킨다.
- of_chosen
- /chosen 노드를 가리킨다.
- of_stdout_option
- 출력 노드명에 사용된 옵션(‘:’문자로 시작하는) 문자열이 저장된다.
__unflatten_device_tree()
drivers/of/fdt.c
/** * __unflatten_device_tree - create tree of device_nodes from flat blob * * unflattens a device-tree, creating the * tree of struct device_node. It also fills the "name" and "type" * pointers of the nodes so the normal device-tree walking functions * can be used. * @blob: The blob to expand * @dad: Parent device node * @mynodes: The device_node tree created by the call * @dt_alloc: An allocator that provides a virtual address to memory * for the resulting tree * @detached: if true set OF_DETACHED on @mynodes * * Returns NULL on failure or the memory chunk containing the unflattened * device tree on success. */
void *__unflatten_device_tree(const void *blob,
struct device_node *dad,
struct device_node **mynodes,
void *(*dt_alloc)(u64 size, u64 align),
bool detached)
{
int size;
void *mem;
pr_debug(" -> unflatten_device_tree()\n");
if (!blob) {
pr_debug("No device tree pointer\n");
return NULL;
}
pr_debug("Unflattening device tree:\n");
pr_debug("magic: %08x\n", fdt_magic(blob));
pr_debug("size: %08x\n", fdt_totalsize(blob));
pr_debug("version: %08x\n", fdt_version(blob));
if (fdt_check_header(blob)) {
pr_err("Invalid device tree blob header\n");
return NULL;
}
/* First pass, scan for size */
size = unflatten_dt_nodes(blob, NULL, dad, NULL);
if (size < 0)
return NULL;
size = ALIGN(size, 4);
pr_debug(" size is %d, allocating...\n", size);
/* Allocate memory for the expanded device tree */
mem = dt_alloc(size + 4, __alignof__(struct device_node));
if (!mem)
return NULL;
memset(mem, 0, size);
*(__be32 *)(mem + size) = cpu_to_be32(0xdeadbeef);
pr_debug(" unflattening %p...\n", mem);
/* Second pass, do actual unflattening */
unflatten_dt_nodes(blob, mem, dad, mynodes);
if (be32_to_cpup(mem + size) != 0xdeadbeef)
pr_warn("End of tree marker overwritten: %08x\n",
be32_to_cpup(mem + size));
if (detached && mynodes) {
of_node_set_flag(*mynodes, OF_DETACHED);
pr_debug("unflattened tree is detached\n");
}
pr_debug(" <- unflatten_device_tree()\n");
return mem;
}
DTB를 파싱하여 확장 포맷으로 변환한 후 of_root 전역 변수가 가리키게 한다.
- 코드 라인 22~25에서 DTB의 첫 부분에 위치한 헤더에서 첫 워드를 통해 DTB 데이터 여부를 체크한다. 추가로 지원 가능한 DTB 버전이 0x02 ~ 0x11인지 확인하여 체크하고, 다른 경우 에러를 출력하고 처리를 하지 않는다.
- 코드 라인 28~30에서 가장 마지막 인자 dryrun을 true로 전달하여 실제 컨버팅 동작을 하지 않고 DTB를 unflatten할 때 만들어질 device_node 구조체들과 properties 구조체들의 구성에 필요한 전체 크기의 크기만을 구한다. 그리고 최종 산출된 크기를 워드(4바이트) 단위로 정렬한다.
- 코드 라인 36~38에서 인자로 전달받은 (*dt_alloc) 함수를 통해 메모리를 할당받는다. 할당 시의 크기로 위에서 산출한 크기에 추가로 끝부분을 나타내기 위한 4바이트만큼을 추가한다. 또한 정렬 단위는 시스템의 최소 정렬 단위가 주어지는데 ARM, ARM64는 4바이트다.
- 코드 라인 42에서 할당된 메모리의 마지막 4바이트에 0xdeadbeef를 저장한다. 이 값은 경계 침범을 모니터링하기 위해 사용한다.
- 코드 라인 47에서 DTB를 파싱하여 device_node, property 구조체 배열로 변환한다.
- 코드 라인 48~50에서 할당된 메모리의 끝에 설치한 경계 침범 값이 오염되었는지 확인하여 경고 출력을 한다.
다음 그림은 바이너리 형태의 DTB를 unflatten하여 확장 포맷으로 변환하는 모습을 보여준다.
unflatten_dt_node()
drivers/of/fdt.c
/** * unflatten_dt_nodes - Alloc and populate a device_node from the flat tree * @blob: The parent device tree blob * @mem: Memory chunk to use for allocating device nodes and properties * @dad: Parent struct device_node * @nodepp: The device_node tree created by the call * * It returns the size of unflattened device tree or error code */
static int unflatten_dt_nodes(const void *blob,
void *mem,
struct device_node *dad,
struct device_node **nodepp)
{
struct device_node *root;
int offset = 0, depth = 0, initial_depth = 0;
#define FDT_MAX_DEPTH 64
struct device_node *nps[FDT_MAX_DEPTH];
void *base = mem;
bool dryrun = !base;
if (nodepp)
*nodepp = NULL;
/*
* We're unflattening device sub-tree if @dad is valid. There are
* possibly multiple nodes in the first level of depth. We need
* set @depth to 1 to make fdt_next_node() happy as it bails
* immediately when negative @depth is found. Otherwise, the device
* nodes except the first one won't be unflattened successfully.
*/
if (dad)
depth = initial_depth = 1;
root = dad;
nps[depth] = dad;
for (offset = 0;
offset >= 0 && depth >= initial_depth;
offset = fdt_next_node(blob, offset, &depth)) {
if (WARN_ON_ONCE(depth >= FDT_MAX_DEPTH))
continue;
if (!IS_ENABLED(CONFIG_OF_KOBJ) &&
!of_fdt_device_is_available(blob, offset))
continue;
if (!populate_node(blob, offset, &mem, nps[depth],
&nps[depth+1], dryrun))
return mem - base;
if (!dryrun && nodepp && !*nodepp)
*nodepp = nps[depth+1];
if (!dryrun && !root)
root = nps[depth+1];
}
if (offset < 0 && offset != -FDT_ERR_NOTFOUND) {
pr_err("Error %d processing FDT\n", offset);
return -EINVAL;
}
/*
* Reverse the child list. Some drivers assumes node order matches .dts
* node order
*/
if (!dryrun)
reverse_nodes(root);
return mem - base;
}
FDT 형태의 디바이스 트리를 파싱하고 확장(expand)하여 디바이스 노드로 변환한다. @blob에 디바이스 트리(FDT)의 시작 주소를 지정하고, 확장된 디바이스 노드가 저장될 @mem을 지정한다. @dad에는 부모 디바이스 노드를 지정하고, 출력 인자 @mynode는 이 함수가 호출되어 생성될 디바이스 노드이다. 처음 호출될 때 @dad에는 null, @mynode에는 루트 디바이스 노드를 가리키는 &of_root가 주어진다.
- 코드 라인 13~14에서 먼저 출력 인자 @nodepp에 null을 대입한다.
- 코드 라인 23~24에서 @dad가 지정된 경우에 한해 depth와 초기 depth를 1부터 시작한다.
- 코드 라인 29~33에서 다음(next) 노드를 읽고 offset을 알아온다. 이 때 읽은 노드의 depth도 알아온다.
- 코드 라인 35~37에서 노드가 enable 또는 ok 상태가 아닌 경우는 skip 한다.
- 코드 라인 39~41에서 노드를 활성화한다. 지금까지 변환한 사이즈를 반환한다.
- 코드 라인 43~44에서 2nd pass에서 @nodepp에 현재 노드를 지정한다. 단 한 번만 지정한다.
- 코드 라인 45~46에서 2nd pass의 루트가 아니고 아직 루트가 지정되지 않은 경우 현재 노드를 루트로 지정한다.
- 코드 라인 49~52에서 노드 파싱에 문제가 있는 경우 에러를 반환한다.
- 코드 라인 58~59에서 2nd pass인 경우 노드를 reverse 한다.
- 코드 라인 61에서 지금까지 변환한 사이즈를 반환한다.
디바이스 노드와 속성 활성화
populate_node()
drivers/of/fdt.c
static bool populate_node(const void *blob,
int offset,
void **mem,
struct device_node *dad,
struct device_node **pnp,
bool dryrun)
{
struct device_node *np;
const char *pathp;
unsigned int l, allocl;
pathp = fdt_get_name(blob, offset, &l);
if (!pathp) {
*pnp = NULL;
return false;
}
allocl = ++l;
np = unflatten_dt_alloc(mem, sizeof(struct device_node) + allocl,
__alignof__(struct device_node));
if (!dryrun) {
char *fn;
of_node_init(np);
np->full_name = fn = ((char *)np) + sizeof(*np);
memcpy(fn, pathp, l);
if (dad != NULL) {
np->parent = dad;
np->sibling = dad->child;
dad->child = np;
}
}
populate_properties(blob, offset, mem, np, pathp, dryrun);
if (!dryrun) {
np->name = of_get_property(np, "name", NULL);
if (!np->name)
np->name = "<NULL>";
}
*pnp = np;
return true;
}
노드를 파싱하여 디바이스 노드로 변환한다. 성공 시 true를 반환한다.
- 코드 라인 12~16에서 노드 명이 null인 경우 출력 인자 @pnp에 null을 대입한 후 더 이상 처리하지 않고 false를 반환한다.
- 코드 라인 20~21에서 @mem에서 노드가 저장될 영역을 확보한다.
- 코드 라인 22~34에서 2nd pass인 경우 노드를 초기화 하고, 노드 명을 지정한 후 노드 간의 관계를 연결한다.
- 코드 라인 36~41에서 속성을 파싱하여 속성 정보로 변환한다. 속성 이름이 없는 경우 “<NULL>” 문자열을 이름으로 지정한다.
- 코드 라인 43~44에서 출력 인자 @pnp에 디바이스 노드를 지정하고, true를 반환한다.
populate_properties()
drivers/of/fdt.c -1/2-
static void populate_properties(const void *blob,
int offset,
void **mem,
struct device_node *np,
const char *nodename,
bool dryrun)
{
struct property *pp, **pprev = NULL;
int cur;
bool has_name = false;
pprev = &np->properties;
for (cur = fdt_first_property_offset(blob, offset);
cur >= 0;
cur = fdt_next_property_offset(blob, cur)) {
const __be32 *val;
const char *pname;
u32 sz;
val = fdt_getprop_by_offset(blob, cur, &pname, &sz);
if (!val) {
pr_warn("Cannot locate property at 0x%x\n", cur);
continue;
}
if (!pname) {
pr_warn("Cannot find property name at 0x%x\n", cur);
continue;
}
if (!strcmp(pname, "name"))
has_name = true;
pp = unflatten_dt_alloc(mem, sizeof(struct property),
__alignof__(struct property));
if (dryrun)
continue;
/* We accept flattened tree phandles either in
* ePAPR-style "phandle" properties, or the
* legacy "linux,phandle" properties. If both
* appear and have different values, things
* will get weird. Don't do that.
*/
if (!strcmp(pname, "phandle") ||
!strcmp(pname, "linux,phandle")) {
if (!np->phandle)
np->phandle = be32_to_cpup(val);
}
/* And we process the "ibm,phandle" property
* used in pSeries dynamic device tree
* stuff
*/
if (!strcmp(pname, "ibm,phandle"))
np->phandle = be32_to_cpup(val);
pp->name = (char *)pname;
pp->length = sz;
pp->value = (__be32 *)val;
*pprev = pp;
pprev = &pp->next;
}
drivers/of/fdt.c -2/2-
/* With version 0x10 we may not have the name property,
* recreate it here from the unit name if absent
*/
if (!has_name) {
const char *p = nodename, *ps = p, *pa = NULL;
int len;
while (*p) {
if ((*p) == '@')
pa = p;
else if ((*p) == '/')
ps = p + 1;
p++;
}
if (pa < ps)
pa = p;
len = (pa - ps) + 1;
pp = unflatten_dt_alloc(mem, sizeof(struct property) + len,
__alignof__(struct property));
if (!dryrun) {
pp->name = "name";
pp->length = len;
pp->value = pp + 1;
*pprev = pp;
pprev = &pp->next;
memcpy(pp->value, ps, len - 1);
((char *)pp->value)[len - 1] = 0;
pr_debug("fixed up name for %s -> %s\n",
nodename, (char *)pp->value);
}
}
if (!dryrun)
*pprev = NULL;
}
아래 그림은 노드명이 full path name으로 바뀌어 저장되는 과정을 설명하였다.
아래 그림은 a@1000 노드의 서브 노드로 a2 노드가 추가될 때의 상황이다.
아래 그림은 cpu@0 노드에 속한 속성들이 연결된 모습을 보여준다.
다음 그림은 속성명에 name이 없는 경우 마지막에 추가되는 모습을 보여준다.
child 노드가 있는 경우 DTB 순서대로 만들기 위해 각 child 노드를 reverse 한다.
unflatten_dt_alloc()
drivers/of/fdt.c
static void *unflatten_dt_alloc(void **mem, unsigned long size,
unsigned long align)
{
void *res;
*mem = PTR_ALIGN(*mem, align);
res = *mem;
*mem += size;
return res;
}
mem 값을 align 단위로 round up 하고 리턴하며 입출력 인수 mem 값은 size만큼 증가시킨다.
early_init_dt_alloc_memory_arch()
drivers/of/fdt.c
static void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align)
{
void *ptr = memblock_alloc(size, align);
if (!ptr)
panic("%s: Failed to allocate %llu bytes align=0x%llx\n",
__func__, size, align);
return ptr;
}
align 단위로 size 만큼의 공간을 memblock으로 부터 할당 받고 그 가상 주소를 리턴한다.
alias 노드 스캔
of_alias_scan()
drivers/of/base.c
/** * of_alias_scan - Scan all properties of the 'aliases' node * * The function scans all the properties of the 'aliases' node and populates * the global lookup table with the properties. It returns the * number of alias properties found, or an error code in case of failure. * * @dt_alloc: An allocator that provides a virtual address to memory * for storing the resulting tree */
void of_alias_scan(void * (*dt_alloc)(u64 size, u64 align))
{
struct property *pp;
of_aliases = of_find_node_by_path("/aliases");
of_chosen = of_find_node_by_path("/chosen");
if (of_chosen == NULL)
of_chosen = of_find_node_by_path("/chosen@0");
if (of_chosen) {
/* linux,stdout-path and /aliases/stdout are for legacy compatibility */
const char *name = NULL;
if (of_property_read_string(of_chosen, "stdout-path", &name))
of_property_read_string(of_chosen, "linux,stdout-path",
&name);
if (IS_ENABLED(CONFIG_PPC) && !name)
of_property_read_string(of_aliases, "stdout", &name);
if (name)
of_stdout = of_find_node_opts_by_path(name, &of_stdout_options);
}
if (!of_aliases)
return;
for_each_property_of_node(of_aliases, pp) {
const char *start = pp->name;
const char *end = start + strlen(start);
struct device_node *np;
struct alias_prop *ap;
int id, len;
/* Skip those we do not want to proceed */
if (!strcmp(pp->name, "name") ||
!strcmp(pp->name, "phandle") ||
!strcmp(pp->name, "linux,phandle"))
continue;
np = of_find_node_by_path(pp->value);
if (!np)
continue;
/* walk the alias backwards to extract the id and work out
* the 'stem' string */
while (isdigit(*(end-1)) && end > start)
end--;
len = end - start;
if (kstrtoint(end, 10, &id) < 0)
continue;
/* Allocate an alias_prop with enough space for the stem */
ap = dt_alloc(sizeof(*ap) + len + 1, __alignof__(*ap));
if (!ap)
continue;
memset(ap, 0, sizeof(*ap) + len + 1);
ap->alias = start;
of_alias_add(ap, np, id, start, len);
}
}
“/chosen” 노드를 검색하여 전역 변수 of_stdout을 “stdout-path”에 연결된 노드로 설정한다. 그리고 “/aliases” 노드의 속성 중 “name” 및 “phandle”을 찾아 aliases_prop 구조체로 구성하여 리스트 aliases_lookup에 추가한다.
- 코드 라인 5에서 “/aliases” 노드를 찾아 전역 of_aliases에 설정한다.
- 코드 라인 6~8에서 “/chosen” 노드를 찾아 전역 of_chosen에 설정한다. 만일 of_chosen 노드가 발견되지 않으면 “/chosen@0”으로 다시 한번 검색한다.
- 코드 라인 10~18에서 “/chosen” 노드가 발견된 경우 of_chosen 노드에 있는 속성들에서 “stdout-path” 속성명으로 검색하여 찾은 속성 value 값을 name에 저장한다. 검색 결과가 없으면 레거시 호환을 위해 “linux,stdout-path” 및 “stdout” 속성명으로도 검색한다.
- 코드 라인 19~20에서 name(of_chosen 노드에서 검색한 “stdout-path” 속성의 value 값)으로 노드를 검색하고 전역 of_stdout_options에는 name 문자열에 옵션(‘:’ 문자로 시작하는 문자열) 값이 있다면 저장한다.
- 코드 라인 23~24에서 등록된 aliases가 없다면 함수를 빠져나간다.
- 코드 라인 26~31에서 of_aliases에 속한 모든 속성에 대해 루프를 돈다.
- 코드 라인 34~37에서 속성명이 “name”, “phandle”, “linux,phandle”인 경우에는 스킵한다.
- 코드 라인 39~41에서 속성의 value 값으로 노드를 검색하고 노드가 발견되지 않으면 스킵한다.
- 코드 라인 45~46에서 속성 값에 있는 노드명이 숫자가 있다면 숫자가 시작되는 위치를 end에 설정한다.
- 예 “/abc/def@1000”
- end = ‘1’ 문자를 가리킴
- 예 “/abc/def@1000”
- 코드 라인 47에서 len에 노드명의 마지막에 있는 주소를 제외한 ‘@’ 문자까지의 노드명 길이가 담긴다.
- 예) “/abc/def@1000”
- len = 9
- 예) “/abc”
- len = 4
- 예) “/abc/def@1000”
- 코드 라인 49~50에서 주소에 대한 문자열을 10진수로 변환하여 id 변수에 저장을 하는데, 에러인 경우에는 스킵한다.
- 코드 라인 53~55에서 alias_prop 구조체 크기 + len + 1 크기만큼 memblock을 할당한다. 만일 할당이 실패하면 스킵한다.
- 코드 라인 56에서 할당받은 메모리를 0으로 초기화한다.
- 코드 라인 57에서 alias가 속성명을 가리키게 한다. /alias 노드의 각 속성명은 ‘ / ’ 문자로 시작하지 않는다.
- 예 name = “uart0”
- 코드 라인 58에서 np, id, stem 값을 저장하고 전역 aliases_lookup 리스트에 추가한다. stem 문자열은 속성명에서 주소 부분을 제외했다.
- 예) 속성 데이터 = “/soc/uart@7e201000”
- stem = “/soc/uart@”
- 예) 속성 데이터 = “/soc/uart@7e201000”
구조체
device_node 구조체
include/linux/of.h
struct device_node {
const char *name;
phandle phandle;
const char *full_name;
struct fwnode_handle fwnode;
struct property *properties;
struct property *deadprops; /* removed properties */
struct device_node *parent;
struct device_node *child;
struct device_node *sibling;
#if defined(CONFIG_OF_KOBJ)
struct kobject kobj;
#endif
unsigned long _flags;
void *data;
#if defined(CONFIG_SPARC)
unsigned int unique_id;
struct of_irq_controller *irq_trans;
#endif
};
property 구조체
include/linux/of.h
struct property {
char *name;
int length;
void *value;
struct property *next;
#if defined(CONFIG_OF_DYNAMIC) || defined(CONFIG_SPARC)
unsigned long _flags;
#endif
#if defined(CONFIG_OF_PROMTREE)
unsigned int unique_id;
#endif
#if defined(CONFIG_OF_KOBJ)
struct bin_attribute attr;
#endif
};
alias_prop 구조체
drivers/of/of_private.h
/** * struct alias_prop - Alias property in 'aliases' node * @link: List node to link the structure in aliases_lookup list * @alias: Alias property name * @np: Pointer to device_node that the alias stands for * @id: Index value from end of alias name * @stem: Alias string without the index * * The structure represents one alias property of 'aliases' node as * an entry in aliases_lookup list. */
struct alias_prop {
struct list_head link;
const char *alias;
struct device_node *np;
int id;
char stem[];
};
- link
- 링크드 리스트
- alias
- alias 속성명
- 예) “chosen”, “uart0”
- alias 속성명
- np
- 노드(device_node)를 가리킨다.
- id
- 노드의 메모리 또는 포트가 사용하는 주소
- 예) 노드명이 serial@12000 인 경우 id=12000
- 노드의 메모리 또는 포트가 사용하는 주소
- stem
- index(id)를 제외한 full path 노드명
- 예) “/soc/uart@”
- index(id)를 제외한 full path 노드명
각 구조체의 Memblock 할당 시 사이즈
- device_node
- 생성할 때 마다 full path 노드명 공간이 추가 할당된다.
- name, type, data 등은 기존 DTB에 있는 문자열이나 값을 가리킨다.
- property
- 생성할 때 마다 property 사이즈만큼 공간이 할당된다. 그러나 DTB에 없는 name 속성을 추가 생성해야 하는 경우에는 property 속성 이외에도 주소제외 노드명 공간을 추가 할당한다.
- alias_prop
- 생성할 때 마다 주소제외 노드명 공간이 추가 할당되고 이 공간은 stem 문자열이 사용하는 공간이다.
참고
- DTB – 구조 | 문c
- DTB – 라즈베리파이2 샘플 소스 | 문c
- DTB (fdt API) | 문c
- DTB (of API) | 문c








