early_fixmap_init 코드 분석
gdb에서 변수 확인 및 분석을 튜닝 진행함
Fixmap 영역은 컴파일 타임에 가상 주소공간이 이미 결정된 매핑 메모리 영역이다.
가상 주소와 물리 주소가 fix 되어 있어 두 주소간의 변환 방식이 MMU를 활용해서 변환 하기 보다는
Kimage_offset 을 사용하여 변환하고 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
|
__attribute__((optimize("-O0"))) void __init early_fixmap_init(void)
{
pgd_t *pgdp, pgd;
pud_t *pudp, *dbg_pudp;
pmd_t *pmdp;
unsigned int dbg_x1;
u64 dbg_x2;
unsigned long addr = FIXADDR_START; //addr = FIXADDR_START = 0xffff7dfffe7f9000
pgdp = pgd_offset_k(addr); // init_pg_dir + index(addr) = 0xffff00001147b000 + (0xfb*8byte) = 0xffff00001147b7d8
pgd = READ_ONCE(*pgdp); // pgd = 0x0
dbg_x1 = pgd_page_paddr(pgd); // 0
dbg_x1 = __pa_symbol(bm_pud); // 0x4140e000
dbg_x1 = __pa_symbol(bm_pmd); // 0x4140d000
dbg_x1 = __pa_symbol(bm_pte); // 0x4140c000
dbg_x1 = PMD_TYPE_TABLE; // 0x03
dbg_x1 = PUD_TYPE_TABLE; // 0x03
__pgd_populate(pgdp, __pa_symbol(bm_pud), 0x00); // *pgdp = 0x4140e000
__pgd_populate(pgdp, __pa_symbol(bm_pud), 0x01); // *pgdp = 0x4140e001
/* __pgd_populate 후 *pgdp 값은 전부 물리주소가 아닌 디스크립터로 사용 된다.
* http://jake.dothome.co.kr/pt64/ 링크에 디스크립터 포맷을 참고 하면 마지막 0x03 을 or 연산 하는지 확인 가능
*/
/* 이 시점에 pgd= READ_ONCE(*pgdp)를 호출 하는 순간 위에 populate로 *pgdp에 값이 들어 가있기 때문에
* pgd 는 0이 아닌 값이 들어가 있고 pgd_none(pgd)는 0 이 되므로 아래 if(pgd_none(pgd))조건을 만족하지 못하게 된다.
*/
dbg_pudp = pud_offset_kimg(pgdp, addr); //0xffff00001140eff8
/* analyze to pud_offset_kimg in function */
dbg_x2 = kimage_voffset; //kimage_voffset = 0xfffeffffd0000000
dbg_x1 = pgd_page_paddr(READ_ONCE(*(pgdp))); //0x4140e000
dbg_x1 = pud_index(addr); //0x1ff
dbg_x1 = pud_offset_phys(pgdp, addr); //0x4140 + 0x1ff(8byte) = 0x4140eff8
dbg_x1 = __phys_to_kimg(dbg_x1); //kimage_voffset(0xfffeffffd0000000) + pud_offset_phys (0x4140eff8) = 0xffff00001140eff8
/* __phys_to_kimg function return is unsigned long.
* so dbg_x1 value is 0xffff00001140eff8 -> 0x1140eff8
* 실제 __phys_to_kimg는 kimage_voffset(가상주소와 물리주소의 offset) 값을 물리주소에 더하여 os에 사용할 가상 주소의 값을 구한다.
* end to analyze */
if (CONFIG_PGTABLE_LEVELS > 3 && // CONFIG_PGTABLE_LEVELS = 4
!(pgd_none(pgd) || pgd_page_paddr(pgd) == __pa_symbol(bm_pud))) {
//pgd_page_paddr = pgd page start address //_pa_symbol(bm_pud) = bm_pud phy address
/*
* We only end up here if the kernel mapping and the fixmap
* share the top level pgd entry, which should only happen on
* 16k/4 levels configurations.
*/
BUG_ON(!IS_ENABLED(CONFIG_ARM64_16K_PAGES)); //pgd_page_apddr 값과 bm_pud 값이 일치 하지 않으면 error 이므로 bug_on 를 실행.
pudp = pud_offset_kimg(pgdp, addr); // 다시 pgd -> pud 로 mapping 한다.
} else {
if (pgd_none(pgd)) // pgd is none. so pgd_none = 0x1 (original source code에는 0이지만 debug code로 인해 값이 있다 하지만 read_once 호출 한 시점에는 없으므로 상관 없다.)
__pgd_populate(pgdp, __pa_symbol(bm_pud), PUD_TYPE_TABLE); //*pgdp = 0x4140e003
pudp = fixmap_pud(addr); // pudp = 0xffff00001140eff8, *pudp = 0x0
dbg_x1 = pud_none(READ_ONCE(*pudp));
}
if (pud_none(READ_ONCE(*pudp))) // pudp is none. so pud_none = 0x1
__pud_populate(pudp, __pa_symbol(bm_pmd), PMD_TYPE_TABLE); //*pudp = 0x4140d003
pmdp = fixmap_pmd(addr); // pmdp = 0xffff00001140df98 , *pmdp = 0x0 fixmap_pmd를 따라가 보면 __phys_to_kimg을 return하여 가상주소를 구한다.
__pmd_populate(pmdp, __pa_symbol(bm_pte), PMD_TYPE_TABLE); // *pmdp = 0x4140c003
/*
* The boot-ioremap range spans multiple pmds, for which
* we are not prepared:
*/
BUILD_BUG_ON((__fix_to_virt(FIX_BTMAP_BEGIN) >> PMD_SHIFT)
!= (__fix_to_virt(FIX_BTMAP_END) >> PMD_SHIFT));
if ((pmdp != fixmap_pmd(fix_to_virt(FIX_BTMAP_BEGIN)))
|| pmdp != fixmap_pmd(fix_to_virt(FIX_BTMAP_END))) {
WARN_ON(1);
pr_warn("pmdp %p != %p, %p\n",
pmdp, fixmap_pmd(fix_to_virt(FIX_BTMAP_BEGIN)),
fixmap_pmd(fix_to_virt(FIX_BTMAP_END)));
pr_warn("fix_to_virt(FIX_BTMAP_BEGIN): %08lx\n",
fix_to_virt(FIX_BTMAP_BEGIN));
pr_warn("fix_to_virt(FIX_BTMAP_END): %08lx\n",
fix_to_virt(FIX_BTMAP_END));
pr_warn("FIX_BTMAP_END: %d\n", FIX_BTMAP_END);
pr_warn("FIX_BTMAP_BEGIN: %d\n", FIX_BTMAP_BEGIN);
}
}
|
cs |
실제 함수에서 동작 흐름을 나타낸 그림이다(문c 블로그의 그림을 참조 함)
각 table 별로 populate 할 시 0x4140e000 이 아닌 0x4140e003 으로 매핑 되는데 그 이유는 아래와 같다.
참고: http://jake.dothome.co.kr/fixmap/
참고:http://jake.dothome.co.kr/pt64/(page entery fomat)
'Linux > ARM64' 카테고리의 다른 글
arch_local_irq_disable() (0) | 2019.12.27 |
---|---|
boot_cpu_init() (0) | 2019.12.27 |
smp_setup_processor_id() (0) | 2019.12.27 |
early_ioremap_init(void) (0) | 2019.12.24 |