Як компілювати завантажуваний модуль ядра без перекомпіляції ядра


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я маю цей вихідний код для дуже простого іграшкового модуля:

привіт.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

Makefilefile

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

Можливо, вам доведеться перезавантажити. Після цього перейдіть до наведених нижче команд, все ще використовуючи кореневий рахунок.

# 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

Файли:

привіт.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 оновлено.
ПНДА

@Edward Зауважте, що це привіт привіт світу. Я побудував ваш модуль, але зрозумів, що це те саме. Єдина відмінність - ваш код не має червоної підсвітки.
ПНДА

@Edward У вашому випадку я думаю, що дотримуйтесь інструкцій, поки 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.

Я рекомендую працювати як ваш звичайний користувач, а не root , тільки insmod, rmmodі make 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
Я думаю, що це правильна відповідь, оскільки ОП (Едуард) ніколи не говорив про це rpi-update, rpi-updateпропонувалося у відповіді pandalion98
pim

@sparkie На момент публікації ядро ​​все ще не було інтегровано у aptсховище Raspbian , якщо я не помиляюся. Оновлення ядра означало запуск rpi-updateсценарію Hexxeh . У наші дні оновлення raspberrypi-kernelчи запуск rpi-updateроблять майже те саме.
PNDA

Що стосується raspberrypi-kernel-headers, як правило, він встановлює невідповідні заголовки ядра з досвіду (заголовки, як правило, більш нової версії, ніж ядро), отже, чому я вирішив "йти вручну".
PNDA

Мабуть, є якась різниця між 'малиновим ядром' та 'rpi-оновленням': одне призводить до '4.9.66+', а інше в '4.9.59+' в цей момент. Тому я думаю, що нам ще належить обробляти обидві процедури збирання окремо
sparkie

2

у getKernel.shфайл

sudo modprobe configs

раніше

zcat /proc/config.gz >.config

(зараз у файлі rpi /proc/config.gz за замовчуванням не існує)

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.