これは何?
Ubuntu18.04でPEX-361316を利用したい。
いくつかモジュールを組み込む必要があるが、カーネルが新しいため、ビルドが必要。ビルドを通す際の記録。
いくつかビルドを通す必要があるが、長くなるため、dpg0100
のみを取り上げます。
ビルドを通すまで
とりあえずmake
$ cd ~/work/PEX-361316/common/dpg0100/src
$ make
cc1: fatal error: /lib/modules/5.0.0-37-generic/build/include/linux/version.h: そのようなファイルやディレクトリはありません
compilation terminated.
gcc -DMODULE -D__KERNEL__ -DEXPORT_SYMTAB -Wall -Wstrict-prototypes -O -fomit-frame-pointer -pipe -ffreestanding -fno-strict-aliasing -fno-common -I/lib/modules/5.0.0-37-generic/build/include -I/lib/modules/5.0.0-37-generic/build/arch/x86/include -I/lib/modules/5.0.0-37-generic/build/include/asm/mach-default -I/lib/modules/5.0.0-37-generic/build/arch/x86/include/asm/mach-generic -mcmodel=kernel -mno-red-zone -include /lib/modules/5.0.0-37-generic/build/include/generated/autoconf.h -D__SMP__ -DEXPORT_SYMTAB -D"KBUILD_STR(s)=#s" -D"KBUILD_BASENAME=KBUILD_STR(dpg0100)" -D"KBUILD_MODNAME=KBUILD_STR(dpg0100)" -c -o dpg0100.o dpg0100.c
cc1: error: code model kernel does not support PIC mode
<ビルトイン>: recipe for target 'dpg0100.o' failed
make: *** [dpg0100.o] Error 1
version.h
が無いため、生成する。
$ sudo apt install linux-headers-`uname -r`
$ cd /usr/src/linux-headers-5.0.0-37/
$ sudo make include/generated/uapi/linux/version.h
$ sudo ln -s /usr/src/linux-headers-5.0.0-37/include/generated/uapi/linux/version.h /lib/modules/5.0.0-37-generic/build/include/linux/version.h
$ cd ~/work/PEX-361316/common/dpg0100/src
$ make
gcc -DMODULE -D__KERNEL__ -DEXPORT_SYMTAB -Wall -Wstrict-prototypes -O -fomit-frame-pointer -pipe -ffreestanding -fno-strict-aliasing -fno-common -I/lib/modules/5.0.0-37-generic/build/include -I/lib/modules/5.0.0-37-generic/build/arch/x86/include -I/lib/modules/5.0.0-37-generic/build/include/asm/mach-default -I/lib/modules/5.0.0-37-generic/build/arch/x86/include/asm/mach-generic -mcmodel=kernel -mno-red-zone -include /lib/modules/5.0.0-37-generic/build/include/generated/autoconf.h -D__SMP__ -DEXPORT_SYMTAB -D"KBUILD_STR(s)=#s" -D"KBUILD_BASENAME=KBUILD_STR(dpg0100)" -D"KBUILD_MODNAME=KBUILD_STR(dpg0100)" -c -o dpg0100.o dpg0100.c
cc1: error: code model kernel does not support PIC mode
<ビルトイン>: recipe for target 'dpg0100.o' failed
make: *** [dpg0100.o] Error 1
以下を/lib/modules/5.0.0-37-generic/build/Makefile
内のall: vmlinux
の下に追加。
# force no-pie for distro compilers that enable pie by default
KBUILD_CFLAGS += $(call cc-option, -fno-pie)
KBUILD_CFLAGS += $(call cc-option, -no-pie)
KBUILD_AFLAGS += $(call cc-option, -fno-pie)
KBUILD_CPPFLAGS += $(call cc-option, -fno-pie)
あわせてdpg0100/src/Makefile
も更新。
CFLAGS += -I$(INCLUDEDIR)
CFLAGS += -fno-pie # 追加
$ make
gcc -DMODULE -D__KERNEL__ -DEXPORT_SYMTAB -Wall -Wstrict-prototypes -O -fomit-frame-pointer -pipe -ffreestanding -fno-strict-aliasing -fno-common -I/lib/modules/5.0.0-37-generic/build/include -fno-pie -I/lib/modules/5.0.0-37-generic/build/arch/x86/include -I/lib/modules/5.0.0-37-generic/build/include/asm/mach-default -I/lib/modules/5.0.0-37-generic/build/arch/x86/include/asm/mach-generic -mcmodel=kernel -mno-red-zone -include /lib/modules/5.0.0-37-generic/build/include/generated/autoconf.h -D__SMP__ -DEXPORT_SYMTAB -D"KBUILD_STR(s)=#s" -D"KBUILD_BASENAME=KBUILD_STR(dpg0100)" -D"KBUILD_MODNAME=KBUILD_STR(dpg0100)" -c -o dpg0100.o dpg0100.c
In file included from /lib/modules/5.0.0-37-generic/build/arch/x86/include/asm/cpufeature.h:5:0,
…
from dpg0100.c:9:
/lib/modules/5.0.0-37-generic/build/arch/x86/include/asm/processor.h:412:15: error: missing binary operator before token "("
#if IS_ENABLED(CONFIG_KVM)
^
…
/lib/modules/5.0.0-37-generic/build/include/linux/mmzone.h: At top level:
/lib/modules/5.0.0-37-generic/build/include/linux/mmzone.h:147:15: error: missing binary operator before token "("
#if IS_ENABLED(CONFIG_ZSMALLOC)
^
In file included from /lib/modules/5.0.0-37-generic/build/arch/x86/include/asm/realmode.h:15:0,
…
from /lib/modules/5.0.0-37-generic/build/include/linux/module.h:13,
from dpg0100.c:9:
/lib/modules/5.0.0-37-generic/build/arch/x86/include/asm/io.h:44:10: fatal error: asm/early_ioremap.h: そのようなファイルやディレクトリはありません
#include <asm/early_ioremap.h>
^~~~~~~~~~~~~~~~~~~~~
compilation terminated.
<ビルトイン>: recipe for target 'dpg0100.o' failed
make: *** [dpg0100.o] Error 1
IS_ENABLED
マクロはkconfig.h
にあるようなので、インクルード対象に追加。
#include <linux/kconfig.h> // 追加
ヘッダファイルが見つからないのは、version.h
と同様にリンクすれば解決する。
$ find /usr/src/linux-headers-5.0.0-37-generic/ -name '*ioremap*'
/usr/src/linux-headers-5.0.0-37-generic/arch/x86/include/generated/asm/early_ioremap.h
/usr/src/linux-headers-5.0.0-37-generic/include/config/have/ioremap
/usr/src/linux-headers-5.0.0-37-generic/include/config/generic/early/ioremap.h
$ sudo ln -s /usr/src/linux-headers-5.0.0-37-generic/arch/x86/include/generated/asm/early_ioremap.h /lib/modules/5.0.0-37-generic/build/arch/x86/include/asm/early_ioremap.h
$ # 以下makeやfindするのは省略
$ sudo ln -s /usr/src/linux-headers-5.0.0-37-generic/arch/x86/include/generated/asm/unistd_64_x32.h /lib/modules/5.0.0-37-generic/build/arch/x86/include/asm/unistd_64_x32.h
$ sudo ln -s /usr/src/linux-headers-5.0.0-37-generic/arch/x86/include/generated/asm/unistd_32_ia32.h /lib/modules/5.0.0-37-generic/build/arch/x86/include/asm/unistd_32_ia32.h
$ sudo ln -s /usr/src/linux-headers-5.0.0-37/include/uapi/linux/rseq.h /lib/modules/5.0.0-37-generic/build/include/linux/rseq.h
$ make
…
/lib/modules/5.0.0-37-generic/build/include/linux/signal_types.h: At top level:
/lib/modules/5.0.0-37-generic/build/include/linux/signal_types.h:13:2: error: expected specifier-qualifier-list before ‘__SIGINFO’
__SIGINFO;
^~~~~~~~~
dpg0100.c:20:10: fatal error: asm/system.h: そのようなファイルやディレクトリはありません
#include <asm/system.h>
^~~~~~~~~~~~~~
compilation terminated.
<ビルトイン>: recipe for target 'dpg0100.o' failed
make: *** [dpg0100.o] Error 1
__SIGINFO
を定義しているヘッダファイルをインクルードできていない。
siginfo.h
を差し替えて対応。
$ sudo mv /usr/include/asm-generic/siginfo.h /usr/include/asm-generic/siginfo.h.bak
$ sudo ln -s /usr/src/linux-headers-5.0.0-37/include/uapi/asm-generic/siginfo.h /usr/include/asm-generic/siginfo.h
<asm/system.h>
は現在、いくつかのヘッダファイルに分割されているらしい。
とりあえずコメントに変更し、make
。いくつかエラーが出てきたため、修正。
//#include <asm/system.h> // コメントに
//return MINOR(((struct file *)file)->f_dentry->d_inode->i_rdev);
return MINOR(((struct file *)file)->f_path.dentry->d_inode->i_rdev);
/*
ret = get_user_pages(current, current->mm, (Buffer & PAGE_MASK),
mdl->NumberOfPages, Direction, 1,
(struct page **)mdl->PageList, NULL);
*/
if(Direction == 1) {
ret = get_user_pages((Buffer & PAGE_MASK), mdl->NumberOfPages,
FOLL_FORCE | FOLL_WRITE, (struct page **)mdl->PageList, NULL);
} else {
ret = get_user_pages((Buffer & PAGE_MASK), mdl->NumberOfPages,
FOLL_FORCE, (struct page **)mdl->PageList, NULL);
}
//page_cache_release((struct page *)mdl->PageList[i]);
put_page((struct page *)mdl->PageList[i]);
// もう1箇所同様に修正
dpg0100.c
のコンパイルが通るようになった。
$ make
In file included from /lib/modules/5.0.0-37-generic/build/include/linux/mm_types.h:5:0,
from /lib/modules/5.0.0-37-generic/build/arch/x86/include/asm/vdso.h:11,
from /lib/modules/5.0.0-37-generic/build/arch/x86/include/asm/elf.h:77,
from /lib/modules/5.0.0-37-generic/build/include/linux/elf.h:5,
from /lib/modules/5.0.0-37-generic/build/include/linux/elfnote.h:62,
from /lib/modules/5.0.0-37-generic/build/include/linux/build-salt.h:4,
from dpg0100.mod.c:1:
/lib/modules/5.0.0-37-generic/build/include/linux/mm_types.h: At top level:
/lib/modules/5.0.0-37-generic/build/include/linux/mm_types_task.h:24:13: error: missing binary operator before token "("
IS_ENABLED(CONFIG_ARCH_ENABLE_SPLIT_PMD_PTLOCK))
^
…
/lib/modules/5.0.0-37-generic/build/arch/x86/include/asm/irq_vectors.h:102:15: error: missing binary operator before token "("
#if IS_ENABLED(CONFIG_HYPERV)
^
Makefile:309: recipe for target 'dpg0100.mod.o' failed
make: *** [dpg0100.mod.o] Error 1
dpg0100.mod.c
が生成されたが、ビルドが通らないため、dpg0100.c
と同じように対処。
#include <linux/kconfig.h> // 追加
$ make
…
ld -m elf_x86_64 -r -o dpg0100.ko dpg0100.o dpg0100.mod.o
$ sudo make install
mkdir -p /lib/modules/5.0.0-37-generic/misc
cp -f dpg0100.ko /lib/modules/5.0.0-37-generic/misc
$
dpg0100
のビルドができました。
カーネル 5.0.37 から 5.3.26 への対応
カーネルの変化でビルドの通し方がちょっと変わった。
以下以外は5.0.37と同じです。
$ sudo ln -s /usr/src/linux-headers-5.3.0-26/include/uapi/linux/time_types.h /lib/modules/5.3.0-26-generic/build/include/linux/time_types.h
$ sudo ln -s /usr/src/linux-headers-5.3.0-26-generic/arch/x86/include/generated/asm/mmiowb.h /lib/modules/5.3.0-26-generic/build/arch/x86/include/asm/mmiowb.h
#include <linux/kconfig.h>
typedef long long __kernel_time64_t; // 追加
#include <linux/kconfig.h> // 追加( 5.0.37の時も )
typedef long long __kernel_time64_t; // 追加
ロード
$ sudo depmod -a
$ sudo modprobe dpg0100
modprobe: ERROR: could not insert 'dpg0100': Unknown symbol in module, or unknown parameter (see dmesg)
$ dmesg
...
[ xxx.xxx] dpg0100: module license 'unspecified' taints kernel.
[ xxx.xxx] Disabling lock debugging due to kernel taint
[ xxx.xxx] dpg0100: module verification failed: signature and/or required key missing - tainting kernel
[ xxx.xxx] dpg0100: Unknown symbol init_timer (err -2)
[ xxx.xxx] dpg0100: Unknown symbol sev_enable_key (err -2)
$
うまくロードできない。
init_timer
, sev_enable_key
は今使用しているLinuxカーネルでは廃止されているらしい。
init_timer
はtimer_setup
に差し替える。
/* コールバック関数、タイマーが切れたときに呼ばれる。 */
static void gpg_timer_fn(struct timer_list *t)
{
return;
}
void gpg_init_timer(void *timer)
{
//init_timer((struct timer_list *)timer);
timer_setup((struct timer_list *)timer, gpg_timer_fn, 0);
return;
}
sev_enable_key
はコード内に現れない。
$ grep -R sev_enable_key ~/work/PEX-361316/
バイナリファイル xxx/PEX-361316/common/dpg0100/src/dpg0100.o に一致しました
バイナリファイル xxx/PEX-361316/common/dpg0100/src/dpg0100.ko に一致しました
$ grep -R sev_enable_key /lib/modules/5.0.0-37-generic/
...
/lib/modules/5.0.0-37-generic/build/arch/x86/include/asm/io.h:extern struct static_key_false sev_enable_key;
/lib/modules/5.0.0-37-generic/build/arch/x86/include/asm/io.h: return static_branch_unlikely(&sev_enable_key);
...
バイナリファイル /lib/modules/5.0.0-37-generic/kernel/drivers/tty/isicom.ko に一致しました
バイナリファイル /lib/modules/5.0.0-37-generic/misc/dpg0100.ko に一致しました
$ sudo grep -R 'sev_enable_key' /boot/
/boot/System.map-5.0.0-37-generic:ffffffff82417c98 r __ksymtab_sev_enable_key
/boot/System.map-5.0.0-37-generic:ffffffff8241b46b r __kstrtab_sev_enable_key
/boot/System.map-5.0.0-37-generic:ffffffff82b57000 B sev_enable_key
/boot/System.map-5.0.0-23-generic:ffffffff823fd988 r __ksymtab_sev_enable_key
/boot/System.map-5.0.0-23-generic:ffffffff8240113e r __kstrtab_sev_enable_key
/boot/System.map-5.0.0-23-generic:ffffffff82b55000 B sev_enable_key
/boot/System.map-5.3.0-26-generic:ffffffff82454268 r __ksymtab_sev_enable_key
/boot/System.map-5.3.0-26-generic:ffffffff82457b4a r __kstrtab_sev_enable_key
/boot/System.map-5.3.0-26-generic:ffffffff82b75690 B sev_enable_key
カーネル内にsev_enable_key
が含まれているようにみえる。sev_enable_key
自体の定義は、EXPORT_SYMBOL_GPL(sev_enable_key);
となっている。
そこで、試しに
MODULE_AUTHOR("Interface Corporation <http://www.interface.co.jp>");
MODULE_LICENSE("GPL"); // 追加
としてみた。
$ make
$ sudo make install
$ sudo modprobe dpg0100
$ dmesg
[ xxx.xxx] dpg0100:Interface Common Device Driver (Ver2.80.13.00) loaded.
$ lsmod | grep dpg
dpg0100 45056 0
GPLライセンス有効とすれば、利用できるようです。
Wikipediaにある以下の記載に引っかかったようです。
ライセンス問題
Linuxカーネルコミュニティによれば、LKMはカーネルの二次的著作物(derivative works)[12]である。Linuxカーネル開発者はプロプライエタリなモジュールの配布を許容しているが、一部のカーネルシンボルはGPLのモジュールにのみ利用を許している。
GPG-3100のreadme.txtを参照し、
PEX-361316を利用する目的での改変であること、'19年8月でサポートが切れている事から、MODULE_LICENSE("GPL");
としても問題ないと前向きに解釈し、進めたいと思います。
本記事を参考にやる方は自己責任でお願いいたします。(ライセンスの話も関わっているので、明記させていただきます。)
CP3100ロード時の問題対処
CP3100をロードすると、Unknown symbol gpg_outl (err -2)
など、なぜか参照できないシンボルがある。
色々検索してみると、リンクに課題があるようです。
思い切って、Makefile
を以下にしたら解決しました。
obj-m = dpg0100.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
install:
cp -f dpg0100.ko /lib/modules/$(shell uname -r)/misc
参考ページ
- compiling - Help locating linux/version.h - Ask Ubuntu
- Linux-kernel 4.15.0-42-generic (Ubuntu 18.04)環境でのデバイスドライバーのコンパイル - エゼキエル書25章17節……
- [Linuxカーネルのソースコードを読む方法(その1) - pyopyopyo - Linuxとかプログラミングの覚え書き - ]
(http://pyopyopyo.hatenablog.com/entry/2019/02/19/133956) - [drivers - asm/system.h header file linux - Super User]
(https://superuser.com/questions/783285/asm-system-h-header-file-linux) - [error: ‘struct file’ has no member named ‘f_dentry’というコンパイルエラーが出たときは | mipsparcのメモ帳]
(https://mipsparc.wordpress.com/2016/09/16/error-struct-file-has-no-member-named-f_dentry%E3%81%A8%E3%81%84%E3%81%86%E3%82%B3%E3%83%B3%E3%83%91%E3%82%A4%E3%83%AB%E3%82%A8%E3%83%A9%E3%83%BC%E3%81%8C%E5%87%BA/) - インターフェイス社ドライバの再コンパイル - Qiita
- c - Unknown symbol vfs_write (err -2) in kernel module in kernel 4.20 - Stack Overflow
- Unknown symbol ... はカーネルが新しくなって無くなったシンボルであることをここで把握
- linuxカーネル内部インターフェースの変更例 - Qiita
- ローダブル・カーネル・モジュール - Wikipedia
- linux - EXPORT_SYMBOLはシンボルをグローバルにエクスポートしません - 答えた
- Linux カーネルモジュールのコンパイル - Qiita