国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
構(gòu)建第一個Linux驅(qū)動模塊
userphoto

2023.08.03 湖北

關(guān)注

上一篇文章介紹了 Linux 驅(qū)動編程需要了解的基礎(chǔ)知識:

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

這篇文章來介紹一下,如何構(gòu)建一個驅(qū)動模塊。構(gòu)建一個模塊,可以在兩個地方完成:

  • 內(nèi)核樹內(nèi)部
  • 內(nèi)核樹外部

除此之外,還需要編寫相應(yīng)的構(gòu)建腳本文件 makefile。

接下來,我們逐步進行介紹。

模塊構(gòu)建的makefile

makefile 是用來執(zhí)行一組操作的特殊文件,其中最重要的操作是程序的編譯。專用工具 make 用于解析makefile。

在說明整個make文件之前,先介紹一下 obj-<X>    kbuild 變量。<X> 可以取值為 y、m、n或者空白。

例如:

obj-y += mymodule.o

告訴 kbuild 在當(dāng)前目錄中有一個名為 mymodule.o 的對象。mymodule.o 將從 mymodule.c 或 mymodule.S 構(gòu)建。<X> 的值決定了如何構(gòu)建以及是否構(gòu)建或鏈接 mymodule.o

  • 如果 <X> 設(shè)置為 m,則使用變量 obj-m,并將 mymodule.o 構(gòu)建為模塊
  • 如果 <X> 設(shè)置為 y,則使用變量 obj-y,mymodule.o將構(gòu)建為內(nèi)核的一部分。也可以說它是一個內(nèi)置模塊。
  • 如果 <X> 設(shè)置為 n,則使用變量 obj-n,不會構(gòu)建 mymodule.o

如果后邊跟著是某個目錄,例如

obj-<X> += onedir/

kbuild 應(yīng)該進入 onedir 目錄,查找其中所有的 makefile 并處理它們,從而決定應(yīng)該構(gòu)建哪些對象。

一份完整的模塊構(gòu)建Makefile 示例:

KERNELDIR ?= /lib/modules/$(shell uname -r)/build

obj-m := helloworld.o

all:
    $(MAKE) -C $(KERNELDIR) M=$(shell pwd) modules;

clean:
    $(MAKE) -C $(KERNELDIR) M=$(shell pwd) clean;
  • obj-m := hellowolrd.o 解析,obj-m 列出要構(gòu)建的模塊。對于每一個 <filename> .o,進行系統(tǒng)構(gòu)建時會查找<filename> .c

  • KERNELDIR := /lib/modules/$(shell uname -r)/build 解析,KERNELDIR 是預(yù)構(gòu)建的內(nèi)核源碼的位置。構(gòu)建任何模塊都需要預(yù)構(gòu)建內(nèi)核。 -C 要求 make 在讀取 makefile 或執(zhí)行其他任何操作之前先更改到指定的目錄。

  • M=$(shell pwd) 解析,這與內(nèi)核構(gòu)建系統(tǒng)相關(guān)。內(nèi)核 makefile 使用這個變量來定位要構(gòu)建的外部模塊的目錄,.c 文件應(yīng)該被放置在這。

  • (MAKE) -C $(KERNELDIR ) M=$(shell pwd) modules; 構(gòu)建驅(qū)動模塊的規(guī)則

內(nèi)核樹內(nèi)的模塊

在內(nèi)核樹中構(gòu)建驅(qū)動程序,需要把驅(qū)動程序的代碼文件放在特定的目錄中。驅(qū)動程序中的每個子目錄都有 makefile 和 kconfig。

例如,驅(qū)動文件 mychardev.c 為字符驅(qū)動程序源碼,則應(yīng)該把他放在內(nèi)核源碼的 drivers/char 目錄中。

一個 kconfig 的示例文件如下:

config PACKT_MYCDEV
    tristate 'Our packtpub special Characterdriver'
    default m
    help
        Say Y here if you want to support the/dev/mycdev device.
        The /dev/mycdev device is used to access packtpub.

同時,在這個目錄下的 makefile 文件中添加一下語句:

obj-$(CONFIG_PACKT_MYCDEV) += mychardev.o

注意,.o 文件名稱必須與 .c 文件名完全一致。

配置完成后,可以分別使用 make 和 make modules 構(gòu)建內(nèi)核和模塊。

內(nèi)核源碼樹中包含的模塊安裝在 /lib/modules/$(KERNELRELEASE)/kernel/ 中。在Linux系統(tǒng)上,它是/lib/modules/$(uname -r)/kernel/

內(nèi)核樹外的模塊

在構(gòu)建外部模塊之前,需要有一個完整的、預(yù)編譯的內(nèi)核源代碼樹。內(nèi)核源碼樹版本必須與將加載和使用模塊的內(nèi)核相同。

有兩種方法可以獲得預(yù)構(gòu)建的內(nèi)核版本:

  • 自己構(gòu)建

  • 從發(fā)行版本庫安裝linux-headers- *包
安裝指令
sudo apt-get update
sudo apt-get install linux-headers-$(uname -r)

這將只安裝頭文件,而不是整個源代碼樹。

頭文件將被安裝在 /usr/src/linux-headers-$(uname -r) 目錄下 。

有一個符號鏈接 /lib/modules/$(uname-r)/build,指向前面安裝的頭文件,這應(yīng)該是在 makefile 中指定為內(nèi)核目錄的路徑。

以上內(nèi)容準(zhǔn)備完成之后,就可以進行構(gòu)建驅(qū)動模塊。

構(gòu)建模塊

處理完 makefile 后,只需要切換到源碼目錄并運行 make 命令,即可開始構(gòu)建模塊。

一個簡單模塊程序 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');

構(gòu)建腳本文件 Makefile

KERNELDIR ?= /lib/modules/`uname -r`/build

obj-m:=   helloworld.o

all :
    $(MAKE) -C $(KERNELDIR) M=$(shell pwd) modules;

clean:
    $(MAKE) -C $(KERNELDIR) M=$(shell pwd) clean;
    rm -f *.ko;

開始構(gòu)建:

$ make
make -C /lib/modules/`uname -r`/build M=/home/user/learn/drivers/chap2 modules;
make[1]: Entering directory '/usr/src/linux-headers-5.15.0-73-generic'
CC [M] /home/user/learn/drivers/chap2/helloworld.o
MODPOST /home/user/learn/drivers/chap2/Module.symvers
CC [M] /home/user/learn/drivers/chap2/helloworld.mod.o
LD [M] /home/user/learn/drivers/chap2/helloworld.ko
BTF [M] /home/user/learn/drivers/chap2/helloworld.ko
Skipping BTF generation for /home/user/learn/drivers/chap2/helloworld.ko due to unavailability of vmlinux
make[1]: Leaving directory '/usr/src/linux-headers-5.15.0-73-generic'

構(gòu)建完成后,在當(dāng)先目錄下會生成一些文件,其中 helloworld.ko,為最終生成的內(nèi)核模塊。

交叉編譯

上面的例子使用的是本地構(gòu)建,在 x86 機器上為x86 機器編譯。交叉編譯怎么實現(xiàn)?

這個過程是在機器 A(稱為宿主機)上編譯,該代碼要運行在機器 B(稱為目標(biāo)機)上;宿主機和目標(biāo)機具有不同的體系結(jié)構(gòu)。

常見的交叉編譯是在 x86 機器上構(gòu)建的代碼要運行在 ARM 架構(gòu)上。交叉編譯內(nèi)核模塊時,構(gòu)建 makefile 需要指定兩個變量:ARCH 和 CROSS_COMPILE,它們分別表示目標(biāo)體系結(jié)構(gòu)和編譯器的前綴名稱。

因此,內(nèi)核模塊本地編譯和交叉編譯之間的差別在于 makefile 構(gòu)建文件。

另外,還需要一份目標(biāo)機器正在使用的內(nèi)核源碼,編譯模塊的時候需要用到。

模塊裝載和卸載

模塊構(gòu)建完成后,可以通過 insmod 指令進行裝載。注意裝載和卸載需要 root 訪問權(quán)限,可以在模塊加載指令之前加上 sudo

$ sudo insmod helloworld.ko

指令執(zhí)行完,看不到任何信息。

加載內(nèi)核模塊,模塊的打印信息需要通過 dmsg 指令查看??梢钥吹饺肟诤瘮?shù) helloworld_init()打印的 Hello world!

卸載模塊,通過 rmmod 指令

sudo rmmod helloworld

同樣出口函數(shù)打印的信息,dmesg 指令查看。

另外,用 modinfo 查看模塊信息如下:

$ modinfo helloworld.ko
filename: /home/user/learn/drivers/chap2/helloworld.ko
license: GPL
author: zsky
srcversion: 6EFA6AC1502C67E96C09216
depends:
retpoline: Y
name: helloworld
vermagic: 5.15.0-73-generic SMP mod_unload modversions

好了,感謝閱讀,加油~

本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊舉報。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
Linux內(nèi)核模塊LKM編譯
Linux內(nèi)核模塊編譯- 高效學(xué)習(xí)Linux內(nèi)核——內(nèi)核模塊編譯
linux內(nèi)核添加新的模塊
ubuntu 2.6.22 內(nèi)核樹建立
內(nèi)核源碼書編譯及簡單驅(qū)動驗證
linux驅(qū)動模塊(多文件)的makefile實現(xiàn)
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服