日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

奇小葩讲设备树(3/5)-- Linux设备树详解(三)u-boot设备树的传递

發布時間:2023/12/15 linux 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 奇小葩讲设备树(3/5)-- Linux设备树详解(三)u-boot设备树的传递 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前面兩節介紹了設備的基本概念、編譯、結構的組成,本章討論的主要內容為

  • dtb如何通過Bootloader引導程序加載到內核
  • bootloader如何解析dbt
  • bootloader支持哪些dtb的操作
  • 1. 傳遞dtb給內核

    對于傳統bootloader提供兩種工作模式:一是啟動加載模式(start loading),一是下載模式(downloading)
    工作在啟動加載模式時,bootloader會自動執行bootcmd命令,
    比如:bootcmd=“nand read 0x100000 0x80000000 0x300000; bootm 0x80000000”
    uboot首先把內核鏡像拷貝到內存地址為0x80000000的地方,然后執行bootm 0x80000000命令。
    bootm命令實際上調用的是do_bootm_linux函數:

    theKernel (0,bd->bi_arch_number, bd->bi_boot_params);
    • 1

    r0,r1,r2三個寄存器的設置

  • r0一般設置為0;
  • r1一般設置為machine id (在使用設備樹時該參數沒有被使用);是讓內核知道是哪個CPU,從而調用對應的初始化函數
  • r2一般設置ATAGS或DTB的開始地址;
  • 以前沒有使用設備樹時,需要bootloader傳一個machine id給內核,內核啟動的時候會根據這個machine_id來比較內核machine_desc(機器描述結構體)中的.nr,如果相等,就選中了對應的machine_desc(機器描述結構體)),然后調用machine_desc(機器描述結構體)中的.init(初始化函數)。現在使用設備樹的話,這個參數就不需要設置了。
    對于我們拿到一個新的bootloader,我們怎么能使代碼支持dtb模式,我們需要配置#define CONFIG_OF_LIBFDT,可讓u-boot支持內核設備樹dts,加載命令如下:

    bootm <uImage_addr> <initrd_addr> <dtb_addr> //bootm + uImage地址 + ramdisk地址 + 設備樹鏡像地址

    比如:

    //1. 下載內核uImage到內存0x30007FC0 tftp 0x30007FC0 uImage //2. 下載dtb到內存32000000 tftp 0x30001000 s3c2440-smdk2440.dtb //3. - 表示不使用ramdisk加載,如果使用ramdisk則提供其加載地址bootm 0x30007FC0 - 0x30001000

    對于我們下載dtb的地址0x32000000,這個地址有什么要求呢?是隨意選的地址就可以,還是要遵循什么原則呢?

  • 不要破壞u-boot本身
  • 不要破壞內核本身: 內核本身的空間不能占用, 內核要用到的內存區域也不能占用
  • 對于該問題,我們拿了一塊2440的地址空間分配圖來說明該問題

    對于dtb的存放,只能存放在空閑區,并且不能與其他區有重合的地方。

    2. fdt命令查看設備樹

    如果修改設備樹中的led設備引腳,有兩種辦法

  • 修改dts文件,重新編譯得到dtb并上傳燒寫
  • 使用uboot提供的一些命令來修改dtb文件,修改后再把它保存到板子上,以后就使用這個修改后的dtb文件移動值,也就是通過memmove處理
  • 對于u-boot提供了fdt的相關命令

    "addr [-c] <addr> [<length>] - Set the [control] fdt location to <addr>\n""fdt move <fdt> <newaddr> <length> - Copy the fdt to <addr> and make it active\n""fdt resize [<extrasize>] - Resize fdt to size + padding to 4k addr + some optional <extrasize> if needed\n""fdt print <path> [<prop>] - Recursive print starting at <path>\n""fdt list <path> [<prop>] - Print one level starting at <path>\n""fdt get value <var> <path> <prop> - Get <property> and store in <var>\n""fdt get name <var> <path> <index> - Get name of node <index> and store in <var>\n""fdt get addr <var> <path> <prop> - Get start address of <property> and store in <var>\n""fdt get size <var> <path> [<prop>] - Get size of [<property>] or num nodes and store in <var>\n""fdt set <path> <prop> [<val>] - Set <property> [to <val>]\n""fdt mknode <path> <node> - Create a new node after <path>\n""fdt rm <path> [<prop>] - Delete the node or <property>\n""fdt header - Display header info\n""fdt bootcpu <id> - Set boot cpuid\n""fdt memory <addr> <size> - Add/Update memory node\n""fdt rsvmem print - Show current mem reserves\n""fdt rsvmem add <addr> <size> - Add a mem reserve\n""fdt rsvmem delete <index> - Delete a mem reserves\n""fdt chosen [<start> <end>] - Add/update the /chosen branch in the tree\n"" <start>/<end> - initrd start/end addr\n"

    實例

    nand read.jffs2 32000000 device_tree // 從flash讀出dtb文件到內存(0x32000000) fdt addr 32000000 // 告訴fdt, dtb文件在哪 fdt print /led pin // 打印/led節點的pin屬性 fdt get value XXX /led pin // 讀取/led節點的pin屬性, 并且賦給環境變量XXX print XXX // 打印環境變量XXX的值 fdt set /led pin <0x00050005> // 設置/led節點的pin屬性 fdt print /led pin // 打印/led節點的pin屬性 nand erase device_tree // 擦除flash分區 nand write.jffs2 32000000 device_tree // 把修改后的dtb文件寫入flash分區

    3. u-boot對dtb的支持

    dtb可以以兩種形式編譯到uboot的鏡像中

    • 1.dtb和uboot的bin文件分離

    現在的uboot已經做得和kernel很像,最主要的一點是,uboot也使用了dtb的方法,將設備樹和代碼分離開來(當然可以通過宏來控制)。

    CONFIG_OF_CONTROL=y // 用于表示是否使用了dtb的方式CONFIG_OF_SEPARATE=y // 是否將dtb和uboot分離表一
    • 2.dtb集成到uboot的bin文件內部
    • 3.通過fdtcontroladdr環境變量來指定dtb的地址

    4. uboot中如何獲取dtb

    在uboot初始化過程中,需要對dtb做兩個操作:

  • 獲取dtb的地址,并且驗證dtb的合法性
  • 根據你編譯的是集成還是分離,如果是集成的話,需要為dtb預留內存空間并進行relocate
  • 重新獲取一次dtb的地址,bootm傳遞給內核
  • 4.1 獲取dtb的地址,并且驗證dtb的合法性

    在系統起來的時候,進行一串的初始化函數中,fdtdec_setup會對dtb進行合法性驗證

    static const init_fnc_t init_sequence_f[] = { ...setup_mon_len, #ifdef CONFIG_OF_CONTROLfdtdec_setup, #endifreserve_fdt, ... }

    對應代碼如下: lib/fdtdec.c

    int fdtdec_setup(void) { #if CONFIG_IS_ENABLED(OF_CONTROL) # ifdef CONFIG_OF_EMBED/* Get a pointer to the FDT */ // 1. 當使用CONFIG_OF_EMBED的方式時,也就是dtb集成到uboot的bin文件中時,通過__dtb_dt_begin符號來獲取dtb地址gd->fdt_blob = __dtb_dt_begin; # elif defined CONFIG_OF_SEPARATE # ifdef CONFIG_SPL_BUILD/* FDT is at end of BSS unless it is in a different memory region */if (IS_ENABLED(CONFIG_SPL_SEPARATE_BSS))gd->fdt_blob = (ulong *)&_image_binary_end;elsegd->fdt_blob = (ulong *)&__bss_end;# elif defined CONFIG_FIT_EMBEDgd->fdt_blob = locate_dtb_in_fit(&_end);if (gd->fdt_blob == NULL || gd->fdt_blob <= ((void *)&_end)) {puts("Failed to find proper dtb in embedded FIT Image\n");return -1;}# else/* FDT is at end of image */ //2. //當使用CONFIG_OF_SEPARATE的方式時,也就是dtb追加到uboot的bin文件后面時,通過_end符號來獲取dtb地址gd->fdt_blob = (ulong *)&_end; # endif # elif defined(CONFIG_OF_BOARD)/* Allow the board to override the fdt address. */gd->fdt_blob = board_fdt_blob_setup(); # elif defined(CONFIG_OF_HOSTFILE)if (sandbox_read_fdt_from_file()) {puts("Failed to read control FDT\n");return -1;} # endif //3. 可以通過環境變量fdtcontroladdr來指定gd->fdt_blob,也就是指定fdt的地址 # ifndef CONFIG_SPL_BUILD/* Allow the early environment to override the fdt address */gd->fdt_blob = (void *)env_get_ulong("fdtcontroladdr", 16,(uintptr_t)gd->fdt_blob); # endif #endifreturn fdtdec_prepare_fdt(); }

    該函數主要做了一下幾件事情

  • 對于集成的dtb的u-boot,使用__dtb_dt_begin符號來獲取dtb地址,如果是分離式的,通過_end符號來獲取dtb地址,同時也支持通過環境參數fdtcontroladdr來配置
  • 然后通過fdtdec_prepare_fdt來對fdt進行合法性檢查,判斷dtb是否存在,以及是否有四個字節對齊。然后再調用fdt_check_header看看頭部是否正常,fdt_check_header主要是檢查dtb的magic是否正確
  • int fdtdec_prepare_fdt(void) {if (!gd->fdt_blob || ((uintptr_t)gd->fdt_blob & 3) ||fdt_check_header(gd->fdt_blob)) { #ifdef CONFIG_SPL_BUILDputs("Missing DTB\n"); #elseputs("No valid device tree binary found - please append one to U-Boot binary, use u-boot-dtb.bin or define CONFIG_OF_EMBED. For sandbox, use -d <file.dtb>\n"); # ifdef DEBUGif (gd->fdt_blob) {printf("fdt_blob=%p\n", gd->fdt_blob);print_buffer((ulong)gd->fdt_blob, gd->fdt_blob, 4,32, 0);} # endif #endifreturn -1;}return 0; }

    4.2 為dtb分配新的內存地址空間

    當使用CONFIG_OF_EMBED方式時,也就是dtb集成在uboot中的時候,relocate uboot過程中也會把dtb一起relocate,所以這里就不需要處理。當為分離式要為該dtb在內存中分配一片空間即可

    static int reserve_fdt(void) { #ifndef CONFIG_OF_EMBED/** If the device tree is sitting immediately above our image then we* must relocate it. If it is embedded in the data section, then it* will be relocated with other data.*/if (gd->fdt_blob) {gd->fdt_size = ALIGN(fdt_totalsize(gd->fdt_blob) + 0x1000, 32);gd->start_addr_sp -= gd->fdt_size;gd->new_fdt = map_sysmem(gd->start_addr_sp, gd->fdt_size);debug("Reserving %lu Bytes for FDT at: %08lx\n",gd->fdt_size, gd->start_addr_sp);} #endifreturn 0; }static int reloc_fdt(void) { #ifndef CONFIG_OF_EMBEDif (gd->flags & GD_FLG_SKIP_RELOC)return 0;if (gd->new_fdt) {memcpy(gd->new_fdt, gd->fdt_blob, gd->fdt_size);gd->fdt_blob = gd->new_fdt;} #endifreturn 0; }

    5. 參考文檔:

    https://blog.csdn.net/kunkliu/article/details/82707282
    https://blog.csdn.net/thisway_diy/article/details/84338249

    總結

    以上是生活随笔為你收集整理的奇小葩讲设备树(3/5)-- Linux设备树详解(三)u-boot设备树的传递的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。