Linux內核源碼分析--內核啓動之(4)Image內核啓動(setup_arch函數)(Linux-3.0 ARMv7)【轉】

在分析start_kernel函數的時候,其中有構架相關的初始化函數setup_arch。
此函數根據構架而異,對於ARM構架的詳細分析以下:

  1. void __init setup_arch(char **cmdline_p)
  2. {
  3.     struct machine_desc *mdesc;

  4. 點擊(此處)摺疊或打開linux

    1. 此爲設備描述結構體,對於任何板子都定義了這樣的一個結構體,我之前的文章有介紹:
    2. 《Uncompressing Linux... done, booting the kernel》 一、machine type 不匹配
  5.     unwind_init();
  6. 點擊(此處)摺疊或打開緩存

    1. 初始化基於ARM EABI的Backtrace Unwind機制(棧回退),此函數主要用於地址轉換(arch/arm/kernel/unwind.c)
  7.     setup_processor();

    點擊(此處)摺疊或打開函數

    1. 再次檢測處理器類型,並初始化處理器相關的底層變量。內核啓動時的處理器信息(包括cache)就是經過這個函數打印的,例如:
      1. CPU: ARMv7 Processor [413fc082] revision 2 (ARMv7), cr=10c53c7f
      2. CPU: VIPT nonaliasing data cache, VIPT aliasing instruction cache
  8.     mdesc = setup_machine_fdt(__atags_pointer);
  9.     if (!mdesc)
  10.         mdesc = setup_machine_tags(machine_arch_type);

    點擊(此處)摺疊或打開源碼分析

    1. 在此處經過bootloader傳遞過來的設備ID來匹配一個 struct machine_desc 結構體
    2. (這個結構體就是在arch/arm/mach-*/mach-*.c中定義的結構體:MACHINE_START~MACHINE_END )
    3. 若是沒有匹配上就死循環。
    4. 若是匹配上了就打印機器名 ,並處理bootloader傳遞過來的tagged_list,將全部的tag信息保存到相應的全局變量或結構體中。
    5. 內核啓動時的機器信息就是這裏打印的,例如:
    6. 點擊(此處)摺疊或打開ui

      1. Machine: ti8168evm
    7. 最後返回結構體指針。
  11.     machine_desc = mdesc;
  12.     machine_name = mdesc->name;

    點擊(此處)摺疊或打開spa

    1. 經過匹配的struct machine_desc 結構體數據,初始化一些全局變量
  13.     if (mdesc->soft_reboot)
  14.         reboot_setup("s");

    點擊(此處)摺疊或打開.net

    1. 經過struct machine_desc 中的soft_reboot數據來設置重啓類型:
    2. 若是存在就爲「s」:softreset;若是不存在就爲「h」:hardreset
  15.     init_mm.start_code = (unsigned long) _text;
  16.     init_mm.end_code = (unsigned long) _etext;
  17.     init_mm.end_data = (unsigned long) _edata;
  18.     init_mm.brk     = (unsigned long) _end;

    點擊(此處)摺疊或打開unix

    1. 這裏經過鏈接腳本中獲得的Linux代碼位置數據來初始化一個mm_struct結構體init_mm中的部分數據
    2. ps:每個任務都有一個mm_struct結構以管理內存空間,init_mm是內核自身的mm_struct
  19.     /* 同時填充cmd_line以備後用, 保護boot_command_line數據 */
  20.     strlcpy(cmd_line, boot_command_line, COMMAND_LINE_SIZE);
  21.     *cmdline_p = cmd_line;

    點擊(此處)摺疊或打開

    1. 將boot_command_line複製到cmd_line中。這裏關鍵是要知道系統啓動的時候的cmdline是如何傳遞的。
  22.     parse_early_param();

    點擊(此處)摺疊或打開

    1. 處理在 struct obs_kernel_param 中定義爲early的啓動參數(主要是內存配置部分的參數)
    2. 其中就分析了mem=size@start參數初始化了struct meminfo meminfo;
    3. 同時若是有vmalloc=size參數也會初始化 vmalloc_min
    4. 參考:《Linux內核高-低端內存設置代碼跟蹤(ARM構架)》
    5. 這裏須要注意的是內核的cmdline中的參數按照其被須要的前後,分爲early和非early的。
    6. include/linux/init.h:

      點擊(此處)摺疊或打開

      1. struct obs_kernel_param {
      2. const char *str;            //在cmdline中相應參數名。
      3. int (*setup_func)(char *);  //對於此參數的專用處理函數
      4. int early;                  //是否爲早期須要處理的參數
      5. };
    7. 兩種不一樣的參數在內核中用了不一樣的宏來定義:
    8. early: #define early_param(str, fn) \
    9.         __setup_param(str, fn, fn, 1)
    10. 非early: #define __setup(str, fn) \
    11.          __setup_param(str, fn, fn, 0)
    12. 使用這兩個宏定義的參數和構架相關,一些構架或者板子能夠定義本身特定的參數和處理函數。對於比較重要的「men」參數就是early參數。
  23.     sanity_check_meminfo();

    點擊(此處)摺疊或打開

    1. 在此處設置struct meminfo meminfo中每一個bank中的highmem變量,
    2. 經過vmalloc_min肯定每一個bank中的內存是否屬於高端內存
  24.     arm_memblock_init(&meminfo, mdesc);

    點擊(此處)摺疊或打開

    1. 在此處按地址數據從小到大排序meminfo中的數據,並初始化全局的memblock數據。
  25.     paging_init(mdesc);

    點擊(此處)摺疊或打開

    1. 設置內核的參考頁表。
    2. 此頁表不只用於物理內存映射,還用於管理vmalloc區。
    3. 此函數中很是重要的一點就是初始化了bootmem分配器!
  26.     request_standard_resources(mdesc);

  27. 點擊(此處)摺疊或打開

    1. 經過獲取設備描述結構體(struct machine_desc)中的數據和編譯時產生的地址數據,初始化內存相關的全局結構體變量
  28.     unflatten_device_tree();

    點擊(此處)摺疊或打開

    1. 經過啓動參數中的「非平坦設備樹」信息(若是有),獲取內存相關信息
  29. #ifdef CONFIG_SMP
  30.     if (is_smp())
  31.         smp_init_cpus();
  32. #endif

    點擊(此處)摺疊或打開

    1. 針對SMP處理器,初始化可能存在的CPU映射 - 這描述了可能存在的CPU
  33.     reserve_crashkernel();

    點擊(此處)摺疊或打開

    1. 用於內核崩潰時的保留內核
    2. 此功能經過內核command line參數中的"crashkernel="保留下內存用於主內核崩潰時獲取內核信息的導出。 
  34.     cpu_init();

    點擊(此處)摺疊或打開

    1. 初始化一個CPU,並設置一個per-CPU棧
  35.     tcm_init();

    點擊(此處)摺疊或打開

    1. 初始化ARM內部的TCM(緊耦合內存)。
    2. 參考資料:《對ARM緊緻內存TCM的理解》
    3. ARM官網也有介紹文檔
  36. #ifdef CONFIG_MULTI_IRQ_HANDLER
  37.     handle_arch_irq = mdesc->handle_irq;
  38. #endif

  39. 點擊(此處)摺疊或打開

    1. 調用設備描述結構體中的mdesc->handle_irq函數,目的未知。
  40. #ifdef CONFIG_VT
  41. #if defined(CONFIG_VGA_CONSOLE)
  42.     conswitchp = &vga_con;
  43. #elif defined(CONFIG_DUMMY_CONSOLE)
  44.     conswitchp = &dummy_con;
  45. #endif
  46. #endif
  47.     early_trap_init();

  48. 點擊(此處)摺疊或打開

    1. 對中斷向量表進行早期初始化
  49.     if (mdesc->init_early)
  50.         mdesc->init_early();

    點擊(此處)摺疊或打開

    1. 若是設備描述結構體定義了init_early函數(應該是早期初始化之意),則在這裏調用。
  51. }
 
這個函數主要是檢查處理器的類型是否匹配,並獲取處理器信息來設置處理器的相關底層參數。
  1. static void __init setup_processor(void)
  2. {
  3.     struct proc_info_list *list;
  4.     /*
  5.      * 在支持處理器列表中定位處理器
  6.    * 鏈接器爲咱們建立這個列表,從                                                                              * arch/arm/mm/proc-*.S中的入口
  7.     */
  8.     list = lookup_processor_type(read_cpuid_id());
  9.     if (!list) {
  10.         printk("CPU configuration botched (ID %08x), unable "
  11.          "to continue.\n", read_cpuid_id());
  12.         while (1);
  13.     }

    點擊(此處)摺疊或打開

    1. 這裏再次覈對處理器類型,雖然這個已經在彙編代碼中執行過一遍了
  14.     cpu_name = list->cpu_name;
  15. #ifdef MULTI_CPU
  16.     processor = *list->proc;
  17. #endif
  18. #ifdef MULTI_TLB
  19.     cpu_tlb = *list->tlb;
  20. #endif
  21. #ifdef MULTI_USER
  22.     cpu_user = *list->user;
  23. #endif
  24. #ifdef MULTI_CACHE
  25.     cpu_cache = *list->cache;
  26. #endif

  27. 點擊(此處)摺疊或打開

    1. 經過從struct proc_info_list獲取的數據初始化CPU相關的全局變量
  28.     printk("CPU: %s [%08x] revision %d (ARMv%s), cr=%08lx\n",
  29.      cpu_name, read_cpuid_id(), read_cpuid_id() & 15,
  30.      proc_arch[cpu_architecture()], cr_alignment);

  31. 點擊(此處)摺疊或打開

    1. 打印內核啓動時的處理器信息
  32.     sprintf(init_utsname()->machine, "%s%c", list->arch_name, ENDIANNESS);
  33.     sprintf(elf_platform, "%s%c", list->elf_name, ENDIANNESS);
  34.     elf_hwcap = list->elf_hwcap;
  35. #ifndef CONFIG_ARM_THUMB
  36.     elf_hwcap &= ~HWCAP_THUMB;
  37. #endif
  38.     feat_v6_fixup();
  39. 點擊(此處)摺疊或打開

    1. 針對特定的ARM核軟件屏蔽一些功能
  40.     cacheid_init();

    點擊(此處)摺疊或打開

    1. 初始化ARM核中的緩存
  41.     cpu_proc_init();

    點擊(此處)摺疊或打開

    1. 宏:
    2. #define cpu_proc_init __glue(CPU_NAME,_proc_init)
    3. 意在調用處理器特定的初始化函數。
  42. }
相關文章
相關標籤/搜索