U-Boot 내장 환경 변수 구현 및 적용 실험

내장 환경 변수의 목적

CFG_ENV_IS_IN_FLASH 또는 CFG_ENV_IS_IN_NAND가 정의된 경우에만 ENV_IS_EMBEDDED 기능이 활성화됩니다. 본 실험에서는 NOR 플래시를 기준으로 설명합니다. U-Boot 바이너리(100KB+)와 환경 변수 저장에 필요한 섹터 크기 간 차이에서 발생하는 문제를 해결합니다. 일반적으로 플래시 전반부에는 8KB 섹터가 존재하나 후반부는 64KB 섹터로 구성됩니다. ENV_IS_EMBEDDED 미사용 시 환경 변수 영역이 코드 영역 뒤에 배치되어 64KB를 강제로 점유하게 되며, 이는 플래시와 RAM 공간 낭비로 이어집니다.

내장 환경 변수 기능 적용 시 환경 변수 영역을 코드 섹션 내(예: 8KB 섹터)에 임베딩하여 공간 효율성을 높입니다. 또한 재배치 시 환경 변수가 코드와 함께 RAM에 자동 복사되어 초기화 과정에서 별도의 메모리 할당 및 복사 작업이 불필요해집니다.

구현 메커니즘 분석

1. 조건부 매크로 정의

#if defined(CONFIG_ENV_IN_FLASH)
  #if (CONFIG_ENV_ADDR >= CONFIG_MONITOR_BASE) && \
      (CONFIG_ENV_ADDR + CONFIG_ENV_SIZE <= \
       CONFIG_MONITOR_BASE + CONFIG_MONITOR_LEN)
    #define ENV_IS_EMBEDDED 1
  #endif
#endif

2. 환경 변수 구조체 강제 배치

#if defined(ENV_IS_EMBEDDED)
  #define __SECTION_TEXT __attribute__((section(".text")))
  
  typedef struct {
    uint32_t crc;
    uint8_t flags;
    char data[CONFIG_ENV_SIZE];
  } env_block;
  
  env_block environment __SECTION_TEXT = {
    ENV_CRC,
    #ifdef CONFIG_REDUNDANT_ENV
    1,
    #endif
    {
      #ifdef CONFIG_BOOTARGS
      "bootargs=" CONFIG_BOOTARGS "\0"
      #endif
      "\0"
    }
  };
#endif

3. 환경 변수 포인터 초기화

#ifdef ENV_IS_EMBEDDED
  extern uint8_t environment[];
  env_block *env_ptr = (env_block *)&environment[0];
#else
  env_block *env_ptr = (env_block *)CONFIG_ENV_ADDR;
#endif

4. 환경 변수 유효성 검증

int env_init() {
  if (crc32(0, env_ptr->data, ENV_SIZE) == env_ptr->crc) {
    global_data->env_addr = (uint32_t)&env_ptr->data;
    global_data->env_valid = 1;
    return 0;
  }
  global_data->env_addr = (uint32_t)default_env;
  global_data->env_valid = 0;
  return 0;
}

실험 및 결과

1. 플래시 메모리 설정

#define CONFIG_ENV_IN_FLASH  1
#define CONFIG_ENV_SIZE      0x2000
#define CONFIG_ENV_ADDR      0x00004000
#define CONFIG_MONITOR_BASE  CONFIG_ENV_ADDR
#define CONFIG_MONITOR_LEN   0x200000

2. 링커 스크립트 수정

.text : {
  cpu/arm920t/start.o(.text)
  . = ENV_OFFSET;
  common/environment.o(.text)
  *(.text)
}

3. 환경 변수 크기 변수 제거

/* common/environment.c 수정 */
// unsigned long env_size __SECTION_TEXT = sizeof(env_block); 주석 처리

실험 결과

  • 초기 실행: 환경 변수가 0x33F84000 주소에 성공적으로 로드
  • 환경 변수 저장: 두 번째 섹터(0x4000)에 정상 저장
  • 재시작: 저장된 환경 변수 CRC 검증 성공 및 정상 부팅

미해결 의문점

  1. 데이터 세그먼트 변수를 텍스트 세그먼트에 배치하는 메커니즘
  2. 컴파일 타임 환경 변수 CRC 생성 과정
  3. 특정 주소(0x33F84000)에 변수를 배치하는 링커 동작 원리

태그: U-Boot EmbeddedLinux FlashMemory Bootloader EnvironmentVariables

6월 17일 20:24에 게시됨