1.本地主機的參數 zhangjun@zhangjun-virtual-machine:~$ uname -a Linux zhangjun-virtual-machine 4.4.0-31-generic #50~14.04.1-Ubuntu SMP Wed Jul 13 01:07:32 UTC ...
1.本地主機的參數
zhangjun@zhangjun-virtual-machine:~$ uname -a
Linux zhangjun-virtual-machine 4.4.0-31-generic #50~14.04.1-Ubuntu SMP Wed Jul 13 01:07:32 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux
zhangjun@zhangjun-virtual-machine:~$ ls /usr/src/linux-headers-4.4.0-31-generic/arch Documentation include Kconfig mm scripts tools zfs
block drivers init kernel Module.symvers security ubuntu
certs firmware ipc lib net sound usr
crypto fs Kbuild Makefile samples spl virt
2.編寫內核模塊文件
編寫自己的內核模塊文件myModule.c,內容如下:
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/types.h>
static int __init myModule_init(void)
{
printk(KERN_INFO"myModule init.\r\n");
return 0;
}
static void __exit myModule_exit(void)
{
printk(KERN_INFO"myModule exit.\r\n");
}
module_init(myModule_init);
module_exit(myModule_exit);
MODULE_LICENSE("GPL");
3.編寫Makefile
#kernel代碼的路徑
KERN_DIR = /usr/src/linux-headers-4.4.0-31-generic/
all:
make -C $(KERN_DIR) M=`pwd` modules
clean:
make -C $(KERN_DIR) M=`pwd` modules clean
obj-m += myModule.o
4.編譯
root@zhangjun-virtual-machine:/home/zhangjun/zj_driver/myModule# make
make -C /usr/src/linux-headers-4.4.0-31-generic/ M=`pwd` modules
make[1]: 正在進入目錄 `/usr/src/linux-headers-4.4.0-31-generic'
CC [M] /home/zhangjun/zj_driver/myModule/myModule.o
Building modules, stage 2.
MODPOST 1 modules
CC /home/zhangjun/zj_driver/myModule/myModule.mod.o
LD [M] /home/zhangjun/zj_driver/myModule/myModule.ko
make[1]:正在離開目錄 `/usr/src/linux-headers-4.4.0-31-generic'
5.安裝驅動
root@zhangjun-virtual-machine:/home/zhangjun/zj_driver/myModule# insmod myModule.ko
root@zhangjun-virtual-machine:/home/zhangjun/zj_driver/myModule# cat /proc/modules
myModule 16384 0 - Live 0xffffffffc03d4000 (OE)
nls_utf8 16384 1 - Live 0xffffffffc016f000
isofs 40960 1 - Live 0xffffffffc03f4000
vmw_vsock_vmci_transport 28672 1 - Live 0xffffffffc03cc000
vsock 36864 2 vmw_vsock_vmci_transport, Live 0xffffffffc0165000
bnep 20480 2 - Live 0xffffffffc0178000
rfcomm 69632 8 - Live 0xffffffffc050b000
nfsd 315392 13 - Live 0xffffffffc05e4000
auth_rpcgss 57344 1 nfsd, Live 0xffffffffc0542000
nfs_acl 16384 1 nfsd, Live 0xffffffffc038b000
nfs 249856 0 - Live 0xffffffffc05a6000
binfmt_misc 20480 1 - Live 0xffffffffc0393000
lockd 90112 2 nfsd,nfs, Live 0xffffffffc052b000
grace 16384 2 nfsd,lockd, Live 0xffffffffc0386000
sunrpc 331776 19 nfsd,auth_rpcgss,nfs_acl,nfs,lockd, Live 0xffffffffc04b9000
fscache 61440 1 nfs, Live 0xffffffffc04a9000
coretemp 16384 0 - Live 0xffffffffc03c7000
kvm_intel 167936 0 - Live 0xffffffffc057c000
kvm 532480 1 kvm_intel, Live 0xffffffffc0426000
snd_ens1371 28672 2 - Live 0xffffffffc0365000
snd_ac97_codec 131072 1 snd_ens1371, Live 0xffffffffc0405000
irqbypass 16384 1 kvm, Live 0xffffffffc0381000
crct10dif_pclmul 16384 0 - Live 0xffffffffc037c000
gameport 16384 1 snd_ens1371, Live 0xffffffffc0373000
crc32_pclmul 16384 0 - Live 0xffffffffc034b000
ac97_bus 16384 1 snd_ac97_codec, Live 0xffffffffc0400000
snd_pcm 106496 2 snd_ens1371,snd_ac97_codec, Live 0xffffffffc03d9000
aesni_intel 167936 0 - Live 0xffffffffc039d000
vmw_balloon 20480 0 - Live 0xffffffffc036d000
snd_seq_midi 16384 0 - Live 0xffffffffc0360000
snd_seq_midi_event 16384 1 snd_seq_midi, Live 0xffffffffc035b000
aes_x86_64 20480 1 aesni_intel, Live 0xffffffffc0355000
lrw 16384 1 aesni_intel, Live 0xffffffffc0321000
gf128mul 16384 1 lrw, Live 0xffffffffc0350000
snd_rawmidi 32768 2 snd_ens1371,snd_seq_midi, Live 0xffffffffc0342000
glue_helper 16384 1 aesni_intel, Live 0xffffffffc033d000
ablk_helper 16384 1 aesni_intel, Live 0xffffffffc0277000
cryptd 20480 2 aesni_intel,ablk_helper, Live 0xffffffffc031b000
joydev 20480 0 - Live 0xffffffffc0315000
input_leds 16384 0 - Live 0xffffffffc0307000
serio_raw 16384 0 - Live 0xffffffffc0233000
snd_seq 69632 2 snd_seq_midi,snd_seq_midi_event, Live 0xffffffffc032b000
snd_seq_device 16384 3 snd_seq_midi,snd_rawmidi,snd_seq, Live 0xffffffffc0326000
snd_timer 32768 2 snd_pcm,snd_seq, Live 0xffffffffc030c000
btusb 45056 0 - Live 0xffffffffc02fb000
btrtl 16384 1 btusb, Live 0xffffffffc0272000
btbcm 16384 1 btusb, Live 0xffffffffc0160000
btintel 16384 1 btusb, Live 0xffffffffc0145000
bluetooth 516096 25 bnep,rfcomm,btusb,btrtl,btbcm,btintel, Live 0xffffffffc027c000
snd 81920 11 snd_ens1371,snd_ac97_codec,snd_pcm,snd_rawmidi,snd_seq,snd_seq_device,snd_timer, Live 0xffffffffc021e000
soundcore 16384 1 snd, Live 0xffffffffc006b000
nfit 32768 0 - Live 0xffffffffc01f0000
vmwgfx 229376 3 - Live 0xffffffffc0239000
ttm 94208 1 vmwgfx, Live 0xffffffffc01d8000
drm_kms_helper 143360 1 vmwgfx, Live 0xffffffffc01fa000
drm 360448 6 vmwgfx,ttm,drm_kms_helper, Live 0xffffffffc017f000
shpchp 36864 0 - Live 0xffffffffc0156000
fb_sys_fops 16384 1 drm_kms_helper, Live 0xffffffffc0151000
syscopyarea 16384 1 drm_kms_helper, Live 0xffffffffc014c000
vmw_vmci 65536 2 vmw_vsock_vmci_transport,vmw_balloon, Live 0xffffffffc0134000
sysfillrect 16384 1 drm_kms_helper, Live 0xffffffffc00fc000
sysimgblt 16384 1 drm_kms_helper, Live 0xffffffffc00b8000
i2c_piix4 24576 0 - Live 0xffffffffc0120000
8250_fintek 16384 0 - Live 0xffffffffc00f7000
parport_pc 36864 0 - Live 0xffffffffc00ae000
ppdev 20480 0 - Live 0xffffffffc0065000
mac_hid 16384 0 - Live 0xffffffffc003d000
lp 20480 0 - Live 0xffffffffc0043000
parport 49152 3 parport_pc,ppdev,lp, Live 0xffffffffc0030000
hid_generic 16384 0 - Live 0xffffffffc004d000
usbhid 49152 0 - Live 0xffffffffc0127000
hid 118784 2 hid_generic,usbhid, Live 0xffffffffc0102000
psmouse 122880 0 - Live 0xffffffffc00d8000
mptspi 24576 2 - Live 0xffffffffc00cd000
mptscsih 40960 1 mptspi, Live 0xffffffffc00be000
mptbase 102400 2 mptspi,mptscsih, Live 0xffffffffc0072000
e1000 135168 0 - Live 0xffffffffc008c000
scsi_transport_spi 32768 1 mptspi, Live 0xffffffffc0052000
ahci 36864 1 - Live 0xffffffffc005b000
libahci 32768 1 ahci, Live 0xffffffffc0027000
pata_acpi 16384 0 - Live 0xffffffffc000f000
fjes 28672 0 - Live 0xffffffffc001f000
vmw_pvscsi 24576 0 - Live 0xffffffffc0014000
vmxnet3 57344 0 - Live 0xffffffffc0000000
安裝驅動應該會調用myModule_init函數,那麼應該有列印輸出,但是實際上沒有;
6.卸載驅動
root@zhangjun-virtual-machine:/home/zhangjun/zj_driver/myModule# rmmod myModule.ko
7.模塊安裝時的列印
步驟5在安裝myModule.ko的時候終端上並沒有列印出信息,但是實際上列印的信息寫入文件/var/log/kern.log,可以通過tail命令查看該文件最後的條目。
root@zhangjun-virtual-machine:/home/zhangjun/zj_driver/myModule# tail -f /var/log/kern.log
Jan 15 11:17:16 zhangjun-virtual-machine kernel: [ 5755.442589] myModule: module verification failed: signature and/or required key missing - tainting kernel
Jan 15 11:17:16 zhangjun-virtual-machine kernel: [ 5755.448875] myModule init.
Jan 15 11:21:12 zhangjun-virtual-machine kernel: [ 5991.177018] myModule exit.
8.關於printk函數
Linux 內核中通過printk輸出信息,信息的類型在文件/usr/src/ linux-headers-4.4.0-31-generic /include/linux/printk.h中(有些源碼在文件include\linux\kernel.h中)定義。
/*
* These can be used to print at the various log levels.
* All of these will print unconditionally, although note that pr_debug()
* and other debug macros are compiled out unless either DEBUG is defined
* or CONFIG_DYNAMIC_DEBUG is set.
*/
#define pr_emerg(fmt, ...) \
printk(KERN_EMERG pr_fmt(fmt), ##__VA_ARGS__)
#define pr_alert(fmt, ...) \
printk(KERN_ALERT pr_fmt(fmt), ##__VA_ARGS__)
#define pr_crit(fmt, ...) \
printk(KERN_CRIT pr_fmt(fmt), ##__VA_ARGS__)
#define pr_err(fmt, ...) \
printk(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__)
#define pr_warning(fmt, ...) \
printk(KERN_WARNING pr_fmt(fmt), ##__VA_ARGS__)
#define pr_warn pr_warning
#define pr_notice(fmt, ...) \
printk(KERN_NOTICE pr_fmt(fmt), ##__VA_ARGS__)
#define pr_info(fmt, ...) \
printk(KERN_INFO pr_fmt(fmt), ##__VA_ARGS__)
如果不指定,預設是 DEFAULT_MESSAGE_LOGLEVE,和KERN_WARNING一樣。
root@vickytong:/usr/src/ linux-headers-4.4.0-31-generic# find . -name “*.h” |
xargs grep “DEFAULT_MESSAGE_LOGLEVE”
./include/generated/autoconf.h: #define CONFIG_MESSAGE_LOGLEVEL_DEFAULT 4
9.交叉編譯
有時候我們需要將模塊移植到其他晶元方案的主機(或開發板)上運行,那麼需要交叉編譯。交叉編譯需要修改Makefile,主要是修改kernel代碼的路徑和編譯工具。kernel代碼的路徑要修改為目的主機系統的源代碼路徑,編譯工具gcc要修改為目的主機晶元架構對應的編譯工具。 設置編譯器,與編譯內核用的編譯器要一致。下麵為編譯驅動時,在terminal終端設置環境變數如下:
root@zhangjun-virtual-machine:/home/zhangjun/zj_driver/myModule# source /opt/Xilinx/SDK/2015.4/settings64.sh
root@zhangjun-virtual-machine:/home/zhangjun/zj_driver/myModule# export ARCH=arm
root@zhangjun-virtual-machine:/home/zhangjun/zj_driver/myModule# export CROSS_COMPILE=arm-xilinx-linux-gnueabi-
說明:在目前ZedBoard上跑的linux系統,使用該編譯器似乎也能編譯驅動插入到內核中去(後面做gpio驅動時仔細驗證):
root@zhangjun-virtual-machine:/home/zhangjun/zj_driver/myModule# export ARCH=arm
root@zhangjun-virtual-machine:/home/zhangjun/zj_driver/myModule# export CROSS_COMPILE= arm-linux-gnueabihf-
makefile文件修改如下:
#kernel代碼的路徑
KERN_DIR = /home/zhangjun/linux
obj-m := myModule.o
all:
make -C $(KERN_DIR) ARCH=arm M=`pwd` modules
clean:
rm -rf .*.cmd *.o *.mod.c *.ko .tmp_versions
10.下載、安裝和卸載
在Zedboard上的linux掛在nfs,在Terminal上做如下操作:
analog@analog:~$ sudo mount -t nfs 192.168.0.25:/home/zhangjun /mnt/
mount.nfs: /mnt is busy or already mounted
analog@analog:~$ cd /mnt
analog@analog:/mnt$ cd zj_driver
analog@analog:/mnt/zj_driver$ ls
driver_demo myModule
analog@analog:/mnt/zj_driver$ cd myModule
analog@analog:/mnt/zj_driver/myModule$ ls
Makefile Module.symvers myModule.c myModule.ko myModule.mod.o
Makefile~ modules.order myModule.c~ myModule.mod.c myModule.o
analog@analog:/mnt/zj_driver/myModule$ insmod myModule.ko
insmod: ERROR: could not insert module myModule.ko: Operation not permitted
analog@analog:/mnt/zj_driver/myModule$ sudo su
root@analog:/mnt/zj_driver/myModule# insmod myModule.ko
root@analog:/mnt/zj_driver/myModule# cat /proc/modules
myModule 737 0 - Live 0xbf000000 (O)
root@analog:/mnt/zj_driver/myModule# rmmod myModule.ko
11.添加模塊參數
有時候需要從用戶態傳參數給內核模塊,這時候在內核模塊中需要通過巨集module_param聲明參數。本例增加兩個參數,一個是字元串參數cString,一個是int型參數iInt,修改後代碼如下:
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/types.h>
static char* cString = NULL;
static int iInt = 0;
module_param(cString, charp, 0644);
module_param(iInt, int, 0644);
static int __init myModule_init(void)
{
printk(KERN_INFO"myModule init, cString = %s, iInt = %d\r\n", cString, iInt);
return 0;
}
static void __exit myModule_exit(void)
{
printk(KERN_INFO"myModule exit.\r\n");
}
module_init(myModule_init);
module_exit(myModule_exit);
MODULE_LICENSE("GPL");
交叉編譯後,下載,安裝命令如下:
/tmp # insmod
myModule.ko cString=helloworld iInt=100
myModule init, cString = helloworld, iInt = 100