原文地址:Linux內核源碼分析--內核啟動之(4)Image內核啟動(setup_arch函數)(Linux-3.0 ARMv7)?作者:tekkamanninja
?轉自:http://blog.chinaunix.net/uid-25909619-id-4938393.html
在分析start_kernel函數的時候,其中有構架相關的初始化函數setup_arch。 此函數根據構架而異,對于ARM構架的詳細分析如下:
void __init setup_arch(char?**cmdline_p){????struct machine_desc?*mdesc;
點擊(此處)折疊或打開
此為設備描述結構體,對于任何板子都定義了這樣的一個結構體,我以前的文章有介紹:《Uncompressing Linux... done, booting the kernel》?1、machine type 不匹配 ????unwind_init(); 點擊(此處)折疊或打開
初始化基於ARM EABI的Backtrace Unwind機制(棧回退),此函數主要用于地址轉換(arch/arm/kernel/unwind.c) ????setup_processor();
點擊(此處)折疊或打開
再次檢測處理器類型,并初始化處理器相關的底層變量。內核啟動時的處理器信息(包括cache)就是通過這個函數打印的,例如:
CPU: ARMv7 Processor [413fc082] revision 2 (ARMv7), cr=10c53c7fCPU: VIPT nonaliasing data cache, VIPT aliasing instruction cache ????mdesc?=?setup_machine_fdt(__atags_pointer);????if?(!mdesc)????????mdesc?=?setup_machine_tags(machine_arch_type);
點擊(此處)折疊或打開
在此處通過bootloader傳遞過來的設備ID來匹配一個 struct machine_desc 結構體(這個結構體就是在arch/arm/mach-*/mach-*.c中定義的結構體:MACHINE_START~MACHINE_END )如果沒有匹配上就死循環。如果匹配上了就打印機器名 ,并處理bootloader傳遞過來的tagged_list,將所有的tag信息保存到相應的全局變量或結構體中。內核啟動時的機器信息就是這里打印的,例如: 點擊(此處)折疊或打開
Machine: ti8168evm 最后返回結構體指針。 ????machine_desc?=?mdesc;????machine_name?=?mdesc->name;
點擊(此處)折疊或打開
通過匹配的struct machine_desc 結構體數據,初始化一些全局變量 ????if?(mdesc->soft_reboot)????????reboot_setup("s");
點擊(此處)折疊或打開
通過struct machine_desc 中的soft_reboot數據來設置重啟類型:如果存在就為“s”:softreset;如果不存在就為“h”:hardreset ????init_mm.start_code?=?(unsigned long)?_text;????init_mm.end_code?=?(unsigned long)?_etext;????init_mm.end_data?=?(unsigned long)?_edata;????init_mm.brk?????=?(unsigned long)?_end;
點擊(此處)折疊或打開
這里通過連接腳本中得到的Linux代碼位置數據來初始化一個mm_struct結構體init_mm中的部分數據ps:每一個任務都有一個mm_struct結構以管理內存空間,init_mm是內核自身的mm_struct ????/*?同時填充cmd_line以備后用,?保護boot_command_line數據?*/????strlcpy(cmd_line,?boot_command_line,?COMMAND_LINE_SIZE);????*cmdline_p?=?cmd_line;
點擊(此處)折疊或打開
將boot_command_line復制到cmd_line中。這里關鍵是要知道系統啟動的時候的cmdline是如何傳遞的。 ????parse_early_param();
點擊(此處)折疊或打開
處理在 struct obs_kernel_param 中定義為early的啟動參數(主要是內存配置部分的參數) 其中就分析了mem=size@start參數初始化了struct meminfo meminfo;同時如果有vmalloc=size參數也會初始化 vmalloc_min參考:《Linux內核高-低端內存設置代碼跟蹤(ARM構架)》 這里需要注意的是內核的cmdline中的參數按照其被需要的先后,分為early和非early的。 include/linux/init.h:
點擊(此處)折疊或打開
struct obs_kernel_param {const char *str; ? ? ? ? ? ?//在cmdline中相應參數名。int (*setup_func)(char *); ?//對于此參數的專用處理函數int early; ? ? ? ? ? ? ? ???//是否為早期需要處理的參數}; 兩種不同的參數在內核中用了不同的宏來定義:early: #define early_param(str, fn) \? ? ? ? __setup_param(str, fn, fn,?1) 非early: #define __setup(str, fn) \? ? ? ? ?__setup_param(str, fn, fn,?0) 使用這兩個宏定義的參數和構架相關,一些構架或者板子可以定義自己特定的參數和處理函數。對于比較重要的“men”參數就是early參數。 ????sanity_check_meminfo();
點擊(此處)折疊或打開
在此處設置struct meminfo meminfo中每個bank中的highmem變量,通過vmalloc_min確定每個bank中的內存是否屬于高端內存 ? ? arm_memblock_init(&meminfo,?mdesc);
點擊(此處)折疊或打開
在此處按地址數據從小到大排序meminfo中的數據,并初始化全局的memblock數據。 ????paging_init(mdesc);
點擊(此處)折疊或打開
設置內核的參考頁表。此頁表不僅用于物理內存映射,還用于管理vmalloc區。此函數中非常重要的一點就是初始化了bootmem分配器! ????request_standard_resources(mdesc);
點擊(此處)折疊或打開
通過獲取設備描述結構體(struct machine_desc)中的數據和編譯時產生的地址數據,初始化內存相關的全局結構體變量。 ????unflatten_device_tree();
點擊(此處)折疊或打開
通過啟動參數中的“非平坦設備樹”信息(如果有),獲取內存相關信息 #ifdef CONFIG_SMP????if?(is_smp())????????smp_init_cpus();#endif
點擊(此處)折疊或打開
針對SMP處理器,初始化可能存在的CPU映射 - 這描述了可能存在的CPU ????reserve_crashkernel();
點擊(此處)折疊或打開
用于內核崩潰時的保留內核此功能通過內核command?line參數中的"crashkernel="保留下內存用于主內核崩潰時獲取內核信息的導出。? ????cpu_init();
點擊(此處)折疊或打開
初始化一個CPU,并設置一個per-CPU棧 ????tcm_init();
點擊(此處)折疊或打開
初始化ARM內部的TCM(緊耦合內存)。 參考資料:《對ARM緊致內存TCM的理解》ARM官網也有介紹文檔 #ifdef CONFIG_MULTI_IRQ_HANDLER????handle_arch_irq?=?mdesc->handle_irq;#endif
點擊(此處)折疊或打開
調用設備描述結構體中的mdesc->handle_irq函數,目的未知。 #ifdef CONFIG_VT#if?defined(CONFIG_VGA_CONSOLE)????conswitchp?=?&vga_con;#elif defined(CONFIG_DUMMY_CONSOLE)????conswitchp?=?&dummy_con;#endif#endif????early_trap_init();
點擊(此處)折疊或打開
對中斷向量表進行早期初始化 ????if (mdesc->init_early)
????????mdesc->init_early();
點擊(此處)折疊或打開
如果設備描述結構體定義了init_early函數(應該是早期初始化之意),則在這里調用。 } 這個函數主要是檢查處理器的類型是否匹配,并獲取處理器信息來設置處理器的相關底層參數。
static void __init setup_processor(void){????struct proc_info_list?*list; ????/*?????*?在支持處理器列表中定位處理器? ?* 連接器為我們創建這個列表,從 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?*?arch/arm/mm/proc-*.S中的入口????*/????list?=?lookup_processor_type(read_cpuid_id());????if?(!list)?{????????printk("CPU configuration botched (ID %08x), unable "?????????"to continue.\n",?read_cpuid_id());????????while?(1);????}
點擊(此處)折疊或打開
這里再次核對處理器類型,雖然這個已經在匯編代碼中執行過一遍了 ????cpu_name?=?list->cpu_name; #ifdef MULTI_CPU????processor?=?*list->proc;#endif#ifdef MULTI_TLB????cpu_tlb?=?*list->tlb;#endif#ifdef MULTI_USER????cpu_user?=?*list->user;#endif#ifdef MULTI_CACHE????cpu_cache?=?*list->cache;#endif
點擊(此處)折疊或打開
通過從struct proc_info_list獲取的數據初始化CPU相關的全局變量 ????printk("CPU: %s [%08x] revision %d (ARMv%s), cr=%08lx\n",???? cpu_name,?read_cpuid_id(),?read_cpuid_id()?&?15,???? proc_arch[cpu_architecture()],?cr_alignment);
點擊(此處)折疊或打開
打印內核啟動時的處理器信息 ????sprintf(init_utsname()->machine,?"%s%c",?list->arch_name,?ENDIANNESS);????sprintf(elf_platform,?"%s%c",?list->elf_name,?ENDIANNESS);????elf_hwcap?=?list->elf_hwcap;#ifndef CONFIG_ARM_THUMB????elf_hwcap?&=?~HWCAP_THUMB;#endif ????feat_v6_fixup(); 點擊(此處)折疊或打開
針對特定的ARM核軟件屏蔽一些功能 ????cacheid_init();
點擊(此處)折疊或打開
初始化ARM核中的緩存 ? ? cpu_proc_init();
點擊(此處)折疊或打開
宏:#define cpu_proc_init __glue(CPU_NAME,_proc_init)意在調用處理器特定的初始化函數。 }
轉載于:https://www.cnblogs.com/sky-heaven/p/4847414.html
總結
以上是生活随笔為你收集整理的Linux内核源码分析--内核启动之(4)Image内核启动(setup_arch函数)(Linux-3.0 ARMv7)【转】...的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。