kernel/head.S – __lookup_processor_type:

__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개 프로세서 정보 리스트가 등록되어 있다.
    • __v7_ca7mp_setup
      • ARM Cortex-A7의 설정 함수가 __v7_proc 매크로의 인수로 사용된다.
      • proc_info_list->__cpu_flush와 동일하다.

 

__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하여 분석

 

kernel_head.s분석2

 

kernel_head.s분석3

 

답글 남기기

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다.