一、內核驅動與啟動流程
1.?Linux內核驅動
-
Nor Flash: 可線性訪問,有專門的數據及地址總線(與內存訪問方式相同)。
-
Nand Flash: 不可線性訪問,訪問需要控制邏輯(軟件)。
2.?Linux啟動流程
-
ARM架構:
-
IRAM (4KB): 內部RAM,用于存儲初始引導程序。
-
Nor Flash (2M): 存儲u-boot程序。
-
內存 (64M): 用于加載內核和根文件系統。
-
Nand Flash (256M): 存儲內核、根文件系統等數據。
-
-
-
啟動過程:
-
Bootloader (u-boot):
-
初始化CPU、異常向量表、棧、時鐘、內存等。
-
關閉看門狗、中斷、Cache、MMU。
-
初始化相關硬件和軟件協議。
-
將內核加載到內存。
-
向內核傳遞參數(根文件系統類型、位置、控制臺等)。
-
啟動內核。
-
-
內核 (kernel):
-
文件管理、內存管理、進程管理、網絡管理、設備管理。
-
啟動到最后階段加載根文件系統。
-
init
進程啟動后臺服務程序、加載配置、啟動shell和應用程序。
-
-
根文件系統 (rootfs):
-
包含程序(應用、系統、命令)、配置文件、庫文件、普通文件(txt、mp3)。
-
-
3.?Windows與Linux對比
-
Windows: 使用BIOS啟動。
-
Linux: 使用bootloader引導內核啟動,內核加載rootfs。
4.?具體啟動步驟
-
Nor Flash:
-
系統上電后,PC指向0地址,直接執行Nor Flash中的u-boot程序。
-
-
Nand Flash:
-
系統上電后,自動搬移u-boot前4KB程序到IRAM。
-
CPU執行IRAM中的代碼,u-boot初始化內存并將剩余代碼搬移到內存執行。
-
5.?內核與文件系統
-
內核 (uImage):
-
啟動前u-boot向內核傳遞參數(
tag_list
)。 -
Nand Flash: u-boot直接讀取Nand Flash中的uImage并寫入內存的0x30008000地址處,啟動內核。
-
Ubuntu: 通過TFTP下載uImage到內存的0x30008000地址處,啟動內核。
-
-
根文件系統 (rootfs):
-
Nand Flash: uImage啟動到最后階段時,直接掛載Nand Flash中的rootfs。
-
Ubuntu: uImage啟動到最后階段時,通過NFS掛載Ubuntu中的rootfs。
-
6.?前置步驟
-
向Nor Flash 0地址處燒寫u-boot.bin。
-
拷貝uImage到Ubuntu的TFTP服務目錄下。
-
將rootfs.tar.gz拷貝到Ubuntu的NFS服務目錄下,并解壓
sudo tar -xvf rootfs.tar.gz
7.?U-Boot命令
-
環境變量管理:
-
printenv
: 打印環境變量。 -
reset
: 重啟。 -
setenv serverip 192.168.1.3
: 設置環境變量。 -
saveenv
: 保存環境變量到Nand Flash。 -
setenv serverip
: 刪除環境變量。
-
-
下載與啟動:
-
tftp 0x30008000 uImage
: 通過TFTP協議下載uImage到內存的0x30008000地址處。 -
bootm 0x30008000
: 啟動內存0x30008000地址處的內核。 -
go 0x30008000
: 運行內存0x30008000地址處的程序。
-
8.?設置啟動參數
setenv bootargs console=ttySAC0,115200 root=/dev/nfs nfsroot=192.168.1.3:/home/linux/nfs/rootfs ip=192.168.1.123 init=/linuxrc
-
console: 控制臺(終端)。
-
root: 根文件系統類型。
-
nfsroot: 根文件系統位置。
-
ip: 內核階段使用的IP。
-
init: 指定init進程。
二、內核編譯
1.?內核編譯步驟
-
Kconfig: 定義
make menuconfig
的配置選項。 -
make menuconfig: 內核配置。
-
.config: 配置文件,決定哪些文件被編譯進內核。
-
CONFIG_SSL = n
: 不啟用SSL。 -
CONFIG_MM = y
: 啟用內存管理。
-
-
makefile: 條件編譯,編譯內核。
2.?內核鏡像類型
-
Image: 可以直接使用的內核鏡像。
-
zImage: 一段解壓代碼 + Image的壓縮文件。
-
uImage: 64字節的頭信息 + zImage。
3.?地址相關代碼
-
地址相關代碼: 鏈接地址和加載地址一致。
-
地址無關代碼: 鏈接地址和加載地址無關。
4.?跳轉指令
-
相對跳轉、短跳轉:
b fun
-
絕對跳轉、長跳轉:
ldr pc, 0x00000000
5.?內核目錄結構
6.?向內核新增文件
以向drivers/char
下添加demo.c
為例:
-
在
drivers/char
目錄下新建并編輯demo.c
。 -
修改同層目錄下的
makefileMakefile
,添加:obj-$(CONFIG_DEMO) += demo.o
-
修改同層目錄下的
Kconfig
,添加一個DEMO的配置。 -
執行
make menuconfig
。 -
執行
make uImage
。
7.?內核編譯命令
-
配置內核
cp config_mini2440_t35 .config make menuconfig
-
編譯內核
make uImage
8.?內核鏡像說明
-
Image: 可直接使用的內核鏡像。
-
zImage: 壓縮的內核鏡像,包含解壓代碼。
-
uImage: 帶有64字節頭信息的壓縮內核鏡像。
9.?Makefile和Kconfig
-
每層目錄都有
Makefile
和Kconfig
文件,用于配置和編譯內核。
10.?編譯流程總結
-
配置內核: 使用
make menuconfig
選擇內核配置選項。 -
編譯內核: 使用
make uImage
生成內核鏡像。 -
驗證內核: 確保生成的內核鏡像可以正常啟動。
11.?注意事項
-
配置文件:
.config
文件決定了哪些模塊被編譯進內核。 -
條件編譯: 使用
obj-$(CONFIG_XXX)
進行條件編譯。 -
目錄結構: 每層目錄都有
Makefile
和Kconfig
文件,確保編譯過程正確。
三、驅動程序
1.?設備文件與驅動模塊
-
設備文件: 用戶空間程序通過設備文件與驅動程序交互。
-
示例:
open("/dev/led");
-
-
驅動模塊: 內核中的驅動程序負責控制硬件設備。
-
示例:
sys_open(led)
調用驅動模塊。
-
2.?設備驅動類型
-
字符設備驅動: 數據按順序訪問,90%以上的設備使用字符設備驅動。
-
塊設備驅動: 可以隨機訪問,主要用于存儲設備。
-
網絡設備驅動: 網卡,集成復雜協議,通過套接字通信,沒有設備號,靠名字維護。
3.?設備號
-
設備號: 用于標識設備。
-
主設備號 (高12位): 區分設備類型。
-
次設備號 (低20位): 區分同類的不同設備。
-
-
示例:
dev_t
是32位設備號。
4.?創建設備節點
-
使用
mknod
命令創建設備節點mknod /dev/demo3 c 255 0
-
/dev/demo3
: 設備節點名。 -
c
: 字符設備。 -
255
: 主設備號。 -
0
: 次設備號。
-
5.?驅動模塊結構
-
驅動模塊: 包含
open
、read
、write
、ioctl
、close
等函數。 -
示例:
drv_led
、drv_key
、drv_adc
分別對應LED、按鍵、ADC設備。
6.?設備驅動流程
-
應用程序調用設備文件:
-
open("/dev/led");
-
-
內核調用驅動模塊:
-
sys_open(led)
→drv_led
。
-
-
驅動模塊控制硬件設備:
-
drv_led
控制LED設備。
-
7.?設備號與驅動模塊關系
-
每個設備號對應一個驅動模塊。
-
內核通過設備號找到對應的驅動模塊。
8.?設備號結構
+--------+--------+----+-------+
| 8 | 8 | 2 | 14 |
+--------+--------+----+-------+
設備類型 命令編號 數據 參數大小
魔幻數 流向
-
設備類型 (魔幻數): 8位,標識設備類型。
-
命令編號: 8位,標識具體命令。
-
數據流向: 2位,標識數據方向。
-
參數大小: 14位,標識參數大小。
9.?設備驅動總結
-
字符設備: 順序訪問,適用于大多數設備。
-
塊設備: 隨機訪問,適用于存儲設備。
-
網絡設備: 復雜協議,通過套接字通信。
-
設備號: 區分設備類型和具體設備。
-
驅動模塊: 內核中的程序,負責控制硬件設備。
10.?關鍵命令
-
創建設備節點:
mknod
。 -
設備文件操作:
open
、read
、write
、ioctl
、close
。
11.?注意事項
-
設備號分配: 確保主設備號和次設備號唯一。
-
驅動模塊編寫: 需要實現
open
、read
、write
等函數。 -
設備文件操作: 應用程序通過設備文件與驅動模塊交互。