Библиотека сайта rus-linux.net
Цилюрик О.И. Модули ядра Linux | ||
Назад | Вперед |
Беглый взгляд на программирование модуля
Все мы умеем и имеем больший или меньший опыт написания программ в Linux 1, которые все, между тем, имеют абсолютно идентичную единую структуру:
int main( int argc, char *argv[] ) { // и здесь далее следует любой программный код, вплоть до вот такого: printf( "Hello, world!\n" ); // ... и далее, далее, далее ... exit( EXIT_SUCCESS ); };
Такую структуру в коде будут неизменно иметь все приложения-программы, будь то тривиальная показанная «Hello, world!», или «навороченная» среда разработки Eclipse 2. Это — в подавляющем большинстве встречаемый случай: пользовательское приложение начинающееся с main() и завершающееся по exit().
Ещё один встречающийся (но гораздо реже) в UNIX случай — это демоны: программы, стартующие с main(), но никогда не завершающие своей работы (чаще всего это сервера различных служб). В этом случае для того, чтобы стать сервером, всё тот же пользовательский процесс должен выполнить некоторую фиксированную последовательность действий [20], называемую демонизацией, который состоит в том, чтобы (опуская некоторые детали для упрощения):
- создать свой собственный клон вызовом fork() и завершить родительский процесс;
- создать новую сессию вызовом setsid(), при этом процесс становится лидером сессии и открепляется (теряет связь) от управляющего терминала;
- позакрывать все ненужные файловые дескрипторы (унаследованные).
Но и в этом случае процесс выполняется в пользовательском адресном пространстве (отдельном для каждого процесса) со всеми ограничениями пользовательского режима: запрет на использование супервизорных команд, невозможность обработки прерываний, запрет (без особых ухищрений) операций ввода-вывода и многих других тонких деталей.
Возникает вопрос: а может ли пользователь написать и выполнить собственный код, выполняющийся в режиме супервизора, а, значит, имеющий полномочия расширять (или даже изменять) функциональность ядра Linux? Да, может! И эта техника программирования называется программированием модулей ядра. И именно она позволяет, в частности, создавать драйверы нестандартного оборудования 3.
Примечание: Как мы будем неоднократно видеть далее, установка (запуск) модуля выполняется посредством специальных команд установки, например, командой:
# insmod <имя-файла-модуля>.ko
После чего в модуле начинает выполняться функция инициализации. Возникает вопрос: а можно ли (при необходимости) создать пользовательское приложение, стартующее, как обычно, с точки main(), а далее присваивающее себе требуемые привилегии, и выполняющееся в супервизорном режиме (в пространстве ядра)? Да, можно! Для этого изучите исходный код утилиты insmod (а Linux — система с абсолютно открытым кодом всех компонент и подсистем), а утилита эта является ничем более, как заурядным пользовательским приложением, выполните в своём коде те манипуляции с привилегиями, которые проделывает insmod, и вы получите желаемое приложение. Естественно, что всё это потребует от приложения привилегий root при запуске, но это то же минимальное требование, которое обязательно при работе с модулями ядра.
1) Замечание здесь о Linux не является оговоркой, а означает, что вышесказанное верно только для операционных систем, языком программирования для которых (самих систем) является классический язык C; в этом контексте точнее говорить даже не о системе Linux, а о любых UNIX-like или POSIX системах.
2) В качестве примера Eclipse указан также не случайно: а). это один из инструментов, который может эффективно использоваться в разработках модулей, и особенно если речь зайдёт о клоне Android на базе ядра Linux, и б). даже несмотря на то, что сам Eclipse писан на Java, а вовсе не на С - всё равно структура приложения сохранится, так как с вызова main() будет начинаться выполнение интерпретатора JVM, который далее будет выполнять Java байт-код. То же относится и к приложениям, написанным на таких интерпретирующих языках как Perl, Python, или даже на языке командного интерпретатора shell: точно ту же структуру приложения будет воспроизводить само интерпретирующее приложение, которое будет загружаться прежде интерпретируемого кода.
3) Это (написание драйверов) - самое важное, но не единственное предназначение модулей в Linux: «всякий драйвер является модулем, но не всякий модуль является драйвером».
Предыдущий раздел: | Оглавление | Следующий раздел: |
Источники информации | Наш первый модуль ядра |