カーネルを再コンパイルせずにロード可能なカーネルモジュールをコンパイルする方法


20

Raspberry Piで(およびそのために)カーネルモジュールをコンパイルする方法についてはかなり読みましたが、なぜそれが機能しないのかを理解することはまだできません。モジュールをビルドできましたInvalid module formatinsmod、結果を表示しようとするとレポートされます。ここに私が従ったプロセスがあります。まず、rootで/root次のシェルスクリプトを実行しました。

getKernel.sh

#! /usr/bin/bash
FIRMWARE_HASH=$(zgrep "* firmware as of" /usr/share/doc/raspberrypi-bootloader/changelog.Debian.gz | head -1 | awk '{ print $5 }')
KERNEL_HASH=$(wget https://raw.githubusercontent.com/raspberrypi/firmware/$FIRMWARE_HASH/extra/git_hash -O -)
git clone https://github.com/raspberrypi/linux 
cd linux
git checkout $KERNEL_HASH
wget https://raw.githubusercontent.com/raspberrypi/firmware/$FIRMWARE_HASH/extra/Module.symvers 
zcat /proc/config.gz >.config
make oldconfig
make modules_prepare
ln -s /root/linux /lib/modules/$(uname -r)/build 

最初の数行はhttp://lostindetails.com/blog/post/Compiling-a-kernel-module-for-the-raspberry-pi-2からのものです

残りの部分は、より多くのプロセスを自動化するために書きました。すべてが正常に実行されると、実行中のカーネルに完全に一致するソース、一致する構成、およびシンボリックリンクが得られます。github Webロケーションからのリダイレクトがいくつかありました(現在はhttps://raw.githubusercontent.com/です)が、実際のエラーはありません。

次に、デフォルトのpiユーザーになり、という名前のディレクトリ/home/pi/projects/lkmに、非常に単純なおもちゃモジュールのこのソースコードがあります。

こんにちはC

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

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Do-nothing test driver");
MODULE_VERSION("0.1");

static int __init hello_init(void){
   printk(KERN_INFO "Hello, world.\n");
   return 0;
}

static void __exit hello_exit(void){
   printk(KERN_INFO "Goodbye, world.\n");
}

module_init(hello_init);
module_exit(hello_exit);

最後に、このMakefileでモジュールをビルドします

メイクファイル

MODSRC=/home/pi/projects/lkm
obj-m+=hello.o

all:
    make -C /lib/modules/$(shell uname -r)/build M=${MODSRC} modules

clean:
    make -C /lib/modules/$(shell uname -r)/build M=${MODSRC} clean

最後に、モジュールをロードしようとします:

sudo insmod hello.ko

しかし、結果は残念です。

insmod:エラー:モジュールhello.koを挿入できませんでした:モジュール形式が無効です

関連する可能性のある詳細

jessieRaspberry Pi2でRaspbianの現在最新バージョンを使用しています。

$ uname --kernel-release --kernel-version
4.1.13-v7+ #826 SMP PREEMPT Fri Nov 13 20:19:03 GMT 2015
$ gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/arm-linux-gnueabihf/4.9/lto-wrapper
Target: arm-linux-gnueabihf
Configured with: ../src/configure -v --with-pkgversion='Raspbian 4.9.2-10' --with-bugurl=file:///usr/share/doc/gcc-4.9/README.Bugs --enable-languages=c,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.9 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.9 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --disable-libitm --disable-libquadmath --enable-plugin --with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-4.9-armhf/jre --enable-java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-4.9-armhf --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-4.9-armhf --with-arch-directory=arm --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --enable-objc-gc --enable-multiarch --disable-sjlj-exceptions --with-arch=armv6 --with-fpu=vfp --with-float=hard --enable-checking=release --build=arm-linux-gnueabihf --host=arm-linux-gnueabihf --target=arm-linux-gnueabihf
Thread model: posix
gcc version 4.9.2 (Raspbian 4.9.2-10) 

残念ながら、これをさらにトラブルシューティングまたは修正する方法がわかりません。手がかりはありますか?


私は、スクリプトにすべての私の調査結果や経験をコンパイルし、参照github.com/x29a/kernel/blob/master/rpi/prepare.shおよび関連ブログ投稿のblog.chris007.de/...
x29a

回答:


23

まず、適切なカーネルヘッダーを使用していることを確認してください。カーネルヘッダーとソースコードは、実行中のカーネルよりも更新されていると思います。

実行してからapt-get update && apt-get upgradeモジュールを再インストールしてください。問題が解決しない場合は、カーネルヘッダーが現在のカーネルと一致することを3回確認し、再コンパイルしてからインストールしてください。


注:私はジェシーを使用しています。

更新: これらをルートとして実行します。

# The usual update routine
apt-get update -y
apt-get upgrade -y

# Update the kernel!
rpi-update

再起動が必要になる場合があります。その後、引き続きルートアカウントを使用して、以下のコマンドを実行します。

# Get rpi-source
sudo wget https://raw.githubusercontent.com/notro/rpi-source/master/rpi-source -O /usr/bin/rpi-source

# Make it executable
sudo chmod +x /usr/bin/rpi-source

# Tell the update mechanism that this is the latest version of the script
/usr/bin/rpi-source -q --tag-update

# Get the kernel files thingies.
rpi-source

rpi-sourceGCCエラー(バージョンの不一致に関する何か)がスローされた場合、現在のGCCバージョンがより高ければ問題ありませんrpi-source --skip-gcc代わりに実行rpi-source

次に、Hello Worldの例を続行します。フォルダーを作成し、その中に入れますcd。次に、ファイルを作成します。

mkdir hello
cd hello

ファイル:

こんにちはC

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

int hello_init(void)
{
    pr_alert("Hello World :)\n");
    return 0;
}
void hello_exit(void)
{
    pr_alert("Goodbye World!\n");
}
module_init(hello_init);
module_exit(hello_exit);

Makefile(大文字と小文字を区別しますか?)

obj-m := hello.o

ファイルができたので、先に進み、通常のHello Worldビルドコマンドを実行できます。

make -C /lib/modules/$(uname -r)/build M=$(pwd) modules
insmod hello.ko

確認してくださいdmesg。最後の行はHello World :)赤で強調表示されて印刷されます。

もしそうなら、おめでとうございます。カーネルモジュールを作成してインストールしました。

次に、を使用して削除し rmmod helloます。dmesgこれでGoodbye World!、赤でハイライト表示されます。

出典:1 2 3


「カーネルヘッダーが現在のカーネルと一致していることを確認する」と言うとき、どうすればいいのでしょうか。
エドワード

@Edwardが更新されました。
PNDA

@Edwardこれがハローワールドの例であることに注意してください。モジュールを作成しましたが、同じであることに気付きました。唯一の違いは、コードに赤いハイライトがないことです。
PNDA

@Edwardあなたの場合、rpi-source部品が十分になるまで指示に従うと思います。その時点からあなたのものを構築してみてください。
PNDA

5

jessiestretchでテストされた、はるかに単純なバージョンがあります

sudo apt-get install raspberrypi-kernel-headers

そして、あなたのファイルが適切な場所にあるとき:

make -C /lib/modules/$(uname -r)/build M=$(pwd) modules

作成しhelloたディレクトリを、中に入ると、以下のファイルを作成しますhello.cMakefile

私はお勧めしますあなたの通常のユーザーとして働いていないルートのみinsmodrmmodおよびmake modules_installコマンドは、root権限を必要とし、必要に応じては、sudo以下のコマンドに示されています。


hello.c(変更なし、ファイル)

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

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Do-nothing test driver");
MODULE_VERSION("0.1");

static int __init hello_init(void){
   printk(KERN_INFO "Hello, world.\n");
   return 0;
}

static void __exit hello_exit(void){
   printk(KERN_INFO "Goodbye, world.\n");
}

module_init(hello_init);
module_exit(hello_exit);

メイクファイル(変更)

obj-m+=hello.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

modules_install: all
    $(MAKE) -C $(KERNEL_SRC) M=$(SRC) modules_install
    $(DEPMOD)   

使用法

  • ビルド:make(Makefileと同じディレクトリ内)
  • テスト
    • モジュールを挿入します sudo insmod hello.ko
    • Hello World :)の出力で見つけるdmesg
    • でモジュールを取り外します sudo rmmod hello
    • Goodbye, world.intの出力を見つけますdmesg
  • インストールは、モジュールが動作しているときに、sudo make modules_installそれが属するモジュールをインストールするため、modprobe動作します。

1
'raspberrypi-kernel'パッケージを使用してインストールされたカーネルに対して非常にうまく機能します。それとは反対に、「pandalion98」によって発行された説明は、「rpi-update」によってインストールされたカーネルを指します。両方の方法は相互に排他的ですか?
sparkie

1
私は、これはについて話したことはありませんOP(エドワード)から有効な回答だと思うrpi-updaterpi-updatepandalion98の答えで提案された
PIM

@sparkie投稿の時点でaptは、私が間違えていなければ、カーネルはまだRaspbianのリポジトリに統合されていませんでした。カーネルの更新は、Hexxehのrpi-updateスクリプトの実行を意味しました。最近では、更新raspberrypi-kernelまたは実行rpi-updateはほぼ同じことを行います。
PNDA

についてはraspberrypi-kernel-headers、通常、経験から不一致のカーネルヘッダーがインストールされます(ヘッダーはカーネルよりも新しいバージョンである傾向があります)。
PNDA

「raspberrypi-kernel」と「rpi-update」にはいくつかの違いがあるようです。現時点では、一方が「4.9.66+」、もう一方が「4.9.59+」になります。だから私たちはまだ個別の両方のビルド手順を処理するために持っていると思う
sparkie

2

getKernel.sh、ファイルの追加

sudo modprobe configs

zcat /proc/config.gz >.config

(現在、デフォルトのrpiイメージに/proc/config.gzは存在しません)

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.