환경 변수의 역할과 저장 구조
환경 변수는 시스템 부팅 시 사용되는 전역 설정 정보를 의미하며, 영구 저장 장치(예: NOR/NAND 플래시)에 저장되어야 하며, 실행 중에 조회 및 수정이 가능해야 합니다. 부팅 과정에서 먼저 환경 변수를 메모리에 로드한 후, 하드웨어 초기화 및 운영체제 시작에 활용됩니다.
환경 변수 저장 위치와 로드 위치 결정
- 플래시 메모리에 저장된 경우:
CFG_ENV_IS_IN_FLASH또는CFG_ENV_IS_IN_NAND정의 시 해당 플래시 섹터에서 읽어옵니다. - 내장된 환경 변수 (Embedded):
ENV_IS_EMBEDDED가 정의되면 환경 변수가 코드 이미지 내부에 포함되며, 리로케이션 시 함께 메모리에 적재됩니다. 캐릭터 스타트업 시 유효성 검사를 통과하면 별도의 복사 없이 바로 사용 가능합니다. - 저장소 미존재 모드:
CFG_ENV_IS_NOWHERE가 활성화되면 플래시나 다른 저장소에 환경 변수가 없으며, 기본 값(default_environment)을 사용합니다.
초기화 흐름 순서
- 검증 단계: 플래시 메모리에 저장된 환경 변수의 CRC 값을 확인하여 유효성을 판단합니다.
- 리로케이션 단계: 유효한 데이터라면 플래시에서 메모리로 복사하고, 그렇지 않으면 기본값으로 대체합니다.
- 함수 호출 체인:
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는 실제 사용할 환경 변수 데이터의 시작 주소를 가리킵니다.