新聞中心

EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計應(yīng)用 > arm linux 從入口到start_kernel 代碼分析 - 2

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

作者: 時間:2016-11-10 來源:網(wǎng)絡(luò) 收藏

本文引用地址:http://butianyuan.cn/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協(xié)處理器的c0寄存器來獲得processor id的指令. 關(guān)于cp15的詳細(xì)內(nèi)容可參考相關(guān)的arm手冊

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

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

下面我們分析__lookup_processor_type函數(shù)
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行是函數(shù)定義
147行: 取地址指令,這里的3f是向前symbol名稱是3的位置,即第178行,將該地址存入r3.
這里需要注意的是,adr指令取址,獲得的是基于pc的一個地址,要格外注意,這個地址是3f處的"運行時地址",由于此時MMU還沒有打開,也可以理解成物理地址(實地址).(詳細(xì)內(nèi)容可參考arm指令手冊)

148行: 因為r3中的地址是178行的位置的地址,因而執(zhí)行完后:
r5存的是176行符號 __proc_info_begin的地址;
r6存的是177行符號 __proc_info_end的地址;
r7存的是3f處的地址.
這里需要注意鏈接地址和運行時地址的區(qū)別. 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(詳細(xì)內(nèi)容請參考ld.info)
這三行的意思是: __proc_info_begin 的位置上,放置所有文件中的 ".proc.info.init" 段的內(nèi)容,然后緊接著是 __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: };

我們當(dāng)前以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. 調(diào)用平臺特定的__cpu_flush函數(shù)"一節(jié)中詳細(xì)分析這部分的內(nèi)容.)

從以上的內(nèi)容我們可以看出: r5中的__proc_info_begin是proc_info_list的起始地址, r6中的__proc_info_end是proc_info_list的結(jié)束地址.

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

150行: 將r5存儲的虛擬地址(__proc_info_begin)轉(zhuǎn)換成物理地址
151行: 將r6存儲的虛擬地址(__proc_info_end)轉(zhuǎn)換成物理地址
152行: 對照struct proc_info_list,可以得知,這句是將當(dāng)前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行: 如果相等,說明我們找到了對應(yīng)的processor type,跳到160行,返回
156行: (如果不相等) , 將r5指向下一個proc_info,
157行: 和r6比較,檢查是否到了__proc_info_end.
158行: 如果沒有到__proc_info_end,表明還有proc_info配置,返回152行繼續(xù)查找
159行: 執(zhí)行到這里,說明所有的proc_info都匹配過了,但是沒有找到匹配的,將r5設(shè)置成0(unknown processor)
160行: 返回



關(guān)鍵詞: armlinuxstart_kernel代碼分

評論


技術(shù)專區(qū)

關(guān)閉