안녕하세요 ___reserved_mem_reserve_reg을 분석하다 이해가 안되는 부분이 있어서 질문을 올리게 되었습니다.
static int __init __reserved_mem_reserve_reg(unsigned long node, const char *uname) { int t_len = (dt_root_addr_cells + dt_root_size_cells) * sizeof(__be32); phys_addr_t base, size; int len; const __be32 *prop; int nomap, first = 1; prop = of_get_flat_dt_prop(node, "reg", &len); if (!prop) return -ENOENT; if (len && len % t_len != 0) { pr_err("Reserved memory: invalid reg property in '%s', skipping node.\n", uname); return -EINVAL; } nomap = of_get_flat_dt_prop(node, "no-map", NULL) != NULL; while (len >= t_len) { base = dt_mem_next_cell(dt_root_addr_cells, &prop); size = dt_mem_next_cell(dt_root_size_cells, &prop); if (size && early_init_dt_reserve_memory_arch(base, size, nomap) == 0) pr_debug("Reserved memory: reserved region for node '%s': base %pa, size %ld MiB\n", uname, &base, (unsigned long)size / SZ_1M); else pr_info("Reserved memory: failed to reserve memory for node '%s': base %pa, size %ld MiB\n", uname, &base, (unsigned long)size / SZ_1M); len -= t_len; if (first) { fdt_reserved_mem_save_node(node, uname, base, size); first = 0; } } return 0; }
코드 중, while문 내에서 reg 프로퍼티에서 예약 메모리의 base와 size을 읽고, 해당 영역을 reserve 또는 remove를 합니다.
또한 처음 한 번만(한 노드에 대해서만 한 영역만?), reserved_mem 테이블에 예약 메모리 영역을 추가하는 것으로 보입니다.
여기서 이해가 안되는 부분은, 앞서 호출한 early_init_dt_reserve_memory_arch의 성공 유무에 상관없이 항상 첫번째 예약 메모리 영역을 fdt_reserved_mem_save_node 함수를 통해 reserved_mem 테이블에 넣는다는 부분입니다.
제가 생각하기에는, 최소한 memblock_reserve/remove에 성공해야 테이블에 추가되어야 할 것 같은데, 그렇지 않아서 이해에 어려움을 겪고 있습니다.
댓글 4
-
문c(문영일)
2020.03.09 22:30
-
DEWH
2020.03.11 12:29
안녕하세요, 답변해주셔서 감사합니다.
설명해주신 대로,
rmem-> size가 0이라면 동적 예약 메모리 영역이라 간주하여, 노드의 size,alignment,alloc-ranges 프로퍼티들을 읽고
할당하는 부분을 확인하였습니다.
제가 보기에도 노드가 아래 예시처럼 구성되는 것은 이상해 보이긴 합니다.
node {
reg = < address , 0 >
size = < size >
}
이것 외에도, 제가 이상하다고 생각하는 부분을 다시 말하자면,
early_init_dt_reserve_memory_arch을 통해 해당 예약 메모리 영역을
reseve/remove를 하는데 실패하더라도(예를 들어, region이 너무 많아서)
reserved_mem 테이블에 추가되어, 초기화 함수가 실행됩니다.
만약 cma 영역이라면, rmem_cma_setup함수를 통해 cma 구조체가 초기화되겠지요.
제가 생각하기에 발생할 수 있는 문제는 remove/reseved되지 않은 영역에 대해,
cma 구조체가 생성될 수 있다는 것입니다.
항상 early_init_dt_reserve_memory_arch는 성공한다고 가정하는 것 일까요?
-
문c(문영일)
2020.03.11 20:05
네. 생각하신 대로 이상해보이고,
early_init_dt_reserve_memory_arch()가 실패할 확률이 없다고 판단하는 것 같습니다.
몇 번의 잘못된 상황이 주어지면 reserve 되지 않은 영역에 cma가 생길 수도 있겠습니다.
어쨋든 코딩이 조금 이상합니다.
-
ybgwon
2020.03.12 23:15
안녕하세요
fdt_reserved_mem_save_node 에서 사용하는 reserved_mem 구조체 배열과
RESERVEDMEM_OF_DECLARE(cma, "shared-dma-pool", rmem_cma_setup)매크로로 등록되는
__reservedmem_of_table 구조체 배열이 다릅니다. rmem_cma_setup 함수는 RESERVEDMEM_OF_DECLARE 매크로를
이용하여 __reservedmem_of_table 섹션에 등록된 of_device_id 구조체 에만 루프를 돌며 해당함수(rmem_cma_setup)가
호출됩니다. fdt_reserved_mem_save_node 는 단지 노드명이나 base, size 등의 정보만을 저장하는것으로 보여지는 데 저는
first flag 를 이용하여 왜 한번만 저장하는 지가 의문입니다. node, uname 은 한번 저장해도 되지만 base, size 는 다른 값이 더 있기에 루프를 한번 더 도는데 그럼 나중것은 저장할 필요가 없는지 의문입니다.
.
안녕하세요? 저도 이 곳이 이상해서 조금 살펴보았습니다.
디바이스 트리에서 reserved-mem 노드를 작성할 때 reg 속성에 시작 주소와 사이즈를
명기하는데, reg 속성이 없는 경우 size 속성을 읽어 reserve 할 수 있습니다.
참고로 secure 영역이나, SRAM을 사용하는 고속 DMA용 전용 버퍼 등을 reserve 하는 경우
해당 영역의 시작 주소 및 사이즈를 가집니다. 그러나 시스템 DRAM을 사용하여
DMA를 사용해야 하는 디바이스가 주소 limitiation이 없는 경우 시작 주소를 명기하지 않고,
DMA 버퍼로 사용할 사이즈만을 필요로 합니다.
문제되는 함수의 코딩을 살펴보면, reg 속성에서 사이즈가 0으로 기재되는 경우도 허용하는 것으로 보입니다.
(실제 디바이스 트리에서 그렇게 지정한 사례는 보이지 않습니다)
어쨋든, 추후 fdt_init_reserved_mem() 함수의 다음 코딩과 같이 사이즈가 0인 경우 size 속성을 찾아 등록합니다.
if (rmem->size == 0)
err = __reserved_mem_alloc_size(node, rmem->name,
&rmem->base, &rmem->size);
결국 fallback 루틴을 적용하였는데, 별로 중요하지는 않은 것 같습니다.