device-tree alias·label 디버깅 — 무엇을 보고 어떻게 맞추나

보드 로그에 serial0이 보이는데 DTS에는 uart0:만 있고, 오버레이 target = <&i2c1>은 되는데 /aliases의 i2c1 경로는 예전 SoC 주소를 가리키는 식의 이름 혼선이 흔합니다. 원인은 대개 alias · label · node를 같은 것으로 취급하는 데 있습니다.

이 글의 축은 셋뿐입니다. alias는? · label vs node? · 디버그 팁은? 오버레이 -@/__symbols__ 자체는 device-tree-overlay-debug 쪽이고, 여기서는 별칭과 라벨을 맞추는 법만 다룹니다. 보드 실측 MB·가격·창작 현장 후기·제휴는 없습니다.

근거: Device Tree Specification — /aliases, DTS Labels, Linux DeviceTree Kernel API(of_find_node_opts_by_path, of_alias_get_id 등).

alias는?

한 줄 답: alias는 루트 /aliases 노드의 프로퍼티입니다. 이름 = 짧은 공개 별칭, 값 = 그 노드의 full path 문자열입니다. DTS의 uart0: 같은 라벨과는 별개입니다.

스펙 요약(§3.3 /aliases):

항목규칙
위치루트 직속, 노드 이름 /aliases
프로퍼티 이름alias 이름 (공개 단축명)
프로퍼티 값full path 문자열 (리프가 아니어도 됨)
이름 문자소문자 a-z, 숫자 0-9, -만 · 1–31자
클라이언트경로 문자열을 볼 때 alias를 감지·치환해야 함

스펙 예(경로는 스펙 예시이며 특정 보드 주장이 아님):

aliases {
    serial0 = "/simple-bus@fe000000/serial@llc500";
    ethernet0 = "/simple-bus@fe000000/ethernet@31c000";
};

DTS에서는 라벨로 full path를 채우는 관용도 흔합니다. 셀 배열 밖의 &Label은 그 노드의 full path로 펼쳐집니다(§6.3):

aliases {
    serial0 = &uart0;   /* → uart0 라벨 노드의 full path 문자열 */
};

리눅스 OF 쪽(Kernel API):

  • of_find_node_opts_by_path(path, …) — path가 /로 시작하지 않으면 /aliases의 그 이름 프로퍼티로 해석합니다.
  • of_alias_get_id(np, stem) / of_alias_get_highest_id(stem) — serial0, serial1처럼 stem + 숫자 alias에서 인덱스를 얻습니다.
  • /chosen의 stdout-path 등은 값이 alias여도 된다고 스펙이 명시합니다(§3.5).

하지 말 것: DTS 라벨 이름(uart0)만 보고 “커널이 uart0 alias를 안다”고 가정하기. alias 테이블에 없으면 path lookup은 그 이름을 모릅니다.

label vs node?

한 줄 답: node는 트리에 남는 실체(이름·unit-address·프로퍼티)이고, label은 DTS 소스 전용 식별자입니다. DTB에는 라벨 문자열이 들어가지 않습니다(스펙 §6.2).

구분nodelabelalias
어디에 있나트리(DTS→DTB)DTS만/aliases 프로퍼티(DTB에 path 문자열로 존재)
표기serial@llc500 { … }uart0: serial@…serial0 = "/…/serial@…";
참조full path / phandle&uart0path 앞의 단축명 serial0
DTB노드·프로퍼티로 인코딩인코딩 안 됨path 문자열 프로퍼티로 인코딩
길이·문자노드 이름 규칙1–31자 · 0-9a-zA-Z_ · 숫자로 시작 금지1–31자 · a-z0-9-만(소문자)

& 참조의 펼침 규칙(§6.3):

  1. 셀 배열 안 < &label > → 그 노드의 phandle(숫자). 예: interrupt-parent = <&mpic>;
  2. 셀 배열 밖 prop = &label; → 그 노드의 full path 문자열. 예: ethernet0 = &EMAC0;
  3. 경로 직접 참조: <&{/soc/interrupt-controller@40000}>

노드 정의 형태:

[label:] node-name[@unit-address] {
    [properties]
    [child nodes]
};

phandle은 스펙상 노드를 가리키는 트리 내 유일 숫자 ID이고, 대부분 DTS에는 명시하지 않으며 dtc가 DTB 생성 시 삽입합니다(basics · phandle). 라벨은 “사람이 &로 쓰기 쉽게” 하는 소스 편의이고, alias는 “부트·드라이버·유저가 짧은 공개 이름으로 path를 말하게” 하는 런타임 테이블입니다.

혼동 포인트:

  • 같은 노드에 uart0: 라벨과 serial0 alias를 둘 다 달 수 있습니다. 이름이 같아질 필요는 없습니다.
  • 오버레이에서 target = <&i2c1>은 베이스의 라벨/심볼 쪽이고, /aliases의 i2c1 = "/…"는 별도 엔트리입니다. 한쪽만 고치면 다른 쪽이 어긋납니다.
  • dtc -@로 __symbols__에 라벨→path가 실리는 경우는 심볼 테이블이지, 스펙 /aliases와 동일하지 않습니다.

디버그 팁은?

한 줄 답: (1) /aliases path 문자열 → (2) 실제 노드 존재 → (3) DTS 라벨/& 참조 → (4) 커널 stem id 순으로 맞추십시오. “라벨 이름 = alias 이름” 가정부터 버리십시오.

1) 살아 있는 트리에서 alias 먼저

# 런타임(권한이 있을 때) — aliases 프로퍼티 = path 문자열
ls /proc/device-tree/aliases/
cat /proc/device-tree/aliases/serial0   # NUL 종료 문자열일 수 있음

# 또는 fs 형태를 DTS로
dtc -I fs -O dts /proc/device-tree 2>/dev/null | sed -n '/aliases/,/^};/p'

확인할 것: alias 이름 철자, 값이 지금 보드의 full path인지, 오버레이·보드 dtsi 병합 뒤 주소가 바뀌었는데 문자열만 옛값인지.

2) DTB/DTS에서 라벨은 “소스에만”

# 바이너리 → 소스: 라벨(: name)은 원래 DTB에 없음 → 복원본에 label이 안 보이는 것이 정상
dtc -I dtb -O dts -o dumped.dts your.dtb

# 심볼을 켠 빌드라면 __symbols__에 label→path가 있을 수 있음(오버레이용)
grep -n '__symbols__\|aliases' dumped.dts

증상 매핑:

증상의심
of_find_node_by_path("uart0") 실패uart0이 alias가 아님. /aliases에 넣거나 full path/& 규칙을 쓸 것
serial0은 찾는데 잘못된 UART/aliases path 문자열이 stale (노드 이동·주소 변경 후 미갱신)
오버레이 target = <&foo> 실패베이스 라벨/심볼 문제(-@, __symbols__). alias 테이블과 별개로 볼 것
ttyS 번호가 기대와 다름serialN stem의 숫자 N(of_alias_get_id)과 바인딩 관행을 확인
DTS엔 foo:가 있는데 dumped DTB에 없음정상 — 라벨은 DTB 미인코딩

3) 소스에서 label ↔ alias를 한 표로

[ ] Label name (DTS):     uart0
[ ] Node path:            /soc/serial@...
[ ] Alias property name:  serial0
[ ] Alias value string:   matches Node path after merge
[ ] Cell refs use:        <&uart0>  (phandle)
[ ] Path-style refs use:  &uart0 or "/soc/serial@..." outside <>
[ ] chosen/stdout-path:   full path OR alias name per Spec

복붙 점검 순서:

1. Locate /aliases in merged DTS or live tree.
2. For each public name (serial0, ethernet0, …): read path string.
3. Resolve that path — node must exist with expected compatible/status.
4. Grep DTS for "label:" used by &refs and overlays — separate from step 2.
5. If stem IDs matter, list aliases matching ^stem[0-9]+$ and sort by N.
6. Never invent board-specific timings/prices; fix names and paths only.

4) 커널 API로 기대 동작 고정

  • path/alias 해석: of_find_node_opts_by_path
  • stem 인덱스: of_alias_get_id / of_alias_get_highest_id
  • phandle 해석: of_find_node_by_phandle, of_parse_phandle*

드라이버·부트 문서가 “serial0 alias 필요”라고 하면 /aliases에 그 프로퍼티를 두는 것이 계약이고, DTS 라벨 uart0:만으로는 부족합니다.

한 줄 정리: label = 소스 &용, alias = /aliases의 path 단축명, node = 트리 실체. 디버그는 path 문자열과 노드 존재부터 맞추고, 라벨은 컴파일·오버레이 참조 축으로 따로 보십시오.

FAQ

alias 이름과 label 이름을 같게 해야 하나?

필수가 아닙니다. 관행상 serial0 alias + uart0: label처럼 공개 번호 체계와 SoC 블록 이름을 나누는 경우가 많습니다. 맞출 때는 의도적으로 맞추고, 문서에 표로 남기십시오.

/aliases 값이 &label이면 DTB에는 무엇이 남나?

셀 밖 참조이므로 dtc가 full path 문자열로 펼칩니다. 런타임에 남는 것은 그 path 문자열이지 라벨 토큰이 아닙니다.

stdout-path에 alias를 넣어도 되나?

스펙상 /chosen의 stdout-path/stdin-path 값은 alias여도 됩니다. 클라이언트는 경로로 볼 때 alias를 해석해야 합니다.

라벨 문자 집합과 alias 문자 집합이 다른 이유는?

스펙이 다릅니다. 라벨은 A-Z·_ 허용·숫자 시작 금지, alias는 소문자·숫자·-만. 대문자 라벨을 그대로 alias 이름으로 복사하면 잘못된 alias 이름이 됩니다.

출처 (Sources)