arm/kernel/head.S (2) – proc_info_list 구조체의 값은 누가 언제 채웠는가?

Makefile 을 보면 processor 관련 config 에 따라 arch/arm/mm 에서 build 하는 파일이 다릅니다.
우리 분석 환경의 .config 에는 다음과 같이 설정되어 있습니다.

CONFIG_CPU_V7=y

CONFIG_CPU_32v6K=y
CONFIG_CPU_32v7=y
CONFIG_CPU_ABRT_EV7=y
CONFIG_CPU_PABRT_V7=y
CONFIG_CPU_CACHE_V7=y
CONFIG_CPU_CACHE_VIPT=y
CONFIG_CPU_COPY_V6=y
CONFIG_CPU_TLB_V7=y
CONFIG_CPU_HAS_ASID=y
CONFIG_CPU_CP15=y
CONFIG_CPU_CP15_MMU=y

그렇다면 우리는 아래와 같은 파일들이 object 로 빌드될 것입니다.

obj-$(CONFIG_CPU_ABRT_EV7)  += abort-ev7.o
...
obj-$(CONFIG_CPU_CACHE_V7)  += cache-v7.o
...
obj-$(CONFIG_CPU_V7)        += proc-v7.o

실제로 build 된 object list 를 보니 위의 파일들이 build 되었네요. (물론 mm 디렉토리에는 다른 파일들도 있습니다.)

-rw-rw-r-- 1 dplee dplee    1448  6월 22 21:29 abort-ev7.o
-rw-rw-r-- 1 dplee dplee   99460  6월 22 21:29 alignment.o
-rw-rw-r-- 1 dplee dplee 1264791  6월 22 21:29 built-in.o
-rw-rw-r-- 1 dplee dplee    4344  6월 22 21:29 cache-v7.o
-rw-rw-r-- 1 dplee dplee   46084  6월 22 21:29 context.o
-rw-rw-r-- 1 dplee dplee   58420  6월 22 21:29 copypage-v6.o
-rw-rw-r-- 1 dplee dplee  148936  6월 22 21:29 dma-mapping.o
-rw-rw-r-- 1 dplee dplee    8292  6월 22 21:29 extable.o
-rw-rw-r-- 1 dplee dplee   64516  6월 22 21:29 fault-armv.o
-rw-rw-r-- 1 dplee dplee   96504  6월 22 21:29 fault.o
-rw-rw-r-- 1 dplee dplee   86744  6월 22 21:29 flush.o
-rw-rw-r-- 1 dplee dplee   82936  6월 22 21:29 highmem.o
-rw-rw-r-- 1 dplee dplee   73764  6월 22 21:29 idmap.o
-rw-rw-r-- 1 dplee dplee  111312  6월 22 21:29 init.o
-rw-rw-r-- 1 dplee dplee   52496  6월 22 21:29 iomap.o
-rw-rw-r-- 1 dplee dplee   80016  6월 22 21:29 ioremap.o
-rw-rw-r-- 1 dplee dplee   63636  6월 22 21:29 mmap.o
-rw-rw-r-- 1 dplee dplee  117880  6월 22 21:29 mmu.o
-rw-rw-r-- 1 dplee dplee    1440  6월 22 21:29 pabort-v7.o
-rw-rw-r-- 1 dplee dplee   64208  6월 22 21:29 pgd.o
-rw-rw-r-- 1 dplee dplee   37188  6월 22 21:29 proc-syms.o
-rw-rw-r-- 1 dplee dplee    6216  6월 22 21:29 proc-v7.o
-rw-rw-r-- 1 dplee dplee    2120  6월 22 21:29 tlb-v7.o

그런데, 우리는 앞의 포스팅의 Flow 그림에서 kernel/head.S 의 초기에 bl  __lookup_processor_type 를 통해서 우리 cpuid 에 맞는 proc_info_list 구조체 pointer 를 찾았었습니다.
이를 찾을 때  __proc_info_begin 와 __proc_info_end 사이의 table entry 들을 검색합니다.

__proc_info_begin 이 가리키는 것은 .proc.info.init  section 입니다.
(이는 object dump 파일을 살펴보면 알 수 있습니다.)

proc-v7.S 파일을 보니 다음과 같은 부분이 있네요.

.proc.info.init section 이 보입니다.

    .section ".proc.info.init", #alloc, #execinstr
 
    /*
     * Standard v7 proc info content
     */
.macro __v7_proc initfunc, mm_mmuflags = 0, io_mmuflags = 0, hwcaps = 0, proc_fns = v7_processor_functions
    ALT_SMP(.long   PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_SECT_AP_READ | \
            PMD_SECT_AF | PMD_FLAGS_SMP | \mm_mmuflags)
    ALT_UP(.long    PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_SECT_AP_READ | \
            PMD_SECT_AF | PMD_FLAGS_UP | \mm_mmuflags)
    .long   PMD_TYPE_SECT | PMD_SECT_AP_WRITE | \
        PMD_SECT_AP_READ | PMD_SECT_AF | \io_mmuflags
    W(b)    \initfunc
    .long   cpu_arch_name
    .long   cpu_elf_name
    .long   HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB | HWCAP_FAST_MULT | \
        HWCAP_EDSP | HWCAP_TLS | \hwcaps
    .long   cpu_v7_name
    .long   \proc_fns
    .long   v7wbi_tlb_fns
    .long   v6_user_fns
    .long   v7_cache_fns
.endm



    .type   __v7_ca15mp_proc_info, #object
__v7_ca15mp_proc_info:
    .long   0x410fc0f0
    .long   0xff0ffff0
    __v7_proc __v7_ca15mp_setup
    .size   __v7_ca15mp_proc_info, . - __v7_ca15mp_proc_info

proc-v7.S 파일을 보면 __v7_ca15mp_proc 매크로가 있고 그 아래로 cpu 별로 주르륵 proc_info_list 구조체를 채워주는 label 들이 있습니다.
__v7_ca15mp_proc_info label 위치가 바로 우리가 __lookup_processor_type 에서 찾았던 그 위치입니다.

즉, proc-v7.S 를 build 할 때 .proc.info.init section 에 v7 cpu 종류별로 proc_info_list 구조체를 채울 값들이 이미 결정되고, kernel/head.S 를 실행할 때 그 중에서 나의 cpuid 와 맞는 것을 __lookup_processor_type 을 통해 찾은 것입니다.

그래서, 우리 cpu 에 맞는 값이나 function pointer 들이 proc_info_list 에 등록되어 있어서 필요할 때 찾아다 사용하면 되는거죠.

__lookup_processor_type 함수 코드를 보면 coprocessor 를 통해 가져온 cpu 정보와 build 할 당시에 proinfo section 에 채워진  proc_info_list entry 의 cpu 정보를 비교해서 자신의 proc_info_list 를 찾게 되어 있습니다.

proc_info_list 구조체에는 아래와 같은 정보들이 들어있습니다.
그러니까, 우리는 우리의 proc_info_list 구조체만 찾으면 아래 구조체의 값을 모두 알아낼 수 있는 것입니다.

__v7_ca15mp_setup 함수를 찾아가는 것도 아래 구조체의 __cpu_flush 를 통해서 찾아가게 된 것입니다.

struct proc_info_list {
    unsigned int        cpu_val;
    unsigned int        cpu_mask;
    unsigned long       __cpu_mm_mmu_flags; /* used by head.S */
    unsigned long       __cpu_io_mmu_flags; /* used by head.S */
    unsigned long       __cpu_flush;        /* used by head.S */
    const char      *arch_name;
    const char      *elf_name;
    unsigned int        elf_hwcap;
    const char      *cpu_name;
    struct processor    *proc;
    struct cpu_tlb_fns  *tlb;
    struct cpu_user_fns *user;
    struct cpu_cache_fns    *cache;
};

__cpu_flush 가 proc_info_list start + 16 byte 위치에 있는 변수이기 때문에, 이것이 곧 __v7_ca15mp_setup 함수가 되는 것이죠.

#define PROCINFO_INITFUNC 16 /* offsetof(struct proc_info_list, __cpu_flush)    @ */

ARM(   add pc, r10, #PROCINFO_INITFUNC )

정리하면, 빌드 시에 이미 procinfo table 에 아키텍쳐별로 proc_info_list 에 대한 값들이 모두 채워지게 됩니다. 이후, kernel/head.S 수행 시에 __enable_mmu 하기 전에 pc 를 proc_info_list 의 __cpu_flush 가 가리키는 setup 함수(__v7_ca15mp_setup)로 이동하여 작업을 수행하는 등 proc_info_list 는 다양하게 이용된다.

 

You may also like...

0 0 votes
Article Rating
Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x