靜態映射:
內核移植時以代碼的形式硬編碼(代碼里已經把它寫固定了,即移植的時候已經設計好了要把哪個物理地址映射哪個虛擬地址),如果要更改的話必須改源代碼后重新編譯內核。開機時調用映射表建立函數,映射表建立函數。該函數根據映射表來建立linux內核的頁表映射關系;
start_kernel
setup_arch
paging_init
devicemaps_init
if (mdesc->map_io)
mdesc->map_io();
對於移植好的內核,在內核啟動時建立靜態映射表,到內核關機時銷毀,中間一直有效;
靜態映射的好處是執行效率高,壞處是始終占用虛擬地址空間;
所謂映射表其實就是頭文件中的宏定義,不同SoC,不同版本內核中靜態映射表位置、文件名可能不同。
動態映射:
驅動程序根據需要隨時動態地建立、使用和銷毀映射;
映射是短期臨時的,映射建立時,是要先申請再映射然后使用,使用完要解除映射時要先解除映射再釋放申請;
動態映射的好處是按需使用虛擬地址空間,壞處是每次使用前后都需要用函數去建立映射和銷毀映射。如:request_mem_region函數向內核申請(報告)需要映射的內存資源,ioremap函數真正用來實現映射,傳給他物理地址他給你映射返回一個虛擬地址,iounmap函數結束映射,release_mem_region函數釋資源。
注:
二種映射並不排斥,可以同時使用;靜態映射類似於C語言中全局變量,動態方式類似於C語言中malloc堆內存。在實際大多數驅動開發工作中用動態還是用靜態我們根本不用考慮,因為我們基本都是移植的。
在驅動開發的過程中需要注意,用戶態的測試程序中的讀/寫函數的本質就是將應用層傳遞過來的數據先復制到內核中,然后將之以正確的方式寫入硬件完成操作。這其實是一件非常復雜的事情,因為內核和應用是工作在不同的地址空間的,且每一個應用程序都有一個自己的虛擬地址空間。對此內核提供了二個函數
(1)copy_from_user,用來將數據從用戶空間復制到內核空間(復制是和mmap的映射相對應去區分的),使用時可以參考內核源代碼。需要特別注意的是函數的返回值定義,和常規有點不同。返回值如果成功復制則返回0,如果 不成功復制則返回尚未成功復制剩下的字節數。
(2)copy_to_user