INIT_MODULE(2) | Руководство программиста Linux | INIT_MODULE(2) |
init_module, finit_module - загружает модуль ядра
int init_module(void *module_image, unsigned long len, const char *param_values);
int finit_module(int fd, const char *param_values, int flags);
Замечание: В заголовочных файлах glibc отсутствует init_module() и finit_module(); смотрите ЗАМЕЧАНИЯ.
Вызов init_module() загружает образ ELF в пространство ядра, выполняет все необходимые перемещения символов, инициализирует значения параметров модуля, предоставленные вызывающим и запускает функцию модуля init. Данный системный вызов требует дополнительных прав.
Аргумент module_image указывает на буфер, содержащий двоичный образ для загрузки; в len задаётся размер этого буфера. Образ модуля должен быть корректным образом в формате ELF, собранным для работающего в данный момент ядра.
Значением param_values является строка, содержащая значения параметров модуля (через пробел), определённых в модуле через module_param() и module_param_array(). Ядро обрабатывает эту строку и инициализирует указанные параметры. Каждый параметр имеет вид:
имя[=значение[,значение…]]
Параметр имя — один из определённых параметров модуля с помощью module_param() (смотрите файл исходного кода ядра Linux include/linux/moduleparam.h). Параметр значение не обязателен в случае параметров с типом bool и invbool. Значение массива параметров указываются через запятую.
Системный вызов finit_module() подобен init_module(), но читает модуль для загрузки из файлового дескриптора fd. Он полезен, если подлинность модуля ядра можно определить по его расположению в файловой системе; в таких случаях затрат на использование криптографически подписанных модулей для определения подлинности модуля можно избежать. Аргумент param_values такой же как у init_module().
Аргумент flags изменяет выполнение finit_module(). Это битовая маска, создаваемая объединением нуля или более следующих флагов:
Есть несколько элементов, встроенных в модуль, которые позволяют убедиться, что модуль подходит для загрузки в ядро. Эти элементы записываются в модуль на этапе сборки и проверяются при загрузке ядра. Во-первых, модуль имеет строку «vermagic», содержащую номер версии ядра и основные свойства (такие как тип ЦП). Во-вторых, если модуль собран с включённым параметром настройки CONFIG_MODVERSIONS, то он содержит хэш версии для каждого используемого модулем символа. Данный хэш основан на типе аргумента и возвращаемом значении функции с именем символа. В этом случае номер версии ядра в строке «vermagic» игнорируется, так как считается, что хэши версий символов достаточно надёжны.
Использование флага MODULE_INIT_IGNORE_VERMAGIC требует игнорировать строку «vermagic», а флаг MODULE_INIT_IGNORE_MODVERSIONS требует игнорировать хэши версий символов. Если ядро собрано с разрешением принудительной загрузки (параметр настройки CONFIG_MODULE_FORCE_LOAD), то загрузка продолжается, в противном случае она завершается ошибкой ENOEXEC, как и ожидается для некорректных модулей.
При успешном выполнении возвращается 0. В случае ошибки возвращается -1, а errno устанавливается в соответствующее значение.
Дополнительно в init_module() могут возникать следующие ошибки:
Дополнительно в finit_module() могут возникать следующие ошибки:
Дополнительно к этим ошибкам, если функция модуля init при выполнении возвратила ошибку, то init_module() или finit_module() завершается с ошибкой и в errno записывается значение, полученное от функции init.
Вызовы finit_module() доступен в Linux, начиная с версии 3.8.
Вызовы init_module() и finit_module() есть только в Linux.
Системный вызов init_module() не поддерживается glibc. В заголовочных файлах glibc он не объявлен, но в недавнем прошлом glibc до версии 2.23 экспортировал ABI для этого системного вызова. Поэтому чтобы получить данный системный вызов достаточно вручную объявить интерфейс в своём коде; или же вы можете вызвать его через syscall(2).
В glibc нет обёртки для finit_module(); запускайте его с помощью syscall(2).
Информацию по уже загруженным модулями можно найти в файле /proc/modules и в соответствующем каждому модулю подкаталогу в /sys/module.
Дополнительную информацию смотрите в файле include/linux/module.h из исходного кода ядра Linux.
В Linux версии 2.4 и более ранних системный вызов init_module() был немного другим:
#include <linux/module.h>
int init_module(const char *name, struct module *image);
(Приложения пользовательского пространства могут определить какая из версий init_module() доступна, вызвав query_module(); этот вызов завершается ошибкой ENOSYS в Linux 2.6 и более новых.)
Старая версия системного вызова загружает перемещённый образ модуля image, в пространство ядра и выполняет функцию модуля init. Вызывающий должен предоставить перемещённый образ (начиная с Linux 2.6, системный вызов init_module() сам делает перемещение).
Образ модуля начинается со структуры модуля, за которой следует код и данные. Начиная с Linux 2.2 структура модуля определена следующим образом:
struct module { unsigned long size_of_struct; struct module *next; const char *name; unsigned long size; long usecount; unsigned long flags; unsigned int nsyms; unsigned int ndeps; struct module_symbol *syms; struct module_ref *deps; struct module_ref *refs; int (*init)(void); void (*cleanup)(void); const struct exception_table_entry *ex_table_start; const struct exception_table_entry *ex_table_end; #ifdef __alpha__ unsigned long gp; #endif };
Все поля указателей, за исключением next и refs, указывают в тело модуля и будут инициализированы в соответствии с адресным пространством ядра, то есть перемещены с остальной частью модуля.
create_module(2), delete_module(2), query_module(2), lsmod(8), modprobe(8)
2017-09-15 | Linux |