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

на главную

Жанры

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

Общий девиз для интерфейсов ОС Unix — это "предоставлять механизм, а не стратегию". Другими словами, системные вызовы существуют для того, чтобы обеспечить определенную функцию в наиболее абстрактном смысле. А то, каким образом используется эта функция, ядра не касается.

Вызовы syscall

Системные вызовы (часто называемые syscall в ОС Linux) обычно реализуются в виде вызова функции. Для них могут быть определены один или более аргументов (inputs), которые могут приводить к тем или иным побочным эффектам [25] , например к записи данных в файл или к копированию некоторых данных в область памяти, на которую указывает переданный указатель. Системные вызовы также имеют возвращаемое значение типа

long
[26] , которое указывает на успешность выполнения операции или на возникшие ошибки. Обычно, но не всегда, возвращение
отрицательного значения указывает на то, что произошла ошибка. Возвращение нулевого значения обычно (но не всегда) указывает на успешность выполнения операции. Системные вызовы ОС Unix в случае ошибки записывают специальный код ошибки в глобальную переменную
errno
. Значение этой переменной может быть переведено в удобочитаемую форму с помощью библиотечной функции
perror
.

25

Следует обратить внимание на слово "могут". Хотя почти все вызовы создают различные побочные эффекты (т.е. приводят к каким-либо изменениям в состоянии системы), тем не менее небольшое количество вызовов, как, например, вызов

getpid
, просто возвращают некоторые данные ядра.

26

Тип

long
используется для совместимости с 64-разрядными платформами.

Системные вызовы, конечно, имеют определенное поведение. Например, системный вызов

getpid
определен для того, чтобы возвращать целочисленное значение, равное значению идентификатора
PID
текущего процесса. Реализация этой функции в ядре очень проста.

asmlinkage long sys_getpid(void) {

 return current->tgid;

)

Следует заметить, что в определении ничего не говорится о способе реализации. Ядро должно обеспечить необходимую функциональность системного вызова, но реализация может быть абсолютно свободной, главное, чтобы результат был правильный. Конечно, рассматриваемый системный вызов в действительности является таким же простым, как и показано, и существует не так уж много различных вариантов для его реализации (на самом деле более простого метода не существует) [27] .

27

Может быть, интересно, почему вызов

getpid
возвращает поле
tgid
, которое является идентификатором группы потоков (thread group ID)? Это делается потому, что дли обычных процессов значение параметра
TGID
равно значению параметра
PID
. При наличии нескольких потоков значение параметра
TGID
одинаково дли всех потоков одной группы. Такая реализация дает возможность различным потокам вызывать функцию
getpid
и получать одинаковое значение параметра
PID
.

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

asmlinkage
в объявлении функции. Это волшебное слово дает компилятору информацию о том, что обращение к аргументам этой функции должно производиться только через стек. Для всех системных вызовов использование этого модификатора является обязательным. Во-вторых, следует обратить внимание, что системный вызов
getpid
объявлен в ядре, как
sys_getpid
. Это соглашение о присваивании имен используется для всех системных вызовов операционной системы Linux: системный вызов
bar
должен быть реализован с помощью функции
sys_bar
.

Номера системных вызовов

Каждому системному вызову операционной системы Linux присваивается номер системного вызова (syscall number). Этот уникальный номер используется для обращения к определенному системному вызову. Когда процесс выполняет системный вызов из пространства пользователя, процесс не обращается к системному вызову по имени.

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

sys_ni_syscall
, которая не делает ничего, кроме того, что возвращает значение, равное
– ENOSYS
, — код ошибки, соответствующий неправильному системному вызову. Эта функция служит для "затыкания дыр" в случае такого редкого событии, как удаление системного вызова.

Ядро поддерживает список зарегистрированных системных вызовов в таблице системных вызовов. Эта таблица хранится в памяти, на которую указывает переменная

sys_call_table
. Данная таблица зависит от аппаратной платформы и обычно определяется в файле
entry.S
.
В таблице системных вызовов каждому уникальному номеру системного вызова назначается существующая функция
syscall
.

Производительность системных вызовов

Системные вызовы в операционной системе Linux работают быстрее, чем во многих других операционных системах. Это отчасти связано с невероятно малым временем переключения контекста. Переход в режим ядра и выход из него являются хорошо отлаженным процессом и простым делом. Другой фактор — это простота как механизма обработки системных вызовов, так и самих системных вызовов.

Обработка системных вызовов

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

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

Таким механизмом, который может подать сигнал ядру, является программное прерывание: создается исключительная ситуация (exception) и система переключается в режим ядра для выполнения обработчика этой исключительной ситуации. Обработчик исключительной ситуации в данном случае и является обработчиком системного вызова (system call handler). Для аппаратной платформы x86 это программное прерывание определено как машинная инструкция

int $0x80
. Она приводит в действие механизм переключения в режим ядра и выполнение вектора исключительной ситуации с номером 128, который является обработчиком системных вызовов. Обработчик системных вызовов— это функция с очень подходящим именем
system_call
. Данная функция зависима от аппаратной платформы и определена в файле
entry.S
[28] . В новых процессорах появилась такая новая функция, как sysenter. Эта функция обеспечивает более быстрый и специализированный способ входа в ядро для выполнения системного вызова, чем использование инструкции программного прерывания —
int
. Поддержка такой функции была быстро добавлена в ядро. Независимо от того, каким образом выполняется системный вызов, основным является то, что пространство пользователя вызывает исключительную ситуацию, или прерывание, чтобы вызвать переход в ядро.

28

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

Определение необходимого системного вызова

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

Для аппаратной платформы x86 номер системного вызова сохраняется в регистре процессора

eax
перед тем, как вызывается программное прерывание. Обработчик системных вызовов после этого считывает это значение из регистра
eax
. Для других аппаратных платформ выполняется нечто аналогичное.

Функция

system_call
проверяет правильность переданного номера системного вызова путем сравнения его со значением постоянной
NR_syscalls
. Если значение номера больше или равно значению
NR_syscalls
, то функция возвращает значение
– ENOSYS
. В противном случае вызывается соответствующий системный вызов следующим образом:

call *sys_call_table(,%eax,4)

Так как каждый элемент таблицы системных вызовов имеет длину 32 бит (4 байт), то ядро умножает данный номер системного вызова на 4 для получения нужной позиции в таблице системных вызовов (рис. 5.2).

Рис. 5.2. Запуск обработчика системных вызовов и выполнение системного вызова

Передача параметров

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

ebx
,
ecx
,
edx
,
esi
,
edi
содержат соответственно первые пять аргументов. В случае редких ситуаций с шестью или более аргументами, используется один регистр, который содержит указатель на память пространства пользователя, где хранятся все параметры.

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

В зоне особого внимания

Иванов Дмитрий
12. Девяностые
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
В зоне особого внимания

Вечный Данж. Трилогия

Матисов Павел
Фантастика:
фэнтези
юмористическая фантастика
6.77
рейтинг книги
Вечный Данж. Трилогия

Холодный ветер перемен

Иванов Дмитрий
7. Девяностые
Фантастика:
попаданцы
альтернативная история
6.80
рейтинг книги
Холодный ветер перемен

Повелитель механического легиона. Том I

Лисицин Евгений
1. Повелитель механического легиона
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Повелитель механического легиона. Том I

Целитель

Первухин Андрей Евгеньевич
1. Целитель
Фантастика:
фэнтези
попаданцы
5.00
рейтинг книги
Целитель

Золушка вне правил

Шах Ольга
Любовные романы:
любовно-фантастические романы
6.83
рейтинг книги
Золушка вне правил

Свадьба по приказу, или Моя непокорная княжна

Чернованова Валерия Михайловна
Любовные романы:
любовно-фантастические романы
5.57
рейтинг книги
Свадьба по приказу, или Моя непокорная княжна

Мифы и Легенды. Тетралогия

Карелин Сергей Витальевич
Мифы и Легенды
Фантастика:
фэнтези
рпг
альтернативная история
5.00
рейтинг книги
Мифы и Легенды. Тетралогия

Газлайтер. Том 4

Володин Григорий
4. История Телепата
Фантастика:
попаданцы
альтернативная история
аниме
5.00
рейтинг книги
Газлайтер. Том 4

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

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

Теневой Перевал

Осадчук Алексей Витальевич
8. Последняя жизнь
Фантастика:
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Теневой Перевал

С Д. Том 16

Клеванский Кирилл Сергеевич
16. Сердце дракона
Фантастика:
боевая фантастика
6.94
рейтинг книги
С Д. Том 16

Купеческая дочь замуж не желает

Шах Ольга
Фантастика:
фэнтези
6.89
рейтинг книги
Купеческая дочь замуж не желает

Охота на попаданку. Бракованная жена

Герр Ольга
Любовные романы:
любовно-фантастические романы
5.60
рейтинг книги
Охота на попаданку. Бракованная жена