[커널 20차] 25주차

2023.10.30 00:24

이민찬 조회 수:120

 

2023.10.28 (25주차) - 약 11명 참여

< __enable_mmu 이어서 진행 >

msr ttbr0_el1, x2 // load TTBR0

load_ttbr1 x1, x1, x3

 

set_sctlr_el1 x0

 

ret

1) 하는 일: ttbr0와 ttbr1 값 설정 

ttbr0_el1 : init_idmap_pg_dir

ttbr1_el1 : reserved_pg_dir

 

reserved_pg_dir은 모두 0으로 채워져있다. 

- 문 C 블로그 -

djvDpr4Q-imjC7cpeDYLpkFXkqPPdlG1OHYuMV7y

 

2) load_ttbr1 

: ttbr1 값을 처리해, ttbr1_el1에 쓴다. 

.macro load_ttbr1, pgtbl, tmp1, tmp2

phys_to_ttbr \tmp1, \pgtbl

offset_ttbr1 \tmp1, \tmp2

msr ttbr1_el1, \tmp1

isb

.endm

phys_to_ttbr 매크로로 PA가 52인 경우 값을 처리.

offset_ttbr1 매크로로 VA_BITS가 52이지만, LVA를 지원하지 않는 경우 offset을 올림.

i1GIq70MHwLyknwCMFdVqDmTN8U71UGFxAFkHqNp

1TLaOTO-BS6MmpE0UEfBS0KuzvVBibWuCbSiDw4v

위 3가지 경우에서 #define pgd_index(a)를 공통적으로 사용할 수 있도록 VA_BITS가 52이지만, LVA not support인 경우에 pgd index를 0x3c0으로 올린다.

 

Q: load_ttbr1에서 offset_ttbr1((2^10 - 2^6) * 8bytes)을 사용하는 이유

A: PGD table에 대해 유저 주소 공간의 경우 52bit와 48bit의 경우 처리된 결과가 동일한데, 커널 주소 공간의 경우 52bit와 48bit의 경우가 달라서, 커널 주소 공간에 맞게 특정 값을 전역적으로 더해주는 것 같음, 유저주소공간은 0부터 시작을 하니깐 예외처리가 필요없는것 같고 커널 가상공간은 0xfff~~ 부터 높은 가상 주소부터 시작할꺼니깐 offset을 올려서 처리해주는 것 같음. 즉, 커널이 52비트이고 아키텍쳐가 48이든 52이든 범용적으로 처리하기 위해 offset 처리를 하는것 같음.

 

2) mmu on

x0: INIT_SCTLR_EL1_MMU_ON

sctlr_el1에 x0 값을 쓴다. mmu를 켠다.

 

< __primary_switch로 돌아와서 kaslr 관련 코드 진행 >

#ifdef CONFIG_RELOCATABLE

adrp x23, KERNEL_START

and x23, x23, MIN_KIMG_ALIGN - 1

#ifdef CONFIG_RANDOMIZE_BASE

mov x0, x22

adrp x1, init_pg_end

mov sp, x1

mov x29, xzr

bl __pi_kaslr_early_init

and x24, x0, #SZ_2M - 1 // capture memstart offset seed

bic x0, x0, #SZ_2M - 1

orr x23, x23, x0 // record kernel offset

#endif

#endif

1) CONFIG_RELOCATABLE

커널 이미지의 위치는 2M align 되어있기 때문에 x23에는 0이 들어간다.

 

2) CONFIG_RANDOMIZE_BASE

x22는 remapped fdt address (in create_idmap)

__pi_kaslr_early_init에서는 kaslr offset을 알아온다.

 

__pi_kaslr_early_init (/arch/arm64/kernel/pi/kaslr.c)

LHZu_jIPCb8RN7VYPvp8eI4Mbqdo1jWe78q5E1tp

is_kaslr_disabled_cmdline(fdt)에서는 kaslr property를 체크한다.

get_kaslr_seed(fdt)에서는 fdt에서 kaslr-seed를 읽어 fdt64_to_cpu()를 해 리턴한다.

seed가 있으면 이 값을 이용해 리턴 값을 만들고, 없으면 rndr을 읽으며 랜덤 시드를 만들어 리턴 값을 만든다.

 

그렇게 랜덤한 offset을 만들어 2M보다 작은 값만 가져와 offset으로 활용한다. 

 

cf) rndr

https://developer.arm.com/documentation/ddi0595/2021-12/AArch64-Registers/RNDR--Random-Number?lang=en

 

Q: RELOCATABLE과 RANDOMIZE_BASE의 관계

A: RELOCATABLE을 설정하려면 RANDOMIZE_BASE가 설정되어있어야 한다. 

https://github.com/torvalds/linux/commit/1e48ef7fcc374051730381a2a05da77eb4eafdb0

 

Q: RELOCATABLE의 의미는 무엇인가요?

A: 커널의 시작 주소가 바뀌게 되면, 혹은 프로그램을 실행할 때 프로그램의 시작 주소가 바뀌게 되면 심볼의 주소 또한 바뀌어야한다. 이런 것을 RELOCATABLE이라고 한다.

 

< clear_page_tables >

SYM_FUNC_START_LOCAL(clear_page_tables)

/*

* Clear the init page tables.

*/

adrp x0, init_pg_dir

adrp x1, init_pg_end

sub x2, x1, x0

mov x1, xzr

b __pi_memset // tail call

SYM_FUNC_END(clear_page_tables)

init_pg_dir부터 init_pg_end까지 0으로 초기화한다.

cf) __pi_memset은 분석하지 않음.

 

< create_kernel_mapping >

SYM_FUNC_START_LOCAL(create_kernel_mapping)

adrp x0, init_pg_dir

mov_q x5, KIMAGE_VADDR // compile time __va(_text)

#ifdef CONFIG_RELOCATABLE

add x5, x5, x23 // add KASLR displacement

#endif

adrp x6, _end // runtime __pa(_end)

adrp x3, _text // runtime __pa(_text)

sub x6, x6, x3 // _end - _text

add x6, x6, x5 // runtime __va(_end)

mov x7, SWAPPER_RW_MMUFLAGS

 

map_memory x0, x1, x5, x6, x7, x3, (VA_BITS - PGDIR_SHIFT), x10, x11, x12, x13, x14

 

dsb ishst // sync with page table walker

ret

SYM_FUNC_END(create_kernel_mapping)

init_pg_dir 테이블의 랜덤 주소 적용된 커널 가상 주소(__va(text) + random offset)에 해당하는 엔트리들에 커널 이미지의 물리 주소 _text ~ _end 까지를 R/W 속성으로 매핑한다.

 

Q: init_pg_dir이 init_idmap_pg_dir에 포함된 영역인가요? 

커널 이미지 안에 있으니까 포함된다. static 영역이라고 생각하면 좋을 듯 하다.

 

< ttbr1_el1 설정 >

adrp x1, init_pg_dir

load_ttbr1 x1, x1, x2

init_pg_dir 주소를 ttbr1으로 설정한다.

SvBxgcODEQZkDtL9YFKUYDxEoRxd1ny4_5WQu1nk


 

< __relocate_kernel >

#ifdef CONFIG_RELOCATABLE

SYM_FUNC_START_LOCAL(__relocate_kernel)

/*

* Iterate over each entry in the relocation table, and apply the

* relocations in place.

*/

adr_l x9, __rela_start

adr_l x10, __rela_end

mov_q x11, KIMAGE_VADDR // default virtual offset

add x11, x11, x23 // actual virtual offset

 

0: cmp x9, x10

b.hs 1f

ldp x12, x13, [x9], #24

ldr x14, [x9, #-8]

cmp w13, #R_AARCH64_RELATIVE

b.ne 0b

add x14, x14, x23 // relocate

str x14, [x12, x23]

b 0b

x12: entry의 offset 값

x13: entry의 info 값

x14: entry의 addend 값

 

offset 값 + kaslr_offset 주소에 addend+kaslr_offset 값을 저장한다. (relocate)

__rela_start와 __rela_end 사이의 영역에 있는 심볼에 대해 재배치를 한다. 

 

리로케이션 엔트리 구조

j01fx6AaL7s2mBQH5lvuHlPnmjJWaPtu7veVr5GI

이 때, Elf64_Sxword r_addend는 signed 64bit 이다.

 

relocation entry를 확인한 결과 

210zDsC64t461_qkmQey9GaFyUWXzepe8Cvxstz7

relocation table의 0번째 엔트리의 offset

BbPsCoe4u95gvyL3JeDlnTxG8Wg-SWRa2703ktuW

Relocation entry의 0번째 엔트리의 addend는 함수 심볼 값

TuW2Agfld5fEM4Top9Ytj-Vy2fcCKPkdxKcSRL4Q

 

http://jake.dothome.co.kr/a64-elf-relocations/

번호 제목 글쓴이 날짜 조회 수
공지 [공지] 스터디 정리 노트 공간입니다. woos 2016.05.14 626
248 [커널 19차] 103 주차 Min 2024.04.28 4
247 [커널 20차] 48주차 무한질주 2024.04.25 22
246 [커널 19차] 102 주차 Min 2024.04.20 37
245 [커널 19차] 101 주차 Min 2024.04.13 63
244 [커널 19차] 100 주차 Min 2024.04.13 16
243 [커널 19차] 99 주차 Min 2024.03.30 82
242 [커널 19차] 98 주차 Min 2024.03.23 55
241 [커널 19차] 97 주차 Min 2024.03.16 50
240 [커널 19차] 96 주차 Min 2024.03.14 32
239 [커널 19차] 95 주차 [2] Min 2024.03.03 111
238 [커널 20차] 32주차 brw 2023.12.16 386
237 [커널 20차] 29주차 brw 2023.11.27 161
236 [커널 20차] 27주차 brw 2023.11.21 86
235 [커널 20차] 26주차 brw 2023.11.21 48
234 [커널 20차] 28주차 이민찬 2023.11.19 64
» [커널 20차] 25주차 이민찬 2023.10.30 120
232 [커널 20차] 24주차 이민찬 2023.10.22 743
231 [커널 20차] 23주차 이민찬 2023.10.14 81
230 [커널 20차] 22주차 이민찬 2023.10.08 76
229 [커널 20차] 21주차 이민찬 2023.09.23 116
XE Login