Реализация системного вызова в Debian Wheezy в реальном времени

В образовательных целях я хочу реализовать системный вызов в Debian Wheezy. Я хочу реализовать его в ядре, которое входит в пакет linux-image-3.2.0 - rt-amd64. Вот обзор того, что я пробовал:

Чтобы получить исходный код ядра:

apt-get source linux-image-3.2.0-4-rt-amd64

Из этого я получаю следующие файлы / каталоги, в которых я выполнил:

linux_3.2.41.orig.tar.xz
linux_3.2.41-2+deb7u2.dsc
linux_3.2.41-2+deb7u2.debian.tar.xz

а также:

linux_3.2.41

который содержит исходный код ядра.

Затем, чтобы внести необходимые изменения для добавления системного вызова, я в основном перешел на эту страницу: Как писать системные вызовы в debian / ubuntu

Ниже приводится сокращенная версия приведенных здесь инструкций, измененных для отражения внесенных мною изменений.

+ Файл 1: linux-x.x.x / vpart_syscalls / vpart_syscalls.c

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

asmlinkage long insert_partition(char*dest, const char* src)
{
    printk("<--- the syscall has been called!");
    return 0;
}
  • Файл 2: linux-x.x.x / vpart_syscalls / Makefile. Создайте Makefile в том же тестовом каталоге, который вы создали выше, и поместите в него эту строку:

    obj-y := vpart_syscalls.o

  • Файл 3: linux-x.x.x / arch / x86 / kernel / syscall_table_32.S. Теперь вам нужно добавить свой системный вызов в таблицу системных вызовов. Добавьте в файл следующую строку:

    .long insert_partition

  • Файл 4: linux-x.x.x / arch / x86 / include / asm / unistd_32.h

В этом файле имена всех системных вызовов будут связаны с уникальным номером. После последней пары системного вызова и номера добавьте строку

#define __NR_insert_partition 349

Затем замените значение NR_syscalls, указав общее количество системных вызовов на (существующее число увеличено на 1), т.е. в этом случае NR_syscalls должно было быть 338, а новое значение - 339.

#define NR_syscalls 350
  • Файл 5: linux-x.x.x / include / linux / syscalls.h

Добавляем в файл прототип нашей функции.

asmlinkage long insert_partition(int lenTicks, int vpid);

непосредственно перед строкой #endif в файле.

  • Файл 6: Makefile в корне исходного каталога.

Откройте Makefile и найдите строку, в которой определено core-y, и добавьте тест каталога в конец этой строки.

core-y += kernel/ mm/ fs/ test/ vpart_syscalls/

Затем я приступил к сборке ядра другим способом, нежели описано здесь:

make localmodconfig
make menuconfig (making no changes)


make-kpkg clean
fakeroot make-kpkg --initrd --append-to-version=+tm kernel_image kernel_headers
cd ..
dpkg -i linux-image-3.8.*
dpkg -i linux-headers-3.8.*

Установленное ядро ​​загружается нормально. Я сделал следующую программу на c для проверки системного вызова:

#include <stdio.h>
#include <linux/unistd.h>
#include <sys/syscall.h>

int main(){
    printk("Calling the new syscall!\n");
    int ret = 100;
    ret = syscall(349, 1, 2);
    printf("call return value: %i\n", ret);
    return 0;

}

Когда я компилирую и запускаю эту программу, я получаю возвращаемое значение -1. Я проверяю сообщения с помощью dmesg, и нет никаких доказательств того, что мой printk был вызван ..

Если кто-нибудь знает, в чем моя проблема, я был бы очень счастлив! Я должен сказать, что у меня нет большого опыта в изменении и сборке ядра, но я многое узнал об этом. Я прочитал книгу Роберта Лавса - разработка ядра Linux и несколько руководств в Интернете.


person Harlequin144    schedule 23.05.2013    source источник
comment
Пожалуйста, опубликуйте результаты uname -a. Кроме того, вы можете проверить свой тест с помощью file -k ./test_name (для проверки 32/64-битного режима программы) и strace ./test_name, чтобы увидеть, был ли вызван системный вызов, какие были аргументы и возвращаемое значение (strace должен сообщать syscall_349 для вашего системного вызова).   -  person osgx    schedule 26.05.2013


Ответы (1)


Думаю, шаги 3 и 4 могут быть неправильными для 64-битных ядер:

File 3: linux-x.x.x/arch/x86/kernel/syscall_table_32.S. 
File 4: linux-x.x.x/arch/x86/include/asm/unistd_32.h

Здесь два файла: http://lxr.linux.no/linux+v3.2.41/arch/x86/kernel/

syscall_64.c    668 2008-12-24 14:26:58 -0800   
syscall_table_32.S  8659    2012-01-04 14:55:50 -0800

Первый определяет содержимое таблицы системных вызовов для 64-битного режима с использованием файла C и обмана макросов с помощью unistd_64.h

#define __SYSCALL(nr, sym) [nr] = sym,

const sys_call_ptr_t sys_call_table[__NR_syscall_max+1] = {
....
#include <asm/unistd_64.h>
};

Где asm/unistd_64.h

 #define __NR_read                               0
 __SYSCALL(__NR_read, sys_read)

и так далее.

И второй, который вы изменили, предназначен для 32-битного режима и написан с использованием asm файла и меток (.long sys_call_name).

Итак, вы определили системный вызов для 32-битного режима и используете linux-image-3.2.0-4-rt-amd64, который в основном предназначен для «64-битных ПК».

Я думаю, вы скомпилировали свою тестовую программу как gcc test.c, который по умолчанию работает в 64-битном режиме. Вы можете попробовать -m32 опцию gcc: gcc -m32 test.c, чтобы получить 32-битное приложение (это будет работать, только если у вас есть правильная кросс-среда для 32-битных сборок) или скомпилировать этот тест на каком-нибудь 32-битном Linux.

Или другой вариант - выполнить шаг «4а»: отредактируйте arch/x86/include/asm/unistd_64.h, чтобы добавить две строки:

 #define __NR_insert_partition                               YOUR_NUMBER
 __SYSCALL(__NR_insert_partition, insert_partition)

Я не уверен, где и как определяется NR_syscalls для 64bit. Он может быть сгенерирован во время сборки.

person osgx    schedule 25.05.2013
comment
Похоже, это и есть ответ. Я видел эти файлы (syscall_64.c, syscall_table_32.S), когда пытался реализовать системный вызов старым способом, и не знал, что с ними делать. Большое спасибо за помощь! - person Harlequin144; 28.05.2013
comment
user1756658, прокомментируйте, пожалуйста, после того, как вы это протестируете. - person osgx; 28.05.2013