[커널 17차] 39주차

2021.05.29 23:36

ㅇㅇㅇ 조회 수:183

paging_init() 계속
- fixmap으로 임시 할당받은 pgdp 가상주소를 해제
- cpu_replace_ttbr1() 함수로 ttbr1 register값을 swapper_pg_dir의 물리주소로 바꾼다
- init_mm.pgd를 swapper_pg_dir로 변경한다
- init_pg_dir의 물리주소 영역을 memblock에서 제거한다 (총 5개 page)
- head.S에서 총 3개의 level로 init_pg_dir을 매핑했음
- 매핑 테이블의 용량은 총 5개 page이고 이는 kaslr에 의한 것임
- 커널 이미지 가상 주소가 랜덤하기 때문에 pgd entry가 512GB boundary를 넘어가 2개가 될 수 있음
- 따라서 pgd 1개, pud 2개, pmd 2개 최대 5개 page가 필요하다
- 최선의 경우엔 pgd/pud/pmd 1개 씩 3개만 있어도 됨
- pud entry가 1GB boundary에서 나누어지는 경우엔 4개가 필요함 (pgd 1, pud 1, pmd 2)
- 이렇게 하면 커널 이미지 매핑 첫 블록과 마지막 블록에는 커널 이미지가 아닌 영역이 매핑되어 있으나 나중에 paging_init()에서 정식으로 swapper_pg_dir을 만들 때 새로 매핑하여 문제가 해결되므로 그 전까지 임시로 블록 매핑 사용함
- memblock_can_resize = 1
- linear mapping이 enable되기 전에는 memblock resize를 금지했었고 paging_init() 이후에 풀어 준다
- http://patches.linaro.org/patch/150391/

 

Common Not Private
- ASID/VMID를 모든 CPU core가 공유하도록 설정하는 TTBR의 비트
- 1로 설정하면 해당 TTBR TLB entry의 ASID/VMID는 모든 CPU가 동일한 의미로 사용함
- https://developer.arm.com/documentation/101811/0101/Address-spaces-in-AArch64
- https://patchwork.kernel.org/project/linux-arm-kernel/patch/1507724395-13735-2-git-send-email-vladimir.murzin@arm.com/


- ARM ARM : Use of ASIDs and VMIDs to reduce TLB maintenance requirements

- For a given TTBR_ELx, if the value of TTBR_ELx.CnP is 1 on multiple PEs in the same Inner Shareable domain, and those PEs meet the other conditions for sharing translation table entries as defined in this section, but those TTBR_ELxs do not point to the same translation table entries, then the system is misconfigured, and performing an address translation using that TTBR_ELx:
• Might generate multiple hits in the TLB, and as a result generate an exception that is reported using the TLB conflict fault code, see TLB conflict aborts on page D5-2791.
• Otherwise, has a CONSTRAINED UNPREDICTABLE result, as described in CONSTRAINED UNPREDICTABLE behaviors due to caching of control or data values on page K1-8247.

 

- For all PEs that are sharing translation table entries for a stage of translation, all system registers bits that apply to that stage of translation and that are described as being permitted to be cached in a TLB must be the same for all the PEs that are sharing the translation table entry. If this condition is not met by software then it is CONSTRAINED UNPREDICTABLE whether or not the value of such a control bit that has a different value between PEs, interpreted by a PE, called PE1 here, takes the value configured for:
• The system register bit of PE1.
• The system register bit of one of the PEs that is sharing the translation table entry.

 

- CNP = 1이면 inner shearable 공유하는 PE들은 TTBR0 값도 같아야 함
- Translation에 관련하고 TLB에 caching되는 system register bit도 같아야 한다 (ASID 포함)

- 현재는 CNP 켜지 않고 나중에 동작시킨다
- https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=5ffdfaedfa0aba3f5db0fbb8ed4f3192be2b39b8


cpu_replace_ttbr1()
- cpu_install_idmap()로 idmap을 ttbr0로 매핑한다
- idmap_cpu_replace_ttbr1() 함수로 ttbr1을 swapper_pg_dir 물리주소로 변경한다
- 이 때 idmap_cpu_replace_ttbr1() 함수는 물리주소로 변경하여 호출한다
- 이는 ttbr0 매핑을 사용한 상태에서 ttbr1을 변경하기 위함이다
- cpu_uninstall_idmap()로 idmap을 unmap한다

 

cpu_install_idmap()
- cpu_set_reserved_ttbr0
- TBL flush 수행
- cpu_set_idmap_tcr_t0sz()
- cpu_switch_mm() 수행하여 ttbr0를 idmap_pg_dir로 바꿈

 

cpu_set_reserved_ttbr0
- ttbr0_el1을 0으로 setting하고 isb() 수행

 

write_sysreg()
- immedate 값이 0인 경우 zero register를 이용하여 temporal register 사용을 아낌

 

cpu_set_idmap_tcr_t0sz()
- 전역 변수 t0sz를 이용하여 tcr_el1 레지스터를 세팅하고 배리어를 수행한다
- tcr_el1 비트 중에 t0sz 값만 변화한다
- 전역 변수 t0sz를 사용하므로 tcr_el1의 t0sz를 디폴트 값으로 바꾸는 것임
- 대부분의 경우 디폴트 값과 같으므로 실제로 레지스터 세팅은 거의 일어나지 않는다

 

cpu_switch_mm()
- pgd가 swapper_pg_dir이면 버그
- cpu_set_reserved_ttbr0로 ttbr0를 0으로 세팅
- cpu_do_switch_mm() 수행하여 ttbr0/ttbr1을 업데이트 한다

 

cpu_do_switch_mm(pgd_phys, mm)
- ttbr1_el1에 설정된 asid를 mm의 asid로 바꾼다
- ttbr0_el1을 pgd_phys로 바꾸고 asid도 mm의 asid로 바꾼다
- 추가로 ttbr0_el1에 CNP bit도 지원되면 설정한다
- 결론적으로 user task의 교체를 위해 ttbr0의 매핑을 바꾸는 함수인듯

 

PAN (priviledged access never)
- https://developer.arm.com/documentation/102376/0100/Permissions-attributes

 

idmap_cpu_replace_ttbr1()
- daif를 모두 mask하고 x2에 원본 daif값을 저장한다
- __idmap_cpu_set_reserved_ttbr1 매크로로 ttbr1을 0으로 만든다
- ttbr1_el1에 x0을 쓴다
- isb 배리어 수행하고 x2로 원본 daif를 복구하고 리턴한다
- 이 함수는 반드시 ttbr0으로 매핑된 상태에서 호출해야 한다
- 따라서 이 함수의 물리주소로 호출해야 한다

 

cpu_uninstall_idmap()
- ttbr0를 0으로 바꿔서 unmap한다
- tlb flush를 수행하고 디폴트 t0sz로 tcr을 세팅한다
- mm이 init_mm이 아니거나 ttbr0가 PAN을 쓰는게 아니면 cpu_switch_mm()를 호출해서 ttbr0와 ttbr1의 asid를 변경시키고 ttbr0를 현재 task의 mm->pgd로 변경한다

 

TTBR zeroing하고 변경하는 이유
- https://github.com/torvalds/linux/commit/50e1881ddde2a986c7d0d2150985239e5e3d7d96#diff-06e4e0038f65519bf8ab7562398c81be

 

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

 

per-cpu
- http://jake.dothome.co.kr/per-cpu/
- 통계 카운터의 경우 0으로 시작해서 임계값이 넘어가면 글로벌 값에 반영하고 다시 0에서 시작

XE Login