Модуль "Hello, World!"

Модуль "Hello, World!"

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

Может показаться банальным, но иметь возможность написать программу, которая выводит сообщение "Hello World!", и не сделать этого- просто смешно. Итак, леди и джентльмены, модуль "Hello, World!".

/*

* hello.c - модуль ядра Hello, World!

*/

#include <linux/init.h>

#include <linux/module.h>

#include <linux/kernel.h>

/*

* hello_init - функция инициализации, вызывается при загрузке модуля,

* В случае успешной загрузки модуля возвращает значение нуль,

* и ненулевое значение в противном случае.

*/

static int hello_init(void) {

 printk(KERN_ALERT "I bear a charmed life. ");

 return 0;

}

/*

* hello_exit - функция завершения, вызывается при выгрузке модуля.

*/

static void hello_exit(void) {

 printk(KERN_ALERT "Out, out, brief candle! ");

}

module_init(hello_init);

module_exit(hello_exit);

MODULE_LICENSE{"GPL");

MODULE_AUTHOR("Shakespeare");

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

int my_init(void);

Так как функция инициализации редко вызывается за пределами модуля, ее обычно не нужно экспортировать и можно объявить с ключевым словом static.

Функции инициализации возвращают значение тина int. Если инициализация (или то, что делает функция инициализации) прошла успешно, то функция должна возвратить значение нуль. В случае ошибки возвращается ненулевое значение.

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

Функция hello_exit() регистрируется в качестве точки выхода из модуля с помощью макроса module_exit(). Ядро вызывает функцию hello_exit(), когда модуль удаляется из памяти. Завершающая функция должна выполнить очистку ресурсов, гарантировать, что аппаратное обеспечение находится в непротиворечивом состоянии, и т.д. После того как эта функция завершается, модуль выгружается.

Завершающая функция должна соответствовать следующему прототипу.

void my_exit(void);

Так же как и в случае функции инициализации, ее можно объявить как static.

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

Макрос MODULE_LICENSE() позволяет указать лицензию на право копирования модуля. Загрузка в память модуля, для которого лицензия не соответствует GPL, приведет к установке в ядре флага tainted (буквально, испорченное). Этот флаг служит для информационных целей, кроме того, многие разработчики уделяют меньше внимания сообщениям об ошибках, в которых указан этот флаг. Более того, модули, у которых лицензия не соответствует GPL, не могут использовать символы, которые служат "только для GPL" (см. раздел "Экспортируемые символы" ниже в этой главе).

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