轉:http://blog.csdn.net/lichengtongxiazai/article/details/38941913 此文章針對高通msm8953平臺,啟動過程中,bootloader(預設是bootable/bootloader/lk)會根據機器硬體信息選擇合適的devicetree ...
轉:http://blog.csdn.net/lichengtongxiazai/article/details/38941913
此文章針對高通msm8953平臺,啟動過程中,bootloader(預設是bootable/bootloader/lk)會根據機器硬體信息選擇合適的devicetree裝入記憶體,把地址等相關信息傳給kernel。kernel中,會根據傳入的信息創建設備。
1,先從little kernel開始:
1.1 總體來說Lk/arch/arm/crt0.S文件中語句:
bl kmain
調用的是lk/kernel/main.c文件中的函數:kmain()
kmain()
|bootstrap2()
|arch_init()
|platform_init()
|target_init()
|apps_init()//call init() of APPs defined using APP_START macro
|aboot_init()
|boot_linux_from_mmc()
|//1,Device tree的第一種方法
|dev_tree_get_entry_info()
|__dev_tree_get_entry_info()
|memmove();
|//2,Device tree的第二種方法
|dev_tree_appended()
|boot_linux()
|update_device_tree()
|entry(0, machtype, tags_phys);//pass control to kernel
Aboot.c (bootable\bootloader\lk\app\aboot)
APP_START(aboot)
.init = aboot_init,
APP_END
在下麵aboot_init() ---> boot_linux_from_mmc()中,調用dev_tree_get_entry_info(),裡面會根據硬體(chipset和platform的id,系統實際跑時的信息在系統boot的更早階段由N側設置並傳來,而DT中的信息由根節點的"qcom,msm-id"屬性定義)來選擇合適的DT,後面會把該DT裝入記憶體,把地址等信息傳給kernel(通過CPU寄存器)。
1 void boot_linux(void *kernel, unsigned *tags, 2 const char *cmdline, unsigned machtype, 3 void *ramdisk, unsigned ramdisk_size) 4 { 5 #if DEVICE_TREE 6 7 8 //更新Device Tree 9 ret = update_device_tree((void *)tags, final_cmdline, ramdisk, ramdisk_size); 10 } 11 12 13 /* Top level function that updates the device tree. */ 14 int update_device_tree(void *fdt, const char *cmdline, 15 void *ramdisk, uint32_t ramdisk_size) 16 { 17 int ret = 0; 18 uint32_t offset; 19 20 21 /* Check the device tree header */ 22 //核查其magic數是否正確:version和size 23 ret = fdt_check_header(fdt); 24 25 26 27 28 /* Add padding to make space for new nodes and properties. */ 29 //Move or resize dtb buffer 30 ret = fdt_open_into(fdt, fdt, fdt_totalsize(fdt) + DTB_PAD_SIZE); 31 32 33 /* Get offset of the memory node */ 34 ret = fdt_path_offset(fdt, "/memory"); 35 36 37 offset = ret; 38 39 40 ret = target_dev_tree_mem(fdt, offset); 41 42 43 /* Get offset of the chosen node */ 44 ret = fdt_path_offset(fdt, "/chosen"); 45 46 47 offset = ret; 48 /* Adding the cmdline to the chosen node */ 49 ret = fdt_setprop_string(fdt, offset, (const char*)"bootargs", (const void*)cmdline); 50 51 52 /* Adding the initrd-start to the chosen node */ 53 ret = fdt_setprop_u32(fdt, offset, "linux,initrd-start", (uint32_t)ramdisk); 54 if (ret) 55 56 57 /* Adding the initrd-end to the chosen node */ 58 ret = fdt_setprop_u32(fdt, offset, "linux,initrd-end", ((uint32_t)ramdisk + ramdisk_size)); 59 60 61 fdt_pack(fdt); 62 63 64 return ret; 65 }
2,Kernel中的處理
主要的數據流包括:
(1)初始化流程,即掃描dtb並將其轉換成Device Tree Structure。
(2)傳遞運行時參數傳遞以及platform的識別
(3)將Device Tree Structure併入linux kernel的設備驅動模型。
2.1,彙編部分的代碼分析
linux/arch/arm/kernel/head.S文件定義了bootloader和kernel的參數傳遞要求:
MMU = off, D-cache = off, I-cache = dont care, r0 = 0, r1 = machine nr, r2 = atags or dtb pointer.
目前的kernel支持舊的tag list的方式,同時也支持device tree的方式。r2可能是device tree binary file的指針(bootloader要傳遞給內核之前要copy到memory中),也可以是tag list的指針。在ARM的彙編部分的啟動代碼中(主要是head.S和head-common.S),machine type ID和指向DTB或者atags的指針被保存在變數__machine_arch_type和__atags_pointer中,這麼做是為了後續C代碼進行處理。
start_kernel()
|setup_arch()
|setup_machine_fdt()//select machine description according to DT info
2.2,獲得machine描述符
1 //根據Device Tree的信息,找到最適合的machine描述符。 2 struct machine_desc * __init setup_machine_fdt(unsigned int dt_phys) 3 { 4 /* 掃描 /chosen node,保存運行時參數(bootargs)到boot_command_line,此外,還處理initrd相關的property,並保存在initrd_start和initrd_end這兩個全局變數中 */
5 of_scan_flat_dt(early_init_dt_scan_chosen, boot_command_line);/* 掃描根節點,獲取 {size,address}-cells信息,並保存在dt_root_size_cells和dt_root_addr_cells全局變數中 */
6 of_scan_flat_dt(early_init_dt_scan_root, NULL);/* 掃描DTB中的memory node,並把相關信息保存在meminfo中,全局變數meminfo保存了系統記憶體相關的信息。*/
7 of_scan_flat_dt(early_init_dt_scan_memory, NULL);/* Change machine number to match the mdesc we're using */
8 __machine_arch_type = mdesc_best->nr;
9 return mdesc_best;
10 }
運行時參數是在掃描DTB的chosen node時候完成的,具體的動作就是獲取chosen node的bootargs、initrd等屬性的value,並將其保存在全局變數(boot_command_line,initrd_start、initrd_end)中。