부트로그 디버깅 — earlyprintk·loglevel·serial 추적
#한 줄 요약
부팅 실패는 4가지 모드로 수렴합니다 — 시리얼 garbage, hang, panic, late hang. 각 모드의 원인 집합은 좁고 명확합니다. 어떤 모드인지 5초 안에 분류하고, 해당 모드의 첫 의심부터 확인하는 것이 BSP 디버깅의 기본기입니다.
Ch 10에서 정상 부팅의 단계를 따라갔다면, 이번 글은 비정상의 카탈로그입니다. 각 패턴을 진단 명령과 함께 정리합니다. 보드 50개를 부팅하는 BSP 엔지니어는 결국 이 카탈로그를 머릿속에 갖게 됩니다.
#모드 1 — 시리얼 garbage
시리얼에 알 수 없는 깨진 문자가 나옵니다. U�4☐2*▒ 같은 형태입니다.
U�4☐2*▒~������원인은 거의 항상 UART baud rate 불일치입니다.
# host side에서 다른 속도로 다시 시도picocom -b 115200 /dev/ttyUSB0picocom -b 921600 /dev/ttyUSB0picocom -b 38400 /dev/ttyUSB0자주 보이는 짝:
| host에서 본 garbage | 실제 보드 baud | 추정 host 설정 |
|---|---|---|
U�4☐2 | 115200 | 38400 또는 9600 |
XXXXXX 반복 | 보통 다른 속도 | 4배 차이 |
짧은 글자 + ~ | 115200 | 230400 |
baud rate가 맞는데도 garbage라면 UART pinmux 잘못입니다.
# 부트로더에서 pinmux dump=> md.l 0x30330014 1 # IOMUXC_SW_PAD_CTL_PAD_<UART_RX>=> md.l 0x30330018 1 # IOMUXC_SW_PAD_CTL_PAD_<UART_TX>DT의 pinctrl-0이 가리키는 핀이 실제 UART 핀이 맞는지, voltage(1.8V vs 3.3V)가 맞는지 확인합니다.
세 번째 가능성은 클럭 부정확입니다. 24 MHz 크리스털이 실제로 23.6 MHz라면 baud rate 계산이 어긋납니다. 오실로스코프로 측정합니다.
#모드 2 — hang (정지)
특정 라인까지 나오고 영영 멈춥니다. 가장 빈번한 패턴이며, 멈춘 마지막 라인이 진단의 핵심 단서입니다.
#패턴 2a — SPL 후 hang
U-Boot SPL 2023.04 (Sep 12 2025 - 14:23:01 +0000)DDR4 dram init doneTrying to boot from MMC1<침묵>ATF BL31 또는 U-Boot proper가 DRAM의 어떤 주소로 로드되지 못했거나, 그 주소로의 점프가 실패한 경우입니다. 흔한 원인:
- ATF BL31의 entry address가 DRAM 범위 밖.
- FIT image의 hash 불일치 (보안 부팅 활성 시).
- U-Boot proper가 SPL과 다른 DDR 구역에 빌드되어 충돌.
부트로더의 imx_load_image.cfg(NXP) 또는 boot.cfg(Rockchip) 같은 image manifest의 주소가 메모리 맵과 일치하는지 확인합니다.
#패턴 2b — U-Boot proper 진입 직후 hang
U-Boot 2023.04 (Sep 12 2025 - ...)
CPU: Freescale i.MX8MMQ rev1.0 1800 MHz (running at 1200 MHz)<침묵>대체로 DRAM training은 통과했지만 동작이 불안정합니다. CPU 코어가 DRAM에 두 번째 접근에서 실패합니다. SPD/calibration값을 다시 측정해 lpddr4_timing.c(또는 ddr3l_timing.c)를 조정합니다.
#패턴 2c — Kernel decompress 후 hang
=> booti ${loadaddr} - ${fdt_addr_r}## Flattened Device Tree blob at 43000000 Booting using the fdt blob at 0x43000000 Loading Device Tree to 00000000bfff7000, end 00000000bffffae8 ... OK
Starting kernel ...
<침묵>earlycon이 설정되지 않음이 1번 의심입니다. bootargs에 다음을 추가합니다.
earlycon=ec_imx6q0,0x30890000,115200n8UART base address는 SoC TRM에 적힌 값을 정확히 써야 합니다. console=ttymxc0,115200만 있어서는 console이 활성화되는 시점까지 침묵합니다.
두 번째 의심은 잘못된 DTB입니다. U-Boot가 다른 보드의 DTB를 로드했거나, 메모리 노드의 base가 잘못되어 커널이 자기 자신을 RAM 밖으로 복사하면 hang합니다.
#패턴 2d — driver probe에서 hang
[ 1.234567] mmc0: registering SD-class host controller<침묵>특정 디바이스 probe에서 멈춥니다. MMC, I2C, SPI 드라이버가 응답하지 않는 디바이스를 폴링하면 timeout 처리 안 한 코드에서 hang합니다.
# bootargs에 추가해 어디서 멈췄는지 정확히 본다initcall_debug printk.time=1 ignore_loglevel이렇게 하면 dmesg에 다음 형태가 나옵니다.
[ 1.234567] calling sdhci_drv_init+0x0/0x40 @ 1[ 1.245678] initcall sdhci_drv_init+0x0/0x40 returned 0 after 11000 usecs[ 1.246789] calling sdhci_pltfm_init+0x0/0x60 @ 1<멈춤 — 이 함수가 범인>#모드 3 — Kernel panic
[ 1.234567] Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0)[ 1.345678] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 6.6.0 #1[ 1.456789] Call trace:[ 1.567890] dump_backtrace+0xe0/0xf0[ 1.678901] show_stack+0x18/0x24[ 1.789012] dump_stack_lvl+0x60/0x84[ 1.890123] panic+0x148/0x350[ 1.901234] mount_block_root+0x180/0x270panic은 원인이 메시지에 적혀 있다는 점이 그나마 다행입니다. 패턴별로 대응:
#“Unable to mount root fs”
bootargs의 root=이 가리키는 디바이스가 없거나 인식 안 됨.
# 진단# 1) MMC 드라이버가 빌트인인지 확인zcat /proc/config.gz | grep -E "MMC|MMC_SDHCI"# CONFIG_MMC=y, CONFIG_MMC_SDHCI=y 여야 함
# 2) 부팅 시 인식된 디바이스 확인[ 1.234567] mmc0: new HS200 MMC card at address 0001[ 1.345678] mmcblk0: mmc0:0001 SDW32G 29.7 GiB[ 1.456789] mmcblk0: p1 p2 p3
# 3) bootargs와 일치하는지 확인root=/dev/mmcblk0p2 # mmcblk0의 p2 — 위 로그와 일치rootwait도 잊지 말아야 합니다. MMC가 비동기로 인식되는 보드는 rootwait 없으면 panic합니다.
#”No init found”
rootfs는 마운트됐지만 /sbin/init가 없음.
# 다른 init 시도rdinit=/bin/sh # initramfs 단계init=/bin/sh # rootfs 단계
# 마운트 후 콘솔 진입해 검증mount /dev/mmcblk0p2 /mntls -l /mnt/sbin/init /mnt/lib/systemd/systemd#NULL pointer dereference
드라이버 버그. Call trace의 PC와 LR로 어느 함수인지 식별.
# 호스트에서 심볼 매칭aarch64-linux-gnu-addr2line -e vmlinux -f 0xffffffc008abcdef# 또는gdb-multiarch vmlinux(gdb) l *0xffffffc008abcdefvmlinux(non-stripped)가 빌드 시 보존되어 있어야 합니다.
#모드 4 — late hang (init 단계 정지)
커널은 정상이고 init까지 진입했는데 userspace에서 멈춥니다.
[ 4.890123] systemd[1]: Reached target Multi-User System.<침묵>원인 후보:
- getty가 시리얼 콘솔에 못 attach:
/etc/systemd/system/getty.target.wants/serial-getty@ttymxc0.service존재하는지. - OOM: 메모리 부족으로 init/systemd 또는 자식이 죽음. 다음 boot 시 dmesg에
Out of memory: Killed process .... - udev rule 무한 대기:
udevadm settle이 timeout까지 기다림.journalctl -b에서 확인.
콘솔이 막혀 진단 어려우면 다음 boot에서 bootargs에 systemd.log_level=debug systemd.log_target=console 추가.
#진단 도구들
#dmesg와 /proc
dmesg # 모든 커널 메시지dmesg -T # 사람 시간으로dmesg -l err,warn # 오류만cat /proc/cmdline # 부팅 시 커널 인자cat /proc/version # 커널 버전, 빌드 정보cat /proc/interrupts # 인터럽트 카운트cat /proc/iomem # I/O 메모리 맵cat /proc/device-tree/... # DT 라이브 뷰#debugfs
mount -t debugfs none /sys/kernel/debug
ls /sys/kernel/debug/# clk/ — clock tree# regmap/ — register cache 들# pinctrl/ — pin 설정# regulator/ — 전원 도메인# gpio — gpio 상태# tracing/ — ftrace
cat /sys/kernel/debug/clk/clk_summarycat /sys/kernel/debug/pinctrl/<dev>/pinmux-functionscat /sys/kernel/debug/regulator/regulator_summaryCONFIG_DEBUG_FS=y가 빌트인이어야 동작합니다.
#earlyprintk vs earlycon
이름이 비슷한 두 메커니즘이 자주 헷갈립니다.
| 옵션 | 의미 | 활성 시기 |
|---|---|---|
earlyprintk | 보드별 fixed early console. legacy. | 일부 보드만 지원 |
earlycon | DT-based 또는 explicit address. 표준 | arm64 표준 |
arm64는 earlycon을 쓰고, 32-bit ARM에서는 earlyprintk가 남아 있는 보드가 있습니다. 새 보드라면 earlycon이 정답입니다.
# 명시적 주소earlycon=uart8250,mmio32,0xfe215040,115200n8
# DT의 stdout-path 사용earlycon#ftrace — 커널 함수 트레이스
cd /sys/kernel/debug/tracingecho function > current_tracerecho 1 > tracing_onsleep 1echo 0 > tracing_oncat trace | head -50probe 단계의 hang을 좁히는 데 효과적입니다. 부팅 단계에서 ftrace를 켜려면 bootargs에 ftrace=function trace_event=irq:* trace_buf_size=4M.
#kgdb와 JTAG
심각한 hang에서는 동적 추적이 한계입니다. JTAG로 정지된 CPU의 PC, LR, SP를 직접 봅니다.
# OpenOCDopenocd -f interface/jlink.cfg -f target/imx8mm.cfg
# 다른 터미널에서 gdbgdb-multiarch vmlinux(gdb) target remote :3333(gdb) info registers(gdb) btJTAG가 없어도 kgdb를 시리얼 위에서 쓸 수 있습니다.
# bootargskgdboc=ttymxc0,115200 kgdbwait부팅 중 kgdbwait에서 멈추고 호스트의 gdb가 attach될 때까지 기다립니다.
#console muxing
여러 콘솔을 동시에 쓸 수 있습니다.
console=ttymxc0,115200 console=tty0마지막에 적은 console이 primary(/dev/console)가 됩니다. 시리얼과 HDMI 모두에 보내고 싶으면 둘 다 적습니다.
#부팅 실패 진단 체크리스트
- 시리얼 어디까지 나왔나? (마지막 5줄 캡처)
- baud rate가 맞나? (다른 속도 2~3개 시도)
- BootROM / SPL / ATF / U-Boot / kernel 중 어디서 멈췄나?
-
earlycon이 인자에 있나? -
bootargs의root=,console=가 보드와 일치하나? -
dmesg -l err에 의심 라인 있나? -
/proc/cmdline이 부팅 인자와 일치하나? - driver probe가 실패한 디바이스 있나?
- OOM 또는 watchdog reboot loop인가?
#흔한 실수
- 시리얼 케이블의 TX/RX 교차: 보드 TX → host RX, 보드 RX → host TX. 한쪽만 들려도 디버그는 가능합니다.
- UART voltage 불일치: 보드 1.8 V UART에 3.3 V USB-Serial을 연결하면 입력은 보이지만 host → 보드 키 입력이 안 됩니다. level shifter 필요.
bootargs를 SPL에서 설정한 줄로 착각: SPL은 보통 bootargs를 안 만집니다. U-Boot proper의bootcmd에서setenv bootargs ...로 설정합니다.CONFIG_PRINTK_TIME비활성: dmesg에 timestamp가 없어 어느 함수가 느린지 분석 불가.- 양산 펌웨어에서
quiet: 필드에서 부팅 문제가 생기면 정보가 거의 없습니다. 양산이라도 시리얼 콘솔에는 verbose를 유지하는 편이 안전.
#정리
- 부팅 실패는 garbage, hang, panic, late hang의 4가지 모드로 분류됩니다.
- 시리얼 garbage는 baud rate, pinmux, 클럭 중 하나입니다.
- Hang은 마지막 라인이 핵심 단서이며, SPL·U-Boot proper·kernel decompress·driver probe 단계에 따라 의심 영역이 다릅니다.
- Kernel panic은 메시지에 원인이 적혀 있으므로
Unable to mount root fs,No init found, NULL deref 패턴을 익혀 둡니다. - Late hang은 systemd unit 실패, OOM, getty miss-attach가 흔합니다.
earlycon은 BSP 초기에 절대 빠뜨리지 말아야 할 인자입니다.- ftrace, kgdb, JTAG로 깊은 진단이 가능하지만 먼저
dmesg와/proc/cmdline을 확인합니다. CONFIG_DEBUG_FS,CONFIG_PRINTK_TIME,CONFIG_MAGIC_SYSRQ는 디버깅 친화 옵션입니다.
#다음 편 예고
Ch 12: 드라이버 추가에서는 보드 specific peripheral을 통합할 때 기존 드라이버 활용과 DT binding 작성을 살펴봅니다.
#관련 항목
BSP Development · 11 of 21
- 1BSP의 본질 분해 — 새 보드 부팅을 위한 코드의 자리
- 2SoC 데이터시트 읽기 — Pin Mux·Clock·Memory Map 파악법
- 3새 보드 Device Tree 설계 — node·property·phandle 작성 흐름
- 4Pin Mux와 Clock Tree 분석 — 보드 부팅의 첫 두 관문
- 5DDR 매개변수 결정 — 보드별 Timing·Training 추출
- 6U-Boot 새 보드 포팅 — defconfig·board.c·DTS 작성 흐름
- 7TF-A·TrustZone 통합 — BL31·secure world·SMC 흐름 적용
- 8Linux 커널 BSP 설정 — defconfig·Kconfig·DT 통합
- 9Multi-core SMP Bring-up — PSCI·Secondary CPU 깨우기
- 10첫 부팅 추적 — 0%부터 login prompt까지의 단계 분석
- 11부트로그 디버깅 — earlyprintk·loglevel·serial 추적
- 12BSP 드라이버 추가 — 보드별 Peripheral 통합 흐름
- 13BSP Power Management — Suspend/Resume·Runtime PM·Regulator
- 14BSP Thermal과 Watchdog — Trip Point·Cooling Device·Hardware Reset
- 15BSP 부트 시간 최적화 — Bootchart·initcall_debug·Parallel Init
- 16BSP RootFS 통합 — Buildroot·Yocto와 보드별 패키지 묶기
- 17BSP 이미지 패키징 — Flash Layout·Partition·GPT 설계
- 18BSP OTA와 Field Recovery — A/B 슬롯·롤백·BootCount
- 19BSP Stability Testing — Stress·Soak·Power Cycle 시나리오
- 20BSP 양산 환경 구축 — CI/CD·재현 가능 빌드·서명
- 21BSP 유지보수 — 업스트림 기여·커널 버전업·LTS 전략