Базовая архитектура драйверов
Базовая архитектура драйверов
Драйвер устройства адресуется старшим номером (major number) устройства. Напомним, что среди атрибутов специальных файлов устройств, которые обеспечивают пользовательский интерфейс доступа к периферии компьютера, это число присутствует наряду с другим, также имеющим отношение к драйверу, — младшим номером (minor number). Младший номер интерпретируется самим драйвером (например, для клонов, оно задает старшее число устройства, которое требуется "размножить"). Другим примером использования младших номеров может служить драйвер диска. В то время как доступ к любому из разделов диска осуществляется одним и тем же драйвером и, соответственно, через один и тот же старший номер, младший номер указывает, к какому именно разделу требуется обеспечить доступ.
Доступ к драйверу осуществляется ядром через специальную структуру данных (коммутатор устройств), каждый элемент которой содержит указатели на соответствующие функции драйвера — точки входа. Старшее число, по существу, является указателем на элемент коммутатора устройств, обеспечивая, тем самым, ядру возможность вызова необходимой функции указанного драйвера. Таким образом, коммутатор устройств определяет базовый интерфейс драйвера устройств.
Этот интерфейс различен для блочных и символьных устройств. Ядро содержит коммутаторы устройств двух типов: bdevsw для блочных и cdevsw для символьных устройств. Ядро размещает отдельный массив для каждого типа коммутатора, и любой драйвер устройства имеет запись в соответствующем массиве. Если драйвер обеспечивает как блочный, так и символьный интерфейсы, его точки входа будут представлены в обоих массивах.
Типичное описание этих двух массивов имеет следующий вид (назначение различных точек входа мы рассмотрим далее в этом разделе):
struct bdevsw[] {
int (*d_open)();
int (*d_close)();
int (*d_strategy)();
int (*d_size)();
int (*d_xhalt)();
...
} bdevsw[];
struct cdevsw[] {
int (*d_open)();
int (*d_close)();
int (*d_read)();
int (*d_write)();
int (*d_ioctl)();
int (*d_xpoll)();
int (*d_xhalt)();
struct streamtab *d_str;
...
} cdevsw[];
Ядро вызывает функцию open() требуемого драйвера следующим образом:
(*bdevsw[getmajor(dev)].d_open)(dev, ...);
передавая ей в качестве одного из параметров переменную dev (типа dev_t), содержащую старший и младший номера. Макрос getmajor() служит для извлечения старшего номера из переменной dev. Благодаря этому драйвер имеет возможность определить, с каким младшим номером была вызвана функция open(), и выполнить соответствующие действия.
Коммутатор определяет абстрактный интерфейс драйвера устройства. Каждый драйвер обеспечивает соответствующую реализацию функций этого интерфейса. Если драйвер не поддерживает каких-либо функций стандартного интерфейса, он заменяет соответствующие точки входа специальными заглушками, предоставляемыми ядром. Когда ядру требуется запросить какую-либо операцию у драйвера устройства, оно определяет элемент коммутатора, соответствующий данному драйверу (используя его старший номер), и вызывает требуемую функцию.
В названиях точек входа драйвера используются определенные соглашения. Поскольку в ядре системы одновременно присутствует большое количество различных драйверов, каждый их них должен иметь уникальное имя во избежание проблем при компиляции (точнее, при редактировании связей) ядра. Каждый драйвер имеет уникальное двухсимвольное обозначение, используемое в качестве префикса названий функций. Например, драйвер виртуальной памяти ядра /dev/kmem имеет префикс mm, таким образом функции этого драйвера будут иметь названия mmopen(), mmclose(), mmread() и mmwrite().
В табл. 5.1 приведены некоторые точки входа, общие для различных типов драйверов, а символами xx, с которых начинается имя каждой функции, обозначен уникальный префикс драйвера. Стандартные точки входа драйвера отличаются для разных версий UNIX. Например, некоторые версии имеют расширенный коммутатор блочных устройств, включающий такие функции, как xxioctl(), xxread() и xxwrite(). В некоторых версиях включены точки входа для инициализации и сброса шины данных.
Таблица 5.1. Типичные точки входа в драйвер устройства
Точка входа Сим- вольный Блочный Низкого уровня Назначение xxopen() + + + Вызывается при каждой операции открытии устройства. Обеспечивает необходимую реинициализацию физического устройства и внутренних данных драйвера. Например, для каждого последующего открытия драйвера могут размещаться дополнительные буферы, обеспечивающие возможность независимой работы с устройством нескольким процессам. xxclose() + + + Вызывается, когда число ссылок на данный драйвер становится равным нулю, т. е. ни один из процессов системы не работает с устройством (не имеет открытым соответствующий файл устройства). Может вызывать отключение физического устройства. Например, драйвер накопителя на магнитной ленте может перемотать ленту в начало. xxread() + - + Производит чтение данных от устройства. xxwrite() + - + Производит запись данных на устройство. xxioctl() + - + Является общим интерфейсом управления устройством. Драйвер может определить набор команд, которые могут быть переданы ему, например с помощью системного вызова ioctl(2). xxintr() + + + Вызывается при поступлении прерывания, связанного с данным устройством. Может выполнить копирование данных от устройства в промежуточные буферы, которые затем считываются функцией xxread() по запросу прикладного процесса. xxpoll() + - + Производит опрос устройства. Обычно используется для устройств, не поддерживающих прерывания, например, для определения поступления данных для чтения. xxhalt() + + + Вызывается для останова драйвера при останове системы или при выгрузке драйвера. xxstrategy() - + + Общая точка входа для операций блочного ввода/вывода. Название функции говорит о том, что устройство может обеспечивать собственную стратегию обработки поступающих запросов, например, изменять их порядок для повышения производительности ввода/вывода. Если устройство занято, функция помещает запросы в очередь. В этом случае фактический ввод/вывод инициирует функция обработки прерывания, которая вызывается, когда устройство закончит предыдущую операцию ввода/вывода. xxprint() - + + Выводит сообщение драйвера на консоль, обычно при запуске системы.Ядро вызывает те или иные функции драйвера в зависимости от запроса. Например, если процесс выполняет системный вызов read(2) для специального файла символьного устройства, ядро вызовет функцию xxread() для соответствующего символьного драйвера. Если же процесс запрашивает ту же операцию для обычного дискового файла, ядро вызовет процедуру xxstrategy() для блочного драйвера, обслуживающего данную файловую систему.
Вообще говоря, можно выделить пять основных случаев, в которых ядро обращается к функциям драйвера:
? Автоконфигурация. Обычно происходит в процессе инициализации UNIX, когда ядро определяет, какие устройства доступны в системе.
? Ввод/вывод. Запрос на операцию ввода/вывода может быть инициирован как прикладным процессом, так и некоторыми подсистемами ядра, например, подсистемой управления памятью.
? Обработка прерываний. Ядро вызывает соответствующую функцию драйвера для обработки прерывания, поступившего от устройства (если устройство способно генерировать прерывания).
? Специальные запросы. Ядро вызывает соответствующую функцию драйвера для обработки специальных команд, полученных с помощью системного вызова ioctl(2).
? Реинициализация/Останов. Некоторые типы аппаратных архитектур могут требовать сброса и реинициализации устройства. Определенные функции драйвера также вызываются при останове операционной системы.
На рис. 5.2 и 5.3 приведены схемы доступа к драйверам символьного и блочного устройств.
Рис. 5.2. Доступ к драйверу символьного устройства
Рис. 5.3. Доступ к драйверу блочного устройства
Как видно из рисунков, схема обработки запроса ядром UNIX различна для символьных и блочных устройств.
При обсуждении точек входа драйверов устройств следует иметь в виду, что большинство функций драйвера, отвечающих за передачу данных, осуществляют копирование информации из адресного пространства ядра, в котором находится сам драйвер, в адресное пространство задачи. Когда ядро вызывает функцию драйвера, все действия выполняются в системном контексте процесса. Однако схема вызова функций может быть различной:
? Функция может быть вызвана по запросу процесса. Например, если процесс выполняет системный вызов read(2), ядро вызывает соответствующую точку входа драйвера xxread(), обеспечивающего работу с файлом. В этом случае говорят, что функция имеет контекст задачи.
? Функция может быть вызвана другой подсистемой ядра операционной системы. Например, для блочного драйвера функция xxstrategy() может быть вызвана страничным демоном, для сохранения страниц во вторичной памяти (как правило, на жестком диске). Поскольку страничный демон представляет собой системный процесс, выполняющийся только в контексте ядра, функция xxstrategy() в этом случае имеет системный контекст.
? Если функция вызывается в процессе обработки прерывания, то она имеет контекст прерывания — специальный вид системного контекста. Функции драйвера, отвечающие за обработку прерывания, например xxintr() имеют этот тип контекста.
Различия в контексте и причинах вызова тех или иных функций драйвера позволяют представить драйвер устройства состоящим из двух частей: верхней части (top half) и нижней части (bottom half). Функции верхней части драйвера имеют синхронный характер, т.е. вызываются по определенным запросам прикладного процесса и выполняются в его контексте. Таким образом, для этих функций доступно адресное пространство и u-area процесса, и при необходимости эти функции могут перевести процесс в состояние сна (вызовом функции sleep() ядра). Функции ввода/вывода и управления принадлежат верхней части драйвера.
Вызов функций нижней части носит асинхронный характер. Например, момент вызова функции обработки прерываний нельзя предугадать, и ядро не может контролировать, когда эта функция будет вызвана. Выполнение таких функций происходит в контексте ядра и обычно не имеет никакого отношения к контексту текущего процесса. Таким образом, функции системного контекста не имеют права адресовать структуры данных текущего процесса, например его u-area, а также не могут перевести процесс в состояние сна, поскольку это заблокирует процесс, не имеющий непосредственного отношения к работе драйвера.
Две части драйвера требуют синхронизации. Например, в случае, когда функции обеих частей используют одну и ту же структуру данных, функция верхней части при выполнении должна заблокировать прерывания на период работы с "разделяемой" областью памяти. В противном случае, прерывание может поступить в тот момент, когда целостность структуры данных нарушена, что приведет к непредсказуемым результатам.
Все представленные выше функции, за исключением xxhalt(), xxpoll() и xxintr(), принадлежат верхней части драйвера. Функция xxhalt() вызывается ядром при останове системы и, таким образом, имеет системный контекст, не связанный с контекстом прикладного процесса.
Функция xxpoll() обычно вызывается при обработке ядром прерывания таймера для всех устройств, указанных как опрашиваемые. Это необходимо, в частности, для устройств, которые не могут или "не хотят" использовать аппаратные прерывания. Вместо этого xxpoll() может использоваться для эмуляции прерываний, например вызывая функцию xxintr() на каждый n-ный тик системного таймера. Поэтому и функция xxpoll() и функция обработки прерывания xxintr() не могут рассчитывать на контекст прикладного процесса. В большинстве версий UNIX функции опроса и обработки прерываний вызываются не через коммутатор устройств, а через специальные таблицы ядра.
В UNIX SVR4 определены две дополнительные точки входа — init() и start(). Драйвер регистрирует эти функции в таблицах ядра io_init[] и io_start[]. Код начальной загрузки системы запускает функции xxinit() перед инициализацией ядра, а функции xxstart() сразу же после инициализации.
Более 800 000 книг и аудиокниг! 📚
Получи 2 месяца Литрес Подписки в подарок и наслаждайся неограниченным чтением
ПОЛУЧИТЬ ПОДАРОКДанный текст является ознакомительным фрагментом.
Читайте также
Базовая сетка
Базовая сетка В типографике базовой линией называют невидимую линию, на которой располагаются буквы. Например, нижний край буквы е лежит на базовой линии, а нижний выносной элемент буквы р находится под ней. Сетка образуется множеством базовых линий, расстояние между
Совет 46: Базовая защита
Совет 46: Базовая защита Пожалуй, каждый обитатель собственного дома или владелец дачи хоть раз мечтал об автоматической оборонительной системе, способной удерживать на расстоянии выстрела воров и продавцов краденного садового инструмента, шумные компании малолетней
Базовая файловая система System V
Базовая файловая система System V Каждый жесткий диск состоит из одной или нескольких логических частей, называемых разделами (partitions). Расположение и размер раздела определяются при форматировании диска. В UNIX разделы выступают в качестве независимых устройств, доступ к
3.1 Базовая функциональность «Мозилла»66
3.1 Базовая функциональность «Мозилла»66 Браузер. Для просмотра страниц WWW и «хождения» по FTP-серверам предназначен компонент «Навигатор». На панели компонент «Мозилла» он изображается морским штурвалом (см. рис. 3-1). Рис. 3-1Все возможности программы доступны из меню,
Базовая конфигурация DNS
Базовая конфигурация DNS Установка конфигурации DNS предполагает решение двух задач: настройка сервера DNS (в пакете BIND функции сервера выполняет программа named) и администрирование домена. В данном разделе обсуждаются особенности выполнения первой задачи, а
Базовая архитектура Skype
Базовая архитектура Skype Skype — программное обеспечение для VoIP, обеспечивающее бесплатную голосовую связь через Интернет между компьютерами, а также платные услуги для связи с абонентами обычной телефонной сети. В отличие от многих других программ IP-телефонии, для
Базовая конфигурация SIP-телефонов в Asterisk
Базовая конфигурация SIP-телефонов в Asterisk Конфигурация SIP-телефона для работы с Asterisk не требует много усилий и времени. Однако здесь можно легко запутаться из-за обилия опций как в Asterisk, так и в конфигурации конкретного телефонного аппарата или программного телефона.
8.9.3. Базовая настройка
8.9.3. Базовая настройка После установки системы LIDS в каталоге /etc у вас появится подкаталог /lids. В нем вы обнаружите четыре файла: lids.cap, lids.net, lids.pw, lids.conf.В первом из них хранятся текущие установки способностей (cap — от capabilities— способности). О том, что такое способности, мы
1.7 Иерархия драйверов систем хранения и типы драйверов
1.7 Иерархия драйверов систем хранения и типы драйверов Как описывалось в предыдущем разделе, Windows NT основана на архитектуре, в которой драйверы формируют многоуровневую иерархию. Преимущество такой архитектуры состоит в расширяемости архитектуры и возможности
5. Базовая раскрутка партнерки
5. Базовая раскрутка партнерки Что делать для привлечения партнеров?? Рассказывайте о партнерской программе везде, на всех ваших сайтах – продающих и не продающих.? У профессионалов вы наверняка видели в конце каждого продающего текста или мини-сайта упоминание о
3.1 Базовая функциональность «Мозилла»
3.1 Базовая функциональность «Мозилла» Браузер. Для просмотра страниц WWW и «хождения» по FTP-серверам предназначен компонент «Навигатор». На панели компонент «Мозилла» он изображается морским штурвалом (см. рис. 3-1). Рис. 3-1Все возможности программы доступны из меню,
15.4.1. Базовая теория make
15.4.1. Базовая теория make При разработке программ на языках С или С++ важной частью для построения приложения является семейство команд компиляции и компоновки, необходимых для получения из файлов исходного кода работающих бинарных файлов. Ввод данных команд — длительная и
Базовая конфигурация и утверждение
Базовая конфигурация и утверждение Основной список бизнес-процессов (Business Process Master List, BPML) — это самое полное представление рамок проекта внедрения SAP. Конфигурация делится на две части — базовая конфигурация и окончательная конфигурация.Эти конфигурационные задания
Базовая форма
Базовая форма Программный объект довольно простое существо, если известен класс, которому он принадлежит. Пусть O - объект. По определению он является экземпляром некоторого класса. Точнее, он является прямым экземпляром (direct instance) только одного класса, например C. С
Робачевский Андрей М.
Просмотр ограничен
Смотрите доступные для ознакомления главы 👉