본문으로 건너뛰기
Bootloader Internals · 5/37

U-Boot Falcon Mode — SPL이 U-Boot Proper 없이 커널 직접 부팅

· Hawk · 7분 읽기

#한 줄 요약

“Falcon Mode는 SPL이 U-Boot Proper를 건너뛰고 커널을 직접 부팅하는 옵션입니다.” — U-Boot Proper에서 1초가 사라집니다. 양산용으로는 매력적이지만 명령 인터페이스가 없어 개발에는 불편합니다. 양산과 개발을 한 빌드로 공존시키는 것이 일반적입니다.

자동차 후방 카메라는 2초 안에 화면이 떠야 합니다. 산업 HMI는 1초 안에 user space가 동작해야 합니다. 일반 부트 흐름에서 U-Boot Proper의 driver probe + 명령 인터프리터 초기화1초 가까이 듭니다. Falcon Mode는 그 1초를 통째로 절약합니다.

#일반 흐름과 Falcon 흐름

단계일반 흐름Falcon 흐름
BootROM0 ms0 ms
SPL100 ms (DDR init 80 ms)150 ms (DDR init + 커널 적재)
U-Boot Proper400~1000 ms — driver probe, env, autoboot delay, bootcmd생략
Linux Kernel부트 시작부트 시작

차이는 수백 ms — U-Boot Proper 단계가 완전히 사라진다.

U-Boot Proper 단계가 완전히 사라집니다. 차이는 수백 ms 입니다.

#”Falcon”의 이름

이름의 유래는 매(falcon)처럼 빠르게 강하한다는 것입니다. SPL이 U-Boot Proper를 우회바로 커널로 점프하는 모양에서 왔습니다. 2012년 DENX의 Wolfgang Denx가 도입했습니다.

#동작 원리

Falcon Mode가 동작하기 위해서는 SPL이 커널을 부트할 모든 정보를 가지고 있어야 합니다. 그 정보는 부트 미디어의 정해진 위치미리 만들어 둔 binary로 저장됩니다.

SD/eMMC 레이아웃 (Falcon Mode):
오프셋 0 ← MBR / GPT
오프셋 1KB ← SPL 이미지 (BootROM이 적재)
오프셋 ~50KB ← U-Boot Proper (개발 모드 대체용)
오프셋 ~800KB ← Falcon args (DTB + bootargs)
오프셋 ~1MB ← Falcon kernel (zImage, Image)
오프셋 ~10MB ← rootfs

SPL이 부팅하면 부트 미디어 + 오프셋에서 args와 kernel바로 적재하고 점프합니다.

/* common/spl/spl.c (Falcon 흐름) */
void board_init_r(gd_t *dummy1, ulong dummy2)
{
/* ... 기본 init ... */
/* CONFIG_SPL_OS_BOOT이 활성화되어 있고, */
/* spl_start_uboot()가 false를 반환하면 → Falcon */
if (CONFIG_IS_ENABLED(OS_BOOT) && !spl_start_uboot()) {
ret = spl_load_image(&spl_image, BOOT_DEVICE_MMC1);
/* spl_load_image가 Linux 부트 정보까지 채움 */
} else {
/* 일반 U-Boot Proper 부트 */
ret = spl_load_uboot(&spl_image, ...);
}
jump_to_image_linux(&spl_image);
}

spl_start_uboot()이 분기점입니다. 어떤 조건에서 U-Boot Proper로 가고, 어떤 조건에서 Falcon인지 보드가 결정합니다.

#defconfig 설정

Falcon Mode를 활성화하는 옵션은 세 줄입니다.

# configs/<board>_defconfig
CONFIG_SPL_OS_BOOT=y
CONFIG_SYS_SPL_ARGS_ADDR=0x80000100
CONFIG_SYS_OS_BASE=0x80008000
옵션의미
CONFIG_SPL_OS_BOOTFalcon Mode 활성화
CONFIG_SYS_SPL_ARGS_ADDRDTB가 적재될 메모리 주소
CONFIG_SYS_OS_BASEkernel image가 적재될 메모리 주소

부트 미디어에서의 오프셋도 보드별로 정의합니다.

CONFIG_SYS_MMCSD_RAW_MODE_KERNEL_SECTOR=0x900 # 1.125 MB
CONFIG_SYS_MMCSD_RAW_MODE_ARGS_SECTOR=0x100 # 128 KB
CONFIG_SYS_MMCSD_RAW_MODE_ARGS_SECTORS=0x80 # 64 KB

이 오프셋이 부트 미디어 굽기 스크립트와 반드시 일치해야 합니다.

#spl_start_uboot() — 분기 결정

보드 코드가 언제 Falcon이고 언제 U-Boot Proper인지를 정합니다.

/* board/<vendor>/<board>/<board>.c */
#include <common.h>
#include <spl.h>
int spl_start_uboot(void)
{
#ifdef CONFIG_SPL_OS_BOOT
/* GPIO 또는 UART signal로 강제 U-Boot Proper */
if (force_uboot_pin_pressed())
return 1; /* U-Boot Proper로 */
/* 그 외는 Falcon */
return 0; /* 커널 직접 부트 */
#else
return 1;
#endif
}

전형적인 결정 기준은 다음과 같습니다.

  • GPIO 핀이 jumper로 short되어 있으면 U-Boot Proper (개발 모드)
  • UART에 키 입력이 있으면 U-Boot Proper
  • 부트 카운트가 임계 초과이면 U-Boot Proper (recovery)
  • 그 외는 Falcon

이 분기로 같은 binary가 양산용·개발용모두 지원합니다.

#args 만들기 — spl export

Falcon이 동작하려면 DTB + bootargs부트 미디어에 미리 굳어져 있어야 합니다. 일반 U-Boot Proper에서 spl export 명령으로 args를 추출합니다.

Terminal window
# 일반 U-Boot Proper 부트
=> setenv bootargs "console=ttymxc1,115200 root=/dev/mmcblk0p2 rw rootwait"
=> load mmc 0:1 ${loadaddr} Image
=> load mmc 0:1 ${fdt_addr} imx8mp-evk.dtb
# 이 시점에 kernel과 dtb가 메모리에 있음
=> spl export atags ${fdt_addr} # ARMv7 (ATAGS)
# 또는
=> spl export fdt ${fdt_addr} # ARMv8 (FDT)

spl export현재의 bootargs를 DTB의 chosen 노드에 fixup완성된 DTB를 만들고, 그 DTB의 주소를 출력합니다.

=> spl export fdt 0x43000000
Argument image is now in RAM: 0x43000000
=>

이 메모리를 부트 미디어에 굽습니다.

=> mmc write 0x43000000 0x100 0x80
MMC write: dev # 0, block # 256, count 128 ... 128 blocks written: OK

이제 SPL이 0x100 sector에서 args를 읽어 부팅하면 Falcon이 동작합니다.

#커널 굽기

Falcon은 FIT image 또는 raw zImage/Image를 지원합니다. raw 모드가 더 간단합니다.

Terminal window
# 호스트에서 SD 카드 굽기
# SPL (오프셋 1KB)
dd if=u-boot-spl.bin of=/dev/sdX bs=1k seek=1
# U-Boot Proper (오프셋 50KB)
dd if=u-boot.bin of=/dev/sdX bs=1k seek=50
# Falcon args (오프셋 128KB)
dd if=args.bin of=/dev/sdX bs=1k seek=128
# Falcon kernel (오프셋 1152KB = 1.125MB)
dd if=Image of=/dev/sdX bs=1k seek=1152
sync

오프셋이 defconfig의 CONFIG_SYS_MMCSD_RAW_MODE_*_SECTOR정확히 일치해야 합니다.

#양산용과 개발용 공존

Falcon은 양산에 최적이지만 개발에는 불편합니다. 환경 변수도 못 만지고, TFTP 부팅도 안 됩니다. 그래서 한 binary에 두 모드를 넣고 strap pin으로 분기하는 패턴이 일반적입니다.

/* board/<vendor>/<board>/<board>.c */
#define DEV_MODE_GPIO IMX_GPIO_NR(1, 5)
int spl_start_uboot(void)
{
int dev_mode;
gpio_request(DEV_MODE_GPIO, "dev_mode");
gpio_direction_input(DEV_MODE_GPIO);
dev_mode = gpio_get_value(DEV_MODE_GPIO);
/* GPIO가 GND이면 dev mode (U-Boot Proper) */
/* GPIO가 VCC이면 release mode (Falcon) */
return (dev_mode == 0) ? 1 : 0;
}

또는 부트 카운트로 연속 실패가 N회이면 강제로 U-Boot Proper로 빠지게 합니다.

int spl_start_uboot(void)
{
u32 boot_count = bootcount_load();
/* 3회 연속 부트 실패 → recovery (U-Boot Proper) */
if (boot_count >= 3) {
bootcount_store(0);
return 1;
}
bootcount_store(boot_count + 1);
return 0; /* Falcon */
}

Ch 17: A/B 업데이트에서 더 다룹니다.

#Falcon Mode 부트 로그

SPL이 U-Boot Proper 없이 바로 커널로 점프할 때의 로그입니다.

U-Boot SPL 2024.04 (May 19 2026 - 09:00:00 +0000)
DDRINFO: start DRAM init
DDRINFO: DRAM rate 4000MTS
DDRINFO: ddrphy calibration done
Falcon Mode: Booting kernel directly ← Falcon 분기 선언
Loading kernel from MMC 0:1
Loading args from MMC 0:1
[ 0.000000] Booting Linux on physical CPU 0x0 ← 바로 커널
[ 0.000000] Linux version 6.6.0 (...)
...

U-Boot 2024.04 (...) 라인이 없습니다. 이것이 Falcon의 시각적 마커입니다.

#부트 시간 비교

실제 측정값(BeagleBone Black, AM335x, 1GB DDR, SD card):

단계일반 부트Falcon Mode
BootROM0.00 s0.00 s
SPL (DDR init)0.15 s0.15 s
U-Boot Proper start0.30 s
driver probe done0.60 s
bootcmd start1.20 s
Linux start1.80 s0.50 s
user space4.50 s3.20 s

1.3초 단축입니다. Linux 부팅이 상수 시간이므로 user space까지의 총 시간에서 차이가 그대로 유지됩니다.

여기서 추가로 단축하려면 Linux 자체를 다듬어야 합니다. CONFIG_DEBUG_KERNEL=n, deferred initcall, async probe. 이는 Embedded Performance Engineering 시리즈에서 다룹니다.

#Falcon의 한계

#1. 상호작용 없음

부트 중 키를 눌러도 반응 없음. 환경 변수 변경 불가, TFTP 부트 불가, 명령 인터프리터 없음.

#2. 부트 미디어 고정

SPL이 raw mode로 정해진 오프셋에서 적재합니다. FAT/ext4를 거치지 않습니다. 파일 이름이 아니라 sector입니다.

#3. 커널 update가 까다로움

raw mode이므로 sector 오프셋에 정확히 굽기 위해 별도 도구가 필요합니다. 일반 파일 시스템 위에 커널을 두는 부트보다 업데이트 절차가 복잡합니다.

#4. recovery가 까다로움

Falcon이 부트 실패했을 때 복구 흐름이 자동이 아닙니다. 보드 코드에서 부트 카운트 + 분기를 직접 짜야 합니다.

#5. DTB fixup 한계

U-Boot Proper의 런타임 fixup(MAC 주소, 메모리 크기, 시리얼)이 동작 안 함. args를 미리 만들 때 모든 fixup이 끝나야 합니다.

#SPL에서의 추가 기능

Falcon Mode에서도 SPL이 조금의 일은 더 해야 합니다. 보드별로 차이가 있지만 일반적으로:

  • watchdog 시작
  • LED indicator (부트 중)
  • splash screen (해상도가 작으면 가능)
  • secure boot 검증 (이미지 서명 확인)
  • A/B 슬롯 선택
/* board/<vendor>/<board>/spl.c */
void spl_board_prepare_for_boot(void)
{
/* WDT 시작 — Linux가 받아서 계속 servicing */
wdt_start(...);
/* GPIO LED 켜기 — 부트 중 indicator */
gpio_set_value(BOOT_LED, 1);
/* A/B 슬롯 결정 */
if (active_slot() == SLOT_B) {
spl_image.entry_point = KERNEL_B_ADDR;
}
}

Ch 16: Verified Boot에서 서명 검증을 다룹니다.

#자주 하는 실수

#args를 생성한 보드부트하는 보드가 다름

spl export로 만든 args는 해당 보드의 DTB + bootargs를 기준으로 합니다. 같은 모델의 다른 개체에서는 시리얼 번호나 MAC만 다르면 동작합니다만, 다른 모델에서는 동작 안 합니다.

#오프셋 불일치

defconfig의 CONFIG_SYS_MMCSD_RAW_MODE_KERNEL_SECTOR=0x900인데 dd seek=1152로 굽지 않고 dd seek=900(decimal)으로 굽는 실수. *sector 단위(512B)*임을 기억합니다.

오프셋 0x900 sector = 0x900 * 512 bytes = 0x120000 bytes = 1.125 MB
dd seek=1152 bs=1024 ← OK
dd seek=2304 bs=512 ← OK
dd seek=0x900 bs=512 ← OK

#spl_start_uboot()항상 0 또는 1만 반환

조건 없이 0을 반환하면 영원히 Falcon이고, 1을 반환하면 Falcon이 꺼진 것입니다. 항상 분기 조건을 점검합니다.

#CONFIG_SPL_OS_BOOT을 켰는데 args를 안 구움

SPL이 args를 못 찾으면 “Failed to load args” 또는 바로 hang. raw mode이므로 어떤 오류 메시지도 없습니다. 시리얼이 조용히 죽음.

#FIT image와 raw mode를 헷갈림

Falcon은 두 모드 모두 가능합니다. defconfig에서 어느 쪽을 쓰는지 확인합니다.

[FIT]
CONFIG_SPL_FIT=y
CONFIG_SPL_LOAD_FIT=y
[raw]
CONFIG_SPL_RAW_IMAGE_SUPPORT=y

#부트가 너무 빠르면 디버깅이 안 됨

Falcon 활성화 직후에는 시리얼이 너무 빨리 흐릅니다. 부트 디버깅 시에는 FORCE_UBOOT GPIO일반 모드로 빠지게 해 두는 것이 필요합니다.

#정리

  • Falcon Mode는 SPL이 U-Boot Proper를 건너뛰고 커널을 직접 부트하는 옵션입니다.
  • 부트 시간이 수백 ms ~ 1초 이상 단축됩니다. 양산 시스템의 sub-second boot에 필수.
  • 활성화는 CONFIG_SPL_OS_BOOT=y + CONFIG_SYS_SPL_ARGS_ADDR + CONFIG_SYS_OS_BASE.
  • args(DTB + bootargs)는 부트 미디어에 미리 굳어져 있어야 합니다. U-Boot Proper에서 spl export로 추출해 sector 단위로 굽습니다.
  • spl_start_uboot() 함수가 Falcon vs U-Boot Proper 분기를 결정합니다. GPIO 또는 부트 카운트 기반.
  • 양산은 Falcon, 개발은 U-Boot Proper로 같은 binary 안에 공존시키는 패턴이 일반적입니다.
  • 한계는 상호작용 없음, raw sector 기반 적재, 런타임 DT fixup 불가. recovery 로직을 별도로 짜야 합니다.
  • 부트 로그에 U-Boot 2024.04 (...) 라인이 없으면 Falcon으로 부팅한 것입니다.

#다음 편

Ch 6: Device Tree와 부트로더에서는 U-Boot이 DTB를 다루는 방식을 봅니다. control DTB(자기 자신용)와 OS DTB(커널에 넘기는 것)의 구분, fdt 명령, 런타임 fixup을 다룹니다.

#관련 항목

Bootloader Internals · 5 of 37

  1. 1ROM부터 init까지 — 임베디드 부팅 단계의 빈자리 분석
  2. 2Das U-Boot vs TF-A vs EDK II — 임베디드 부트로더 생태계 비교
  3. 3U-Boot 빌드 시스템 분석 — Kconfig·Makefile·defconfig 동작 추적
  4. 4ARM 임베디드 부트 4단계 분해 — BL1·SPL·TPL·U-Boot Proper의 역할
  5. 5U-Boot Falcon Mode — SPL이 U-Boot Proper 없이 커널 직접 부팅
  6. 6Device Tree DTB 부트로더 처리 — 로딩 시점과 fixup 메커니즘 추적
  7. 7U-Boot Driver Model 내부 — uclass·driver·device 추상화 구조
  8. 8U-Boot 보드 초기화 시퀀스 — board_init_f와 board_init_r 분리 이유
  9. 9DDR Controller 프로그래밍과 PHY Training — SPL의 가장 어려운 작업
  10. 10임베디드 스토리지 부팅 분석 — MMC·SCSI·NAND·SPI Flash 비교
  11. 11임베디드 네트워크 부팅 — TFTP·PXE·BOOTP 시퀀스 분석
  12. 12U-Boot USB 부팅 — fastboot·UMS·USB host 메커니즘
  13. 13U-Boot 환경 변수와 bootcmd — 부팅 시나리오 정의하기
  14. 14Modern U-Boot bootflow / bootmeth — 새 추상화 레이어 분석
  15. 15FIT image 구조 분석 — multi-image·hash·configuration 추적
  16. 16U-Boot Verified Boot — RSA 서명과 public key 임베딩 흐름
  17. 17임베디드 A/B 부팅 이중화 — OTA 안전성을 위한 부트 슬롯 설계
  18. 18U-Boot의 EFI 호환 분석 — bootefi 명령과 EFI loader 동작 원리
  19. 19Linux Boot ABI — ARM/ARM64 커널 진입 규약 추적
  20. 20임베디드 펌웨어 업데이트 — RAUC vs SWUpdate 비교
  21. 21새 보드 U-Boot 포팅 실전 — defconfig 작성부터 첫 부팅까지
  22. 22부트로더 디버깅 기법 — DEBUG·JTAG·serial·post-mortem 분석
  23. 23SoC BootROM·eFuse·OTP — 부팅의 0단계 분석
  24. 24SPL·TPL 내부 해부 — 가장 작은 부트 단계의 동작 추적
  25. 25ARM Trusted Firmware-A 통합 — BL1·BL2·BL31·BL32·BL33 흐름
  26. 26DDR Training과 PHY Calibration — 보드별 파라미터 튜닝
  27. 27임베디드 Chain of Trust — 다단계 서명 검증의 전체 흐름
  28. 28임베디드 Flash Layout 설계 — partition·NAND·eMMC·UBI 비교
  29. 29U-Boot Distro Boot — extlinux·boot.scr 표준화 분석
  30. 30부트로더 CI 구축 — build matrix와 자동 부팅 테스트
  31. 31TF-A BL31 EL3 Runtime 분석 — PSCI·SDEI·RAS dispatcher 추적
  32. 32PSCI와 SMCCC ABI — ARM 표준 SMC 호출 규약 분석
  33. 33ARM64 Secondary Core Bring-up — PSCI CPU_ON 호출부터 EL1 진입까지
  34. 34U-Boot PCIe Enumeration — 부트로더가 디바이스를 찾는 흐름 분석
  35. 35EFI·UEFI에서 CXL 초기화 — CEDT 생성과 HDM Decoder 사전 설정
  36. 36부트 시 메모리 토폴로지 결정 — DDR + CXL.mem 통합 인식
  37. 37UEFI Secure Boot 인증서 만료 — 2011→2023 CA 롤오버와 PQC 대비