Реализация syscall в режиме реального времени 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.Теперь вы должны добавить свой системный вызов в таблицу системных вызовов. Добавьте к файлу следующую строку:

    .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 и найдите строку, в которой определено ядро-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 для тестирования syscall:

#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: %in", ret);
    return 0;

}

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

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

1 5

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+В3.2.41/арки/х86/ядра/

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

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

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

Или другой выбор - сделать шаг "4a": edit arch/x86/include/asm/unistd_64.h добавить две строки:

 #define __NR_insert_partition                               YOUR_NUMBER
 __SYSCALL(__NR_insert_partition, insert_partition)

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