linux進階:內核模塊

来源:https://www.cnblogs.com/couvrir/archive/2023/08/08/17613829.html
-Advertisement-
Play Games

現代內核派系 巨集內核 關鍵功能(基本功能,不可裁剪、擴展)和服務功能(如文件系統、設備驅動、網路服務等,可裁剪、擴展)均在內核空間提供。運行效率高。擴展性較差。system call(系統調用)能夠先入內核態來使用內核提供的服務。 微內核 內核空間只提供關鍵功能,服務功能在用戶空間提供。運行效率較低 ...


現代內核派系

巨集內核

關鍵功能(基本功能,不可裁剪、擴展)和服務功能(如文件系統、設備驅動、網路服務等,可裁剪、擴展)均在內核空間提供。運行效率高。擴展性較差。system call(系統調用)能夠先入內核態來使用內核提供的服務。

 

微內核

內核空間只提供關鍵功能,服務功能在用戶空間提供。運行效率較低。安全性、擴展性較高

在Linux內核源碼中有超過50%的代碼都與設備驅動相關。Linux為巨集內核架構(windows、鴻蒙等為微內核架構),如果開啟所有的功能,內核就會變得十分臃腫。內核模塊實現了某個功能的一段內核代碼,在內核運行過程,可以載入這部分代碼到內核,從而動態地增加了內核的功能。基於這種特性,進行設備驅動開發時,以內核模塊的形式編寫設備驅動,只需要編譯相關的驅動代碼即可,無需對整個內核進行編譯

在設備驅動開發過程中,用戶可以隨意將正在測試的驅動程式添加到內核或從內核中移除,每次修改內核模塊的代碼不需要重新啟動內核。

在開發板上,用戶也不需要將內核模塊程式,或設備驅動程式的ELF文件存放在開發板,免去占用不必要的存儲空間。當需要載入內核模塊時,可以掛在NFS伺服器,將存放在其它設備的內核模塊載入到開發板上

 

內核模塊

為解決linux內核可擴展性和可維護性相對較差的缺陷。我們編寫的內核模塊,經過編譯,最終形成.ko為尾碼的ELF文件。ko文件是elf格式,是一種普通的可重定位目標文件。這類文件包含了代碼和數據,可以被用來鏈接成可執行文件或共用目標文件,靜態鏈接庫也可以歸為這一類。

 

內核模塊頭文件

#include <linux/init.h>      /*包含module_init()和module_exit()函數的聲明*/
#include <linux/module.h>    /*包含內核模塊信息聲明的相關函數*/
#include <linux/kernel.h>    /*包含內核提供的各種函數,如printk*/

 

內核模塊載入與卸載

載入內核模塊:insmod

卸載內核模塊:rmmod

 

內核模塊出入口

module_init():載入模塊時該函數自動執行,進行初始化操作
module_exit():卸載模塊時該函數自動執行,進行清理操作

 

內核模塊信息聲明

MODULE_LICENSE():表示模塊代碼接受的軟體許可協議,Linux內核遵循GPL V2開源協議,內核模塊與linux內核保持一致即可。
MODULE_AUTHOR():描述模塊的作者信息。
MODULE_DESCRIPTION():對模塊的簡單介紹。
MODULE_ALIAS():給模塊設置一個別名。

 

列印函數printk

printf:glibc庫實現的列印函數,工作於用戶空間。

printk:內核模塊無法使用glibc庫函數,內核自身實現的一個類printf函數,但是需要指定列印等級。

#include <linux/kernel.h>
/*printk列印等級,數字越小,等級越高*/
#define KERN_EMERG    "<0>"    /*通常是系統崩潰前的信息*/
#define KERN_ALERT    "<1>"    /*需要立即處理的消息*/
#define KERN_CRIT     "<2>"    /*嚴重情況*/
#define KERN_ERR      "<3>"    /*錯誤情況*/
#define KERN_WARNING  "<4>"    /*有問題的情況*/
#define KERN_NOTICE   "<5>"    /*註意信息*/
#define KERN_INFO     "<6>"    /*普通消息*/
#define KERN_DEBUG    "<7>"    /*調試信息*/

cat /proc/sys/kernel/printk查看當前系統printk列印等級

終端輸出:

當前控制台日誌級別(小於該等級才能列印在當前控制台)

預設消息日誌級別

最小的控制台級別當前控制台日誌級別的最小值

預設控制台日誌級別(沒指定等級時預設級別)

dmesg:列印內核所有列印信息。

lsmod:查看當前系統載入內核情況。

 

實驗環境(野火為例)

開發板燒錄好Debian鏡像。啟動開發板,搭建好nfs客戶端,掛載共用文件夾。獲取Debian鏡像的內核源碼並編譯。(選擇4.19.71版本內核,內核模塊的功能需要依賴內核提供的各種底層介面。)

註:cat /etc/issue查看鏡像日期。新版內核是4.19.35版本(22年之後),看驅動文檔的“驅動章節實驗環境搭建”。

 

下載linux內核源碼(基於野火linux開發板,ebf-buster-linux存放著內核相關)

git clone https://github.com/Embedfire/ebf-buster-linux.git
git clone https://gitee.com/Embedfire/ebf-buster-linux.git

 

安裝必要環境工具庫(make工具、gcc交叉編譯鏈、gcc編譯工具、bison語法分析器、flex詞法分析器、libssl-dev OpenSSL通用庫、lzop LZO壓縮庫的壓縮軟體)

sudo apt install make gcc-arm-linux-gnueabihf gcc bison flex libssl-dev dpkg-dev lzop

 

前往ebf-buster-linux目錄,執行腳本,一鍵編譯內核 

sudo ./make_deb.sh

 

獲取編譯出來的內核相關文件(make_deb.sh腳本指定存放路徑)

/home/couvrir/桌面/ebf-buster-linux/build_image/build

make_deb.sh如下:

deb_distro=bionic
DISTRO=stable
build_opts="-j 6"
build_opts="${build_opts} O=build_image/build"            //O執行編譯文件的存放路徑
build_opts="${build_opts} ARCH=arm"
build_opts="${build_opts} KBUILD_DEBARCH=${DEBARCH}"
build_opts="${build_opts} LOCALVERSION=-imx-rl"
build_opts="${build_opts} KDEB_CHANGELOG_DIST=${deb_distro}"
build_opts="${build_opts} KDEB_PKGVERSION=l${DISTRO}"
build_opts="${build_opts} CROSS_COMPILE=arm-linux-gnueabihf-"
build_opts="${build_opts} KDEB_SOURCENAME=linux-upstream"
make ${build_opts} npi_v7+defconfig
make ${build_opts}
make ${build_opts} bindeb-pkg

 

實驗一

helloworld.c文件

#include <linux/init.h>      
#include <linux/module.h>    
#include <linux/kernel.h>  
 
static int __init hello_init(void)    //__init指將這段函數指定保存在__init段記憶體
{
    printk(KERN_EMERG "[ KERN_EMERG ] Hello World Module Init\n");  //指定等級
    printk("[ default ] Hello World Module Init\n");           //預設等級
    return 0;
}
 
static int __exit hello_exit(void)    //__exit指將這段函數指定保存在__exit段記憶體
{
    printk("[ default ] goodbye\n");                    //預設等級
}
 
module_init(hello_init);    //hello_init作為模塊函數入口
module_exit(hello_exit);    //hello_exit作為模塊函數出口
 
MODULE_LICENSE("GPL2");                     //表示模塊代碼接受的軟體許可協議
MODULE_AUTHOR("couvrir");                   //描述模塊的作者信息
MODULE_DESCRIPTION("hello world module");   //對模塊的簡單介紹
MODULE_ALIAS("test module");                //給模塊設置一個別名

 Makefile文件

KERNEL_DIR=/home/couvrir/桌面/ebf-buster-linux/build_image/build    //將內核源碼編譯生成的內核文件存放在該路徑

ARCH=arm                                //交叉編譯的目標架構
CROSS_COMPILE=arm-linux-gnueabihf-        //交叉編譯的編譯工具鏈
export ARCH CROSS_COMPILE                //將架構和編譯鏈導出到子Makefile,使其在當前shell環境中生效

obj-m:=helloworld.o
all:                                    //預設目標,用於編譯所有模塊 
        $(MAKE) -C $(KERNEL_DIR) M=$(CURDIR) modules    //執行內核源碼目錄的Makefile文件,並將當前目錄作為模塊的源碼目錄
//通過執行Makefile文件,可以將helloworld.c文件編譯成一個內核模塊

.PHONY:clean copy
clean:
        $(MAKE) -C $(KERNEL_DIR) M=$(CURDIR) clean        //執行內核源碼目錄的Makefile文件的clean目標,清理編譯生成的文件
copy:
        sudo cp *.ko /home/couvrir/workdir                //將ko文件存到共用文件夾

obj-m:=<模塊名>.o指定要編譯的模塊文件

-C指定子Makefile的路徑,M=描述內核關於內核模塊的源碼路徑。CURDIR為當前目錄路徑。
make modules:執行linux頂層Makefile的偽目標,它實現內核模塊的源碼讀取並編譯為.ko文件。

執行make、make copy。

然後開發板上sudo insmod xxx.ko。

dmesg:列印內核所有列印信息。

lsmod:查看當前系統載入內核情況。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 前言 大家好,我是wacky,最近在工作中遇到一個有趣的問題,同事反饋說WPF中有一個樹形結構的集合,在載入時會直接報堆棧溢出,一直沒時間(懶得)看,導致很久了也沒人解決掉。於是,組長就把這個"艱巨"的任務交給了我。作為新人中的"高手",必然要義不容辭地接受挑戰嘍,廢話不多說,走起。 分析 由於同事 ...
  • LINQ是C#3.0引入的特性,讓處理對象就像執行SQL語句一樣簡單,對於提高C#開發效率有革命性的作用。 對於每個.NET開發者來說,掌握C#的LINQ知識點是非常重要的。LINQ是C#的一個強大的特性,它為數據查詢和操作提供了簡潔、統一的語法,使得數據處理變得更加直觀和靈活。 以下是.NET開發 ...
  • # Unity IUnityLinkerProcessor Unity IUnityLinkerProcessor是Unity引擎中的一個介面,它允許開發者在Unity項目構建時對代碼進行鏈接處理。這個介面可以用來優化項目構建大小,減少不必要的代碼和資源,提高項目的性能和載入速度。 ## 介面定義 ...
  • 博客推行版本更新,成果積累制度,已經寫過的博客還會再次更新,不斷地琢磨,高質量高數量都是要追求的,工匠精神是學習必不可少的精神。因此,大家有何建議歡迎在評論區踴躍發言,你們的支持是我最大的動力,你們敢投,我就敢肝 ...
  • 大家好,我是痞子衡,是正經搞技術的痞子。今天痞子衡給大家分享的是**藉助i.MXRT10xx系列INIT_VTOR功能可以縮短程式熱重啟時間**。 最近痞子衡寫了篇文章 [《i.MXRT從Serial NAND啟動時間測量》](https://www.cnblogs.com/henjay724/p/ ...
  • yum update更新報錯 Transaction Check Error 解決方法 yum update 引起錯誤Transaction Check Error的原因很多,要根據錯誤概要去判斷具體原因。 錯誤現象: 報錯內容: file /usr/share/man/man1/gtk-query ...
  • 哈嘍大家好,我是鹹魚 相信小伙伴們都知道在 Linux 中,安裝軟體一般有三種方式 * yum 安裝 * rpm 安裝 * 源碼編譯安裝 鹹魚平時三種安裝方式都會用,但是具體原理和區別卻沒有去深入瞭解過 結果上周部門剛來的新人問我這幾種安裝方式的時候,一下子把我問懵了 那麼今天鹹魚將會向小伙伴們介紹 ...
  • ## 開篇 現在流行的開源項目經歷了長時間的開發, 積累了大量的代碼, 想要一行一行地閱讀代碼去學習開源項目, 需要的時間成本是巨大的. 所以, 我們也需要用一種高效的方式去"閱讀"代碼. 電腦科學發展到現在, 產生了很多高效成熟的工具, 調試器就是其中之一(扯句題外話, 那些大牛程式員似乎就是喜 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...