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 는 다양하게 이용된다.