Как скомпилировать загружаемый модуль ядра без перекомпиляции ядра

20

Я прочитал довольно много о том, как скомпилировать модуль ядра на (и для) Raspberry Pi, но я до сих пор не могу понять, почему он не работает. Я был в состоянии построить модуль, но он сообщает, Invalid module formatкогда я пытаюсь получить insmodрезультат. Вот процесс, которым я следовал. Во-первых, от имени пользователя 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 (по-видимому, теперь это https://raw.githubusercontent.com/ ), но никаких реальных ошибок не было.

Затем я стал piпользователем по умолчанию, и в каталоге с именем у /home/pi/projects/lkmменя есть этот исходный код для очень простого игрушечного модуля:

Привет

#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

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: Неверный формат модуля

Возможно соответствующие детали

Я использую последнюю jessieверсию Raspbian на Raspberry Pi2.

$ 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затем переустановите модуль. Если проблема не устранена, проверьте трижды, что заголовки ядра соответствуют вашему текущему ядру, перекомпилируйте снова и попробуйте установить.


Примечание: я использую Джесси.

ОБНОВЛЕНИЕ: Запустите их как root.

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

# Update the kernel!
rpi-update

Вам может потребоваться перезагрузка. После этого выполните приведенные ниже команды, по-прежнему используя учетную запись root.

# 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-sourceвыдает ошибку GCC (что-то из-за несоответствия версий), это нормально, если ваша текущая версия GCC выше . Запустить rpi-source --skip-gccвместоrpi-source

Затем перейдите к примеру Hello World. Создайте папку и cdв нее. Затем создайте файлы.

mkdir hello
cd hello

файлы:

Привет

#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

PNDA
источник
Когда вы говорите «проверьте, что ваши заголовки ядра соответствуют вашему текущему ядру», как именно вы подразумеваете, что я должен сделать это?
Эдвард
@ Эдвард обновлен.
PNDA
@ Эдвард Обратите внимание, что это пример Привет, мир. Я построил ваш модуль, но понял, что это то же самое. Разница лишь в том, что ваш код не имеет красной подсветки.
PNDA
@ Эдвард В вашем случае, я думаю, следуя инструкциям, пока rpi-sourceчасти не будет достаточно. Вы можете попробовать построить свой с этого момента.
PNDA
5

Здесь есть намного более простая версия, проверенная на Джесси и Стретч .

sudo apt-get install raspberrypi-kernel-headers

а затем, когда ваши файлы на месте:

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

пример

Создайте helloкаталог, зайдите внутрь и создайте следующие файлы: hello.cи Makefile.

Я рекомендую работать от имени обычного пользователя, а не только rootinsmod , rmmodа для 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);

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)   

использование

  • Build: 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. Оба метода являются взаимоисключающими, верно?
Искорка
1
Я думаю , что это правильный ответ , так как OP (Эдвард) никогда не говорил о том rpi-update, rpi-updateбыл предложен в ответ на pandalion98 в
ПИМ
@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 не существует)

Игорь Николаев
источник