В реальном режиме (при отключенной страничной переадресации) физический адрес, фигурирующий на системной шине, совпадает с линейным адресом, формируемым прикладной программой. Тут все просто, правда, в стандартном (а не большом) реальном режиме доступен только первый мегабайт адресного пространства (то есть из устройств доступны только отображенные на область UMA).
В защищенном режиме, в принципе, доступно все физическое адресное пространство, но появляются проблемы, связанные с отображением линейных адресов на физические. Страничной переадресацией (поддержкой таблиц) ведает ОС, и у разных программных компонентов (приложений, драйверов, динамических модулей) имеются различающиеся возможности взаимодействия с системой управления памятью. Заметим, что у каждой задачи может быть своя карта адресов, в которой не обязательно будут присутствовать физические адреса всех устройств.
Для обращения к регистрам устройства (или к области памяти устройства), расположенным в пространстве памяти, программа должна узнать физический адрес данной области. Далее она должна запросить у ОС линейный адрес, на который отображается этот физический адрес, и обращаться к устройству по этому линейному адресу. Иного пути добраться до физического устройства у программы нет, и если ОС откажет в данном запросе, устройство окажется для этой программы недоступным. Для обращения к устройствам через пространство памяти у процессоров х86 предусмотрено большое число разнообразных инструкций — как выполняющих просто пересылку, так и работающих с операндами в памяти (то есть в устройстве). Инструкции, модифицирующие ячейки памяти, порождают на системной шине блокированные транзакции «чтение-модификация-запись». Этот тип транзакций не приветствуется с точки зрения эффективности использования времени шины, так что предпочтительно избегать таких инструкций при взаимодействии с устройствами. Заметим, что инструкции процессора обычно не порождают эффективных пакетных транзакций на шине PCI, они вызывают лишь одиночные транзакции1. Некоторые программные ухищрения, позволяющие повысить эффективность программно-управляемого обмена, описаны в 14.4.
При организации прямого доступа к памяти как по стандартным каналам DMA, так и при использовании ведущих устройств шин ISA и PCI возникает ряд проблем, связанных со страничным преобразованием адресов. Программе требуется организовать обмен данными между устройством и некоторым буфером данных в ОЗУ, с которым программа общается по линейным адресам, а устройство — по физическим. Отметим ряд существенных моментов:
♦ Программа должна запросить у ОС физический адрес, которому соответст вует линейный адрес предполагаемого буфера обмена. Именно этот физиче ский адрес должен задаваться устройству, осуществляющему DMA (или централизованному контроллеру DMA), при инициализации сеанса обмена (при указании начального адреса, длины блока и запуске канала).
♦ Физические страницы, к которым обращаются посредством DMA, должны быть зафиксированы: механизм замещения страниц не должен их затраги вать — по крайней мере, пока не завершится обмен посредством DMA.
Если буфер данных не умещается в одной логической странице, возникает проблема пересечения границ. Обычный контроллер DMA работает по последовательно изменяемым (инкрементируемым или декрементируемым) адресам. При пересечении границы логической страницы, возможно, потребуется скачок физического адреса, поскольку следующая логическая страница может быть физически отображена на произвольное (относительно предыдущей страницы) место ОЗУ. Чаще всего ОС оперирует страницами по 4 Кбайт, при этом пересылка больших блоков данных ведется «короткими перебежками», между которыми должна выполняться повторная инициализация контроллера DMA.
Проблема пересечения границ решается усложнением контроллеров DMA — применением «разбросанной записи» (scatter write) в память и «собирающего чтения» (gather read) памяти. В этом случае контроллеру DMA задается список описателей блоков (начальный адрес и длина), каждый из которых не пересекает границ логической страницы. Обработав очередной блок памяти, контроллер переходит к следующему, и так до конца списка. Такие возможности имеет, например, стандартный контроллер PCI IDE. Для передачи логически непрерывного блока данных его описатель может быть сокращен. Так, можно задать полный физический адрес начала блока, его длину и только список базовых адресов занимаемых им страниц. На каждой странице, кроме начальной, данные будут начинаться с нулевого адреса; на каждой странице, кроме последней, данные будут доходить до последнего адреса. Вместо длины блока можно задавать и физический адрес его конца. Такие варианты описаний используются, например, в хост-контроллерах шин USB и FireWire.
Проблема пересечения границ может решаться и иначе, без усложнения контроллера DMA. Для этого в памяти резервируется буфер значительного размера, отображенный на непрерывную область физической памяти, и обмен данными физическое устройство выполняет только с этим буфером. Однако рядовое приложение не может создать такой буфер, он может быть организован лишь драйвером устройства. Приложения могут лишь получать указатели на этот буфер и обмениваться с ним данными. Таким образом, по пути от приложения к устройству появляются дополнительная «перевалочная база» (буфер драйвера) и дополнительная пересылка данных, что приводит к дополнительным затратам времени.