Embedded System/Bootloader & System Startup

임베디드 개발자를 위한 U-Boot 커스텀 명령어 추가 및 활용 가이드 U_BOOT_CMD 완벽 분석

임베디드 친구 2025. 12. 7. 20:33
반응형

임베디드 시스템 개발 현장에서 U-Boot는 단순히 운영체제를 부팅하는 통로가 아니라, 하드웨어 초기화와 시스템 검증을 수행하는 핵심적인 개발 플랫폼입니다. 특히 시스템을 브링업(Bring-up)하는 과정에서 개발자가 직접 정의한 사용자 정의 명령어를 추가할 수 있다면, 하드웨어 테스트나 디버깅 자동화를 훨씬 효율적으로 수행할 수 있습니다. 이번 글에서는 Rockchip RK3399 보드를 사례로 들어, U-Boot에 새로운 명령어를 추가하는 메커니즘과 실제 코드 구현 방법을 단계별로 정리해 보겠습니다.

Generated by Gemini AI.

핵심 요약

  • U-Boot의 모든 명령어는 cmd/ 디렉토리 내에 모듈화되어 관리되며, U_BOOT_CMD 매크로를 통해 등록됩니다.
  • 명령어 실행 함수(do_xxx)는 표준 C의 main 함수와 유사한 구조를 가지며, 인자 처리와 반환값 설정으로 비즈니스 로직을 구현합니다.
  • 커스텀 명령어를 추가한 후에는 반드시 Kconfig와 Makefile을 수정하여 빌드 시스템에 해당 파일을 포함시켜야 합니다.

1. U-Boot 명령어 시스템 구조

U-Boot는 명령어를 체계적으로 관리하기 위해 고유의 구조를 사용합니다.

디렉토리/섹션 주요 역할
cmd/ 명령어 관련 소스 코드 위치 (메모리, GPIO, 네트워크 등)
U_BOOT_CMD 매크로 새로운 명령어를 U-Boot 시스템에 등록하는 표준 방법
.u_boot_list_2_cmd_2 빌드 시 생성되는 명령어 목록이 담긴 특수 섹션

2. 명령어 등록 도구: U_BOOT_CMD 매크로

명령어 정의 시 사용하는 매크로의 인자들은 다음과 같습니다.

인자 설명
name 콘솔에서 호출할 실제 명령어 이름 (예: hello)
maxargs 명령어와 인자를 포함한 최대 개수
repeatable 엔터 입력 시 명령 재실행 여부 (0: 불가, 1: 허용)
cmd_func 명령 실행 시 호출할 C 언어 함수 (do_xxx 형태)
usage help 명령 시 출력될 짧은 한 줄 요약
help 상세 도움말 (여러 줄 작성 가능)

3. [실습] RK3399에 커스텀 명령 추가하기

간단한 출력 명령과 실제 하드웨어를 제어하는 GPIO 명령을 구현하는 예제입니다.

기초: "hello" 출력 명령 (cmd/cmd_hello.c)

C
 
#include <common.h>
#include <command.h>

static int do_hello(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[]) {
    printf("Welcome to Software Factory! This is RK3399 Custom Command.\n");
    return CMD_RET_SUCCESS;
}

U_BOOT_CMD(
    hello, 1, 0, do_hello,
    "Print greeting message",
    "No arguments required. Prints a welcome message for RK3399."
);

심화: RK3399 GPIO 제어 명령 (cmd/cmd_gpio_test.c)

C
 
#include <common.h>
#include <asm/gpio.h>

static int do_gpio_test(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[]) {
    int pin = 64; // RK3399 GPIO 핀 번호
    
    if (gpio_request(pin, "test_led")) {
        printf("GPIO %d 요청 실패\n", pin);
        return CMD_RET_FAILURE;
    }

    gpio_direction_output(pin, 1);
    printf("RK3399 GPIO %d가 HIGH로 설정되었습니다.\n", pin);
    
    return CMD_RET_SUCCESS;
}

U_BOOT_CMD(
    gpio_test, 1, 0, do_gpio_test,
    "Control RK3399 GPIO for testing",
    "Sets a predefined GPIO pin to HIGH for hardware validation."
);

4. 빌드 시스템 연결

파일을 작성한 후에는 반드시 빌드 과정에 포함시켜야 합니다.

  • Kconfig 수정: cmd/Kconfig에 옵션을 추가하여 make menuconfig 메뉴에 보이게 합니다.
  • Makefile 수정: cmd/Makefile에 해당 오브젝트 파일을 추가하여 조건부로 빌드되게 합니다.

5. 개발을 위한 팁

  • 환경 변수 활용: env_get()과 env_set()을 적극적으로 활용하십시오. 커스텀 명령 내에서 환경 변수를 읽어오면, 코드를 수정하지 않고도 부팅 시나리오나 디버그 레벨을 유연하게 제어할 수 있습니다.
  • 자동화 로직: setenv bootcmd "hello; gpio_test; run boot_linux"와 같이 커스텀 명령을 부팅 스크립트에 포함하면, 부팅 시 특정 하드웨어 검증을 자동으로 수행하게 만들 수 있습니다.

6. 흔히 하는 실수

  • 함수 선언 누락: 명령어 실행 함수는 반드시 struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[] 인자 구조를 정확히 따라야 합니다.
  • 반환값 오류: 함수의 마지막에 CMD_RET_SUCCESS나 CMD_RET_FAILURE를 적절히 반환하지 않으면, U-Boot 쉘이 해당 명령의 성공 여부를 판단하지 못해 스크립트 실행이 꼬일 수 있습니다.

결론

U-Boot에 나만의 명령어를 추가하는 것은 단순한 기능을 넘어 하드웨어 브링업 단계에서 매우 강력한 무기가 됩니다. 특히 회로 설계 팀과 협업할 때, 레지스터 상태를 확인하거나 물리 핀을 제어하는 전용 명령어를 제공하면 문제 해결 속도를 비약적으로 높일 수 있습니다. 오늘 다룬 예제를 바탕으로 직접 보드에 필요한 명령어를 추가하여 개발 효율을 극대화해 보시기 바랍니다.

반응형