본문 바로가기

Linux/ARM64

early_fixmap_init(void)

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/

 

Fixmap

Fixmap 주요 용도 고정 매핑 영역(이하 fixmap 영역)은 컴파일 타임에 가상 주소가 결정(fix)되는 공간이다. 따라서 주로 매핑 서브시스템(vmap 등)이 활성화되기 전에 매핑이 필요할 때 fixmap을 사용한다. 예를 들어, 콘솔 디바이스를 정식 초기화하기 전에 우선 사용하기 위해 이 공간에 임시 매핑한다. 런타임 시에도 커널 코드를 변경하거나 페이지 테이블의 갱신이 필요할 때 등의 용도로 사용한다.…

jake.dothome.co.kr

참고: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