U-Boot 환경 변수 초기화 메커니즘 분석

환경 변수의 역할과 저장 구조

환경 변수는 시스템 부팅 시 사용되는 전역 설정 정보를 의미하며, 영구 저장 장치(예: NOR/NAND 플래시)에 저장되어야 하며, 실행 중에 조회 및 수정이 가능해야 합니다. 부팅 과정에서 먼저 환경 변수를 메모리에 로드한 후, 하드웨어 초기화 및 운영체제 시작에 활용됩니다.

환경 변수 저장 위치와 로드 위치 결정

  • 플래시 메모리에 저장된 경우: CFG_ENV_IS_IN_FLASH 또는 CFG_ENV_IS_IN_NAND 정의 시 해당 플래시 섹터에서 읽어옵니다.
  • 내장된 환경 변수 (Embedded): ENV_IS_EMBEDDED가 정의되면 환경 변수가 코드 이미지 내부에 포함되며, 리로케이션 시 함께 메모리에 적재됩니다. 캐릭터 스타트업 시 유효성 검사를 통과하면 별도의 복사 없이 바로 사용 가능합니다.
  • 저장소 미존재 모드: CFG_ENV_IS_NOWHERE가 활성화되면 플래시나 다른 저장소에 환경 변수가 없으며, 기본 값(default_environment)을 사용합니다.

초기화 흐름 순서

  1. 검증 단계: 플래시 메모리에 저장된 환경 변수의 CRC 값을 확인하여 유효성을 판단합니다.
  2. 리로케이션 단계: 유효한 데이터라면 플래시에서 메모리로 복사하고, 그렇지 않으면 기본값으로 대체합니다.
  3. 함수 호출 체인:
    • env_init(): 환경 변수 소스를 결정하기 위해 플래시 데이터의 무결성 검사를 수행합니다.
    • env_relocate(): 메모리에 버퍼를 할당하고, 실제 데이터를 이동하거나 기본 환경 변수를 적용합니다.
    • env_relocate_spec(): 플래시에서 환경 변수를 메모리로 복사하는 핵심 함수입니다.

핵심 코드 분석

1. 전역 변수 정의

// 환경 변수 저장 위치 (플래시 주소)
env_t *env_ptr = (env_t *)CFG_ENV_ADDR;

// 기본 환경 설정 문자열
uchar default_environment[] = {
    "bootargs=" CONFIG_BOOTARGS "\0",
#ifdef CONFIG_EXTRA_ENV_SETTINGS
    CONFIG_EXTRA_ENV_SETTINGS
#endif
    "\0"
};

2. env_init 함수 (common/env_flash.c)

int env_init(void)
{
    if (crc32(0, env_ptr->data, ENV_SIZE) == env_ptr->crc) {
        gd->env_addr = (ulong)&env_ptr->data;
        gd->env_valid = 1;  // 플래시에서 유효한 환경 변수
        return 0;
    }
    gd->env_addr = (ulong)&default_environment[0];
    gd->env_valid = 0;  // 유효하지 않음 → 기본 값 사용
    return 0;
}

3. env_relocate 함수 (common/env_common.c)

void env_relocate(void)
{
    env_ptr = (env_t *)malloc(CFG_ENV_SIZE);
    DEBUGF("%s[%d] malloced ENV at %p\n", __FUNCTION__, __LINE__, env_ptr);

    if (gd->env_valid == 0) {
        if (sizeof(default_environment) > ENV_SIZE) {
            puts("*** Error - default environment is too large\n\n");
            return;
        }
        memset(env_ptr, 0, sizeof(env_t));
        memcpy(env_ptr->data, default_environment, sizeof(default_environment));
        env_crc_update();  // CRC 재계산
        gd->env_valid = 1;
    } else {
        env_relocate_spec();  // 플래시에서 복사
    }

    gd->env_addr = (ulong)&env_ptr->data;
}

4. env_relocate_spec 함수 (common/env_flash.c)

void env_relocate_spec(void)
{
    memcpy(env_ptr, (void*)flash_addr, CFG_ENV_SIZE);
}

소스 위치와 로드 위치 확인

  • 소스 위치: flash_addr = (env_t *)CFG_ENV_ADDR;0x70000 (NOR 플래시 섹터)
  • 로드 위치: env_ptr = (env_t *)malloc(CFG_ENV_SIZE); → 동적 메모리 할당 (힙 영역)

최종적으로 memcpy(env_ptr, flash_addr, CFG_ENV_SIZE)를 통해 플래시 내용이 메모리로 이동됩니다.

결론

env_init()는 환경 변수의 출처를 결정하며, env_relocate()는 메모리 공간을 확보하고, 유효성 여부에 따라 플래시에서 복사하거나 기본 값을 사용합니다. 이후 gd->env_addr는 실제 사용할 환경 변수 데이터의 시작 주소를 가리킵니다.

태그: U-Boot embedded systems environment variables flash memory crc32

6월 6일 02:07에 게시됨