一 前言
什么是Circle?
Circle是一個叫rsta2的大佬用C++寫的bare-metal的樹莓派驅動框架,同時支持現存的幾乎所有版本樹莓派,能夠驅動樹莓派上的大部分設備,包SD卡控制器、有線和無線網卡、GPIO、USB控制器及一些常用USB設備等。
這些設備驅動中有一些是rsta2參考Linux或其它bare-metal的實現自己寫的,還有一些是他直接從其它系統移植過來的。各驅動對外封裝成了C++類的形式,可以按需對其實例化和使用。對于在樹莓派上編寫自制操作系統并且希望盡快驅動一些設備的場景,將Circle整個移植過來是非常值得考慮的選項。當然,需要注意的是,Circle的開源協議是GPLv3,具有傳染性,應該把它作為系統的非必要組件來使用。
本文干了什么?
本文將簡要記述將Circle驅動框架移植到一個自制微內核操作系統(實際上是實驗室項目),作為用戶態驅動進程的過程。
由于只是簡要地記錄移植過程和經驗總結,本文不會深入到每一個具體的細節,如果你恰好有相似的需求,除了參考本文,還需要具體地去研究Circle的代碼,并根據具體情況具體分析。
二 確定需求
首先一開始不要盲目移植,先確定一下自己需要Circle中的哪些設備驅動,比如說,如果你只是需要USB相關驅動,那么在移植過程中可以不關心WLAN那塊是否有不兼容。
然后跑一些Circle提供的sample,確定Circle確實可以滿足需求。
三 移植基本部分
這部分包括一些非常必要的組件,比如mailbox訪問,許多驅動都需要通過mailbox獲取信息或申請資源等。這部分移植完成后,將可以在啟動時獲取機器信息,并點亮LED燈。
具體地,主要需要做下面這些事情:
1.修改Rules.mk和Makefile,去掉任何boot相關的代碼。
2.重新實現一些模塊,去除需要特權指令的地方,并使用用戶態lib提供的功能代替:
assert:assert失敗后不要真的關機或重啟,可以exit;
interrupt:一開始可簡單打印點內容,不用真的實現;
logger:改為printf輸出;
new:使用malloc分配;
sysinit:提供假實現;
timer:使用nanosleep實現SimpleusDelay;
memory:CMemorySystem類可以直接去掉,一開始會有地方用到CMemorySystem::GetCoherentPage;
改用系統提供的分配物理上連續的non-cacheable內存的接口。
3.Circle進程啟動時將物理地址的外設區域直接對等映射到當前進程的虛擬地址空間,這樣將不需要改動Circle中通過MMIO訪問外設時使用的地址。
經過一些調試后,可以點亮LED燈,輸出日志到stdout,然后退出(需要編寫適當的kernel.cpp,可參考sample),這意味著簡單的MMIO已經可以了。
四 驅動屏幕
這一步同樣需要重新實現一些模塊:
synchronize:主要是刷cache相關操作;
bcmframebuffer:向GPU申請frame buffer后需要將其映射到當前進程的虛擬地址。
經過一些調試后,可以通過HDMI輸出內容到屏幕。
五 模擬實現Timer
對于一些稍復雜的驅動,例如USB和WLAN,會依賴timer獲取當前tick,因此需要重新實現timer模塊。
具體地,可以在CTimer::Initialize中創建一個新的線程,每隔10ms(利用nanosleep等函數)調用一次CTimer::InterruptHandler,其它代碼幾乎不用改動。此外,還需要實現CTimer::GetClockTicks以獲得當前 tick數。
經過一些調試后,輸出的日志中能夠包含當前時間,此時說明timer基本實現對了。
六 解決內存相關的一系列問題
許多驅動在運行的過程中需要分配內存以供外設進行DMA,同時又需要在進程內訪問這塊內存以讀寫跟外設交互的數據。因此,這塊內存既需要能通過虛擬地址訪問,又需要能獲取到物理地址,同時在物理地址上連續且non-cacheable。malloc是不能滿足這個需求的,因為malloc只保證分配出的內存虛擬地址連續,不能保證物理地址連續,也無法配置成non-cacheable。
要解決這個問題,需要內核提供分配物理上連續且non-cacheable的內存并映射到虛擬地址空間的相關系統調用,然后再在Circle中利用這些系統調用重新實現內存相關模塊。其實在前面已經粗略地實現了,但在這一步需要確保實現的正確性。對Circle的修改主要涉及CMemorySystem::GetCoherentPage、DMA_BUFFER、BUS_ADDRESS、new(HEAP_DMA)的定義及使用它們的地方。
七 用戶態處理中斷
對于像USB和WLAN這些需要利用中斷通知操作系統發生了特定事件的設備,還需要把之前虛假實現的interrupt模塊實現對。
首先要求內核提供讓特定用戶態進程處理特定IRQ的能力,具體來說就是驅動進程要能夠通過系統調用注冊一個函數作為特定編號的IRQ的用戶態處理函數,然后內核在收到IRQ后調用此函數來處理。
接著重新實現interrupt模塊,把CInterruptSystem::ConnectIRQ改為使用上述注冊IRQ處理函數的系統調用,暫時用不到的函數可以不實現,比如與FIQ相關的。
八驅動USB
Timer、DMA buffer、中斷這幾個重要的部分移植完成后,比較容易就可以驅動USB控制器,進而可以檢測并驅動USB鍵盤、鼠標、存儲、串口轉換器等設備,對于樹莓派3,還可以驅動有線網卡(LAN7800)。
九其它驅動
到目前為止已經移植了大部分驅動所需的運行環境,之后的移植工作主要看具體的需求了,比如如果需要網絡協議棧,還要重新實現sched模塊,里面包括線程抽象、調度、線程同步機制等。
審核編輯:劉清
-
控制器
+關注
關注
112文章
16332瀏覽量
177808 -
Linux系統
+關注
關注
4文章
593瀏覽量
27392 -
GPIO
+關注
關注
16文章
1204瀏覽量
52052 -
C++語言
+關注
關注
0文章
147瀏覽量
6989 -
樹莓派
+關注
關注
116文章
1706瀏覽量
105607
原文標題:移植樹莓派驅動框架Circle到自制操作系統
文章出處:【微信號:Ithingedu,微信公眾號:安芯教育科技】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論