부트로더 구간까지 잡다 — U-Boot에서 LTDC 끄기
지난 글에서 PH12/EM_INT/RCD_INT가 재부팅 직후 잠깐 켜졌다 꺼지는 걸 확인했다. 원인은 이미 알고 있었다 — U-Boot이 LTDC를 초기화하고, 커널이 넘겨받는 그 사이 구간. 커널 DTS로는 못 막는 영역이라 U-Boot 소스를 직접 고쳐야 했다.
결과부터 말하면 끝냈다. 다만 가는 길에 생각보다 많은 게 걸렸다.
소스부터 확인 — 진짜 그 바이너리가 맞는지
MYiR 사이트에서 U-Boot 소스를 받았다. 받았다고 바로 믿을 게 아니라, 지금 보드에 올라가 있는 그 바이너리랑 같은 소스인지부터 확인했다.
root@myir:~# printenv
...
ver=U-Boot 2020.01-stm32mp-r1 (Nov 03 2021 - 07:47:19 +0000)
받은 소스의 git 로그를 봤다.
$ git log -1 --format="%H %ad"
62f4cbc4 Wed Nov 3 00:47:19 2021 -0700
-0700을 UTC로 바꾸면 07:47:19 — 초 단위까지 정확히 일치했다. 이 소스가 맞다.
<dc만 끄면 안 됐다
지난 글에서 U-Boot의 stm32mp15-u-boot.dtsi에 이런 게 있다고 짐작했었다.
/* pre-reloc probe = reserve video frame buffer in video_reserve() */
<dc {
u-boot,dm-pre-proper;
};
실제로 있었다. env·splash 설정과 무관하게 무조건 이른 시점에 probe되도록 박혀 있었다. 그래서 지금까지 환경변수로는 못 잡았던 거다.
그런데 보드 파일(stm32mp157c-ya157c-512d-v2.dts)을 열어보니, <dc만 끄는 걸로는 부족했다.
panel_rgb: panel-rgb {
compatible = "simple-panel";
pinctrl-0 = <<dc_pins_a>; /* PH12/13/14/15 등을 AF14로 */
backlight = <&panel_backlight>;
status = "okay";
...
};
<dc {
status = "okay";
//pinctrl-names = "default"; /* ← 주석 처리돼 있다 */
...
};
<dc 자신은 pinctrl-names가 주석 처리돼 있어서 핀을 안 잡는다. 실제로 PH12/13/14/15를 드라이브하는 건 panel_rgb다. 별도 디바이스라서 자기 pinctrl-0을 독립적으로 적용한다. <dc만 껐으면 panel_rgb가 여전히 그 핀들을 잡았을 거다.
하나 더 있었다.
panel_backlight: panel-backlight {
compatible = "gpio-backlight";
gpios = <&gpiob 8 GPIO_ACTIVE_HIGH>; /* PB8 = 우리 보드 C_AC_ON */
default-on;
status = "okay";
};
default-on. probe되는 순간 PB8을 HIGH로 민다. 커널 쪽에서 이미 /delete-node/로 지웠던 바로 그 문제가, U-Boot 쪽에도 그대로 있었다.
셋 다 껐다.
&panel_rgb { status = "disabled"; };
&panel_backlight { status = "disabled"; };
<dc { status = "disabled"; };
<dc만 보고 끝냈으면 절반만 고친 채로 “됐다”고 착각했을 거다.
빌드 — 에러가 네 개 연달아 나왔다
빌드 스크립트는 커널 것(kbuild.sh)을 거의 그대로 재사용했다. 그런데도 U-Boot 특유의 문제가 네 개 연달아 걸렸다. 하나씩 원인을 짚었다.
1. multiple definition of yylloc
/usr/bin/ld: scripts/dtc/dtc-parser.tab.o:(.bss+0x10): multiple definition of `yylloc'
이 U-Boot(2020년산)에 번들된 dtc 파서 소스가 오래됐다. GCC 10부터 기본값이 -fno-common으로 바뀌면서, 예전엔 봐주던 전역변수 중복 선언이 진짜 에러가 됐다.
make ... HOSTCFLAGS=-fcommon
2. undefined reference to image_get_checksum_algo
/usr/bin/ld: tools/image-host.o: in function `fit_image_setup_sig':
undefined reference to `image_get_checksum_algo'
처음엔 pkg-config가 아예 없어서 그런가 싶었다.
$ pkg-config --exists libcrypto
bash: pkg-config: command not found
설치했다.
sudo apt-get install -y pkg-config
3. 같은 에러가 또 났다
pkg-config를 설치했는데도 똑같은 에러였다. .config를 열어보고서야 진짜 원인을 찾았다.
# CONFIG_FIT_SIGNATURE is not set
tools/Makefile을 보면 이유가 나온다.
FIT_SIG_OBJS-$(CONFIG_FIT_SIGNATURE) := common/image-sig.o
image_get_checksum_algo의 실제 정의가 있는 common/image-sig.o는 CONFIG_FIT_SIGNATURE가 켜져 있을 때만 컴파일된다. 그런데 tools/image-host.c의 fit_image_setup_sig()는 이 함수들을 조건 없이 호출한다. 정의는 빠지고 호출부만 남는 비대칭이 생긴 거다. pkg-config는 애초에 무관한 문제였다.
sed -i 's/# CONFIG_FIT_SIGNATURE is not set/CONFIG_FIT_SIGNATURE=y/' .config
make olddefconfig
4. __WORDSIZE is not defined — 수백 줄
가장 알아보기 어려웠던 에러다.
error: #error "__WORDSIZE is not defined"
error: unknown type name '__STD_TYPE'
stdint.h, sys/types.h 같은 기본 헤더가 통째로 깨졌다. 호스트용 gcc가 갑자기 ARM 타깃 헤더를 읽고 있다는 신호였다.
pkg-config를 직접 쳐보고서야 잡았다.
$ pkg-config --cflags libcrypto
-I/opt/st/myir/3.1-snapshot/sysroots/cortexa7t2hf-neon-vfpv4-ostl-linux-gnueabi/usr/include
ARM sysroot 경로가 그대로 나왔다. SDK가 export한 PKG_CONFIG_SYSROOT_DIR이 범인이었다. 이 변수는 원래 “다른 패키지를 ARM용으로 크로스 컴파일할 때” 쓰라고 있는 건데, U-Boot의 호스트 툴(mkimage)이 OpenSSL을 찾는 과정에서도 그대로 새어 들어간 거다. 호스트 gcc가 ARM용 stdint.h를 읽으니 __WORDSIZE가 정의될 리 없었다.
unset PKG_CONFIG_SYSROOT_DIR PKG_CONFIG_PATH
네 개를 정리하면 이렇다.
| # | 증상 | 진짜 원인 | 조치 |
|---|---|---|---|
| 1 | yylloc 중복 정의 |
GCC 10+ 기본값 변경 vs 구형 dtc | HOSTCFLAGS=-fcommon |
| 2 | undefined reference | pkg-config 없음 (곁가지) |
설치 |
| 3 | 같은 에러, 설치 후에도 지속 | CONFIG_FIT_SIGNATURE 꺼짐 (진짜 원인) |
.config 수정 |
| 4 | __WORDSIZE 대량 에러 |
PKG_CONFIG_SYSROOT_DIR가 ARM sysroot로 새어들어감 |
unset |
2번에서 멈췄으면 3번을 못 찾았을 거고, 매번 에러 메시지가 가리키는 곳과 진짜 원인이 다른 곳에 있었다. kbuild.sh에 다음처럼 다 몰아넣고서야 한 번에 통과했다.
#!/bin/bash
set -e
. /opt/st/myir/3.1-snapshot/environment-setup-cortexa7t2hf-neon-vfpv4-ostl-linux-gnueabi
unset LDFLAGS CFLAGS CPPFLAGS CXXFLAGS KCFLAGS PKG_CONFIG_SYSROOT_DIR PKG_CONFIG_PATH
export PATH=/usr/local/bin:/usr/bin:/bin:$PATH
cd ~/work/U-boot
exec make O="$HOME/work/build-trusted" ARCH=arm CROSS_COMPILE=arm-ostl-linux-gnueabi- "$@"
빌드 산출물과, 디컴파일해서 실제로 값이 들어갔는지 확인했다.
$ dtc -I dtb -O dts u-boot.dtb | grep -A5 panel-rgb
panel-rgb {
...
status = "disabled";
panel-backlight, ltdc 노드도 전부 disabled로 확인됐다.
배포 — 라벨을 믿었다가 하마터면 eMMC를 쓸 뻔했다
이번 작업에서 가장 아찔했던 순간이다.
SSBL 파티션을 찾으려고 이렇게 쳤다.
root@myir:~# ls -l /dev/disk/by-partlabel/
fsbl1 -> ../../mmcblk1p1
fsbl2 -> ../../mmcblk1p2
ssbl -> ../../mmcblk2p1 ← 이거
...
ssbl이 mmcblk2를 가리켰다. 이 프로젝트에서 mmcblk2는 eMMC다. 처음부터 “eMMC는 건드리지 않는다”로 지켜온 원칙에 정면으로 걸릴 뻔했다.
/dev/disk/by-partlabel/는 라벨 하나당 링크 하나만 만든다. SD카드(mmcblk1)와 eMMC(mmcblk2) 양쪽 다 ssbl이라는 이름의 파티션을 갖고 있으면, udev가 나중에 잡은 쪽만 보여주고 나머지는 가려진다. fsbl1/fsbl2는 SD를 가리키는데 ssbl만 eMMC를 가리키는 건 그 자체로 이상한 신호였다.
바로 쓰지 않고 장치별로 직접 봤다.
root@myir:~# lsblk -o NAME,PARTLABEL,SIZE /dev/mmcblk1
mmcblk1p3 ssbl 2M ← SD카드에도 있다
root@myir:~# lsblk -o NAME,PARTLABEL,SIZE /dev/mmcblk2
mmcblk2p1 ssbl 2M ← eMMC에도 있다
둘 다 있었다. 라벨만 보고 썼으면 원본 eMMC 부트로더를 덮어썼을 것이다. SD카드 쪽 진짜 경로는 /dev/mmcblk1p3였다.
심볼릭 링크는 편하려고 있는 거지, 보장하려고 있는 게 아니다. 같은 이름이 두 군데 있을 수 있다는 걸 미리 의심하지 않으면, “편한 이름”이 “틀린 대상”을 가리키고 있어도 모르고 지나간다.
경로를 명시해서 진행했다.
# 백업 먼저
dd if=/dev/mmcblk1p3 of=/home/root/ssbl-sd-original-backup.bin
# 크기 확인 (파티션 2MB, 새 바이너리 861KB — 여유 있음)
blockdev --getsize64 /dev/mmcblk1p3
# 쓰기
dd if=/home/root/u-boot.stm32 of=/dev/mmcblk1p3
sync
reboot
작은 것도 하나 걸렸다. 백업 파일을 /root/에 두려다 실패했다.
dd: failed to open '/root/ssbl-sd-original-backup.bin': No such file or directory
이 이미지는 Yocto 기반이라 root의 홈이 /root가 아니라 /home/root다. 이미 printenv에서 HOME=/home/root로 나왔던 걸 지나쳤다가 한 번 더 확인한 셈이다.
재부팅 후
root@myir:~# grep -E "\(PH(12|14|15)\)|\(PB8\)" /sys/kernel/debug/pinctrl/*50002000*/pinconf-pins
PH12/PH14/PH15, PB8 전부 정상으로 돌아왔고, 재부팅 직후부터 LED가 켜지지 않는다. 지난 글에서 남겨뒀던 “짧은 트랜지언트, 전원 인가마다 반복”이 이걸로 사라졌다.
정리
이번 건은 처음부터 끝까지 표면과 실체가 계속 어긋났다.
<dc를 껐다고 끝난 게 아니었다 —panel_rgb가 별도로 같은 핀을 잡고 있었다- 빌드 에러 메시지가 가리키는 지점과 진짜 원인이 매번 달랐다 (
pkg-config없음 → 사실은 Kconfig,undefined reference→ 사실은 sysroot 오염) - 파티션 라벨을 그대로 믿었으면 eMMC를 덮어썼을 뻔했다
공통점은 하나다. “이름”이나 “가장 눈에 띄는 에러”를 그대로 믿지 않고, 그 뒤에 실제로 뭐가 있는지 한 단계 더 파고들었을 때만 진짜 원인이 나왔다. DTS 작업 때부터 반복돼온 패턴인데, 부트로더와 파티션 레벨까지 내려와서도 똑같았다.
이제 PH12 LED 건은 완전히 닫혔다. 남은 건 QCA7005 PLC 모뎀 바인딩이다.
참고 링크
- github 주소 https://github.com/MYiR-Dev/myir-st-u-boot
댓글남기기