Чтение онлайн

на главную

Жанры

Разработка ядра Linux
Шрифт:

...

#define __NR_mq_unlink 278

#define __NR_mq_timedsend 279

#define __NR_mq_timedreceive 280

#define __NR_mq_notify 281

#define __NR_mq_getsetattr 282

В конец файла добавляется следующая строка.

#define __NR_foo 283

В конце концов необходимо реализовать сам системный вызов

foo
. Так как системный вызов должен быть вкомпилорован в образ ядра во всех конфигурациях, мы его поместим в файл
kernel/sys.c
. Код необходимо
размещать в наиболее подходящем файле. Например, если функция относится к планированию выполнения процессов, то ее необходимо помещать в файл
sched.c
.

/*

* sys_foo - всеми любимый системный вызов.

*

* Возвращает размер стека ядра процесса

*/

asmlinkage long sys_foo(void) {

 return THREAD_SIZE;

}

Это все! Загрузите новое ядро. Теперь из пространства пользователя можно вызвать системную функцию

foo
.

Доступ к системным вызовам из пространства пользователя

В большинстве случаев системные вызовы поддерживаются библиотекой функций языка С. Пользовательские приложения могут получать прототипы функций из стандартных заголовочных файлов и компоновать программы с библиотекой С для использования вашего системного вызова (или библиотечной функции, которая вызывает ваш системный вызов). Однако если вы только что написали системный вызов, то маловероятно, что библиотека

glibc
уже его поддерживает!

К счастью, ОС Linux предоставляет набор макросов-оболочек для доступа к системным вызовам. Они позволяют установить содержимое регистров и выполнить машинную инструкцию

int $0x80
. Эти макросы имеют имя
syscalln
, где
n
— число от нуля до шести. Это число соответствует числу параметров, которые должны передаваться в системный вызов, так как макросу необходима информация о том, сколько ожидается параметров, и соответственно, нужно записать эти параметры в регистры процессора. Например, рассмотрим системный вызов
open
, который определен следующим образом.

long open(const char *filename, int flags, int mode)

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

#define NR_open 5

_syscall3(long, NR_open, const char*, filename, int, flags, int, mode);

После этого приложение может просто вызывать функцию

open
.

Каждый макрос принимает

2 + 2*n
параметров. Первый параметр соответствует типу возвращаемого значения системного вызова. Второй параметр — имя системного вызова. После этого следуют тип и имя каждого параметра в том же порядке, что и у системного вызова. Постоянная
NR_open
, которая определена в файле
<asm/unistd.h>
, — это номер системного вызова. В функцию на языке программирования С такой вызов превращается с помощью вставок на языке ассемблера, которые выполняют рассмотренные в предыдущем разделе шаги. Значения аргументов помещаются в соответствующие регистры, и выполняется программное прерывание, которое перехватывается в режиме ядра. Вставка данного макроса в приложение — это все, что необходимо для выполнения системного вызова
open
.

Напишем макрос, который позволяет вызвать нашу замечательную системную функцию, и соответствующий

код, который позволяет этот вызов протестировать.

#define __NR_foo 283

__syscall0(long, foo)

int main {

 long stack_size;

stack_size = foo;

 printf("Размер стека ядра равен %ld\n" , stack_size);

 return 0;

}

Почему не нужно создавать системные вызовы

Новый системный вызов легко реализовать, тем не менее это необходимо делать только тогда, когда ничего другого не остается. Часто, для того чтобы обеспечить новый системный вызов, существуют более подходящие варианты. Давайте рассмотрим некоторые "за" и "против" и возможные варианты.

Для создания нового интерфейса в виде системного вызова могут быть следующие "за".

• Системные вызовы просто реализовать и легко использовать.

• Производительность системных вызовов в операционной системе Linux очень высока.

Возможные "против".

• Необходимо получить номер системного вызова, который должен быть официально назначен в период работы над разрабатываемыми сериями ядер.

• После того как системный вызов включен в стабильную серию ядра, он становится "высеченным в камне". Интерфейс не должен меняться, чтобы не нарушить совместимости с прикладными пользовательскими программами.

• Для каждой аппаратной платформы необходимо регистрировать отдельный системный вызов и осуществлять его поддержку.

• Для простого обмена информацией системный вызов — это "стрельба из пушки по воробьям".

Возможные варианты.

• Реализовать файл устройства и использовать функции

read
и
write
для этого устройства, а также использовать функцию
ioctl
для манипуляции специфическими параметрами или для получения специфической информации.

• Некоторые интерфейсы, например семафоры, могут быть представлены через дескрипторы файлов. Управлять этими устройствами также можно по аналогии с файлами.

• Добавить информационный файл в соответствующем месте файловой системы

sysfs
.

Для большого числа интерфейсов, системные вызовы — это правильный выбор. В операционной системе Linux пытаются избегать простого добавления системного вызова для поддержки каждой новой, вдруг появляющейся абстракции. В результате получился удивительно четкий уровень системных вызовов, который принес очень мало разочарований и привел к малому числу не рекомендованных к использованию и устаревших (deprecated) интерфейсов (т.е. таких, которые больше не используются или не поддерживаются).

Малая частота добавления новых системных вызовов свидетельствует о том, что Linux — это стабильная операционная система с полным набором функций. Очень немного системных вызовов было добавлено во время разработки серий ядер 2.3 и 2.5. Большая часть из новых системных вызовов предназначена для улучшения производительности.

В заключение о системных вызовах

В этой главе было рассмотрено, что такое системные вызовы и как они соотносятся с вызовами библиотечных функций и интерфейсом прикладных программ (API). После этого было описано, как системные вызовы реализованы в ядре Linux, а также была представлена последовательность событий для выполнения системного вызова: программное прерывание ядра, передача номера системного вызова и аргументов системного вызова, выполнение соответствующей функции системного вызова и возврат результатов работы в пространство пользователя.

Поделиться:
Популярные книги

Мастер Разума VII

Кронос Александр
7. Мастер Разума
Фантастика:
боевая фантастика
попаданцы
аниме
5.00
рейтинг книги
Мастер Разума VII

Счастливый торт Шарлотты

Гринерс Эва
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Счастливый торт Шарлотты

Мир-о-творец

Ланцов Михаил Алексеевич
8. Помещик
Фантастика:
альтернативная история
5.00
рейтинг книги
Мир-о-творец

Имперец. Том 4

Романов Михаил Яковлевич
3. Имперец
Фантастика:
попаданцы
альтернативная история
аниме
5.00
рейтинг книги
Имперец. Том 4

Внешняя Зона

Жгулёв Пётр Николаевич
8. Real-Rpg
Фантастика:
фэнтези
попаданцы
рпг
5.00
рейтинг книги
Внешняя Зона

Возвышение Меркурия

Кронос Александр
1. Меркурий
Фантастика:
героическая фантастика
попаданцы
аниме
5.00
рейтинг книги
Возвышение Меркурия

Сколько стоит любовь

Завгородняя Анна Александровна
Любовные романы:
любовно-фантастические романы
6.22
рейтинг книги
Сколько стоит любовь

Партиец

Семин Никита
2. Переломный век
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Партиец

Идущий в тени 4

Амврелий Марк
4. Идущий в тени
Фантастика:
боевая фантастика
6.58
рейтинг книги
Идущий в тени 4

Хозяйка старой усадьбы

Скор Элен
Любовные романы:
любовно-фантастические романы
8.07
рейтинг книги
Хозяйка старой усадьбы

Защитник. Второй пояс

Игнатов Михаил Павлович
10. Путь
Фантастика:
фэнтези
5.25
рейтинг книги
Защитник. Второй пояс

Гром над Академией. Часть 2

Машуков Тимур
3. Гром над миром
Фантастика:
боевая фантастика
5.50
рейтинг книги
Гром над Академией. Часть 2

Кодекс Крови. Книга I

Борзых М.
1. РОС: Кодекс Крови
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Кодекс Крови. Книга I

Дядя самых честных правил 8

Горбов Александр Михайлович
8. Дядя самых честных правил
Фантастика:
попаданцы
альтернативная история
аниме
5.00
рейтинг книги
Дядя самых честных правил 8