[커널 17차] 29주차

2021.03.26 00:33

ㅇㅇㅇ 조회 수:103

arm64_memblock_init() 분석 계속 진행

 

- linear region size를 CPU에서 지원하는 가상 주소의 절반으로 설정 (48 VA bit면 128TB)
- fdt_enforce_memory_region() 호출하여 FDT에서 정해준 영역외의 memblock을 모두 제거한다

 

 

fdt_enforce_memory_region()
- 일단 size 0 짜리 memblock_region을 하나 만든다
- FDT를 스캔해서 "linux,usable-memory-range" property를 찾는다
+-- FDT loop(FDT 노드 loop)로 early_init_dt_scan_usablemem() 호출한다
(여기서부터 early_init_dt_scan_usablemem 내용)
+-- depth가 1이고 name이 "chosen"인 노드가 아니면 다시 loop
+-- depth 1 "chosen" 노드에 해당 property가 없으면 그냥 리턴하고 loop break
+-- property를 찾으면 region->base, region->size에 property data를 기록한다
+-- 이후 리턴하고 loop break
- memblock_cap_memory_range()에서 FDT에서 표시한 usable memory range 외의 memblock 영역을 모두 제거한다

 


- 지원되는 최대 물리주소 위의 범위를 memblock에서 제거한다
+-- ARM64에서 지원되는 물리주소 이상의 범위
- memstart_addr에 가장 낮은 물리주소를 align하여 저장 (1GB align)
+-- 여기서 가장 낮은 물리주소는 FDT에서 읽은 값임
- PHYS_OFFSET는 memstart_addr와 같다
- http://jake.dothome.co.kr/fixmap/의 커널 VA 영역 변경(new) 그림 참조
- physvirt_offset은 물리주소 base - kernel 가상 주소 base로 정의
- 그림에서 VMEMMAP_END 위에 2MB 공간이 있어야 됨
- vmemmap : 물리주소를 넣으면 page struct가 나오는 변환용 변수
+-- 예를 들어 물리주소 base가 0x8000...0000이면 vmemmap + (0x8000...0000 >> PAGE_SHIFT)는 VMEMMAP_START를 나타내고 여기에 첫 번째 물리주소에 대한 page 구조체가 있다

+-- VMEMMAP_START = vmemmap[memstart_addr >> PAGE_SHIFT];

 

5.9 kernel에 버그가 있어서 아래와 같이 바뀌었음
- https://github.com/torvalds/linux/commit/7bc1a0f9e1765830e945669c99c59c35cf9bca82
- vmemmap / __phys_to_virt / __lm_to_phys가 다 매크로로 바뀌어서 memstart_addr가 바뀌면 알아서 자동으로 바뀌게 되어 있음
- memstart_addr가 바뀌면 PHYS_OFFSET가 바뀌고 그러면 위 매크로로 자동으로 바뀜


- kernel이 memstart_addr + linear_region_size보다 위에 있으면 kernel 위 부분을 memblock에서 제거
- 이후 kernel image end에서 아래 쪽으로 linear_region_size 만큼 아래 부분을 memstart_addr로 지정하고 그 아래는 memblock에서 제거
- 왜냐면 linear_region_size 만큼만 물리주소 접근가능할 것이기 때문 (memblock 제한)
- 즉 memstart_addr부터 _end까지만 memblock으로 관리하고 나머지는 버림


- parse_early_param()에서 FDT가 mem_limit이 setting되어 있으면 (parameter "mem")
- arch/arm64/mm/init.c의 early_mem() 함수에서 memory_limit을 지정함
- 0부터 mem_limit 사이를 모두 날리고 커널 부분을 다시 add

 

 

Ramdisk
- 부트로더가 initrd를 만들어서 커널에게 넘겨준다
- 커널이 initrd를 이용해서 여러 하드웨어 및 모듈을 setup한다
- 부트로더가 FDT를 메모리에 올려줄 때 initrd도 같이 추가해서 올려 줄 것이다

 

CONFIG_BLK_DEV_INITRD가 enable된 경우
- setup_fdt에서 처리했던 phys_initrd_start와 phys_initrd_size를 사용함
- 위에서 init ramdisk 영역을 날려버렸을 수도 있기 때문에 ramdisk 영역을 memblock에서 지우고 다시 추가한 뒤 reserve하는 작업 수행 (memblock flag clear)
- FDT setup할 때 hotplug flag 영역에 flag를 설정한 적이 있다
- 만약 linear mapping 영역 안에 initrd가 안들어오면 부트로더가 이상한 것이다 (경고 띄움)

 

CONFIG_RANDOMIZE_BASE가 enable된 경우
- kaslr_early_init()에서 memstart_offset_seed를 FDT seed를 이용해서 설정했었음
- 주어진 물리 메모리 크기보다 linear mapping 가상 주소 영역이 충분히 크면 (1GB 마진) memstart_addr를 memstart_offset_seed를 이용해서 randomize한다
- PAGE_OFFSET에서 randomize된 offset 만큼 더한 가상 주소 지점이 물리메모리 처음 주소가 대응되기를 원함
- 그래서 최대 움직일수 있는 범위(range)를 계산하고 이를 seed를 이용해서 약간 줄여서 대응시킨다

 

이후 커널 영역을 memblock reserve한다

 

CONFIG_BLK_DEV_INITRD가 enable된 경우
- initrd_start를 phys_initrd_start에 해당하는 가상주소로 세팅
- initrd_end를 initrd_start + phys_initrd_size로 세팅

 

==========================================

 

오후 시간 : PCIe 스펙 스터디

- 폼팩터와 PCI legacy에 대한 내용이 많아서 필요한 부분과 거리가 있음. 차주 어떻게 진행할지 재논의 필요함

XE Login