在分析start_kernel函數的時候,其中有構架相關的初始化函數setup_arch。
此函數根據構架而異,對於ARM構架的詳細分析以下:
- void __init setup_arch(char **cmdline_p)
- {
- struct machine_desc *mdesc;
- unwind_init();
-
- 初始化基於ARM EABI的Backtrace Unwind機制(棧回退),此函數主要用於地址轉換(arch/arm/kernel/unwind.c)
- setup_processor();
- 再次檢測處理器類型,並初始化處理器相關的底層變量。內核啓動時的處理器信息(包括cache)就是經過這個函數打印的,例如:
- CPU: ARMv7 Processor [413fc082] revision 2 (ARMv7), cr=10c53c7f
- CPU: 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_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();
- tcm_init();
- #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();
-
- cacheid_init();
- cpu_proc_init();
- 宏:
- #define cpu_proc_init __glue(CPU_NAME,_proc_init)
- 意在調用處理器特定的初始化函數。
- }