久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

Linux驅(qū)動編程必備基礎(chǔ)知識

 漢無為 2023-08-03 發(fā)布于湖北

驅(qū)動程序是專用于控制和管理特定硬件設(shè)備的軟件,因此也被稱作設(shè)備驅(qū)動程序,。從操作系統(tǒng)的角度來看,,它可以位于內(nèi)核空間(以特權(quán)模式運行),也可以位于用戶空間(具有較低的權(quán)限) ,。

對于 Linux 驅(qū)動程序來說,,其運行在內(nèi)核空間,把硬件功能提供給用戶程序,。

本篇文章主要介紹Linux驅(qū)動程序的一些基礎(chǔ)知識,。后面的文章再逐步展開。

內(nèi)核空間和用戶空間

內(nèi)核空間和用戶空間的概念有點抽象,,主要涉及內(nèi)存的訪問權(quán)限,。內(nèi)核是有特權(quán)的,而用戶應(yīng)用程序則是受限制的,。

內(nèi)核空間

內(nèi)核駐留和運行的地址空間,。

內(nèi)核內(nèi)存受訪問標志保護,只能由內(nèi)核訪問,用戶應(yīng)用程不能訪問,。另一方面,,內(nèi)核可以訪問整個系統(tǒng)內(nèi)存,因為它在系統(tǒng)上以更高的優(yōu)先級運行,。在內(nèi)核模式下,,CPU可以訪問整個內(nèi)存(內(nèi)核空間和用戶空間)

用戶空間

用戶程序運行的地址空間。

在用戶模式下,,CPU只能訪問標有用戶空間訪問權(quán)限的內(nèi)存,。用戶應(yīng)用程序運行到內(nèi)核空間的唯一方法是通過系統(tǒng)調(diào)用。

當進程執(zhí)行系統(tǒng)調(diào)用時,,軟件中斷被發(fā)送到內(nèi)核,,這將打開特權(quán)模式,以便該進程可以在內(nèi)核空間中運行,。系統(tǒng)調(diào)用返回時,,內(nèi)核關(guān)閉特權(quán)模式,進程再次受限,。

模塊

Linux內(nèi)核可以在運行時擴展,。當系統(tǒng)運行時,我們可以向內(nèi)核添加,、刪除功能。

可以在運行時添加到內(nèi)核中的代碼被稱為“模塊”,。內(nèi)核模塊是即插即用的,,一旦插入就可以使用。

模塊要運行,,應(yīng)該先把它加載到內(nèi)核,,可以用 insmod 或 modprobe 來實現(xiàn),前者需要指定模塊路徑作為參數(shù),,這是開發(fā)期間的首選,;后者更智能化,是生產(chǎn)系統(tǒng)中的首選,。

insmod /test/mydrv.ko

常用的模塊卸載命令是 rmmod,,使用該命令時,應(yīng)該把要卸載的模塊名作為參數(shù)向其傳遞,。當卸載某個模塊時,,不會有其他影響,則會直接卸載,;若有不良影響,,內(nèi)核會阻止這次卸載。

rmmod mymodule

或者使用下邊的指令

modeprobe -r mymodule

設(shè)備模塊分類

Linux系統(tǒng)的模塊有三種基本類型:

  • 字符模塊

  • 塊模塊

  • 網(wǎng)絡(luò)模塊

對應(yīng)的設(shè)備設(shè)備驅(qū)動程序:

  • 字符設(shè)備驅(qū)動

  • 塊設(shè)備驅(qū)動

  • 網(wǎng)絡(luò)設(shè)備驅(qū)動

字符設(shè)備是個能夠像字節(jié)流一樣被訪問的設(shè)備,由字符設(shè)備驅(qū)動程序來實現(xiàn),。

塊設(shè)備每次只能傳輸一個或者多個完整的塊,,每塊包含512字節(jié)(或者2的更高次冪字節(jié)的數(shù)據(jù))。

網(wǎng)絡(luò)接口由內(nèi)核中的網(wǎng)絡(luò)子系統(tǒng)驅(qū)動,,負責發(fā)送和接收數(shù)據(jù)包,。網(wǎng)絡(luò)驅(qū)動程序不需要知道各個連接的相關(guān)信息,它只負責處理數(shù)據(jù)包即可,。

當然還有其他劃分驅(qū)動程序模塊的方法,,此處不再贅述。

驅(qū)動程序框架

Linux 驅(qū)動程序是有固定框架的,,我們按照既定的框架,,填寫內(nèi)容即可。

先看一個簡單的內(nèi)核模塊程序 helloworld.c

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>

/* 模塊入口點函數(shù) */
static int helloworld_init(void)
{
pr_info('Hello world!\n');
return 0;
}

/* 模塊出口點函數(shù) */
static void helloworld_exit(void)
{
pr_info('End of the world\n');
}

/* 指定函數(shù)用途 */
module_init(helloworld_init);
module_exit(helloworld_exit);

MODULE_AUTHOR('zsky');
MODULE_LICENSE('GPL');

內(nèi)核驅(qū)動程序與用戶空間的程序是有很大區(qū)別的,。

內(nèi)核模塊驅(qū)動程序有入口點和出口點,,函數(shù)名字可以任意。用戶程序的入口函數(shù)名稱一般為 main(),。

對于內(nèi)核模塊程序來說,,需要開發(fā)人員指定入點和出點函數(shù)。在上例中,,module_init()用于聲明模塊加載(使用 insmod 或 modprobe)時應(yīng)該調(diào)用的函數(shù)為 helloworld_init,,入口函數(shù)中要完成的操作是定義模塊的行為。

module_exit() 用于聲明模塊卸載(使用 rmmod )時應(yīng)該調(diào)用的函數(shù)為  helloworld_exit,。

模塊加載或者卸載后,,init 函數(shù)或者 exit 函數(shù)立即運行一次。

在編寫驅(qū)動程序的時候,,需要包含很多頭文件,,以便獲取函數(shù)、數(shù)據(jù)類型,、變量的定義,。有幾個頭文件是專門用于模塊的:

#include <linux/init.h>
#include <linux/module.h>

module.h包含可裝載模塊需要的大量符號和函數(shù)的定義。init.h 用于指定入口函數(shù)和出口函數(shù),。

模塊信息

內(nèi)核模塊使用其 .modinfo 部分來存儲關(guān)于模塊的信息,,所有MODULE_*宏都用參數(shù)傳遞的值更新這部分的內(nèi)容 。

其中一些宏是 MODULE_DESCRIPTION(),、MODULE_AUTHOR() 和 MODULE_LICENSE(),。

MODULE_LICENSE() 告訴內(nèi)核模塊采用何種許可,他對模塊行為有影響,,如果與指定的許可不兼容將導(dǎo)致內(nèi)核模塊被污染,。

MODULE_AUTHOR() 用于聲明模塊的作者。

MODULE_DESCRIPTION() 簡要描述模塊的功能。

錯誤和消息打印

在模塊函數(shù)處理過程中,,一定要檢測返回值,,確保所有的請求操作已經(jīng)真正成功。

當遇到錯誤時,,必須撤銷在這個錯誤發(fā)生之前的所有設(shè)置,。通常的做法是使用goto語句。

ptr = kmalloc(sizeof (device_t));
if(!ptr)
{
  ret = -ENOMEM
  goto err_alloc;
}
ev = init(&ptr);
if(dev)
{
ret = -EIO
 goto err_init;
}
eturn 0;

err_init:
  free(ptr);
err_alloc:
  return ret;

若模塊裝載過程中出錯,,要將出錯之前的任何注冊工作全部撤銷,,否則內(nèi)核會處于一種不穩(wěn)定的狀態(tài),因為內(nèi)核中包含了一些指向并不存在的代碼內(nèi)部指針,。

錯誤有時會跨越內(nèi)核空間,,傳播到用戶空間。如果返回的錯誤是對系統(tǒng)調(diào)用(open,、read,、ioctl、mmap)的響應(yīng),,則該值將自動賦給用戶空間 errno 全局變量,,在該變量上調(diào)用 strerror(errno) 可以將錯誤轉(zhuǎn)換為可讀字符串。

當返回指針的函數(shù)返回錯誤時,,通常返回的是NULL 指針,。而去檢查為什么會返回空指針是沒有任何意義的,因為無法準確了解為什么會返回空指針,。為此,,內(nèi)核提供了3個函數(shù) ERR_PTR、IS_ERR 和 PTR_ERR:

void *ERR_PTR(long error);
long IS_ERR(const void *ptr);
long PTR_ERR(const void *ptr);

ERR_PTR 函數(shù)實際上把錯誤值作為指針返回,。假若函數(shù)在內(nèi)存申請失敗后要執(zhí)行語句 return -ENOMEM,則必須改為這樣的語句:return ERR_PTR (-ENOMEM);,。

IS_ERR 函數(shù)用于檢查返回值是否是指針錯誤:if(IS_ERR(foo)),。

PTR_ERR 函數(shù)返回實際錯誤代碼:return PTR_ERR(foo);。

消息打印--printk()

不同于用戶空間的 printf()函數(shù),。printk()是在內(nèi)核空間使用的,,其作用和在用戶空間使用 printf() 一樣,執(zhí)行 dmesg 命令可以顯示 printk() 寫入的信息,。

根據(jù)所打印消息的重要性不同,,可以選用 include/linux/kern_levels.h 中定義的八個級別的日志消息,每個級別對應(yīng)iyge字符串格式的數(shù)字,,其優(yōu)先級與該數(shù)字的值成反比:

#define KERN_SOH '\001'  /* ASCII頭開始 */
#define KERN_SOH_ASCII '\001'

#define KERN_EMERG KERN_SOH   '0'   /* 系統(tǒng)不可用*/
#define KERN_ALERT KERN_SOH   '1'   /* 必須立即采取行動*/
#define KERN_CRIT KERN_SOH     '2'   /* 重要條件*/
#define KERN_ERR KERN_SOH     '3'   /* 錯誤條件*/
#define KERN_WARNING KERN_SOH '4'   /* 警報條件*/
#define KERN_NOTICE KERN_SOH   '5'   /* 正常但重要的情況*/
#define KERN_INFO KERN_SOH     '6'   /* 信息 */
#define KERN_DEBUG KERN_SOH   '7'   /* 調(diào)試級別消息 */

舉例:

printk(KERN_ERR 'This is an error\n');

實際上可以使用以下宏,,其名稱更有意義,它們是對前面所定義內(nèi)容的包裝—— pr_emerg、pr_alert,、pr_crit,、pr_err、pr_warning,、pr_notice,、pr_info和 pr_debug。

printk() 的實現(xiàn)是這樣的:調(diào)用它時,,內(nèi)核會將消息日志級別與當前控制臺的日志級別進行比較,;如果前者比后者更高(值更低),則消息會立即打印到控制臺,。

模塊參數(shù)

像用戶程序一樣,,內(nèi)核模塊也可以接收命令行參數(shù)。這樣能夠根據(jù)給定的參數(shù)動態(tài)地改變模塊的行為,,開發(fā)者不必在測試/調(diào)試期間無限期地修改/編譯模塊,。 

為了對此進行設(shè)置,首先應(yīng)該聲明用于保存命令行參數(shù)值的變量,,并在每個變量上使用 module_param() 宏:

module_param(name, type, perm);
  • name:用作參數(shù)的變量的名稱,。

  • type:參數(shù)的類型(bool、charp,、byte,、short、ushort,、int,、uint、long,、ulong),,其中 charp 代表字符指針。

  • perm:代表/sys/module/<module>/parameters/<param>文件的權(quán)限,,其中包括S_IWUSR,、S_IRUSR、S_IXUSR,、S_IRGRP,、S_WGRP和S_IRUGO 。

當使用模塊參數(shù)時,,應(yīng)該用 MODULE_PARM_DESC 描述每個參數(shù),。這個宏將把每個參數(shù)的描述填充到模塊信息部分。

舉例:

module_param(myint, int, S_IRUGO);
module_param(mystr, charp, S_IRUGO);
module_param_array(myarr, int,NULL, S_IWUSR|S_IRUSR);

MODULE_PARM_DESC(myint,'this is my int variable');
MODULE_PARM_DESC(mystr,'this is my char pointer variable');
MODULE_PARM_DESC(myarr,'this is my array of int');

要在加載該模塊時提供參數(shù),,請執(zhí)行以下操作:

# insmod hellomodule-params.ko 
mystring='packtpub' myint=15 myArray=1,2,3

在加載模塊之前,,執(zhí)行modinfo可以顯示該模塊支 持的參數(shù)說明:

modinfo ./helloworld-params.ko

好了,,感謝閱讀。加油~

圖片

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購買等信息,,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請點擊一鍵舉報,。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多