Главная страница

Второе издание


Скачать 3.09 Mb.
НазваниеВторое издание
Дата08.09.2019
Размер3.09 Mb.
Формат файлаpdf
Имя файлаLav_Robert_Razrabotka_yadra_Linux_Litmir.net_264560_original_254.pdf
ТипДокументы
#86226
страница43 из 53
1   ...   39   40   41   42   43   44   45   46   ...   53
Использование дерева каталогов исходных кодов ядра
В идеале модуль является частью официального ядра и находится в каталоге ис- ходных кодов ядра. Введение вашей разработки непосредственно в ядро может вна- чале потребовать больше работы, но обычно такое решение более предпочтитель- но.
На первом этапе необходимо решить, где именно будет находиться модуль в де- реве исходных кодов ядра. Драйверы необходимо хранить в подкаталогах каталога d r i v e r s / , который находится в корне дерева исходных кодов ядра. Внутри этого каталога драйверы делятся на классы, типы и собственно на отдельные драйверы.
Символьные устройства находятся в каталоге d r i v e r s / c h a r / , блочные— в каталоге d r i v e r s / b l o c k / , устройства USB — в каталоге d r i v e r s / u s b / . Эти правила не есть жесткими, так как многие устройства USB также являются и символьными устрой- ствами. Но такая организация является понятной и четкой.
Допустим, что вы хотите создать свой подкаталог и ваш воображаемый драйвер разработан для удочки с числовым программным управлением, которая имеет интер- фейс Fish Master XL 2000 Titanium для подключения к компьютеру. Следовательно,
необходимо создать подкаталог f i s h i n g внутри каталога d r i v e r s / c h a r / .
После этого необходимо добавить новую строку в файл Makefile, который на- ходится в каталоге d r i v e r s / c h a r / . Для этого отредактируйте файл d r i v e r s / c h a r /
Makefile и добавьте в него следующую запись.
obj-m += fishing/
Модули 345

Эта строка указывает системе компиляции, что необходимо войти в подкаталог f i s h i n g / при компиляции модулей. Скорее всего, компиляция драйвера определя- ется отдельным конфигурационным параметром, например, CONFIG_FISHING_POLE
(как создавать новые конфигурационные параметры, рассмотрено ниже в этой главе в разделе "Управление конфигурационными параметрами"). В этом случае необходи- мо добавить строку следующего вида.
obj-$(CONFIG_FISHING_POLE) += fishing/
И наконец, в каталоге d r i v e r s / c h a r / f i s h i n g необходимо добавить новый файл
Makefile, содержащий следующую строку.
obj-m += fishing.о
При таких настройках система компиляции перейдет в каталог f i s h i n g / и ском- пилирует модуль f i s h i n g . к о из исходного файла f i s h i n g . с . Да, расширение объ- ектного файла указано как .о, но в результате будет создан модуль с расширением
.ко.
И снова, скорее всего, факт компиляции модуля будет зависеть от конфигура- ционного параметра, в таком случае в Makefile необходимо добавить следующую строку.
obj-$(CONFIG_FISHING_POLE) += fishing.о
Однажды драйвер удочки может стать очень сложным. Введение функции авто- детектирования наличия лески может привести к тому, что модуль станет очень большим и теперь будет занимать больше одного файла исходного кода. Никаких проблем! Просто нужно внести в Makefile следующую запись.
obj-$(CONFIG_FISHING_POLE) += fishing.о fishing-objs := fishing-main.о fishing-line.о
В последнем случае будут скомпилированы файлы f i s h i n g - m a i n . с и f i s h i n g - l i n e . с и скомпонованы в файл модуля f i s h i n g . к о .
Наконец, может потребоваться передать компилятору gcc дополнительные кон- фигурационные параметры. Для этого в файле Makefile необходимо добавить сле- дующую строку.
EXTRA_CFLAGS += -DTITANIUM_POLE
Если вы желаете поместить ваши файлы в каталог d r i v e r s / c h a r / , вместо того чтобы создавать новый подкаталог, то необходимо просто прописать указанные строки (тс, что должны быть прописаны в файле M a k e f i l e подкаталога d r i v e r s /
c h a r / f i s h i n g / ) в файле drivers/char/Makefile.
Для компиляции просто запустите процесс сборки ядра, как обычно. Если ком- пиляция модуля зависит от конфигурационного параметра, как в данном случае она зависит от параметра CONFIG_FISHING_POLE, то необходимо включить этот конфи- гурационный параметр перед компиляцией.
346 Глава 16

Компиляция вне дерева исходных кодов ядра
Если вы предпочитаете разрабатывать и поддерживать ваш модуль отдельно от дерева исходных кодов ядра и жить жизнью аутсайдера, просто создайте файл
Makefile следующего вида в том каталоге, где находится модуль.
obj-m := fishing.о
Такая конфигурация позволяет скомпилировать файл fishing. с в файл fishing. ко.
Если ваш исходный код занимает несколько файлов, то необходимо добавить две строки.
obj-m := fishing.о fishing-objs := fishing-main.о fishing-line.о
Такая конфигурация позволяет скомпилировать файлы f i s h i n g - m a i n . с и f i s h i n g - l i n e . с и создать модуль fishing, ко.
Главное отличие от случая, когда модуль находится внутри дерева исходного кода,
состоит в процессе сборки. Так как модуль находится за пределами дерева исходных кодов ядра, необходимо указать утилите make местонахождение исходных файлов ядра и файл Makefile ядра. Это также делается просто с помощью следующей ко- манды.
make -С /kerncl/source/location SUBDTRS=$PWD modules
В этом примере / k e r n e l / s o u r c e / l o c a t i o n — путь к сконфигурированному де- реву исходных кодов ядра. Вспомните, что не нужно хранить копию дерева исходных кодов ядра, с которой вы работаете, в каталоге /usr/src/linux, эта копия должна быть где-то в другом месте, скажем где-нибудь в вашем домашнем каталоге.
Инсталляция модулей
Скомпилированные модули должны быть инсталлированы в каталог /lib/modules/
version/kernel. Например, для ядра 2.6.10 скомпилированный модуль управления удочкой будет находиться в файле /lib/modules/2.6.10/kernel/drivers/char/
f i s h i n g . к о , если исходный код находился непосредственно в каталоге d r i v e r s /
char/.
Для инсталляции скомпилированных модулей в правильные каталоги использует- ся следующая команда.
make modules_install
Разумеется, эту команду необходимо выполнять от пользователя root.
Генерация зависимостей между модулями
Утилиты работы с модулями ОС Linux поддерживают зависимости между моду- лями. Это означает, что если модуль chum зависит от модуля b a i t , то при загрузке модуля chum модуль b a i t будет загружен автоматически. Информация о зависимо- стях между модулями должна быть сгенерирована администратором. В большинстве поставок ОС Linux эта информация генерируется автоматически и обновляется при
Модули 347
загрузке системы. Для генерации информации о зависимостях между модулями не- обходимо от пользователя root выполнить следующую команду.
depmod
Для быстрого обновления и генерации информации только о более новых моду- лях, чем сам файл информации, необходимо от пользователя root выполнить другую команду.
depmod -A
Информация о зависимостях между модулями хранится в файле / l i b / m o d u l e s /
version/modules.dep.
Загрузка модулей
Наиболее простой способ загрузки модуля — это воспользоваться утилитой insmod.
Эта утилита выполняет самые общие действия. Она просто загружает тот модуль,
который ей указан в качестве параметра. Утилита insmod не отслеживает зависимо- сти и не выполняет никакой интеллектуальной обработки ошибок. Использовать ее очень просто. От пользователя root необходимо просто выполнить команду insmod module где module— это имя модуля, который необходимо загрузить. Для загрузки модуля управления удочкой необходимо выполнить команду.
insmod fishing
Удалить модуль можно аналогичным образом с помощью утилиты rmmod. Для это- го от пользователя root нужно просто выполнить команду.
rmmod module
Например, удалить модуль управления удочкой можно следующим образом.
rmmod fishing
Тем не менее, эти утилиты тривиальные и не обладают интеллектуальным по- ведением. Утилита modprobe позволяет обеспечить удовлетворение зависимостей,
оповещение об ошибках, интеллектуальную обработку ошибок, а также выполняет множество других расширенных функций. Её настоятельно рекомендуется исполь- зовать.
Для загрузки модуля в ядро с помощью утилиты modprobe необходимо от пользо- вателя root выполнить команду modprobe module [ module parameters ]
где параметр module — это имя модуля, который необходимо загрузить. Все следую- щие аргументы интерпретируются как параметры, которые передаются модулю при загрузке. Параметры модулей обсуждаются ниже в одноименном разделе.
Утилита modprobe пытается загрузить не только указанный модуль, но и все мо- дули, от которых он зависит. Следовательно, это наиболее предпочтительный меха- низм загрузки модулей ядра.
348 Глава 16

Команда modprobe также может использоваться для удаления модулей из ядра.
Для этого с правами пользователя root необходимо выполнить ее следующим обра- зом.
modprobe Pr modules где параметр modules — имя одного или нескольких модулей, которые необходимо удалить. В отличие от команды rmmod, утилита modprobe также удаляет и все моду- ли, от которых указанный модуль зависит, если последние не используются.
В восьмом разделе страниц руководства операционной системы Linux приведен список других, менее используемых ключей этой команды.
Управление конфигурационными параметрами
В предыдущих разделах рассматривалась компиляция модуля управления удочкой при условии, что установлен конфигурационный параметр CONFIG_FISHING_POLE.
Конфигурационные параметры рассматривались в предыдущих главах, а теперь да- вайте рассмотрим добавление нового параметра в продолжение примера модуля управления удочкой.
Благодаря новой системе компиляции ядра "kbuild", которая появилась в серии ядер 2.6, добавление нового конфигурационного параметра является очень простым делом. Все, что необходимо сделать, — это добавить новую запись в файл Kconf ig,
который отвечает за конфигурацию дерева исходных кодов ядра. Для драйверов этот файл обычно находится в том же каталоге, в котором находится и исходный код. Если код драйвера удочки находится в каталоге d r i v e r s / c h a r / , то необходи- мо использовать файл drivers/char/Kconfig.
Если был создан новый каталог и есть желание, чтобы файл конфигурации на- ходился в этом новом каталоге, то необходимо на него сослаться из существующего файла Kconf ig. Это можно сделать путем добавления строки source Tdrivers/char/fishing/Kconfig в существующий файл Kconfig, скажем в файл drivers/char/Kconfig.
Конфигурационные записи в файле Kconfig добавляются очень просто. Для мо- дуля управления удочкой эта запись может выглядеть следующим образом.
config FISHING_POLE
tristate "Fish Master XL support"
default n help
If you say Y here, support for the Fish Master XL 2000 Titanium with computer interface will be compiled into the kernel and accessible via device node. You can also say M here and the driver will be built as a module named fishing.ko.
If unsure, say N.
Модули 349

Первая строка определяет, какой конфигурационный параметр создается.
Обратите внимание, что префикс CONFIG_ указывать не нужно, он добавляется ав- томатически.
Вторая строка указывает на то, что параметр может иметь три состояния (tristate),
которые соответствуют следующим значениям: статическая компиляция в ядро (Y),
компиляция в качестве модуля (М) или не компилировать драйвер вообще (N). Для того чтобы запретить компиляцию кода, который соответствует конфигурационному параметру, в качестве модуля (допустим, что этот параметр определяет не драйвер.
а просто некоторую дополнительную функцию) необходимо указать ТИП параметра bool вместо t r i s t a t e . Текст в кавычках, который следует после этой директивы,
определяет название конфигурационного параметра и будет отображаться различны- ми утилитами конфигурации.
Третья строка позволяет указать значение этого параметра по умолчанию, кото- рый соответствует в данном случае запрещению компиляции.
Директива h e l p указывает на то, что остальная часть текста будет интерпре- тироваться как описание данного модуля. Различные конфигурационные утилиты могут при необходимости отображать этот текст. Так как этот текст предназначен для пользователей и разработчиков, которые будут компилировать ядро, то он дол- жен быть коротким и ясным. Обычные пользователя, скорее всего, не будут компи- лировать ядро, а сели будут, то тогда они должны понимать, что в этом описании сказано.
Существуют также и другие директивы файла конфигурации. Директива depends указывает на конфигурационные параметры, которые должны быть установлены перед тем, как может быть установлен текущий параметр. Если зависимости не бу- дут удовлетворены, то текущий параметр будет запрещен. Например, можно указать следующую директиву.
depends on FISH_TANK
При этом текущий модуль не будет разрешен, пока не будет разрешен модуль, со- ответствующий конфигурационному параметру CONFIG_FISH_TANK.
Директива s e l e c t аналогична директиве d e p e n d s , за исключением того, что она принудительно включает указанный конфигурационный параметр, если вклю- чается текущая конфигурационная опция. Ее не нужно использовать так же часто,
как директиву depends, потому что она включает другие конфигурационные опции.
Использовать ее так же просто.
select BAIT
В этом случае конфигурационный параметр CONF'IG_BAIT автоматически активи- зируется при включении конфигурационного параметра CONFIG_FISHING_POLE.
Как для директивы s e l e c t , так и для директивы depends можно указывать не- сколько параметров с помощью оператора &&. В директиве depends с помощью вос- клицательного знака перед параметром можно указать требование, что некоторый конфигурационный параметр не должен быть установлен. Например, следующая запись указывает, что для компиляции текущего драйвера необходимо, чтобы был установлен конфигурационный параметр CONFIG_DUMB_DRIVERS и не был установ- лен параметр CONFIG_NO_FISHING_ALLOWED.
depends on DUMB_DRIVERS && !NO_FISHING_ALLOWED
350 Глава 16

После директив t r i s t a t e и b o o l можно указать директиву if, что позволяет сделать соответствующий параметр зависимым от другого конфигурационного па- раметра. Если условие не выполняется, то конфигурационный параметр не только запрещается, но и не будет отображаться утилитами конфигурации. Например, сле- дующая строка указывает, что функция "Deep Sea Mode" будет доступна, только если разрешен конфигурационный параметр CONFIG_OKEAN.
bool TDeep Sea ModeY if OCEAN
Директива if также может быть указана после директивы d e f a u l t , что означает,
что значение по умолчанию будет установлено, только если выполняется условие,
указанное в директиве if.
Система конфигурации экспортирует несколько метапараметров, чтобы упро- стить процесс конфигурации. Параметр CONFIG_EMBEDDED устанавливается только тогда, когда пользователь указывает, что он хочет видеть вес параметры, отвечаю- щие за запрещение некоторых ключевых позможностей ядра (обычно с целью со- хранения памяти на встраиваемых системах). Параметр CONFIG_BROKEN_ON_SMP
используется, чтобы указать, что драйвер не рассчитан на системы с симметричной многопроцессорностью. Обычно этот параметр не устанавливается, при этом от пользователя требуется, чтобы он сам убедился в возможности компиляции драйве- ра для SMP. Новые драйверы этот флаг использовать не должны.
Параметр CONFIG_EXPERIMENTAL используется для указания экспериментальных или не очень хорошо оттестированных возможностей. По умолчанию этот параметр отключен, что требует от пользователя лично убедиться в степени риска при разре- шении компиляции того или иного драйвера.
Параметры модулей
Ядро Linux предоставляет возможность драйверам определять параметры, кото- рые пользователь будет указывать при загрузке ядра или модуля. Эти параметры бу- дут доступны коду модуля в качестве глобальных переменных. Указанные параметры модулей также будут отображаться в файловой системе sysfs (см. главу 17, "Объекты kobject и файловая система sysf "). Определять параметры модуля и управлять ими просто.
Параметр модуля определяется с помощью макроса module_param () следующим образом.
module_param(name, type, perm);
где аргумент name — это имя неременной, которая появляется в модуле, и имя пара- метра, который может указать пользователь. Аргумент t y p e — это тип данных па- раметра. Значения типа могут быть следующими: b y t e , s h o r t , u s h o r t , i n t . u i n t ,
long, u l o n g , c h a r p , b o o l или i n v b o o l . Эти значения соответствуют следующим типам данных: байт; короткое целое число; короткое целое число без знака; целое число; целое число без знака; длинное целое; длинное целое число без знака; указа- тель на строку символов; булев тип; булев тип, значение которого инвертируется по сравнению с тем, которое указывает пользователь. Данные типа b y t e хранятся в пе- ременной типа char, а данные булевых типов — в переменных типа i n t . Остальные- типы соответствуют аналогичным типам языка С. Наконец, аргумент perm указыва-
М одул и 351
ет права доступа к соответствующему файлу в файловой системе sysfs. Права досту- па можно указать как в обычном восьмеричном формате, например 0644 (владелец имеет права на чтение и запись, группа имеет права на чтение и запись, остальные пользователи имеют право только на чтение), так и в виде определений препроцес- сора, объединенных с помощью оператора " | " , например S_IRUGO | S_IWUSR (все могут считывать данные, а владелец также и записывать). Нулевое значение этого параметра приводит к тому, что соответствующий файл в файловой системе sysfs не появляется.
Этот макрос не определяет переменную. Перед тем как использовать макрос, соот- ветствующую переменную нужно определить. В связи с этим типичный пример ис- пользования может быть следующим.
/* параметр модуля, который управляет переменной bait */
static int allow live bait = 1; /* по умолчанию включено */
module_param(allow_live_bait, bool, 0644); /* булев тип */
Это определение должно быть в глобальной области видимости, т.е. неременная a l l o w _ l i v e _ b a i t должна быть глобальной.
Существует возможность дать внешнему параметру модуля имя, отличное от име- ни переменной. Это можно сделать с помощью макроса module_param_named ().
module_param_named(name, variable, type, perm);
где name — это имя внешнего параметра модуля, a v a r i a b l e — имя внутренней гло- бальной переменной модуля, как показано ниже.
static unsigned int max_test = DEFAULT_МАХ_LINE_TEST;
module_param_named (maximum_line_test, max_test, int, 0 ) ;
Для того чтобы определить параметр модуля, значением которого является стро- ка символов, необходимо использовать тип charp. Ядро копирует переданную поль- зователем строку символов в память и присваивает переменной указатель на эту строку, как в следующем примере.
static char *name;
module_param(name, charp, 0 ) ;
При необходимости ядро может скопировать строку в заранее определенный массив символов, который указывает разработчик. Это делается с помощью макроса m o d u l e _ p a r a m _ s t r i n g ( ) .
module_param_string(name, string, len, perm);
где name — это имя внешнего параметра, s t r i n g — имя внутренней переменной,
которая содержит указатель на область памяти массива, len — размер буфера string
(или некоторое меньшее число, чем размер буфера, что, однако, обычно не имеет смысла), perm — права доступа к файлу на файловой системе sysfs (нулевое значение запрещает доступ к параметру через sysfs). Пример показан ниже.
static char species[BUF_LEN];
module_param_string (specif ies, species, BUF_LEN, 0 ) ;
В качестве параметров модуля также можно передавать список значений, кото- рые разделены запятой и в коде модуля будут записаны в массив данных. Эти пара-
352 Глава 16
метры модуля можно обработать с помощью макроса module_param_array() следу- ющим образом.
module_param array(name, type, nump, perm);
В данном случае аргумент name — это имя внешнего параметра и внутренней пере- менной, type — это тип данных одного значения, a perm — это права доступа к файлу на файловой системе sysfs. Новый аргумент nump — это указатель на целочисленное значение, где ядро сохраняет количество элементов, записанных в массив. Обратите внимание, что массив, который передается в качестве параметра name, должен быть выделен статически. Ядро определяет размер массива на этапе компиляции и гаран- тирует, что он не будет переполнен. Как использовать данный макрос, показано в следующем примере.
static int fish[MAX_FISH];
static int nr_fish;
module_param_array(fish, int, &nr_fish, 0444);
Внутренний массив может иметь имя, отличное от имени внешнего параметра, в этом случае следует использовать макрос module_param_array_named ().
module_param_array_named(name, array, type, nump, perm);
Параметры идентичны аналогичным параметрам других макросов.
Наконец, параметры модуля можно документировать, используя макрос MODULE_
PARM_DESC() .
static unsigned short size = 1;
module_param(size, ushort, 0644);
MODULE_PARM__DESC(size, "The size in inches of the fishing pole " \
"connected to this computer.");
Вес описанные в этом разделе макросы требуют включения заголовочного файла
.
1   ...   39   40   41   42   43   44   45   46   ...   53


написать администратору сайта