__lookup_processor_type:
processor id를 사용하여 링커가 만들어내는 별도의 섹션 공간에서 지원되는 프로세서 리스트를 검색하여 찾아낸다. MMU를 사용하지 않으므로 여기서 절대주소로 __proc_info 리스트를 사용할 수 없어서 offset을 계산하여 사용해야 한다.
arch/arm/kernel/head-common.S
__FINIT .text /* * Read processor ID register (CP#15, CR0), and look up in the linker-built * supported processor list. Note that we can't use the absolute addresses * for the __proc_info lists since we aren't running with the MMU on * (and therefore, we are not in the correct address space). We have to * calculate the offset. * * r9 = cpuid * Returns: * r3, r4, r6 corrupted * r5 = proc_info pointer in physical address space * r9 = cpuid (preserved) */ __lookup_processor_type: adr r3, __lookup_processor_type_data ldmia r3, {r4 - r6} sub r3, r3, r4 @ get offset between virt&phys add r5, r5, r3 @ convert virt addresses to add r6, r6, r3 @ physical address space 1: ldmia r5, {r3, r4} @ value, mask and r4, r4, r9 @ mask wanted bits teq r3, r4 beq 2f add r5, r5, #PROC_INFO_SZ @ sizeof(proc_info_list) cmp r5, r6 blo 1b mov r5, #0 @ unknown processor 2: ret lr ENDPROC(__lookup_processor_type)
- __FINIT
- 해당 매크로엔 .previous 지시자가 담겨있다.
- 현재 사용하고 있는 섹션 이전에 사용했던 섹션으로 변경된다.
- r3를 사용하여 offset을 계산한다.
- rpi2: 0x8000_0000 (물리 주소 – 가상 주소)
- r5: __proc_info_begin 물리 주소
- r6: __proc_info_end 물리 주소
- ldmia r5, {r3, r4}
- 루프의 시작으로 proc_info_list 구조체의 첫 부분에 있는 cpu value와 cpu mask를 읽어서 r3, r4에 잃어온다.
- beq 2f
- cpu를 판별하여 일치하면 2f 레이블로 이동하고 리턴한다.
- add r5, r5, #PROC_INFO_SZ
- r5를 구조체 사이즈만큼 증가시킨다.
- #PROC_INFO_SZ = 52
- 구조체 proc_info_list와 동일한 사이즈
- cmp r5, r6
- r5가 아직 r6보다 작으면 1f 레이블로 이동하여 루프를 돈다.
프로세서 정보 리스트(proc_info_list)가 저장되는 곳
- 지원되는 각종 프로세서 정보들은 .init.proc.info 섹션에 저장된다.
- rpi2:
- 이 위치에 저장된 정보는 ARMv7 관련된 것만 약 520여 바이트로 구성되어 있다.
- arch/arm/mm/proc-v7.S – __v7_ca7mp_proc_info: 레이블 위치
- 저장되는 섹션 위치를 기술한 소스
arch/arm/kernel/vmlinux.lds
.init.proc.info : { . = ALIGN(4); __proc_info_begin = .; *(.proc.info.init) __proc_info_end = .; }
__lookup_processor_type_data: 객체
arch/arm/kernel/head-common.S
/* * Look in <asm/procinfo.h> for information about the __proc_info structure. */ .align 2 .type __lookup_processor_type_data, %object __lookup_processor_type_data: .long . .long __proc_info_begin .long __proc_info_end .size __lookup_processor_type_data, . - __lookup_processor_type_data
__v7_ca7mp_proc_info: 객체
아래는 ARM Cortex-A7 아키텍처가 사용하는 프로세서 정보 리스트로 proc_info_list 구조체와 동일하다.
arch/arm/mm/proc-v7.S
/* * ARM Ltd. Cortex A7 processor. */ .type __v7_ca7mp_proc_info, #object __v7_ca7mp_proc_info: .long 0x410fc070 .long 0xff0ffff0 __v7_proc __v7_ca7mp_setup .size __v7_ca7mp_proc_info, . - __v7_ca7mp_proc_info
- __v7_proc __v7_ca7mp_setup
- __v7_proc 매크로
- ARMv7 아키텍처는 모두 공통적으로 사용된다.
- 현재 소스에는 11개 프로세서 정보 리스트가 등록되어 있다.
- ARMv7 아키텍처는 모두 공통적으로 사용된다.
- __v7_ca7mp_setup
- ARM Cortex-A7의 설정 함수가 __v7_proc 매크로의 인수로 사용된다.
- proc_info_list->__cpu_flush와 동일하다.
- __v7_proc 매크로
__v7_proc 매크로
arch/arm/mm/proc-v7.S
.section ".rodata" string cpu_arch_name, "armv7" string cpu_elf_name, "v7" .align .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
- 44 바이트로 구성되어 있고 proc_info_list(56 바이트)에서 cpu value와 mask 정보 이후의 중간을 구성하는 정보이다.
- 참고: start_kernel() – setup_arch() – setup_processor() | 문c
proc_info_list 구조체
arch/arm/include/asm/procinfo.h
/* * Note! struct processor is always defined if we're * using MULTI_CPU, otherwise this entry is unused, * but still exists. * * NOTE! The following structure is defined by assembly * language, NOT C code. For more information, check: * arch/arm/mm/proc-*.S and arch/arm/kernel/head.S */ 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; };
compressed 커널의 내부를 hexdump하여 분석