[커널 17차] 41주차

2021.06.13 23:30

ㅇㅇㅇ 조회 수:36507

DTB 복습
- http://jake.dothome.co.kr/dtb1/

 

unflatten_device_tree()
- __unflatten_device_tree() 함수를 call하여 device node tree를 형성한다

 

__unflatten_device_tree()

 

- 3 단계로 나누어서 실행된다
1) 각 node 및 property의 size를 총 합을 계산
2) 계산된 size를 바탕으로 memory allocation 수행
3) 실제 unflatten 수행

 

- 처음에 fdt magic, total size, version check를 수행한다
- fdt header sanity check를 수행한다

- first pass에서 함수 unflatten_dt_nodes()를 수행해서 device node tree를 저장하기 위한 총 메모리 사이즈를 계산한다
- 사이즈가 0이면 NULL 리턴
- 사이즈를 4 byte align을 맞추고 early_init_dt_alloc_memory_arch() 함수를 이용해서 사이즈 만큼 memblock 메모리를 할당받는다. 이 때 할당 받은 메모리의 linear mapping 가상 주소를 리턴 받는다. 또한 할당 받는 메모리는 device node 구조체 크기만큼 align하도록 요청한다.
- 메모리 할당 실패하면 NULL 리턴
- 할당된 메모리를 0으로 memset한다
- 할당된 메모리의 마지막에 overwrite check를 위한 "0xdeadbeef"를 넣는다
- second pass에서 함수 unflatten_dt_nodes()를 수행해서 device tree node를 생성한다
- 메모리 마지막에 "0xdeadbeef"가 없으면 overwrite된 것이므로 경고를 출력한다
- detached 인자가 true이면 root device node의 flag를 OF_DETACHED로 설정한다
- 생성된 device node tree의 주소를 리턴한다

 

unflatten_dt_nodes(blob, mem, dad, nodepp)
- mem이 NULL이면 노드와 속성 크기의 총 합만 계산해서 리턴한다
- mem이 NULL이 아니면 mem 영역에 device node tree를 생성해서 리턴한다
- dad는 parent node인에 지금은 NULL
- nodepp은 생성된 device node tree의 최상위 루트이고 1st pass에서는 NULL이다

- dryrun은 메모리 크기만 계산한다는 의미이다 (1st pass)

- FDS로 FDT 노드를 방문한다 (fdt_next_node() 함수)
- 커널 config로 CONFIG_OF_KOB가 disable이고 노드에 "status" property가 존재함에도 "ok" 또는 "okay" 값이 아니면 해당 노드는 skip한다
- populate_node() 함수로 방문한 노드를 생성한다. nps[depth]는 부모 노드이고 nps[depth+1]은 지금 방문해서 생성하려는 노드이다
- dryrun이 아니면 reverse_nodes() 함수로 parent가 첫 생성된 child를 가리키게 하고 child가 다음으로 생성된 child를 sibling으로 가리키게 한다
- 끝으로 만들어진 device node tree의 크기를 리턴한다

 

populate_node()
- fdt_get_name() 함수로 node name을 가져온다
- device_node 구조체와 node name 길이 + 1만큼 unflatten_dt_alloc() 함수로 메모리를 받는다
- unflatten_dt_alloc() 함수는 메모리 할당 요청된 사이즈만큼 포인터를 증가시키고 할당할 영역의 포인터를 반환한다
- dryrun이 아니면 할당 영역의 끝부분에 node name을 쓰고 앞 부분에는 device_node 구조체를 할당한다. node의 parent, sibling을 업데이트한다
- dad->child = np 할당
- populate_properties() 함수로 노드의 속성을 device_node 구조체에 업데이트한다
- dryrun이 아닌 경우 of_get_property() 함수로 "name" 속성을 가져와서 np->name에 할당한다
- "name" 속성이 없으면 np->name에 상수 "<NULL>"을 할당한다
- nps[depth+1] = np 할당

 

fdt_get_name()
- fdt_offset_ptr_() 함수로 노드 header를 가져온다
- 노드 header는 노드 시작 tag와 노드 name을 의미함
- header로부터 노드 name과 노드 name 길이를 리턴한다

 

fdt_offset_ptr_()
- return (const char *)fdt + fdt_off_dt_struct(fdt) + offset

 

of_get_property()
- 노드의 속성 중 name이 일치하는 것을 골라서 속성의 value를 리턴한다

 

populate_properties()
- node의 속성들을 모두 방문하여 아래 항목을 수행한다
- fdt_getprop_by_offset() 함수로 속성 이름, 길이, value를 구함
- 이름, value에 대해 sanity check 수행
- 속성 이름이 "name"이면 has_name = true 처리
- unflatten_dt_alloc()으로 property 구조체 만큼 메모리 할당
- dryrun이면 여기서 다음 속성으로 이동
- dryrun이 아닌 경우 계속
- 속성 이름이 "phandle"이거나 "linux,phandle"이면 np->phandle이 NULL인 경우 속성 value로 np->phandle을 업데이트 한다
- 속성 이름이 "ibm,phandle"이면 np->phandle을 속성 vlaue로 업데이트
- 이 후 할당된 메모리 영역의 property 구조체를 만든다
- 속성 이름, 길이, value를 구조체에 업데이트하고 다음 속성으로 이동
- 속성 처리가 끝나고 has_name이 false이면 "name"이라는 속성을 직접 만든다
- 노드 이름이 "/a/b/c@1000"이면 len을 c의 길이 + 1 만큼으로 잡는다
- unflatten_dt_alloc()로 property 구조체 + len 만큼 메모리 할당
- 속성 이름 = "name", 길이 = len, value = "c"로 할당한다
- 마지막 속성의 경우 next를 NULL로 하고 종료

 

fdt_getprop_by_offset()
- 속성 offset으로부터 속성 이름, 길이, 속성 value를 구한다

 

reverse_nodes()
- 생성 과정에서 device node tree는 parent가 마지막 child를 가리키고, child는 그 전에 생성된 child를 sibling으로 가키리도록 되어 있음
- 이 함수는 방향을 반대로 하여 parent가 첫 번째 child를 가리키고 child는 다음에 생성된 child를 sibling으로 가리키게 한다

 

===================================================

 

of_alias_scan()
- alias node의 모든 속성을 검색해서 글로벌 테이블에 해당 속성들을 정리한다

- 함수 of_find_node_by_path()를 이용해서 "/aliases" 노드와 "/chosen" 노드를 구해서 of_aliases, of_chosen 전역 변수에 저장. 만약 "/chosen" 노드가 없으면 "/chosen@0"으로도 검색한다
- chosen 노드가 발견되면 of_property_read_string() 함수로 chosen 노드에서 "stdout-path" property를 검색, 그 value 값을 name에 업데이트한다
- "stdout-path" 속성이 발견되지 않으면 "linux,stdout-path"로 다시 검색한다
- Power PC이고 name이 업데이트 안되었으면 "/aliases" node에서 "stdout" 속성을 검색한다
- 위 속성들이 검색되면 of_find_node_opts_by_path() 함수로 검색된 name을 path로 하여 노드를 검색하고 노드를 of_stdout 전역변수에 저장한다. 이 때 전역 변수 of_stdout_options에 path의 옵션을 저장한다
- "/aliases" 노드가 없으면 리턴한다

- of_aliases 노드에 대해서 모든 속성에 대해 struct alias_prop 구조체를 만들고 이를 전역변수 aliases_lookup list head에 연결한다
- property value로부터 노드를 구한다
- property name에서 id를 구한다 (예: ethernet0에서 0에 해당)
- 함수 early_init_dt_alloc_memory_arch()를 이용해서 alias_prop 구조체 + name 길이 + 1 만큼의 메모리를 memblock으로부터 할당받는다
- 할당 받은 영역에 alias_prop 구조체 instance를 만든다
- 함수 of_alias_add()를 이용해서 구조체에 노드, id, alias, stem 등의 멤버값을 채우고 aliases_lookup 테이블에 linked list로 연결한다

 

of_find_node_by_path()
- of_find_node_opts_by_path() 함수를 호출하여 path로부터 device node를 구한다

 

of_find_node_opts_by_path()
- path로부터 노드를 검색하여 리턴한다. 이 때 path에 설정된 option도 인자로 리턴한다. (path:option)

 

- 두 단계로 나누어 수행된다
1) alias path인 경우 우선 alias path가 가리키는 노드와 그 노드의 아래 path를 구하고 다음 단계로 넘어간다. (alias path가 아닌 경우에는 root 노드와 주어진 path를 그대로 이용)
2) 노드로부터 path에 해당하는 서브 노드를 계산해서 리턴한다 (함수 __of_find_node_by_full_path() 이용)

 

예를 들어 

aliases {
        ethernet0 = &enet0;
        serial0 = &serial0;
        serial1 = &serial1;
        pci0 = &pci0;
    };

 

인 경우 ethernet0/a/b/c path가 들어오면 "/aliases" 노드에서 "ethernet0" 속성을 찾고 그 value를 구한다. 그 value는 ethernet0가 가리키는 노드의 path이고 path로부터 ethernet0가 가리키는 노드를 구해서 np로 assign한다. 이후 path = "/a/b/c"가 되고 np에서 해당 path를 검색해서 노드 검색을 계속하게 된다.

 

(https://stackoverflow.com/questions/17738709/dts-file-explanation-aliases)

 

- raw_spin_lock_irqsave()로 devtree_lock spinlock을 건다
- np = NULL이면 np를 루트 노드로 설정한다
- __of_find_node_by_full_path() 함수로 np 노드에서 path를 검색해서 새 노드 np를 구한다
- raw_spin_unlock_irqrestore()로 devtree_lock spinlock을 푼다
- 구한 np 노드를 리턴한다


__of_find_node_by_full_path(np, path)
- 디바이스 노드 np에서 path를 검색해서 해당하는 서브 노드를 리턴한다
- 예를 들어 path = "/a/b/c/d:option"으로 되어 있으면 한 단계씩 아래로 내려가면서 검색을 수행한다 (a -> b -> c -> d 순서)
- __of_find_node_by_path() 함수를 이용해서 바로 아래 단계의 노드를 구한다
- path 역시 한 단계를 아래로 내려가면서 검색 수행 ("/a/b/c/d" --> "/b/c/d")
- "d" 까지 내려가서 path와 이름이 일치하는 노드를 리턴한다


__of_find_node_by_path()
- parent 노드에서 path에 해당하는 child 노드를 검색해서 리턴한다
- __for_each_child_of_node 매크로로 루프 수행
- kbasename() 함수로 child의 leaf name을 구한다
- path의 첫 번째 아래의 child를 검색한다
- 예를 들어 path = "a/b/c/d:option"가 들어오면 name = "a"인 child node를 검색해서 리턴한다


of_property_read_string()
- device node로부터 propery name을 검색하여 property의 value string의 포인터를 구한다
- of_find_property() 함수로 device node에서 property name을 검색하여 name이 일치하는 property를 구한다
- property가 없으면 EINVAL을 리턴한다
- property가 있는데 value가 없으면 ENODATA를 리턴한다
- value도 있는데 value string이 null 문자로 끝나지 않으면 EILSEQ를 리턴한다
- prop->value를 인수로 리턴한다

 

of_find_property(np, propname, lenp)
- raw_spin_lock_irqsave()로 devtree_lock에 spinlock을 건다 (irq/preemption disable)
- __of_find_property() 함수로 np 노드에서 propname 문자열을 이름으로 가지는 property를 구한다. 이 때 lenp에 property length도 가져온다
- raw_spin_unlock_irqrestore()로 devtree_lock spinlock을 푼다 (irq/preemption restore)
- 위에서 구한 property를 리턴한다

 

__of_find_property(np, name, lenp)
- device node np의 property 중 이름이 name인 것을 찾아서 리턴한다
- 찾은 property의 길이를 lenp에 업데이트한다

번호 제목 글쓴이 날짜 조회 수
공지 [공지] 스터디 정리 노트 공간입니다. woos 2016.05.14 617
82 [커널 17차] 49주차 ㅇㅇㅇ 2021.08.07 215
81 [커널 17차] 48주차 ㅇㅇㅇ 2021.08.01 166
80 [커널 18차] 9주차 Runixs 2021.07.29 256
79 [커널 17차] 47주차 ㅇㅇㅇ 2021.07.24 82
78 [커널 18차] 8주차 Runixs 2021.07.22 168
77 [커널 17차] 46주차 ㅇㅇㅇ 2021.07.18 60
76 [커널 18차] 7주차 Runixs 2021.07.12 129
75 [커널 17차] 45주차 ㅇㅇㅇ 2021.07.10 127
74 [커널 17차] 44주차 ㅇㅇㅇ 2021.07.04 76
73 [커널 18차] 6주차 V4bel 2021.07.03 75
72 [커널 17차] 43주차 ㅇㅇㅇ 2021.06.27 138
71 [커널 18차] 5주차 V4bel 2021.06.26 102
70 [커널 17차] 42주차 ㅇㅇㅇ 2021.06.20 290
69 [커널 18차] 4주차 V4bel 2021.06.19 92
» [커널 17차] 41주차 ㅇㅇㅇ 2021.06.13 36507
67 [커널 18차] 3주차 V4bel 2021.06.12 103
66 [커널 17차] 40주차 ㅇㅇㅇ 2021.06.05 280
65 [커널 18차] 2주차 V4bel 2021.06.05 269
64 [커널 17차] 39주차 ㅇㅇㅇ 2021.05.29 177
63 [커널 18차] 1주차 V4bel 2021.05.29 3595
XE Login