Способы доступа к буферным областям
Диспетчер ввода/вывода предоставляет драйверам два разных метода для осуществления доступа к пользовательским буферным областям. Драйвер, при инициализации, должен сообщить Диспетчеру ввода/вывода, какой из методов он планирует использовать. Выбор определяется логикой и скоростью работы устройства, которое обслуживает драйвер.
Первая стратегия состоит в том, чтобы поручить Диспетчеру ввода/вывода копирование пользовательской буферной области в специальную область оперативной памяти, которая не является страничной и зафиксирована в физической памяти. Драйвер использует копию буфера для работы с устройством и осуществления операций ввода/вывода. По завершении работы, Диспетчер ввода/вывода обычно производит копирование данных из системного буфера в пользовательский. При запросе на операцию записи (то есть при переносе данных в обслуживаемое устройство), пользовательская область копируется в область в системном адресном пространстве до того, как последняя будет представлена драйверу. При запросе на чтение (получение данных из обслуживаемого устройства) копирование системного буфера в пользовательский производится после того, как драйвер помечает запрос как завершенный. Стандартные запросы на чтение или запись не требуют выполнения двунаправленного копирования, хотя при обработке IOCTL запросов (выполненных в пользовательских приложениях при помощи функции DeviceIoControl) это может потребоваться.
Описанный выше метод носит название buffered I/O — буферизованного ввода/вывода. Он используется медленными устройствами, которые редко работают с большими объемами данных. Этот метод не сложен для реализации в логике драйвера, но требует дополнительных временных затрат на операции по копированию буферных областей.
Вторая стратегия позволяет избежать операций копирования путем предоставления драйверу прямого доступа к пользовательской буферной области в оперативной физической памяти. В начале выполнения операции Диспетчер ввода/вывода фиксирует всю область пользовательского буфера в памяти, что предотвращает перемещение этого блока в swap-файл и саму возможность возникновения ошибки отсутствующей страницы (page fault). Затем он создает список элементов страничной таблицы, которые отображаются на область памяти выше 2 Гбайт (на системную область), таким образом, устраняя повод для переключений контекста процесса. В сложившейся ситуации, когда память и элементы страничной таблицы зафиксированы на время обработки всего запроса ввода/вывода, драйверный код может без опаски работать с пользовательским буфером. Правда, свойства этого буфера существенно изменились: теперь эта область зафиксирована в памяти (фактически стала нестраничной), а оригинальный пользовательский адрес транслирован в другой адрес, пригодный для использования только в коде, работающем в режиме ядра.
Второй метод хорошо подходит для использования драйверами быстрых устройств, выполняющих перенос больших объемов данных. Этот метод известен как direct I/O — прямой ввод/вывод. Устройства, имеющие способность к операциям DMA, практически всегда используют этот механизм.