Одной из важнейших функций операционной системы является управление всеми устройствами ввода-вывода, подключенными к компьютерной системе. Операционная система должна передавать устройствам команды, перехватывать прерывания и обрабатывать ошибки, она также должна обеспечивать унифицированный абстрактный интерфейс этих устройств в системе.
Устройства ввода-вывода делятся на два типа:
- Блок-ориентированные устройства (block-oriented). Это устройства прямого доступа, которые хранят информацию в блоках фиксированного размера, каждый из которых имеет свой адрес. Адресуемость блоков приводит к тому, что для дисков, являющихся устройствами прямого доступа, появляется возможность кэширования данных в оперативной памяти. Это обстоятельство значительно влияет на общую организацию ввода-вывода для блок-ориентированных драйверов.
- Байт-ориентированные устройства (character-oriented). Устройства, обмен информацией с которыми производится побайтно. К таким устройствам относятся: терминалы, некоторые принтеры, сетевые адаптеры. При таком взаимодействии информация не адресуется и не позволяется производить операцию поиска. Работа с устройством происходит следующим образом: устройство посылает системе последовательности байт, либо, при отправке данных устройству, данный передаются побайтно.
Замечание 3.2. Некоторые внешние устройства не относятся ни к одному из указанных типов, которые, не адресуемы, но и не порождают потока байтов. Примером может служить системный таймер. Это устройство только выдает сигнал прерывания в некоторые моменты времени. |
С каждым внешним устройством, как правило, связан его контроллер, выполняющий функции управления устройством. Контроллер обычно выполняет простые функции, например, преобразует поток бит в блоки, состоящие из байтов, и осуществляет контроль и исправление ошибок. Каждый контроллер имеет несколько регистров, называемых портами.
|
|
Операционная система обычно имеет дело не с устройством, а с контроллером и выполняет ввод-вывод, записывая команды в регистры контроллера.
Например, контроллер гибкого диска принимает 15 команд, таких как READ, WRITE, SEEK, FORMAT и т.д. Когда команда принята, процессор оставляет контроллер и занимается другой работой. При завершении команды контроллер организует прерывание для того, чтобы передать управление процессором операционной системе, которая должна проверить результаты операции. Процессор получает результаты и статус устройства, читая информацию из регистров контроллера.
Программное обеспечение ввода-вывода обычно организуется в виде четырех уровней. У каждого уровня есть четко очерченная функция, которую он должен выполнять, и строго определенный интерфейс с соседними уровнями:
|
|
- Первичный обработчик прерываний
Это небольшая часть ядра операционной системы, тесно связанная с аппаратурой. При возникновении прерывания операционная система выполняет ряд действий по сохранению контекста текущего процесса, запуску процедуры-обработчика прерываний, а также выбор нового процесса для выполнения.
- Драйверы устройств
Драйвером устройства называется программа, которая управляет данным устройством и содержит весь специфический для данного устройства код.
Драйвер обычно пишется производителем устройства и поставляется вместе с ним.
Только драйвер устройства знает о его конкретных особенностях. Драйверы принимают от вышележащего уровня некоторые универсальные для всех устройств ввода-вывода команды и переводят их в последовательность команд, которые может выполнить контроллер данного устройства.
Типичным запросом, который может получить драйвер, является чтение п блоков данных. Драйвер жесткого диска должен, например, преобразовать номера блоков в номера цилиндров, головок, секторов, проверить, работает ли мотор, находится ли головка над нужным цилиндром и т.д.
Драйверы блок-ориентированных и бит-ориентированных устройств предоставляют вышележащему уровню различные интерфейсы.
- Независимый от устройств слой операционной системы.
Задачей этого слоя (вместе с двумя нижележащими) является представление всех устройств ввода-вывода в виде единообразной абстракции. Ранее уже упоминались такие унифицированные абстракций, например, файловая абстракция (файловые потоки, специальные файлы).
Типичными функциями данного слоя являются:
· обеспечение общего интерфейса к драйверам устройств;
Одним из аспектов единообразного интерфейса является именование устройств ввода-вывода. Независимо от устройств программное обеспечение занимается отображением символьных имен устройств на соответствующие драйверы.
С именованием устройств тесно связан вопрос защиты устройств от работы с ними тех пользователей, у которых нет на это соответствующих полномочий.
· обеспечение независимого размера блока;
Верхним слоям программного обеспечения неудобно работать с блоками разной величины, поэтому данный слой обеспечивает единый размер блока, например за счет объединения нескольких различных блоков в единый логический блок.
· уведомление об ошибках при работе с устройством.
- Пользовательский слой программного обеспечения.
В этом слое присутствуют программные модули (или даже целостные операционные среды), которые обеспечивают высокоуровневое взаимодействие с соответствующим устройством.
Более детально остановимся на понятии драйвер. Первоначально термин «драйвер» применялся в достаточно узком смысле; под драйвером понимается программный модуль, который:
· входит в состав ядра ОС, работая в привилегированном режиме;
· непосредственно управляет внешним устройством, взаимодействуя с его контроллером с помощью команд ввода-вывода компьютера;
· обрабатывает прерывания от контроллера устройства;
· предоставляет прикладному программисту удобный логический интерфейс работы с устройством, абстрагированный от низкоуровневых деталей управления устройством и организации его данных;
· взаимодействует с другими модулями ядра ОС с помощью строго оговоренного интерфейса, описывающего формат передаваемых данных, структуру буферов, способы включения драйвера в состав ОС, способы вызова драйвера, набор общих процедур подсистемы ввода-вывода, которыми драйвер может пользоваться и т. п.
Согласно этому определению драйвер вместе с контроллером устройства и прикладной программой воплощали идею многослойного подхода к организации программного обеспечения. Контроллер представлял низкий слой управления устройством, выполняющий операции в терминах блоков и агрегатов устройства (например, параметры, передаваемые жесткому диску из примера ранее). Драйвер выполнял более сложные операции, преобразуя данные, адресуемые в терминах номеров цилиндров, головок и секторов диска, в линейную последовательность блоков. В результате прикладная программа работала с данными, преобразованными в достаточно понятную форму — файлами, таблицами баз данных, текстовыми окнами на мониторе и т. п., не вдаваясь в детали представления этих данных в устройствах ввода-вывода.
|
|
В описанной схеме драйверы не делились на слои. Постепенно, по мере развития операционных систем и усложнения структуры подсистемы ввода-вывода, наряду с традиционными драйверами в ОС появились так называемые высокоуровневые драйверы, которые располагаются в общей модели подсистемы ввода-вывода над традиционными драйверами. Появление таких драйверов можно считать развитием идеи многоуровневой организации подсистемы ввода-вывода, когда ее функции декомпозируются между несколькими модулями в соседних слоях иерархии (таких примеров много, например семиуровневая модель сетевых протоколов).
Традиционные драйверы, которые стали называть аппаратными, низкоуровневыми, или драйверами устройств, освобождаются от высокоуровневых функций и занимаются только низкоуровневыми операциями. Эти низкоуровневые операции составляют фундамент, на котором можно построить тот или иной набор операций в драйверах более высоких уровней.
При каком подходе повышается гибкость и расширяемость функции по управлению устройством. Например, если различным приложениям необходимо работать с различными логическими модулями одного и того же физического устройства, то для этого в системе достаточно установить несколько драйверов на одном уровне, работающих над одним аппаратным драйвером. Несколько драйверов, управляющих одним устройством, но на разных уровнях, можно рассматривать как один многоуровневый драйвер.
|
|
На практике используют от двух до пяти уровней драйверов, поскольку с увеличением числа уровней снижается скорость выполнения операций ввода-вывода.
Высокоуровневые драйверы оформляются по тем же правилам и придерживаются тех же внутренних интерфейсов, что и аппаратные драйверы. Как правило, высокоуровневые драйверы не вызываются по прерываниям, так как взаимодействуют с устройством через посредничество аппаратных драйверов.
В модулях подсистемы ввода-вывода кроме драйверов могут присутствовать и другие модули, например дисковый кэш. Достаточно специфичные функции кэша делают нецелесообразным оформление его в виде драйвера, взаимодействующего с другими модулями ОС только с помощью услуг менеджера ввода-вывода. Другим примером модуля, который чаще всего не оформляется в виде драйвера, является диспетчер окон графического интерфейса. Иногда этот модуль вообще выносится из ядра ОС и реализуется в виде пользовательского интерфейса. Таким образом был реализован диспетчер окон в Windows NT 3.5 и 3.51, но этот микроядерный подход заметно замедляет графические операции, поэтому в Windows 4.0 диспетчер окон и высокоуровневые графические драйверы, а также графическая библиотека GDI были перенесены в пространство ядра.
Аппаратные драйверы после запуска операции ввода-вывода должны своевременно реагировать на завершение контроллером заданного действия путем взаимодействия с системой прерывания. Драйверы более высоких уровней вызываются не по прерываниям, а по инициативе аппаратных драйверов или драйверов вышележащего уровня. Не все процедуры аппаратного драйвера нужно вызывать по прерываниям, поэтому драйвер обычно имеет определенную структуру, в которой выделяется секция обработки прерываний (Interrupt Service Routine, ISR), которая и вызывается от соответствующего устройства диспетчером прерываний.
В унификацию драйверов большой вклад внесла ОС UNIX. Упомянутое ранее деление устройств на блок-ориентированные и байт-ориентированные было впервые введено именно в UNIX. Это более общее деление, чем деление на вертикальные подсистемы.
В свое время ОС UNIX сделала очень важный шаг по унификации операций и структуризации программного обеспечения ввода-вывода. В ОС UNIX все устройства рассматриваются как виртуальные (специальные) файлы, что дает возможность использовать общий набор базовых операций ввода-вывода для любых устройств независимо от их специфики. Подобная идея реализована позже в MS DOS, где последовательные устройства — монитор, принтер и клавиатура считаются файлами со специальными именами: con, prn, con.