3. 理論與實作背景
3.6 Component
要了解 eCos,則了解元件的基礎架構 非常重要。元件基礎架構專為滿足嵌入式 系統和嵌入式設計的相關需求而存在。設 計的 eCos 元件基礎架構可以控制元件達
到最小記憶體使用、允許使用者控制時間 行為以符合即時性、和使用一般的程式語 言,如 HAL 的實作就包括 C、C++、和組 語。大部份嵌入式系統本身所支援的功能 比特定應用程式需要的功能更多。通常系 統內多餘的程式碼支援的功能,卻是嵌入 式程式開發者所不關心也不需要的,而且 更多的程式碼使產生錯誤的機會更大。舉 Hello world 程式為例。很多即時作業系統 支援了 mutexes, task switch,卻是在此簡 單程式所不需要的。eCos 給開發者最終 run time 元件的控制權,沒必要的功能可 以輕易地被移除。eCos 系統的大小可由幾 百 Byte 到幾百 K-Byte 彈性地增減。
即時嵌入式系統的標準功能包括包 括插斷處理,例外處理,錯誤處理,執行 緒同步,排程,計時器,和裝置驅動程式。
這些標準的功能在 eCos 中由各個元件負 責,稱之為標準元件。這些標準元件由即 時 kernel 為核心組成。列出元件如下:
Hardware Abstraction Layer (HAL)—
硬體抽象層隱藏每一個支援的 CPU 和平台的特別特徵,以至於 kernel 和 其他 run time 元件都是在一個容易移 植的形式。
Kernel—Kernel,包括記憶體、快取、
插斷處理、例外處理,執行緒、同步 機制,排程器,計時器,計數器和鬧 鐘。
ISO C and math libraries—常用標準程 式庫。
u-ITRON and POSIC —μITRON and POSIX 應用程式者介面
Device drivers—裝置驅動程式,支援 廣 泛 的 裝 置 標 準 序 列 埠 控 制 器 , Ethernet 網路控制器,PCMCIA 控制 器,USB 控制器,PCI 控制器,和 Flash Rom 等等。
RebBoot ROM monitor — RedBoot ROM monitor 是一個 Bootstrap 應用程 式,為了方便移植它使用 eCos HAL,
而且他可以透過序例埠和網路兩種 booting 方式。
GNU debugger (GDB) support—GNU 除錯器,提供目標平台軟體可以和 GDB host 溝通,對應用程式除錯。
其 它 軟 體 元 件 — SNMP, HTTP, TFTP, 和 FTP。
eCos kernel 或 是 應 用 程 式 都 是 在 supervisor 模式下執行,所以在 eCos 系統 中,user 模式和 kernel 模式並沒有區分。
Fig. 8為 eCos 系統區塊圖[18]:
Fig. 8. eCos 系統區塊圖
下面段落將介紹三個重要的 eCos 元 件,分別是 HAL、kernel、及 RedBoot。
i. HAL
HAL 將處理器架構的底層硬體和平 台的底層硬體抽象化可以有效率地移植 eCos kernel 到別的平台。為了移植 eCos 到新的平台,主要的工作是修改 HAL 以 適應支援新的硬體平台,因此了解 HAL 這個軟體元件的架構相當重要。HAL 有一 般化的 API,把特殊的硬體行為封裝起 來,由硬體來完成設計的功能,並且允許 應用層直接存取硬體和任何架構特徵。例 如有同樣意義的 interrupt,實際執行插斷 的程序依不同架構而相異。為了使 HAL 的可用性達到最廣的範圍,HAL 是用 C 語 言和組合語言實作。另外為了 HAL 介面 實作上的效率,HAL 是用 C/ CPP 巨集實 作,可以使用 inline C 語言,inline 組合語 言,或外部呼叫 C 語言和外部呼叫組合語 言。
HAL 含 概 三 個 不 同 的 模 組 : Architecture HAL, Variant HAL, 和 Platform HAL。
第一個 HAL 模組定義 architecture。每 個被 eCos 支援的處理器家族都被認定為
不同的 architecture。每個 architecture 模組 會包含所需的 CPU 啟動程式碼,interrupt delivery 程式碼,context switching 程式碼 和其他指令集架構特殊功能的程式碼。第 二個 HAL 模組定義了 variant。一個 variant 是一個處理器家族當中的一個特定處理 器。例如定義不同的 on-chip MMU 或是快 取 , 也 處 理 任 何 晶 片 上 的 週 邊 , 如 記 memory controller 和 interrupt controller。第 三個 HAL 副模組是定義 platform。一個 platform 是一塊特別的硬體平台,它包括 選擇處理器的 architecture 和 variant。傳統 上這個模組包括平台啟動,晶片選擇設 定,interrupt controller 和計時裝置。這三 層的介定不必很清楚,因為各模組的功能 性在不同硬體平台有不同的設定。例如快 取和 MMU 可以在 architecture HAL 或 variant HAL。
Fig. 9是 HAL 啟動期間副程式被引用 的流程圖[18]。啟動程序可能會依不同架 構和平台的使用有些微的不同。此外,啟 動程序可能也因為 HAL 的一些設定選項 的不同而與此流程圖有所差異。
Fig. 9. HAL 啟動流程圖
1. 系統在電力週期啟動之後開始運作。此 啟動程序也是 soft reset 的啟動方式。
2. 在 hard reset 或 soft reset 發生後,處理 器會跳到 reset vector。Reset vector 對處 理 器 會 用 到 的 最 少 數 量 暫 存 器 做 設 定,使得系統可以繼續初始化程序。
3. 接 著 reset vector 會跳到 _start , 是 HAL 初始化的主要開啟點。
4. 呼叫 hal_cpu_init,這個程式設定處理 器的暫存器,如關閉指令和資料快取。
確保對於剩下的初使化程序而言,處理 器在一個正常的狀態。
5. 下 一 個 被 呼 叫 的 副 程 式 叫 hal_hardware_init,硬體設定包含快取 設定,設定插斷暫存器為預設狀態,關 閉處理器的 watchdog,設定即時時鐘 暫存器,和設定晶片選擇暫存器,這些 都是基於平台特有的硬體而不同。
6. 接著是設定 interrupt stack 的區域,在
interrupt 發生時可以儲存處理器狀態。
在整個初始化程序中,都是利用這一段 stack 做 為 呼 叫 C 副 程 式 會 用 到 的 stack。因為此時 interrupt 是關閉的,不 會有衝突發生。
7. 下一步執行 hal_mon_init 程式,確保預 設的 exception 處理器安裝給每一個處 理器支援的例外情況。
8. 接著清理 BSS 部份,它包含所有未初 始化的區域和全域變數。
9. 然後設定 stack,以致於 C 程式呼叫可 以被實行,不再使用 interrupt stack。
10. 呼 叫 hal_platform_init 或 呼 叫 hal_if_init,初始 virtual vector table。
11. 初始化 MMU,處理 logical addresses 和 physical addresses 的轉換,同時提供 保護和快取機制。
12. 接著啟動指令快取和資料快取。
13. 執 行 hal_IRQ_Init , 設 定 Communications Processor Module (CPM),它接受和按優先順序處理內外 部 interrupt。
14. 下 一 步 , cyg_hal_invoke_constructors 呼 叫 所 有 global C++ constructors 。 Linker 會提供 global constructor 的名 單,cyg_type.h 則用巨集定義這份名單 上 constructor 被呼叫的順序。
15. 如果設定當中有除錯環境而且 ROM monitor 沒有提供除錯支援,下一個要 呼叫的是 initialize_stub。initialize_stub 安裝 standard trap handler 並把硬體設 定在適合除錯的狀態。
16. 最 後 一 個 步 驟 是 把 控 制 權 轉 給 kernel。cyg_start 就是控制權由 HAL 轉 入 kernel 的點。
ii. The Kernel
Kernel 是 eCos 系統的中樞。Kernel 提供即時作業中的標準功能例如插斷和例 外處理、排程、執行緒和同步。在 eCos 系統下可以對這些組成 kernel 的標準功能 元件完全地設定,以達到特殊的需要。eCos kernel 以 C++實作,允許用 C++寫成的應 用 程 式 直 接 透 過 C kernel API 介面和 kernel 溝 通 。 eCos kernel 也 支 援 標 準 u-ITRON 和 POSIX compatibility layers 介
面。為了符合即時性需求,eCos kernel 依 循下列準則發展:
Interrupt latency—interrupt 回應和開 始 執 行 ISR 的 時 間 要 少 而 且 deterministic。
Dispatch latency—執行緒準備完成可 以執行的狀態到開始執行的時間要少 並且 deterministic。
Memory footprint—對一個設定完成 的系統,程式或資料所需求的記憶體 資源要保持最小化和 deterministic。而 且要確保嵌入式系統的動態記憶體配 置不會使用超出所有記憶體的量。
Deterministic kernel primitives—所有 kernel 的行為都要是可預期的且符合 即時性的需求。
eCos kernel API 不回傳錯誤訊息。在 嵌入式系統當中,處理錯誤回傳訊息會導 致許多問題,如消耗貴重的執行週期和程 式空間來檢查回傳的訊息。為了程式發展 的便利性 eCos kernel 提供 assertion,它可 以被 eCos package 開啟或關閉。傳統上,
assertion 在除錯階段會開啟,允許 kernel 程式顯示錯誤檢查。如果錯誤產生了,就 會回傳一個 assertion 失敗並且會中止應用 程式。除錯程序完畢之後,assertion 就在 kernel package 之中關閉。此方法有很多好 處,如限制程式中錯誤檢查的 overhead,
消除應用程式錯誤檢查的需要;如果有一 個錯誤發生,應用就被暫停,可以立即知 道發生錯誤的地點,而不是依賴回傳訊息 再去檢查。
kernel 提供開發多執行緒應用所需的 重要功能。
在硬體都啟動完成之後,HAL 中呼叫 Kernel 啟動的程序。cyg_start 是 kernel 啟 重程序的啟始點。它呼叫其他預設的啟動 程式來處理不同初始化的任務。只要在應 用 程 式 之 中 提 供 相 同 程 式 名 稱 , 預 設 kernel 啟動程式可以被簡單的替換,以完 成使用者特殊的初始化工作。Kernel 啟動 程序如圖 5 [18]。
Fig. 10. Kernel 啟動程序
Core kernel 啟 動 程 式 , cyg_star 。 Cyg_start 之 後 下 一 個 被 呼 叫 的 程 式 是 cyg_prestart 。 它 預 設不完成任何初始任 務,讓使用者自行決定在其他系統初始化 之前該被完成的初始化都可以在這裡執 行。接著呼叫 cyg_package_start,在應用 程式開始之前初始化將用到的 package,如 u-ITRON 和 ISO C 程式庫。之後呼叫 cyg_user_start,它是應用程式的進入點。
建議 cyg_user_start 被使用來完成任何應 用 指 定 的 初 始 化 、 產 生 執 行 緒 、 產 生 synchronization primitives、設定鬧鐘、和 註 冊 任 何 需 要 的 interrupt handlers 。 當 cyg_user_start return 時會自動執行呼叫排 程器。
iii. The Scheduler
eCos kernel 的核心是排程器。排程器 的工作是去選擇最適合的執行緒執行,提 供 執 行 中 執 行 緒 同 步 的 機 制 和 控 制 interrupt 在執行緒執行的影響。在排程器 程 式 程 式 碼 執 行 期 間 , 不 會 關 閉 interrupt,因為 interrupt latency 十分短。排 程器內存在一個計數器,它決定排程器是 自由地執行或是關閉。如果計數器非零,
排程器就被關閉,當計數器回到零,排程 就會啟動。在 ISR 執行期間,HAL 預設 interrupt handler 會修改計數器來停止排程 動作。執行緒也有能力開關排程器。
a. Multilevel Queue Scheduler
MLQ 排程器允許同一個 priority 有多 個執行緒可執行。priority 可由 1 設定到 32,對應到數字是 0(最高)到 31(最低)。
MLQ 排 程 器 允 許 不 同 priority 可 有 preemption。Preemption 是指低 priority 執 行緒的被 context switch 暫停執行,因此高 priority 的 執 行 緒 開 始 執 行 。 在 同 一 個 priority 中,MLQ 排程器有 time-slicing 功 能。每一個執行緒在一段特定的時間內執 行稱之為 time-slicing,統系開發者可以設 定 time-slicing 的長度。MLQ 排程器的駐 列實作上是用 double linked circular list 來 連結同一個層級的不同執行緒和不同層級 的執行緒。
b. Bitmap Scheduler
Bitmap 排程器的執行緒也是有多個 priorities ; 然 而 每 層 級 只 能 有 一 個 執 行
Bitmap 排程器的執行緒也是有多個 priorities ; 然 而 每 層 級 只 能 有 一 個 執 行