reserved_mem 분석 노트

2020 2 29 스터디 내용

1. Before you read

Have to read reserved-memory.txt arrow-up-rightcarefully.

1.1 reserved-memory 간단 정

Reserved-memory 노드에 기술된 프로퍼티는 다음과 같다.

Reserved-memory 노드의 property

value

#address-cells, #size-cells (필수 속성)

루트 노드의 값과 동일해야 한다.

ranges (필수 속성)

값은 비어 있어야 한다.(empty)

Reserved-memory의 자식 노드들은 1개 이상의 예약 메모리 영역을 가진다. 예약 메모리 영역은

  1. reg 프로퍼티를 사용하여 예약된 메모리의 특정 범위(base, size)를 지정하거나,

  2. size 프로퍼티를 사용하여 동적으로 예약받을 수 있다. (이 옵션에 더불어 alignment, alloc-ranges 프로퍼티를 같이 사용할 수 있다.)

circle-exclamation
triangle-exclamation

2. Function schematic

┗━start_kernel
  ┗━setup_arch
    ┗━arm64_memblock_init
      ┗━early_init_fdt_scan_reserved_mem  
        ┠━of_scan_flat_dt                 <----------------------------- START
        ┃ ┗━__fdt_scan_reserved_mem       
        ┃   ┠━____reserved_mem_reserve_reg
        ┠   ┗━fdt_reserved_mem_save_node
        ┗━fdt_init_reserved_mem
          ┠━__rmem_check_for_overlap
          ┠━__reserved_mem_alloc_size
          ┗━__reserved_mem_init_node

3. Dive into function

  • Line 24: Reserved memory child node일 경우에 해당 루틴이 실행된다.

  • Line 28: 해당 노드로부터 reg 프로퍼티 값을 읽는다.

    • __reserved_mem_reserve_reg 진입

    • Line 7: 루트로부터 어드레스의 크기, 사이즈의 크기를 넘겨 받는다.

    • Line 13~14: reg 프로퍼티를 읽는다. 만약 프로퍼티가 존재하지 않으면, ENOENT를 리턴한다. reg 프로퍼티가 있다는 말은, 정적 예약 메모리라는 말이고, 프로퍼티가 없다면 동적 예약 메모리이란 말이다. 해당 함수는 정적 예약 메모리만 처리한다.

    • Line 17~21: 프로퍼티의 길이를 검증한다.

    • Line 24: 선택 프로퍼티 no-map이 있는지 확인한다.

    • Line 26~37: base와 size를 읽어오고, nomap 프로퍼티가 존재한다면, 해당 영역을 memblock_remove, 존재하지 않으면 memblock_reserve한다.

    • Line 38~41: 첫 번째의 경우(오류와 상관없이?), fdt_reserved_mem_save_node를 호출한다.

  • Line 29~30: 동적 예약 메모리를 사용하는 노드라면, fdt_reserved_mem_save_node를 호출한다. (단 base, size는 모두 0으로 삽입된다.)

circle-info

fdt_reserved_mem_save_node는 정적/동적 예약 메모리 영역 모두 호출하게 된다. 이 함수는 동적 예약 메모리를 지원하기 위한 패치arrow-up-right에 등장했다.

  • Line 6: 등록된 정적 예약 메모리 영역 중 겹치는 부분이 있다면, 경고를 띄운다.

    • 내부 구현은 간단하다. 정렬을 하고, 순회하면서 겹치는 영역을 찾는다.

  • Line 8~19: 예약 메모리 영역을 순회하면 노드에 핸들 프로퍼티가 있다면, 값을 저장한다.

  • Line 21~22: size가 0이라면, 동적 예약 메모리 영역이므로, 적절한 영역을 할당해주어야 한다. 따라서 __reserved_mem_alloc_size를 호출한다.

    • __reserved_mem_alloc_size로 진입.

    • 동적 예약 메모리 할당의 핵심인 __reserved_mem_alloc_size으로 진입.

    • Line 12~20: size 프로퍼티의 값을 읽는다. 해당 프로퍼티는 필수이므로, 프로퍼티를 못찾으면 바로 리턴한다.

    • Line 22~32: no-map 프로퍼티가 설정되어 있는지 확인, align 프로퍼티가 존재한다면 값을 읽는다.

    • Line 35~42: cma 영역이라면, align을 조정할 필요가 있다, 조정되지 않는다면, cma 셋업에 실패하게 된다. 해당 패치arrow-up-right를 참고하라.

    • Line 46~59: alloc-range 프로퍼티의 값이 존재하면, 그 값을 읽는다.

    • Line 61~69: 읽은 range를 대상으로 memblock_find_in_range을 호출하여 빈 영역을 찾는다. 만약 no-map이라면 해당 영역을 memblock_remove를 하고, 아니라면 memblock_reserve한다.

    • Line 73~77: alloc-range 프로퍼티가 존재하지 않으므로, 모든 영역에 대해서 빈 영역을 찾고, 해당 영역을 memblock_remove/reserve 한다.

    • Line 80~88: 메모리 할당에 실패시 에러 코드를 리턴, 성공시 인자로 들어온 base, size에 할당받은 주소와 사이즈를 대입한다.

  • Line 24~25: 오류가 없다면, __reserved_mem_init_node 함수를 호출한다. 해당 함수는 예약 메모리 드라이버 지원 추가를 위한 패치arrow-up-right에 도입되었다.

    • Line 8: RESERVEDMEM_OF_DECLARE로 추가되는 테이블을 순회하며, 지원하는 노드에 대해 초기화 함수를 실행한다.

<200229_Memblock 발췌>

  • Line 6~10: 각 예약 메모리 영역을 순회하면서, of_flat_dt_is_compatible 함수를 호출해서 compatible이 일치하는지 확인한다. 일치하지 않으면 스킵한다.

  • Line 13~17: initfn 함수를 실행하는데 이 함수는 아래의 열거된 함수와 대응된다.

    • rmem_dma_setup

    • rmem_cma_setup

rmem_cma_setup 함수를 훑어보면

  • Line 9~16: 노드가 reusable하고 no-map이 아닌지 확인한다. 또한 base와 size의 align을 검증한다. 앞서 봤던 복잡한 조건문이 해당 셋업 함수를 위한 것이다.

  • Line 18: cma 테이블에서 정적인 cma struct를 받아 초기화 한다.(내용 추가 필요!)

  • Line 24: fixup 함수를 호출(내용은 비어있다)

  • Line 26~27: linux,cma-default 프로퍼티가 존재한다면(해당 예약 메모리 영역이 cma-default 영역이라면), dma_continguos_set_default함수를 호출한다.

Last updated