將操作系統移植到新的晶元架構的經驗
曾經有人問我,為什麼計算機被稱為「計算機」,它們做的事情可遠不止計算數字。一台現代的個人電腦可以瀏覽互聯網、播放音頻和視頻、為視頻遊戲和電影生成漂亮的圖形、模擬和預測複雜的天氣模式和流行病風險、將建築和工程藍圖變為現實等等。
計算機之所以能做到這些,是因為所有這些問題都可以歸結為數字方程,而計算機的 CPU —— 其中央處理單元 —— 實際上不過是一個簡單的計算器。
為了讓 CPU 向硬碟驅動器發送信號以寫入數據,或向顯示器發送信號以顯示圖像,它必須接收指令。這些指令是以 「代碼」 的形式出現的,這是一種簡明的說法,即必須有人寫一個 程序 ,與CPU 「說」 同樣的語言。CPU 理解的是 機器語言,這是一個大多數人都無法理解的比特陣列,大多數人都不可能手動寫出來。相反,我們使用像 C、C++、Java、Python 等編程語言。這些語言被解析並編譯成機器語言,然後交付給 CPU。
如果你試圖用一種它不理解的語言來指示 CPU,它不知道該怎麼做。你可以通過嘗試用 x86_64 RHEL 鏡像啟動 樹莓派 來體驗這種誤傳嘗試的尷尬結果。如果它能工作就好了,但是不能。
將一個操作系統移植到一個新的架構上
RT-Thread 項目 為嵌入式系統程序員提供了一個開源的操作系統(OS)。嵌入式領域是非常多樣化的,有很多物聯網(IoT)、定製工業和業餘設備。RT-Thread 的目標是使嵌入式編程對每個人來說都很容易,無論你使用什麼設備。有時,這意味著要將一個操作系統移植到一個新的架構上,不管是用於相同架構但指令集略有不同的的晶元,還是用於全新的架構。
一開始處理這個問題可能會有點嚇人 —— 你可能不知道從哪裡開始或如何開始。這篇文章收集了 RT-Thread 維護者在將 RTOS 移植到新的晶元架構時學到的經驗。
你在開始之前需要知道什麼
這裡是一個看似難以逾越的過程的高屋建瓴的觀點。這對你的項目來說可能有所不同,但從概念上來說,這是相對普遍的,即使一些具體的細節是不同的:
- 準備好一個 C 語言的執行環境
- 確認可以通過串列埠發送和接收字元
- 確認上下文切換代碼可以工作
- 獲取支持的硬體定時器
- 確認中斷程序可以通過串口接收和解析數據
執行模式
對於大多數先進的體系結構,操作系統和用戶應用程序運行在不同的許可權級別上。這可以防止有功能故障的代碼影響操作系統的集成和安全。例如,在 ARMv7-A 架構中,操作系統通常在系統模式下運行,而在 ARMv8-A 中,操作系統可以在 EL2 或 EL3 許可權級別上運行。
通常情況下,晶元在通電時以最高許可權級別執行啟動代碼。但在此之後,操作系統會將特權級別切換到其目標模式。
1、執行 C 代碼
這一步的關鍵動作是將 塊起始符號 (.bss)部分設置為零,並設置堆棧指針。
在 C 語言的實現中,未初始化的全局變數和靜態變數通常存儲在 .bss 部分,它不佔用存儲設備的任何空間。當程序被載入時,相應的空間被分配到內存中,並被初始化為零。當操作系統啟動時,它必須自己做這項工作。
另一方面,操作系統必須初始化堆棧空間並設置堆棧指針。由於 C 語言程序在進入和退出函數時在堆棧上保存和恢復局部變數,所以在調用任何 C 函數之前必須設置堆棧指針。RT-Thread 必須為每個新創建的線程做這個步驟。
2、至少使用一個串列驅動器
RT-Thread 通過串口輸出信息和日誌,這也有助於在移植過程中對代碼進行調試。在這個階段,通過串口 接收 數據是不必要的。當我們第一次在串口上看到我們友好的、熟悉的 RT-Thread 的標誌時,我們就知道我們走對了路!
3、確認上下文切換邏輯
一個任務的上下文是它的整個執行環境,它包含通用寄存器、程序計數器、堆棧幀的位置等等。當一個新的線程被創建時,RT-Thread 必須手動分配和設置它的上下文,這樣調度器就可以切換到新的線程,就像它對其他線程一樣。
有三件事需要注意:
- 首先,當 RT-Thread 啟動時,默認情況下中斷是禁用的。當任務調度器第一次被啟用時,它們就會被啟用;這個過程是在上下文切換期間用彙編語言實現的。
- 第二,當一個線程退出時,下一個調度將開始,這時擁有的資源會被空閑的線程回收。
- 第三,數據被推入堆棧的順序必須與從堆棧中彈出數據的順序一致。
一般來說,你希望正常進入主函數和 msh 控制台。然而,在這個階段無法實現輸入控制,因為串列輸入中斷還沒有實現。當串列中斷實現後,就可以進行 msh 輸入了。
4、設置定時器
RT-Thread 需要一個定時器來定期產生中斷;它被用來計算自系統啟動以來所經過的「滴答」。計數器的編號用於提供軟體中斷功能,並指示內核何時開始調度一個任務。
設置時間片的值可能是一件棘手的事情。它通常是 10ms 到 1ms。如果你在一個慢速的 CPU 上選擇一個小的時間片,大部分時間就會花在任務切換上 —— 不利於完成其他事情。
5、確認串口工作正常
在這一步,我們通過串口與 RT-Thread msh 進行交互。我們發送命令,按回車鍵,然後看著 msh 執行命令並顯示結果。
這個過程通常不難實現。不過,有一點要提醒大家。在某些平台上,在處理完串口中斷後,別忘了清除中斷標誌。
一旦串口工作正常,移植過程基本上就完成了。
實踐
為了將你的項目移植到不同的晶元架構上,你需要非常清楚地了解你所針對的晶元的架構。熟悉你的項目中最關鍵的部分的底層代碼。通過對照晶元的手冊結合大量的實際工作經驗,你會了解晶元的特權模式、寄存器和編譯方法。
如果你沒有需要移植到新晶元的項目,請加入我們;RT-Thread 項目總是需要幫助將 RTOS 移植到新的晶元上!作為一個開源項目,RT-Thread 正在改變開源嵌入式編程的面貌。請在 RT-Thread 俱樂部介紹你自己並尋求幫助!
本文基於 DEV 社區上的 如何將操作系統移植到不同的晶元架構上?,並經許可轉載。
via: https://opensource.com/article/21/5/port-chip-architectures
作者:Alan Smithee 選題:lujun9972 譯者:wxy 校對:wxy
本文轉載來自 Linux 中國: https://github.com/Linux-CN/archive