天天看點

AliOS Things核心延遲加載技術一、概述二、作業系統可執行程式的組成三、延遲加載四、總結開發者技術支援

一、概述

在某些應用場景中,要求系統能快速啟動。從使用者視角看,隻有當系統的應用邏輯開始運作的時候,才算啟動完成。是以,啟動時間并不隻是從系統上電到作業系統完成初始化,還包從初始化完成到基本功能開始運作的時間。比如IP Camera要求從上電到第一幀穩定出圖的時間小于250ms,這個啟動時間包含了第一幀圖像的采集與顯示。

本文闡述了AliOS Things上的核心延遲加載技術,可有效降低系統啟動時間。

二、作業系統可執行程式的組成

作業系統的可執行程式主要包含text、rodata、data、bss段。其中text存放代碼;rodata段存放隻讀資料,比如字元串;data段存放初始化為非0的全局變量;bss段存放未初始化和初始化為0的全局變量。

編譯生成的可執行程式bss段上并沒有實質性内容,隻需在OS初始化時将其對應的記憶體區域全部清0即可,是以生成的系統鏡像隻包含text、rodata、data段。

AliOS Things核心延遲加載技術一、概述二、作業系統可執行程式的組成三、延遲加載四、總結開發者技術支援

編譯生成系統鏡像後,用燒錄器将鏡像燒寫到Flash上。當系統上電或RESET時,首先運作BootLoader,它從FLASH讀取系統鏡像,并将其寫到指定的RAM區域,然後跳轉到系統入口。

為了盡早暴露問題,提高系統的穩定性,作業系統通常根據段的特點設定其所在記憶體的屬性。text段設定為隻讀可執行,這樣往該區域寫資料将直接觸發異常,避免指令被誤修改引發不可預知的問題。rodata段也類似,作業系統隻會從該段讀取資料不會往該段寫資料,是以設定為隻讀屬性。

三、延遲加載

讀取Flash較為耗時,以讀速度20MB/s的flash為例,BootLoader讀取2MB核心鏡像需要約100ms。對于需在250ms内出圖的IP Camera應用來說,這個時間已經耗去40%,必須降低該時間。

從作業系統初始化到啟動完成并不需要所有的代碼段與資料段。是以可以把核心的加載操作分為兩個階段,第一階段由BootLoader加載,包括作業系統啟動需要的代碼和資料。第二階段在作業系統完成啟動後,由作業系統自己把鏡像剩餘部分加載到記憶體。各個階段的如下:

AliOS Things核心延遲加載技術一、概述二、作業系統可執行程式的組成三、延遲加載四、總結開發者技術支援

具體而言,延遲加載技術通過連結腳本将OS鏡像分為啟動加載和延遲加載兩部分。從原始的text、rodata、data段中分離出延遲加載的post_text、post_rodata、post_data段。其中text、rodata、data段由BootLoader加載,post_text、post_rodata、post_data段由作業系統加載。具體劃分如下圖所示:

AliOS Things核心延遲加載技術一、概述二、作業系統可執行程式的組成三、延遲加載四、總結開發者技術支援

連結腳本有兩種方式來支援上述核心鏡像布局。

3.1、正向選擇

連結腳本文法如下:

archive:file (.segment)

其中,archive是庫名,通常是.a為字尾的庫。file是庫内檔案,通常為.o字尾的目标檔案,file也可以省略,表示連結archive内的所有檔案。archive:file也可以用通配符*,表示連結所有的檔案。通過該語句可以指定隻連結某個庫的段或連結所有庫的段。是以可在連結腳本中先連結啟動加載部分的代碼與資料,然後再連結剩餘部分。示例如下:

/* 連結啟動加載部分 */

  1. __text_start = .;
  2. .text :
  3. {
  4. kernel.a:(.text .text*)
  5. }
  6. .rodata :
  7. kernel.a:(.rodata .rodata*)
  8. .data :
  9. kernel.a:(.data .data*)

/* 連結剩餘部分 */

  1. .post_text :
  2. __post_text_start = .;
  3. *(.text .text*)
  4. __post_text_end = .;
  5. .post_rodata :
  6. __post_rodata_start = .;
  7. *(.rodata .rodata*)
  8. __post_rodata_end = .;
  9. .post_data ALIGN(0x1000):
  10. __post_data_start = .;
  11. *(.data .data*)
  12. __post_data_end = .;
  13. .bss :
  14. *(.bss .bss*)

3.2、反向選擇

如果啟動加載部分的庫比較多,且很難清理出一個完整的清單。那麼可以利用連結腳本提供的EXCLUDE_FILE關鍵字反向選擇。即把可以放到延遲加載部分的庫梳理出來,然後從第一部分剔除。EXCLUDE_FILE文法如下:

EXCLUDE_FILE (archive0 archive1 archive2) *(.segment)

EXCLUDE_FILE語句一次可以指定排除多個庫。示例如下:

  1. EXCLUDE_FILE(post.a) *(.text .text*)
  2. EXCLUDE_FILE(post.a) * (.rodata .rodata*)
  3. EXCLUDE_FILE(post.a) * (.data .data*)

連結腳本中定義了符号text_start,同時為延遲加載的段定義了三組符号:post_text_start/post_text_end,post_rodata_start/post_rodata_end,post_data_start/post_data_end。系統啟動後可以根據這些符号确定加載到記憶體的位置,以及設定相應的讀寫屬性。可以根據post_text_start-__text_start的偏移值計算出指定延遲加載段在flash中的偏移。

在實際項目中,通過上述反向選擇方式,BootLoader隻需加載原鏡像的60%,BootLoader耗時從114ms降為72ms。

在代碼和資料被加載前,存放延遲加載段的記憶體上的值是随機值,是以該記憶體區域的屬性宜在加載前設定,以避免誤通路該區域産生不可預知的問題。作業系統從Flash加載延遲部分的流程如下。它将根據是否使能延遲加載功能來決定是否從flash讀取延遲加載的段。

AliOS Things核心延遲加載技術一、概述二、作業系統可執行程式的組成三、延遲加載四、總結開發者技術支援

最後,還有一個問題需要解決:BootLoader如何獲得第一部分的加載長度。第一種方式是靜态配置,即配置BootLoader源碼的加載長度宏。這種方式實作簡單,适合在核心鏡像變化不大的情況下使用。第二種方式是建構體系自動探測。編譯生成核心鏡像後,建構體系讀取連結時生成的map檔案,然後擷取第一部分加載長度,并設定BootLoader的編譯宏。第三種方式是在核心鏡像頭部存放第一部分加載長度的資訊,BootLoader先讀取核心鏡像頭部,獲得第一部分的加載長度後,再繼續加載。

四、總結

本文闡述了AliOS Things上的核心延遲加載技術。提供了兩種調整核心鏡像的方式,可有效降低啟動時間。

開發者技術支援

如需更多技術支援,可加入釘釘開發者群,或者關注微信公衆号

AliOS Things核心延遲加載技術一、概述二、作業系統可執行程式的組成三、延遲加載四、總結開發者技術支援

更多技術與解決方案介紹,請通路阿裡雲AIoT首頁

https://iot.aliyun.com/

繼續閱讀