新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > arm linux 從入口到start_kernel 代碼分析 - 2

        arm linux 從入口到start_kernel 代碼分析 - 2

        作者: 時間:2016-11-10 來源:網絡 收藏

        本文引用地址:http://www.104case.com/article/201611/317212.htm

        1. 確定 processor type


        arch/arm/kernel/head.S中:
        00075: mrcp15, 0, r9, c0, c0@ get processor id
        00076: bl__lookup_processor_type@ r5=procinfo r9=cpuid
        00077: movsr10, r5@ invalid processor (r5=0)?
        00078: beq__error_p@ yes, error p

        75行: 通過cp15協處理器的c0寄存器來獲得processor id的指令. 關于cp15的詳細內容可參考相關的arm手冊

        76行: 跳轉到__lookup_processor_type.在__lookup_processor_type中,會把processor type 存儲在r5中
        77,78行: 判斷r5中的processor type是否是0,如果是0,說明是無效的processor type,跳轉到__error_p(出錯)

        __lookup_processor_type 函數主要是根據從cpu中獲得的processor id和系統中的proc_info進行匹配,將匹配到的proc_info_list的基地址存到r5中, 0表示沒有找到對應的processor type.

        下面我們分析__lookup_processor_type函數
        arch/arm/kernel/head-common.S中:

        00145: .type__lookup_processor_type, %function
        00146: __lookup_processor_type:
        00147: adrr3, 3f
        00148: ldmdar3, {r5 - r7}
        00149: subr3, r3, r7@ get offset between virt&phys
        00150: addr5, r5, r3@ convert virt addresses to
        00151: addr6, r6, r3@ physical address space
        00152: 1:ldmiar5, {r3, r4}@ value, mask
        00153: andr4, r4, r9@ mask wanted bits
        00154: teqr3, r4
        00155: beq2f
        00156: addr5, r5, #PROC_INFO_SZ@ sizeof(proc_info_list)
        00157: cmpr5, r6
        00158: blo1b
        00159: movr5, #0@ unknown processor
        00160: 2:movpc, lr
        00161:
        00162:
        00165: ENTRY(lookup_processor_type)
        00166: stmfdsp!, {r4 - r7, r9, lr}
        00167: movr9, r0
        00168: bl__lookup_processor_type
        00169: movr0, r5
        00170: ldmfdsp!, {r4 - r7, r9, pc}
        00171:
        00172:
        00176: .long__proc_info_begin
        00177: .long__proc_info_end
        00178: 3:.long.
        00179: .long__arch_info_begin
        00180: .long__arch_info_end


        145, 146行是函數定義
        147行: 取地址指令,這里的3f是向前symbol名稱是3的位置,即第178行,將該地址存入r3.
        這里需要注意的是,adr指令取址,獲得的是基于pc的一個地址,要格外注意,這個地址是3f處的"運行時地址",由于此時MMU還沒有打開,也可以理解成物理地址(實地址).(詳細內容可參考arm指令手冊)

        148行: 因為r3中的地址是178行的位置的地址,因而執行完后:
        r5存的是176行符號 __proc_info_begin的地址;
        r6存的是177行符號 __proc_info_end的地址;
        r7存的是3f處的地址.
        這里需要注意鏈接地址和運行時地址的區別. r3存儲的是運行時地址(物理地址),而r7中存儲的是鏈接地址(虛擬地址).

        __proc_info_begin和__proc_info_end是在arch/arm/kernel/vmlinux.lds.S中:
        00031:__proc_info_begin = .;
        00032:*(.proc.info.init)
        00033:__proc_info_end = .;

        這里是聲明了兩個變量:__proc_info_begin 和 __proc_info_end,其中等號后面的"."是location counter(詳細內容請參考ld.info)
        這三行的意思是: __proc_info_begin 的位置上,放置所有文件中的 ".proc.info.init" 段的內容,然后緊接著是 __proc_info_end 的位置.

        kernel 使用struct proc_info_list來描述processor type.
        在 include/asm-arm/procinfo.h 中:
        00029: struct proc_info_list {
        00030: unsigned intcpu_val;
        00031: unsigned intcpu_mask;
        00032: unsigned long__cpu_mm_mmu_flags;
        00033: unsigned long__cpu_io_mmu_flags;
        00034: unsigned long__cpu_flush;
        00035: const char*arch_name;
        00036: const char*elf_name;
        00037: unsigned intelf_hwcap;
        00038: const char*cpu_name;
        00039: struct processor*proc;
        00040: struct cpu_tlb_fns*tlb;
        00041: struct cpu_user_fns*user;
        00042: struct cpu_cache_fns*cache;
        00043: };

        我們當前以at91為例,其processor是926的.
        在arch/arm/mm/proc-arm926.S 中:
        00464: .section ".proc.info.init", #alloc, #execinstr
        00465:
        00466: .type__arm926_proc_info,#object
        00467: __arm926_proc_info:
        00468: .long0x41069260@ ARM926EJ-S (v5TEJ)
        00469: .long0xff0ffff0
        00470: .long PMD_TYPE_SECT |
        00471: PMD_SECT_BUFFERABLE |
        00472: PMD_SECT_CACHEABLE |
        00473: PMD_BIT4 |
        00474: PMD_SECT_AP_WRITE |
        00475: PMD_SECT_AP_READ
        00476: .long PMD_TYPE_SECT |
        00477: PMD_BIT4 |
        00478: PMD_SECT_AP_WRITE |
        00479: PMD_SECT_AP_READ
        00480: b__arm926_setup
        00481: .longcpu_arch_name
        00482: .longcpu_elf_name
        00483: .longHWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_VFP|HWCAP_EDSP|HWCAP_JAVA
        00484: .longcpu_arm926_name
        00485: .longarm926_processor_functions
        00486: .longv4wbi_tlb_fns
        00487: .longv4wb_user_fns
        00488: .longarm926_cache_fns
        00489: .size__arm926_proc_info, . - __arm926_proc_info

        從464行,我們可以看到 __arm926_proc_info 被放到了".proc.info.init"段中.
        對照struct proc_info_list,我們可以看到 __cpu_flush的定義是在480行,即__arm926_setup.(我們將在"4. 調用平臺特定的__cpu_flush函數"一節中詳細分析這部分的內容.)

        從以上的內容我們可以看出: r5中的__proc_info_begin是proc_info_list的起始地址, r6中的__proc_info_end是proc_info_list的結束地址.

        149行: 從上面的分析我們可以知道r3中存儲的是3f處的物理地址,而r7存儲的是3f處的虛擬地址,這一行是計算當前程序運行的物理地址和虛擬地址的差值,將其保存到r3中.

        150行: 將r5存儲的虛擬地址(__proc_info_begin)轉換成物理地址
        151行: 將r6存儲的虛擬地址(__proc_info_end)轉換成物理地址
        152行: 對照struct proc_info_list,可以得知,這句是將當前proc_info的cpu_val和cpu_mask分別存r3, r4中
        153行: r9中存儲了processor id(arch/arm/kernel/head.S中的75行),與r4的cpu_mask進行邏輯與操作,得到我們需要的值
        154行: 將153行中得到的值與r3中的cpu_val進行比較
        155行: 如果相等,說明我們找到了對應的processor type,跳到160行,返回
        156行: (如果不相等) , 將r5指向下一個proc_info,
        157行: 和r6比較,檢查是否到了__proc_info_end.
        158行: 如果沒有到__proc_info_end,表明還有proc_info配置,返回152行繼續查找
        159行: 執行到這里,說明所有的proc_info都匹配過了,但是沒有找到匹配的,將r5設置成0(unknown processor)
        160行: 返回



        評論


        技術專區

        關閉
        主站蜘蛛池模板: 延津县| 夏邑县| 江孜县| 汾阳市| 嵩明县| 新密市| 通辽市| 临海市| 北碚区| 武强县| 沛县| 海城市| 莒南县| 漯河市| 沅陵县| 阳江市| 连平县| 旺苍县| 钦州市| 长春市| 巴彦淖尔市| 东阿县| 青冈县| 大埔区| 长宁县| 阿拉善盟| 安吉县| 内丘县| 石渠县| 曲阳县| 长垣县| 西贡区| 会东县| 嫩江县| 水城县| 定边县| 中宁县| 梨树县| 清水河县| 武城县| 洞头县|