使用Virtual Box撰寫適用於RPi 4B的自定義driver
使用Virtual Box撰寫適用於RPi 4B的自定義driver
在本文提供的自定義driver步驟中,首先由撰寫一個可每隔一段時間印出HELLO WORLD
的driver原始檔(.c)開始,並將其定義為Character device。接下來則透過Virtual Box Cross Compile後,安裝自定義driver至Rasbberry Pi 4B中。
注意
有關Linux Kernel for Raspberry Pi的source code下載,請參考這篇,本文的~\linux
目錄與其相同。
建立自定義Driver(Hello.c)
在
~/linux/drivers/char
中,新增一個hello
目錄mkdir ~/linux/drivers/char/hello cd ~/linux/drivers/char/hello
在其中新增一個
Hello.c
檔案vi Hello.c
在
Hello.c
檔案編輯畫面中,撰寫以下程式碼程式說明
此程式會每隔1秒印出一次"HELLO, WORLD!"到kernel ring buffer中,可使用
dmesg
指令查看。#include <linux/module.h> #include <linux/kernel.h> #include <linux/timer.h> #define DELAY 1 * HZ // 1 sec static struct timer_list my_timer; void print_hello_world(struct timer_list *timer){ printk(KERN_INFO "HELLO, WORLD!\n"); mod_timer(&my_timer, jiffies + DELAY); } static int __init hello_init(void){ printk(KERN_INFO "Init 'HELLO, WORLD!' timer.\n"); timer_setup(&my_timer, print_hello_world, 0); mod_timer(&my_timer, jiffies + DELAY); return 0; } static void __exit hello_exit(void){ printk(KERN_INFO "Stop 'HELLO, WORLD!' timer.\n"); del_timer(&my_timer); } module_init(hello_init); // insmod //late_initcall(hello_init); // built-in module_exit(hello_exit); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("A simple HELLO WORLD kernel module"); MODULE_AUTHOR("USER");
請注意Driver init時間點
在第31與32行中,有兩種呼叫程式初始化的函式:
- 如果準備使用insmod安裝driver,可使用
module_init()
即可。 - 如果準備使用built-in方式直接安裝driver到kernel,請使用
late_initcall()
。- 原因:在boot的過程中,built-in driver可能在timer及printk還未啟用的情況下就初始化,造成執行失敗。而
late_initcall()
可確保driver在boot結束後才啟用,防止上述問題。
- 原因:在boot的過程中,built-in driver可能在timer及printk還未啟用的情況下就初始化,造成執行失敗。而
- 如果準備使用insmod安裝driver,可使用
在
~/linux/drivers/char/hello
目錄中,建立一個Makefile
vi Makefile
在
Makefile
中撰寫以下程式obj-$(CONFIG_HELLO) += hello.o
driver/char
的Kernel設定
移動至
~/linux/drivers/char/
目錄cd ~/linux/drivers/char/
編輯
Makefile
,在最後一行加入剛剛建立的hello/
目錄# SPDX-License-Identifier: GPL-2.0 # # Makefile for the kernel character device drivers. # obj-y += mem.o random.o ... obj-$(CONFIG_HELLO) += hello/
編輯
Kconfig
,在第12行開始加入hello
module設定# SPDX-License-Identifier: GPL-2.0 # # Character device configuration # menu "Character devices" source "drivers/char/broadcom/Kconfig" source "drivers/tty/Kconfig" config HELLO tristate "Enable Hello" default y help Example hello ...
default設定
- y: 將編譯built-in driver(直接安裝到kernel)
- m: 將編譯.ko檔案(用於稍後執行
insmod
) - n: 不編譯driver
可在
menuconfig
中找到剛剛建立的設定cd ~/linux make menuconfig
在選單中依序選擇
Device Drivers->Character devices->Enable Hello
。
執行編譯
回到
~/linux
cd ~/linux
make編譯指令
指令詳細說明請參考先前文章(Kernel Cross Compile)
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- bcm2711_defconfig make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- LOCALVERSION="-[customname]-raspi-" Image modules dtbs
提示
如果先前已經進行cross compilation,此步驟將只編譯新的driver(module)及Kernel Image。
安裝Driver
相關信息
安裝部分分為built-in與insmod:
A. built-in
複製新Kernel Image及dtb檔案到SD Card中
sudo cp arch/arm64/boot/Image /media/[username]/bootfs/kernel-[custom_name].img sudo cp arch/arm64/boot/dts/broadcom/*.dtb /media/[username]/bootfs/ sudo cp arch/arm64/boot/dts/overlays/*.dtb* /media/[username]/bootfs/overlays
安裝新driver
sudo env PATH=$PATH make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- M=drivers/char/hello INSTALL_MOD_PATH=/media/[username]/rootfs modules_install
指令說明
M=[path/to/driver]
可指定要安裝的driver,如此便不須全部重新安裝將SD Card插入Raspberry Pi,並在樹梅派中查看訊息
執行
dmesg | tail
後,可看到HELLO, WORLD!
每隔1秒印出。user@rpi:~$ dmesg | tail [ 41.502956] HELLO, WORLD! [ 42.526977] HELLO, WORLD! [ 43.550955] HELLO, WORLD! [ 44.574955] HELLO, WORLD! [ 45.598962] HELLO, WORLD! [ 46.622967] HELLO, WORLD! [ 47.646964] HELLO, WORLD! [ 48.670959] HELLO, WORLD! [ 49.694963] HELLO, WORLD! [ 50.718964] HELLO, WORLD!
B. insmod
在
~/linux/drivers/char/hello
目錄底下,可看到hello.ko
檔案cd ~/linux/drivers/char/hello ls
複製
hello.ko
檔案到樹梅派SD Card的rootfs\home\[username]\
下cp hello.ko \media\[vb_username]\rootfs\home\[rpi_username]\
將SD Card插入Raspberry Pi,並使用
insmod
指令安裝driversudo insmod hello.ko
查看訊息(dmesg)
user@rpi:~$ dmesg | tail [ 50.032457] Init 'HELLO, WORLD!' timer. [ 51.039001] HELLO, WORLD! [ 52.062995] HELLO, WORLD! [ 53.087001] HELLO, WORLD! [ 54.111005] HELLO, WORLD! [ 55.951000] HELLO, WORLD! [ 56.974998] HELLO, WORLD! [ 57.998998] HELLO, WORLD! [ 58.022998] HELLO, WORLD! [ 59.047000] HELLO, WORLD!
移除driver
sudo rmmod hello
查看訊息(dmesg)
user@rpi:~$ dmesg | tail [ 61.151014] HELLO, WORLD! [ 62.175002] HELLO, WORLD! [ 63.199002] HELLO, WORLD! [ 64.222998] HELLO, WORLD! [ 64.485384] Stop 'HELLO, WORLD!' timer.
- 0
- 0
- 0
- 0
- 0
- 0
Preview: