Linux驅動:手把手教hello world驅動配置、編譯進內核或爲模塊

《關注、星標嵌入式客棧,精彩及時送達

[導讀] 回想自己剛剛學寫Linux 驅動時,覺得很難,簡直無從下手。現在寫公衆號,也常遇到一些朋友對於寫一個Linux驅動不知道這個驅動究竟如何編譯、如何裝載、如何測試,本文就如何編譯進內核或者模塊來聊一聊我的一些體會。

大家週末好,最近來了很多新朋友,感謝小夥伴們關注小號,讓我們一起進步,一起成長!如果喜歡小號請星標,星標的作用將會使本號最新文章在列表中置頂,這樣就不會錯過推送的文章了。

基本概念

要學習Linux驅動開發,個人體會是要建立清晰的概念,對於概念儘量理解清楚其內涵以及作用。

驅動模型

先來看看驅動處在Linux系統中的什麼位置:

  • 驅動運行於內核空間中

  • 驅動程序像是一個黑盒子:

    • 對上層用戶空間提供操作設備的接口,並隱藏設備的實現細節

    • 對下層的具體硬件設備進行控制、管理,通過用戶空間的訪問對具體的硬件設備操作。

這裏有兩個重要概念需要理解,啥是內核空間?啥又是用戶空間?現代宏操作系統(相對於微內核而言)通常將虛擬內存分割隔離成內核空間和用戶空間兩個部分。或許會問爲啥要這樣處理呢?這樣隔離分割可提供內存保護和硬件保護,以防止惡意或錯誤的軟件行爲。再進一步說說就好理解了,用戶空間需要訪問內核空間需要訪問內核空間以及底層設備要怎麼做呢?利用操作系統提供的操作系統調用(OS API)進而訪問內核空間,這些操作接口是內核經過精心設計且提供了完備的保護機制,故而對內核空間是安全的。

內核職責

對於Linux內核而言,其主要功能職責有這麼幾個:

  • 進程管理:進程管理子系統負責進程的管理(包括創建、銷燬以及調度)控制對CPU的進程訪問。調度程序執行一項調度策略,以確保進程可以公平地訪問CPU,同時確保內核按時執行必要的硬件操作。

  • 內存管理:允許多個進程安全地共享機器的主內存系統。內存管理器主要使用虛擬內存管理機制,該虛擬內存允許Linux支持使用的內存量超過系統可用內存的進程。使用文件系統將未使用的內存換出到非易失性存儲器(如硬盤,eMMC等),然後在需要時交換回來。

  • 文件系統:幾乎所有的對象(所有的設備都是文件對象)都可以看成文件,底層文件系統涵蓋了真實的文件系統還有虛擬文件系統,形成一個文件系統框架。

  • 設備管理:利用設備驅動框架,對硬件設備控制管理,並通過虛擬文件系統對用戶空間應用程序提供統一的系統操作接口集。

  • 網絡功能:實現了常見的網絡協議棧,以及對底層網絡設備的控制。

如想對內核有個整體認識,可以閱讀這篇文章,點擊跳轉閱讀:

Linux 內核架構分析

驅動類型

回到驅動這個概念,Linux驅動已基本明瞭在整個系統中處於什麼位置。Linux根據設備特點,將設備驅動程序大致分爲下面三大類:

  • 字符設備驅動:設備的訪問特點可以如字節流一樣訪問,對用戶提供統一的文件訪問接口集:open/close/read/write等,具體有哪些呢,比如串口。

  • 塊設備驅動:塊設備上基本可以容納文件系統,例如常見的存儲設備。

  • 網絡設備驅動:這個就比較好理解了,常見對外的網絡接口,比如以太網設備驅動等。

驅動的編譯方式

剛剛接觸Linux設備驅動開發的朋友,往往對這一步會不知道如何下手,這裏來描述一下兩種方式。這是本文想重點想分享的內容。

Linux內核代碼主要採用了Kconfig/Makefile進行配置以及構建管理。

  • Kconfig:主要用於配置以及依賴裁剪管理

  • Makefile:編譯規則,這個無需多說。

代碼及配置

以<<Linux設備驅動程序>>中hello word代碼進行說明。

#include <linux/module.h>
#include <linux/init.h>
MODULE_LICENSE("Dual BSD/GPL");

static int hello_init(void)
{
 printk(KERN_ALERT "Hello word");
 return 0;
}
static void hello_exit(void)
{
 printk(KERN_ALERT "Goodbye,Hello word");
}

/* register the init and exit routine of the module */
module_init( hello_init );
module_exit( hello_exit );

1.在./driver下創建目錄,比如創建爲hello文件夾

2.在該文件夾創建hello.c將上述代碼編輯進這個文件保存,具體怎麼操作就不詳述了。

3.在該文件夾下創建Kconfig,Makefile兩個文件

Kconfig內容:

config HAVE_HELLO
 tristate "hello driver"  
 help
   This hello driver is just to shaow how to develop driver process.

   This driver can also be built as a module. If so, the module
   will be called .
 default y 

#endmenu

表示如果使能了CONFIG_HAVE_HELLO在內核裁剪配置文件中,將顯示hello driver菜單,默認編譯進內核:

  • y: 編譯進內核

  • m:編譯爲模塊.ko文件

  • n:表示不編譯,未使能。

Makefile內容:

obj-$(CONFIG_HAVE_HELLO) += hello.o 

表示CONFIG_HAVE_HELLO使能時,編譯規則指定的文件爲hello.c

4.編輯driver頂層的Kconfig,Makefile文件

Kconfig文件

menu "Device Drivers"
source "drivers/amba/Kconfig"
......

source "drivers/hello/Kconfig"
endmenu

在endmenu前添加hello文件夾的配置文件解析:source "drivers/hello/Kconfig"

如此一來,配置系統就會按照這個配置去解析hello文件夾下的Kconfig

Makefile文件:

#
# Makefile for the Linux kernel device drivers.
#
# 15 Sep 2000, Christoph Hellwig <[email protected]>
# Rewritten to use lists instead of if-statements.
#

obj-y    += irqchip/
obj-y    += bus/

.......

obj-$(CONFIG_HAVE_HELLO) += hello/

在原Makefile後添加obj-$(CONFIG_HAVE_HELLO) += hello/,這句話的作用是當CONFIG_HAVE_HELLO使能後,在哪裏去找源文件。在結合hello文件下模塊Makefile就形成了層次式Makefile

接下來看看如何編譯。

編譯

首先調用make distclean,清除原來的配置。

然後調用make ARCH=arm xxx_defconfig:

configuration written to .config表示這步操作成功,如果失敗檢查Kconfig配置是否出錯。

ARCH=arm 表示使用的是ARM平臺的目標機,如nanopi2_linux_defconfig 表示配置文件,該文件存在於:

然後來看看hello是否生效,調用make ARCH=arm menuconfig

進入Device Drivers子目錄,移動光標到最底部,就看到添加的hello driver配置菜單了。

那麼這裏如前文所說我們有這麼幾種選擇:

  • 編譯進內核,敲y,顯示<*>表示編譯進內核映象

  • 編譯爲模塊,敲M表示編譯爲模塊,最後生成hello.ko,可以使用insmod命令裝載,這裏比較容易查到具體如何怎麼操作,就不贅述了

  • 不編譯,敲N表示不使能。

選擇好,保存配置,剩下就是編譯了:

編譯進內核

編譯爲模塊

最後在./driver/hello文件下生成hello.ko就成了,剩下就是動態加載調試了。

總結一下

通過上文閱讀,應能掌握如何配置、編譯進內核或者模塊的基本操作,對於剛入手學習Linux驅動開發屬於必掌握的基本操作,由於書籍中少有這種實戰介紹,所以這裏總結分享一下這些基礎操作。當然對於熟悉了內核驅動開發而言,完全可以直接編輯xxx_defconfig,如如這裏可以這麼做:

CONFIG_HELLO_DRIVER=m

這就修改爲=y表示編譯進內核,=m表示編譯爲模塊,=n表示不使能.

本文辛苦原創總結,如果覺得有價值也請幫忙點贊/在看/轉發支持,不勝感激!

END

往期精彩推薦,點擊即可閱讀

▲Linux內核中I2C總線及設備長啥樣? 

Linux 內核架構分析

手把手教系列之IIR數字濾波器設計實現

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章