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

歡迎訪問 生活随笔!

生活随笔

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

linux

linux内核设备树及编译--完整清晰

發布時間:2023/12/15 linux 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 linux内核设备树及编译--完整清晰 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1、設備樹的概念

? ? ? ? 在內核源碼中,存在大量對板級細節信息描述的代碼。這些代碼充斥在/arch/arm/plat-xxx和/arch/arm/mach-xxx目錄,對內核而言這些platform設備、resource、i2c_board_info、spi_board_info以及各種硬件的platform_data絕大多數純屬垃圾冗余代碼。為了解決這一問題,ARM內核版本3.x之后引入了原先在Power?PC等其他體系架構已經使用的Flattened?Device?Tree。

? ? ? ? 開源文檔中對設備樹的描述是,一種描述硬件資源的數據結構,它通過bootloader將硬件資源傳給內核,使得內核和硬件資源描述相對獨立。

? ? ? ? ?Device?Tree可以描述的信息包括CPU的數量和類別、內存基地址和大小、總線和橋、外設連接、中斷控制器和中斷使用情況、GPIO控制器和GPIO使用情況、Clock控制器和Clock使用情況。

? ? ? ? ?另外,設備樹對于可熱插拔的設備不進行具體描述,它只描述用于控制該熱插拔設備的控制器。

? ? ? ? ?設備樹的主要優勢:對于同一SOC的不同主板,只需更換設備樹文件.dtb即可實現不同主板的無差異支持,而無需更換內核文件。

(注:要使得3.x之后的內核支持使用設備樹,除了內核編譯時需要打開相對應的選項外,bootloader也需要支持將設備樹的數據結構傳給內核。)

2、設備樹的組成和使用

?

? ? ? ? 設備樹包含DTC(device?tree?compiler),DTS(device?tree?source和DTB(device?tree?blob)。

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

2.1 DTS和DTSI(源文件)

? ? ? ? .dts文件是一種ASCII文本對Device?Tree的描述,放置在內核的/arch/arm/boot/dts目錄。一般而言,一個.dts文件對應一個ARM的machine。

? ? ? ? ?由于一個SOC可能有多個不同的電路板(??.dts文件為板級定義,?.dtsi文件為SoC級定義),而每個電路板擁有一個?.dts。這些dts勢必會存在許多共同部分,為了減少代碼的冗余,設備樹將這些共同部分提煉保存在.dtsi文件中,供不同的dts共同使用。.dtsi的使用方法,類似于C語言的頭文件,在dts文件中需要進行include?.dtsi文件。當然,dtsi本身也支持include?另一個dtsi文件。

2.2?DTC (編譯工具)

? ? ? ? DTC為編譯工具,dtc編譯器可以把dts文件編譯成為dtb,也可把dtb編譯成為dts文件。在3.x內核版本中,DTC的源碼位于內核的scripts/dtc目錄,內核選中CONFIG_OF,編譯內核的時候,主機可執行程序DTC就會被編譯出來。?即scripts/dtc/Makefile中

  • hostprogs-y?:=?dtc
  • always?:=?$(hostprogs-y)??
  • ? ? ? ? 在內核的arch/arm/boot/dts/Makefile中,若選中某種SOC,則與其對應相關的所有dtb文件都將編譯出來。在linux下,make?dtbs可單獨編譯dtb。以下截取了TEGRA平臺的一部分。

  • ifeq?($(CONFIG_OF),y)
  • dtb-$(CONFIG_ARCH_TEGRA)?+=?tegra20-harmony.dtb?\
  • tegra30-beaver.dtb?\
  • tegra114-dalmore.dtb?\
  • tegra124-ardbeg.dtb??
  • ? ? ? ? 在2.6.x版本內核中,只在powerpc架構下使用了設備樹,DTC的源碼位于內核的arch/powerpc/boot/dtc-src目錄,編譯內核后,可將DTC編譯出來,DTC編譯工具位于arch/powerpc/boot目錄下。

    2.3?DTB (二進制文件)

    ? ? ? ?DTC編譯.dts生成的二進制文件(.dtb),bootloader在引導內核時,會預先讀取.dtb到內存,進而由內核解析。

    ? ? ? ??在2.6.x版本內核中,在powerpc架構下,dtb文件可以單獨進行編譯,編譯命令格式如下:

    ?

    dtc [-I input-format] [-O output-format][-o output-filename] [-V output_version] input_filename

    參數說明

    input-format:

    - “dtb”: “blob” format

    - “dts”: “source” format.

    - “fs” format.

    output-format:

    - “dtb”: “blob” format

    - “dts”: “source” format

    - “asm”: assembly language file

    output_version:

    定義”blob”的版本,在dtb文件的字段中有表示,支持1 2 3和16,默認是3,在16版本上有許多特性改變

    (1)??Dts編譯生成dtb

    ./dtc -I dts -O dtb -o B_dtb.dtb A_dts.dts

    把A_dts.dts編譯生成B_dtb.dtb

    (2)??Dtb編譯生成dts

    ./dtc -I dtb -O dts -o A_dts.dts A_dtb.dtb

    把A_dtb.dtb反編譯生成為A_dts.dts

    ? ? ? ? 在linux 3.x內核中,可以使用make的方式進行編譯。

    2.4?Bootloader(boottloader支持)

    ????Bootloader需要將設備樹在內存中的地址傳給內核。在ARM中通過bootm或bootz命令來進行傳遞。????

    ????bootm?[kernel_addr]?[initrd_address]?[dtb_address],其中kernel_addr為內核鏡像的地址,initrd為initrd的地址,dtb_address為dtb所在的地址。若initrd_address為空,則用“-”來代替。

    ?

    3、linux內核對硬件的描述方式

    ? ? ? ?在以前的內核版本中:
    1)內核包含了對硬件的全部描述;
    2)bootloader會加載一個二進制的內核鏡像,并執行它,比如uImage或者zImage;
    3)bootloader會提供一些額外的信息,成為ATAGS,它的地址會通過r2寄存器傳給內核;
    ??? ATAGS包含了內存大小和地址,kernel command line等等;
    4)bootloader會告訴內核加載哪一款board,通過r1寄存器存放的machine type integer;
    5)U-Boot的內核啟動命令:bootm <kernel img addr>
    6)Barebox變量:bootm.image (?)


    現今的內核版本使用了Device Tree:
    1)內核不再包含對硬件的描述,它以二進制的形式單獨存儲在另外的位置:the device tree blob
    2)bootloader需要加載兩個二進制文件:內核鏡像和DTB
    ??? 內核鏡像仍然是uImage或者zImage;
    ??? DTB文件在arch/arm/boot/dts中,每一個board對應一個dts文件;
    3)bootloader通過r2寄存器來傳遞DTB地址,通過修改DTB可以修改內存信息,kernel command line,以及潛在的其它信息;
    4)不再有machine type;
    5)U-Boot的內核啟動命令:bootm <kernel img addr> - <dtb addr>
    6)Barebox變量:bootm.image,bootm.oftree


    ? ? ? ? 有些bootloader不支持Device Tree,或者有些專門給特定設備寫的版本太老了,也不包含。為了解決這個問題,CONFIG_ARM_APPENDED_DTB被引進。?
    ??? 它告訴內核,在緊跟著內核的地址里查找DTB文件;
    ??? 由于沒有built-in Makefile rule來產生這樣的內核,因此需要手動操作:
    ??????? cat arch/arm/boot/zImage arch/arm/boot/dts/myboard.dtb > my-zImage
    ??????? mkimage ... -d my-zImage my-uImage
    ??? (cat這個命令,還能夠直接合并兩個mp3文件哦!so easy!)
    另外,CONFIG_ARM_ATAG_DTB_COMPAT選項告訴內核去bootloader里面讀取ATAGS,并使用它們升級DT。

    ?

    4、DTB加載及解析過程

    ?

    ????先從uboot里的do_bootm出發,根據之前描述,DTB在內存中的地址通過bootm命令進行傳遞。在bootm中,它會根據所傳進來的DTB地址,對DTB所在內存做一系列操作,為內核解析DTB提供保證。上圖為對應的函數調用關系圖。

    ????在do_bootm中,主要調用函數為do_bootm_states,第四個參數為bootm所要處理的階段和狀態。?

    ????在do_bootm_states中,bootm_start會對lmb進行初始化操作,lmb所管理的物理內存塊有三種方式獲取。起始地址,優先級從上往下:

  • ?環境變量“bootm_low”
  • ?宏CONFIG_SYS_SDRAM_BASE(在tegra124中為0x80000000)
  • ?gd->bd->bi_dram[0].start
  • 大小:

  • ?環境變量“bootm_size”
  • ?gd->bd->bi_dram[0].size
  • ????經過初始化之后,這塊內存就歸lmb所管轄。接著,調用bootm_find_os進行kernel鏡像的相關操作,這里不具體闡述。

    ????還記得之前講過bootm的三個參數么,第一個參數內核地址已經被bootm_find_os處理,而接下來的兩個參數會在bootm_find_other中執行操作。

    ????首先,bootm_find_other根據第二個參數找到ramdisk的地址,得到ramdisk的鏡像;然后根據第三個參數得到DTB鏡像,同檢查kernel和ramdisk鏡像一樣,檢查DTB鏡像也會進行一系列的校驗工作,如果校驗錯誤,將無法正常啟動內核。另外,uboot在確認DTB鏡像無誤之后,會將該地址保存在環境變量“fdtaddr”中。

    ????接著,uboot會把DTB鏡像reload一次,使得DTB鏡像所在的物理內存歸lmb所管理:????

    • ①boot_fdt_add_mem_rsv_regions會將原先的內存DTB鏡像所在的內存置為reserve,保證該段內存不會被其他非法使用,保證接下來的reload數據是正確的;
    • ②boot_relocate_fdt會在bootmap區域中申請一塊未被使用的內存,接著將DTB鏡像內容復制到這塊區域(即歸lmb所管理的區域)

    注:若環境變量中,指定“fdt_high”參數,則會根據該值,調用lmb_alloc_base函數來分配DTB鏡像reload的地址空間。若分配失敗,則會停止bootm操作。因而,不建議設置fdt_high參數。

    ????接下來,do_bootm會根據內核的類型調用對應的啟動函數。與linux對應的是do_bootm_linux。

    • ①?boot_prep_linux

    ????????為啟動后的kernel準備參數

    • ②?boot_jump_linux

    ?

    ????以上是boot_jump_linux的片段代碼,可以看出:若使用DTB,則原先用來存儲ATAG的寄存器R2,將會用來存儲.dtb鏡像地址。

    ????boot_jump_linux最后將調用kernel_entry,將.dtb鏡像地址傳給內核。

    ?

    ????下面我們來看下內核的處理部分:

    ????在arch/arm/kernel/head.S中,有這樣一段:

    ?

    ????_vet_atags定義在/arch/arm/kernel/head-common.S中,它主要對DTB鏡像做了一個簡單的校驗。

    ?

    ????真正解析處理dbt的開始部分,是setup_arch->setup_machine_fdt。這部分的處理在第五部分的machine_mdesc中有提及。

    ?

    ????如圖,是setup_machine_fdt中的解析過程。

    • ????解析chosen節點將對boot_command_line進行初始化。
    • ????解析根節點的{size,address}將對dt_root_size_cells,dt_root_addr_cells進行初始化。為之后解析memory等其他節點提供依據。
    • ????解析memory節點,將會把節點中描述的內存,加入memory的bank。為之后的內存初始化提供條件。

    ?

    • ????解析設備樹在函數unflatten_device_tree中完成,它將.dtb解析成device_node結構(第五部分有其定義),并構成單項鏈表,以供OF的API接口使用。

    下面主要結合代碼分析:/drivers/of/fdt.c

    ?

    ?

    ?

    總的歸納為:

    ????①?kernel入口處獲取到uboot傳過來的.dtb鏡像的基地址

    ????②?通過early_init_dt_scan()函數來獲取kernel初始化時需要的bootargs和cmd_line等系統引導參數。

    ????③?調用unflatten_device_tree函數來解析dtb文件,構建一個由device_node結構連接而成的單向鏈表,并使用全局變量of_allnodes保存這個鏈表的頭指針。

    ????④?內核調用OF的API接口,獲取of_allnodes鏈表信息來初始化內核其他子系統、設備等。

    總結

    以上是生活随笔為你收集整理的linux内核设备树及编译--完整清晰的全部內容,希望文章能夠幫你解決所遇到的問題。

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