LinuxKernelStartARM
ARM Linux內核啟動過程.
Updated Feb 24, 2011 by swordhui...@gmail.com
注: 本文轉自ChinaUnix 作者為XPL.
本文針對arm linux, 從kernel的第一條指令開始分析,一直分析到進入 start_kernel()函數. 我們當前以linux-2.6.19內核版本作為范例來分析,本文中所有的代碼,前面都會加上行號以便于和源碼進行對照, 例: 在文件init/main.c中: 00478: asmlinkage void init start_kernel(void) 前面的'00478:' 表示478行,冒號后面的內容就是源碼了.
在分析代碼的過程中,我們使用縮進來表示各個代碼的調用層次.
由于啟動部分有一些代碼是平臺特定的,雖然大部分的平臺所實現的功能都比較類似,但是為了更好的對code進行說明,對于平臺相關的代碼,我們選擇 at91(ARM926EJS)平臺進行分析.
另外,本文是以uncompressed kernel開始講解的.對于內核解壓縮部分的code,在 arch/arm/boot/compressed中,本文不做討論.
一. 啟動條件
通常從系統上電到執行到linux kenel這部分的任務是由boot loader來完成. 關于boot loader的內容,本文就不做過多介紹. 這里只討論進入到linux kernel的時候的一些限制條件,這一般是boot loader在最后跳轉到kernel之前要完成的:
1. CPU必須處于SVC(supervisor)模式,并且IRQ和FIQ中斷都是禁止的;
2. MMU(內存管理單元)必須是關閉的, 此時虛擬地址對物理地址;
3. 數據cache(Data cache)必須是關閉的
4. 指令cache(Instruction cache)可以是打開的,也可以是關閉的,這個沒有強制要求;
5. CPU 通用寄存器0 (r0)必須是 0;
6. CPU 通用寄存器1 (r1)必須是 ARM Linux machine type (關于machine type, 我們后面會有講解)
7. CPU 通用寄存器2 (r2) 必須是 kernel parameter list 的物理地址(parameter list 是由boot loader傳遞給kernel,用來描述設備信息屬性的列表,詳細內容可參考'Booting ARM Linux'文檔).
二. starting kernel
首先,我們先對幾個重要的宏進行說明(我們針對有MMU的情況):
宏 | 位置 | 默認值 | 說明 |
KERNEL_RAM_ADDR | arch/arm/kernel/head.S +26 | 0xc0008000 | kernel在RAM中的的虛擬地址 |
PAGE_OFFSET | include/asm-arm/memeory.h +50 | 0xc0000000 | 內核空間的起始虛擬地址 |
TEXT_OFFSET | arch/arm/Makefile +137 | 0x00008000 | 內核相對于存儲空間的偏移 |
TEXTADDR | arch/arm/kernel/head.S +49 | 0xc0008000 | kernel的起始虛擬地址 |
PHYS_OFFSET | include/asm-arm/arch-xxx/memory.h | 平臺相關 | RAM的起始物理地址 |
內核的入口是stext,這是在arch/arm/kernel/vmlinux.lds.S中定義的:
00011: ENTRY(stext)
對于vmlinux.lds.S,這是ld script文件,此文件的格式和匯編及C程序都不同,本文不對ld script作過多的介紹,只對內核中用到的內容進行講解,關于ld的詳細內容可以參考ld.info 這里的ENTRY(stext) 表示程序的入口是在符號stext. 而符號stext是在arch/arm/kernel/head.S中定義的: 下面我們將arm linux boot的主要代碼列出來進行一個概括的介紹,然后,我們會逐個的進行詳細的講解.
在arch/arm/kernel/head.S中 72 - 94 行,是arm linux boot的主代碼: 00072: ENTRY(stext)
00073: msr cpsr_c, #PSR_F_BIT | PSR_I_BIT | SVC_MODE @ ensure svc mode
00074: @ and irqs disabled
00075: mrc p15, 0, r9, c0, c0 @ get processor id
00076: bl __lookup_processor_type @ r5=procinfo r9=cpuid
00077: movs r10, r5 @ invalid processor (r5=0)?
00078: beq __error_p @ yes, error 'p'
00079: bl __lookup_machine_type @ r5=machinfo
00080: movs r8, r5 @ invalid machine (r5=0)?
00081: beq __error_a @ yes, error 'a'
00082: bl __create_page_tables
00083:
00084: /*
00085: * The following calls CPU specific code in a position independent
00086: * manner. See arch/arm/mm/proc-*.S for details. r10 = base of
00087: * xxx_proc_info structure selected by __lookup_machine_type
00088: * above. On return, the CPU will be ready for the MMU to be
00089: * turned on, and r0 will hold the CPU control register value.
00090: */
00091: ldr r13, __switch_data @ address to jump to after
00092: @ mmu has been enabled
00093: adr lr, __enable_mmu @ return (PIC) address
00094: add pc, r10, #PROCINFO_INITFUNC
其中,73行是確保kernel運行在SVC模式下,并且IRQ和FIRQ中斷已經關閉,這樣做是很謹慎的.
arm linux boot的主線可以概括為以下幾個步驟:
1. 確定 processor type (75 - 78行)
2. 確定 machine type (79 - 81行)
3. 創建頁表 (82行)
4. 調用平臺特定的cpu_flush函數 (在struct proc_info_list中) (94 行)
5. 開啟mmu (93行)
6. 切換數據 (91行)
最終跳轉到start_kernel (在switch_data的結束的時候,調用了 b start_kernel)
下面,我們按照這個主線,逐步的分析Code.
1. 確定 processor type
arch/arm/kernel/head.S中:
00075: mrc p15, 0, r9, c0, c0 @ get processor id
00076: bl __lookup_processor_type @ r5=procinfo r9=cpuid
00077: movs r10, 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: adr r3, 3f
00148: ldmda r3, {r5 - r7}
00149: sub r3, r3, r7 @ get offset between virt&phys
00150: add r5, r5, r3 @ convert virt addresses to
00151: add r6, r6, r3 @ physical address space
00152: 1: ldmia r5, {r3, r4} @ value, mask
00153: and r4, r4, r9 @ mask wanted bits
00154: teq r3, r4
00155: beq 2f
00156: add r5, r5, #PROC_INFO_SZ @ sizeof(proc_info_list)
00157: cmp r5, r6
00158: blo 1b
00159: mov r5, #0 @ unknown processor
00160: 2: mov pc, lr
00161:
00162: /*
00163: * This provides a C-API version of the above function.
00164: */
00165: ENTRY(lookup_processor_type)
00166: stmfd sp!, {r4 - r7, r9, lr}
00167: mov r9, r0
00168: bl __lookup_processor_type
00169: mov r0, r5
00170: ldmfd sp!, {r4 - r7, r9, pc}
00171:
00172: /*
00173: * Look in include/asm-arm/procinfo.h and arch/arm/kernel/arch.[ch] for
00174: * more information about the __proc_info and __arch_info structures.
00175: */
00176: .long __proc_info_begin
00177: .long __proc_info_end
00178: 3: .long .
00179: .long __arch_info_begin
00180: .long __arch_info_end
上一篇:玩轉S3C6410之一 交叉工具鏈制作(gcc4.5.1-armv6-vfp)
下一篇:s3c6410學習筆記-燒寫uboot+構建文件系統
推薦閱讀最新更新時間:2025-06-16 17:04



設計資源 培訓 開發板 精華推薦
- LT3757,一個 10V30V 輸入、48V/1A 輸出升壓轉換器
- 使用 Semtech 的 SC2446 的參考設計
- LTC5585 的典型應用 - 具有 IIP2 和 DC 偏移控制的寬帶 IQ 解調器
- EVAL-ADG5208FEBZ,ADG5208F 過壓保護 8:1 多路復用器評估板
- LTC3455EUF 演示板,USB 電源解決方案,USB/鋰離子適配器,3.15V @ 500mA,1.8V @ 400mA,Vin = 5V +/- 5%
- LTC3892IUH 高效率、雙路 5V/12V 輸出同步降壓型 DC/DC 控制器的典型應用電路
- LTC3642EMS8E、5V、50mA 降壓轉換器的典型應用電路
- 用于安全應用的 L9654 Quad 爆管驅動器和雙傳感器接口 ASIC 的典型應用
- REP019: 調諧于單一110MHz IF的雙頻前端CDMA IC
- OM13076、LPCXpresso 18S37 開發板,用于 LPC43/43S00 和 LPC18S00 系列 Cortex-M MCU
- 納祥科技2W 24位數字功放NX4920,可用于AI語音播報、WIFI播放器
- 常用解調器的定義和工作原理
- 從性能與網絡傳輸出發,講講鐵威馬MAX系列為什么一騎絕塵
- 惠普選中Hailo下一代人工智能加速器,革新零售業與酒店業運營模式
- 跨國商務溝通困局破解之道:時空壺 W4Pro 全場景應用解析
- 從矢量降噪到雙向同傳,時空壺 W4Pro 如何重構 AI 同傳技術標準?
- LoRa+NB-IoT雙模融合,地下車庫信號盲區電梯場景等的冗余通信
- LoRa與UWB的“定位之戰”,成本敏感場景高精度需求的場景切割
- 時空壺X1再升級:引領AI同傳新時代,革新演講翻譯體驗
- ARXML 規則下 ECU 總線通訊與 ADTF 測試方案