커널을 재 컴파일하지 않고로드 가능한 커널 모듈을 컴파일하는 방법


20

Raspberry Pi에서 커널 모듈을 컴파일하는 방법에 대해 꽤 많이 읽었지만 여전히 작동하지 않는 이유를 알 수는 없습니다. 모듈을 만들 수 있었지만 결과를 Invalid module format보려고 할 때보고합니다 insmod. 내가 따르는 과정은 다음과 같습니다. 먼저 루트 아래 /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 웹 위치에서 리디렉션이 있었지만 (현재 https://raw.githubusercontent.com/ ) 실제 오류는 없습니다.

그런 다음 기본 pi사용자가되고 디렉토리 /home/pi/projects/lkm에 매우 간단한 장난감 모듈에 대한이 소스 코드가 있습니다.

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);

마지막 으로이 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 21:48의

답변:


23

우선, 적절한 커널 헤더를 사용하십시오. 커널 헤더와 소스 코드가 실행중인 커널보다 더 업데이트 된 것으로 가정합니다.

할 시도 apt-get update && apt-get upgrade후 모듈을 다시 설치합니다. 문제가 지속되면 커널 헤더가 현재 커널과 일치하는지 세 번 확인하고 다시 컴파일 한 다음 설치를 시도하십시오.


참고 : Jessie를 사용하고 있습니다.

업데이트 : 루트로 실행하십시오.

# 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

파일 :

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이 예제는 hello world 예제입니다. 나는 당신의 모듈을 만들었지 만 같은 것을 깨달았습니다. 유일한 차이점은 코드에 빨간색 강조 표시가 없다는 것입니다.
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.

나는 추천 일반 사용자로 작업 하지 루트insmod, rmmodmake modules_install명령은 루트 권한이 필요하고, 필요가 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);

Makefile (변경됨)

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-update, rpi-updatepandalion98의 대답에 제안했다

@sparkie 게시 apt할 때 내가 실수 하지 않으면 커널이 여전히 Raspbian의 저장소에 통합 되지 않았습니다. 커널을 업데이트한다는 것은 Hexxeh의 rpi-update스크립트를 실행하는 것을 의미했습니다 . 요즘 업데이트 raspberrypi-kernel또는 실행 rpi-update은 거의 동일합니다.
PNDA December

에 관해서는 raspberrypi-kernel-headers, 일반적으로 경험에서 일치하지 않는 커널 헤더를 설치합니다 (헤더는 커널보다 최신 버전 인 경향이 있습니다). 그래서 나는 "go manual"을 선택했습니다.
PNDA December

'raspberrypi-kernel'과 'rpi-update'사이에는 약간의 차이가 있습니다. 하나는 현재 '4.9.59+'에서 다른 하나는 '4.9.66+'가됩니다. 우리는 여전히 개별적으로 모두 빌드 절차를 처리해야 내가 생각하는 그래서
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.