Аппаратные интерфейсы, описанные в книге, в IBM-PC-совместимом компьютере «живут» в специфическом архитектурном окружении. Эту специфику приходится учитывать при проектировании аппаратной части устройств, чтобы обеспечить с ними эффективное программное взаимодействие. В этой главе вкратце рассматриваются особенности процессоров x86 и связанные с этими особенностями распределение памяти, организация ввода-вывода и прерываний. Здесь же рассматривается традиционный контроллер DMA, системные средства измерения времени, а также способы внедрения собственных расширений BIOS и нетрадиционной (бездисковой) загрузки ПО в специализированные компьютеры на базе IBM PC.
12.1. Пространство физической памяти
Основную часть физического адресного пространства PC занимает оперативная память (ОЗУ), начинающаяся с нулевого адреса. В нее вклинивается область адресов A0000h-FFFFFh — Upper Memory Area (UMA), 384 Кбайт — верхняя память, зарезервированная со времен IBM PC для системных нужд. В UMA размещаются области буферной памяти адаптеров шины (E)ISA (например, видеопамять) и постоянная память (BIOS с расширениями). ОЗУ продолжается и за областью UMА. Под самой верхней границей физического адресного пространства имеется образ памяти системной ROM BIOS.
Для доступности сервисов BIOS в реальном режиме все ПК имеют образ ROM BIOS в адресах E0000h-FFFFFh или F0000h-0FFFFFh. Кроме того, образ BIOS должен находиться и под самой верхней границей адресного пространства, поскольку все процессоры х86 по аппаратному сбросу стартуют с адреса начала последнего параграфа памяти (FFFF0h — 8086/88, FFFFF0h — 80286 и 386SX, FFFFFFF0h — 386DX и выше с 32-разрядной шиной адреса, FFFFFFFF0h — P6 и выше с 36-разрядной шиной адреса).
Для компьютеров класса АТ-286 и 386SX с 24-битной шиной адреса верхняя граница оперативной памяти — FDFFFFh (максимальный размер 15,9 Мбайт). Область FE0000h-FFFFFFh содержит образ ROM BIOS, обращение к этой области эквивалентно обращению к ROM BIOS по адресам 0E0000h-0FFFFFh.
Для ПК на процессорах 386DX и выше с 32-битной шиной адреса теоретический предел объема ОЗУ — почти 4 Гбайт, верхний образ BIOS находится в адресах FFFE0000h-FFFFFFFFh. Для ПК на процессорах P6+ с 36-битной шиной адреса предел объема ОЗУ — почти 64 Гбайт и верхний образ BIOS находится в адресах FFFFE0000h-FFFFFFFFFh.
Области физических адресов, не занятые ОЗУ и ROM BIOS, могут быть использованы устройствами шин (E)ISA и PCI (AGP).
Для памяти адаптеров, устанавливаемых в шину ISA, безусловно доступна часть области адресов UMA A0000h-EFFFFh или A0000h-DFFFFh (до начала ROM BIOS). В этой области располагаются и модули расширений BIOS (см. п. 12.7.1). Карты ISA могут иметь память и в области FE0000h-FFFFFFh, но она программно доступна лишь в защищенном (и большом реальном) режимах процессора. Для отображения этой области памяти на шину ISA (а не ОЗУ) в CMOS Setup предусмотрен параметр Memory Hole At 15-16М, но его включение не позволит использовать оперативную память свыше 15 Мбайт.
Поскольку шина ISA имеет 24-разрядную шину адреса, ведущие устройства этих шин (ISA Bus Master) способны обращаться к памяти (ОЗУ и память адаптеров) в пределах первых 16 Мбайт (000000-FFFFFFh). To же ограничение касается и стандартного контроллера DMA, которым могут пользоваться устройства шины ISA (и иные устройства системной платы).
Шина PCI имеет 32-разрядную шину адреса, так что ее ведущим устройствам доступна вся физическая память. Для устройств PCI могут выделяться любые области адресов, свободные от ОЗУ, ROM BIOS и устройств ISA. Области адресов памяти, используемые каждым устройством PCI, описаны в заголовках их конфигурационных пространств. Эти данные требуются при распределении ресурсов и настройке мостов PCI в процессе инициализации шины.
12.2. Пространство ввода-вывода
Пространство ввода-вывода в IBM PC, как и в процессорах х86, отделено от пространства памяти. У всех этих процессоров, в том числе и 32-разрядных, в пространстве ввода-вывода используется 16-разрядная адресация (диапазон адресов 0-FFFFh). Для дешифрации адресов портов в оригинальном PC из 16 бит использовались только младшие 10 (А0-А9), что обеспечивает обращением портам в диапазоне адресов 0-3FFL Старшие биты адреса, хотя и поступают на шину, устройствами игнорируются. В результате обращения по адресам, к примеру 378h, 778h, B78h и F78h, будут восприниматься устройствами одинаково. Это упрощение, нацеленное на снижение стоимости как системной платы, так и схем плат адаптеров, для шины ISA никто не отменял. Традиционные адаптеры для шины ISA, называемые Legacy Card («наследие тяжелого прошлого»), для старших бит адреса не имеют даже печатных ламелей на своем краевом разъеме. Впоследствии перешли к 12-битной адресации устройств шины ISA, но ее приходится применять с оглядкой на возможное присутствие устройств с 10-битной адресацией. В адаптерах для шин MCA и PCI и во всех современных системных платах используются все 16 бит адреса. Карта распределения адресов ввода-вывода стандартных устройств PC приведена в табл. 12.1. Эта карта подразумевает 10-битную дешифрацию адреса. Естественно, что в конкретном компьютере реально присутствуют не все перечисленные устройства, но в то же время там могут оказаться другие, не попавшие в таблицу.
Таблица 12.1. Стандартная карта портов ввода-вывода
AT и PS/2 | PC/XT | Назначение |
000-00F | 000-00F | Контроллер DMA #1 8237 |
010-01F | PS/2 — расширение DMA#1 | |
020-021 | 020-021 | Контроллер прерываний #1 — 8259A |
040-05F | 040-043 | Таймер (PC/XT: 8253, AT: 8254) |
060 | 060 | Диагностический регистр POST (только запись) |
060-063 | Системный интерфейс 8255 | |
060, 064 | Контроллер клавиатуры AT 8042 | |
061 | Источники NMI и управление звуком | |
070-07F | Память CMOS и маска NMI | |
080 | Диагностический регистр | |
080-08F | 080-083 | Регистры страниц DMA |
090-097 | PS/2 микроканал, арбитр | |
0А0 | Маска NMI | |
0A0-0BF | Контроллер прерываний #2 — 8259A | |
0C0-0DF | Контроллер DMA #2 8237A-5 | |
0F0-0FF | Сопроцессор 80287 | |
100-1EF | PS/2 управление микроканалом | |
170-177 | Контроллер НЖМД #2 (IDE#2) | |
1F0-1F7 | Контроллер НЖМД #1 (IDE#1) | |
200-207 | 200-20F | Игровой адаптер |
210-217 | Блок расширений | |
238-23F | COM4 | |
278-27F | 278-27F | Параллельный порт LPT2 (LPT3 при наличии MDA) |
2A2-2A3 | часы MSM48321RS | |
2C0-2DF | 2C0-2DF | EGA #2 |
2E0-2E7 | COM4 | |
2E8-2EF | COM4 | |
2F8-2FF | 2F8-2FF | COM2 |
300-31F | Плата прототипа | |
320-32F | Жесткий диск XT | |
338-33F | COM3 | |
370-377 | Контроллер НГМД #2 | |
376-377 | Порты команд IDE#2 | |
378-37F | 378-37F | Параллельный порт LPT1 (LPT2 при наличии MDA) |
380-38F | 380-38F | Синхронный адаптер SDLC/BSC #2 |
3A0-3AF | 3A0-3A9 | Синхронный адаптер BSC#1 |
3B0-3BB | 3B0-3BB | Монохромный адаптер (MDA) |
3B4-3C9 | PS/2 видеосистема | |
3BC-3BF | 3BC-3BF | Параллельный порт LPT1 платы MDA |
3C0-3CF | 3C0-3CF | EGA#1 |
3C0-3DF | 3C0-3DF | VGA |
3D0-3DF | 3D0-3DF | CGA/EGA |
3E0-3E7 | COM3 | |
3E8-3EF | COM3 | |
3F0-3F7 | 3F0-3F7 | Контроллер НГМД #1 |
3F6-3F7 | Порты команд IDE#1 | |
3F8-3FF | 3F8-3FF | COM1 |
Каждой шине назначается своя область адресов ввода, поэтому дешифратор адресов, расположенный на системной плате, при чтении открывает соответствующие буферы данных, так что реально считываться будут данные только с одной шины. При записи в порты данные (и сигнал записи) могут распространяться по всем шинам компьютера. В стандартном распределении адреса 0h-0FFh отведены для устройств системной платы. При наличии (и разрешении работы) периферийных устройств на системной плате чтение по этим адресам не распространяется на шины расширения. Для современных плат со встроенной периферией и несколькими шинами (ISA, PCI) распределением адресов управляет BIOS через регистры конфигурирования чипсета.
12.3. Аппаратные прерывания
Аппаратные прерывания обеспечивают реакцию процессора на события, происходящие асинхронно по отношению к исполняемому программному коду. Прерывания в процессорах х86 подробно рассмотрены в литературе [6, 7]. Здесь напомним, что аппаратные прерывания делятся на маскируемые и немаскируемые.
На немаскируемое прерывание (NMI) процессор реагирует всегда (если обслуживание предыдущего NMI завершено); этому прерыванию соответствует фиксированный вектор 2. Немаскируемые прерывания в PC используются для сигнализации о фатальных аппаратных ошибках. Сигнал на линию NMI приходит от схем контроля паритета памяти, от линий контроля шины ISA (IOCHK) или шины PCI (SERR#). Сигнал NMI блокируется до входа процессора установкой в 1 бита 7 порта 070h, отдельные источники разрешаются и идентифицируются битами порта 061h:
♦ бит 2 R/W — ERP — разрешение контроля ОЗУ и сигнала SERR# шины PCI;
♦ бит 3 R/W — EIC — разрешение контроля шины ISA;
♦ бит 6 R — IOCHK — ошибка контроля на шине ISA (сигнал IOCHK#);
♦ бит 7 R — PCK — ошибка четности ОЗУ или сигнал SERR# на шине PCI.
Реакция процессора на маскируемые прерывания может быть задержана сбросом его внутреннего флага IF (инструкции СLI — запретить прерывания, STI — разрешить). По возникновении события, требующего реакции, адаптер (контроллер) устройства формирует запрос прерывания, который поступает на вход контроллера прерываний. Контроллер прерываний формирует общий запрос маскируемого прерывания для процессора, а когда процессор подтверждает этот запрос, контроллер сообщает процессору вектор прерывания, по которому выбирается программная процедура обработки прерываний. Процедура должна выполнить действия по обслуживанию данного устройства, включая сброс его запроса для обеспечения возможности реакции на следующие события и посылку команды завершения в контроллер прерываний. Вызывая процедуру обработки, процессор автоматически сохраняет в стеке значение всех флагов и сбрасывает флаг IF, что запрещает маскируемые прерывания. При возврате из процедуры (по инструкции IRET) процессор восстанавливает сохраненные флаги, в том числе и установленный IF, что снова разрешает прерывания. Если во время работы обработчика прерываний требуется реакция на иные прерывания (более приоритетные), то в обработчике должна присутствовать инструкция STI. Особенно это касается длинных обработчиков; здесь инструкция STI должна вводиться как можно раньше, сразу после критической (не допускающей прерываний) секции. Следующие прерывания того же или более низкого уровня приоритета контроллер прерываний будет обслуживать только после получения команды завершения прерывания EOI (End Of Interrupt).
Маскируемые прерывания используются для сигнализации о событиях в устройствах. Обработка сигналов запросов прерывания выполняется контроллером прерываний, программно совместимым с 8259A. Контроллер прерываний позволяет маскировать отдельные входы запросов и организовывать систему приоритетов запросов от различных входов. В машинах класса AT применяется каскадное соединение двух контроллеров. Ведущий контроллер 8259А#1 обслуживает запросы 0, 1, 3–7; его выход подключается к входу запроса прерываний процессора. К его входу 2 подключен ведомый контроллер 8259А#2, который обслуживает запросы 8-15. При этом поддерживается вложенность приоритетов — запросы 8-15 со своим рядом убывающих приоритетов вклиниваются между запросами 1 и 3 ведущего контроллера, приоритеты запросов которого также убывают с ростом номера. В XT каскадирование не применялось, и один контроллер 8259А обслуживал все 8 линий запросов.
Контроллер прерываний i8259A подробно описан в литературе [1, 7]; здесь приведем лишь необходимые сведения, в большинстве случаев достаточные для работы. Контроллеры расположены по адресам 20-21h (8259A#1) и A0-A1h (8259A#2), обращаться к ним следует как к однобайтным портам ввода-вывода. После инициализации (процедурой POST и при загрузке ОС) все неиспользуемые входы контроллеров замаскированы (на запросы прерываний реагировать не будут), а их векторы прерываний указывают на «заглушку» — процедуру с единственной инструкцией IRET. Первым делом программа должна загрузить в память свой обработчик и подставить указатель на его начало в соответствующее место таблицы прерываний. Далее следует размаскировать вход, для чего выполняется чтение регистра маски (адрес 21h для 8259А#1, A1h для 8259А#2), обнуление соответствующего бита (см. табл. 12.2) и запись в регистр нового значения маски. При работе с контроллером прерываний от программы требуется лишь управление маской своего запроса (при инициализации программы нужно обнулить маску требуемого запроса) и корректное завершение обработки прерываний. Каждая процедура обработки аппаратного прерывания должна завершаться командой EOI (End Of Interruption), посылаемой контроллеру:
♦ для 1-го контроллера — посылка байта 20h по адресу 20h;
♦ для 2-го контроллера — посылка байта 20h по адресу A0h (EOI для ведомого контроллера), затем посылка байта 20h по адресу 20h (EOI для ведущего контроллера).
Таблица 12.2. Аппаратные прерывания (в порядке убывания приоритета)
Имя (номер¹) | Вектор | Контроллер/маска | Описание |
NMI | 02h | Контроль канала, паритет (в XT — сопроцессор) | |
IRQ0 | 08h | #1/1h | Таймер (канал 0 8253/8254) |
IRQ1 | 09h | #1/2h | Клавиатура |
IRQ2 | 0Ah | #1/4h | XT — резерв, AT — недоступно (подключается каскад IRQ8-IRQ15) |
IRQ8 | 70h | #2/1h | CMOS RTC — часы реального времени |
IRQ9 | 71h | #2/2h | Резерв |
IRQ10 | 72h | #2/4h | Резерв |
IRQ11 | 73h | #2/8h | Резерв |
IRQ12 | 74h | #2/10h | PS/2-Mouse (резерв) |
IRQ 13 | 75h | #2/20h | Математический сопроцессор |
IRQ14 | 76h | #2/40h | HDC — контроллер НЖМД |
IRQ15 | 77h | #2/80h | Резерв |
IRQ3 | 0Bh | #1/4h | COM2, COM4 |
IRQ4 | 0Ch | #1/10h | COM1, COM3 |
IRQ5 | 0Dh | #1/20h | XT — HDC, AT — LPT2, Sound (резерв) |
IRQ6 | 0Eh | #1/40h | FDC — контроллер НГМД |
IRQ7 | 0Fh | #1/80h | LPT1 — принтер |
¹ Запросы прерываний 0, 1, 8 и 13 на шины расширения не выводятся.
Некорректно завершенная процедура не позволит повторно использовать данный или другие запросы прерываний. Если обработчик прерывания удаляется из памяти, предварительно должен быть замаскирован соответствующий ему вход контроллера. Все изменения в таблице прерываний должны выполняться при замаскированных прерываниях, чтобы избежать попытки использования вектора в процессе его модификации (это приведет к «вылету» программы).
На входы контроллеров прерываний поступают запросы от системных устройств (клавиатура, системный таймер, CMOS-таймер, сопроцессор), периферийных контроллеров системной платы и от карт расширения. Традиционно все линии запросов, не занятые перечисленными устройствами, присутствуют на всех слотах шины ISA/EISA. Эти линии обозначаются как IRQx и имеют общепринятое назначение (табл. 12.2). Часть этих линий отдается в распоряжение шины PCI. В таблице отражены и приоритеты прерываний — запросы расположены в порядке их убывания. Номера векторов, соответствующих линиям запросов контроллеров, система приоритетов и некоторые другие параметры задаются программно при инициализации контроллеров. Эти основные настройки остаются традиционными для обеспечения совместимости с программным обеспечением.
Для запросов прерывания с шины PCI используются 4 линии запросов прерывания, которые обозначают как INTR А, В, С, D. Эти линии работают по низкому уровню, что дает возможность их разделения (совместного использования). Линии циклически сдвигаются в слотах и независимо коммутируются на доступные линии IRQx с помощью конфигурационных регистров чипсета. Линии IRQx, используемые шиной PCI, становятся недоступными для шины ISA. «Дележку» линий между шинами, а также управление чувствительностью отдельных линий обеспечивают параметры CMOS Setup, а также система PnP. В параметрах ISA или Legacy подразумевают использование линий IRQx традиционными адаптерами шины ISA (статическое распределение), a PCI/PnP — использование адаптерами шины PCI или адаптерами PnP для шины ISA (динамическое распределение). Общая схема формирования запросов прерываний изображена на рис. 12.1.
Рис. 12.1. Коммутация запросов прерываний
Каждому устройству, для поддержки работы которого требуются прерывания, должен быть назначен свой номер прерывания. Назначения номеров прерываний выполняются с двух сторон: во-первых, адаптер, нуждающийся в прерываниях, должен быть сконфигурирован на использование конкретной линии шины (джамперами или программно). Во-вторых, программное обеспечение, поддерживающее данный адаптер, должно быть проинформировано о номере используемого вектора. В процессе назначения прерываний может участвовать система PnP для шин ISA и PCI, для распределения линий запросов между шинами служат специальные параметры CMOS Setup.
Контроллер прерываний позволяет программировать свои входы на чувствительность к уровню или перепаду сигнала.
♦ Чувствительность к уровню (level sensitive) означает, что контроллер прерываний вырабатывает запрос прерывания процессора по факту обнаружения определенного уровня (на ISA — высокого) на входе DRQx. Если к моменту завершения обработки этого запроса (после записи команды EOI в регистр контроллера прерываний) контроллер снова обнаруживает активный уровень на том же входе DRQx, то он снова сформирует запрос на прерывание процессора.
♦ Чувствительность к перепаду (edge sensitive) означает, что контроллер прерываний вырабатывает запрос прерывания процессора только по факту обнаружения перепада (на ISA — положительного) на входе DRQx. Повторно запрос по этому входу возможен только по следующему такому же перепаду, то есть сигнал предварительно должен вернуться в исходное состояние.
В любом случае сигнал запроса аппаратного прерывания IRQx должен удерживаться генерирующей его схемой, по крайней мере, до цикла подтверждения прерывания процессором. В противном случае источник прерывания корректно идентифицирован не будет, и контроллер сообщит ложный вектор прерывания (spurious interrupt), соответствующий его входу с максимальным номером (IRQ7 для первого контроллера и IRQ15 для второго). Обычно адаптеры строят так, что сигнал запроса сбрасывается при обращении программы обслуживания прерывания к соответствующим регистрам адаптера.
В шине ISA прерывание вырабатывается по положительному перепаду сигнала на линии запроса. Это плохо по двум причинам: такой способ подачи сигнала, во-первых, имеет меньшую помехозащищенность, чем срабатывание по отрицательному перепаду, во-вторых, отрезает путь к нормальному разделению линий запросов (см. ниже), для которого полностью пригоден способ подачи сигнала по низкому уровню. Поскольку традиционный контроллер позволяет задавать чувствительность — уровень (Level) или перепад (Edge) — только для всех входов одновременно, в общем случае разделяемые прерывания на шине ISA вместе с корректной работой системных устройств использоваться не могут.
На современных системных платах функции контроллеров прерываний возлагаются на чипсет, который может иметь и более гибкие возможности управления, чем пара контроллеров 8259A. В операционном режиме всегда сохраняется программная совместимость с 8259A. Процедура инициализации контроллеров может и отличаться от традиционной, но ею занимается тест POST, который «знает» особенности системной платы. В симметричных мультипроцессорных системах аппаратные прерывания работают сложнее, поскольку их могут обслуживать различные процессоры. Для реализаций системы прерываний процессоры Pentium и выше имеют встроенный контроллер прерываний APIC (Advanced Programmable Interruption Controller). Внутренние контроллеры процессоров связаны между собой по шине APIC, к которой подключена и «ответная часть» чипсета, преобразующая запросы аппаратных прерываний в сигналы протокола APIC. В операционном режиме такая связка также совместима с 8259A.
12.3.1. Совместное использование прерываний
Линии запросов прерываний в компьютере, насыщенном дополнительными адаптерами, являются самым дефицитным ресурсом, поэтому возникает желание использовать эти линии совместно, то есть применять разделяемые прерывания между несколькими устройствами (shared interrupts). Обработчики прерываний (программы) от разных устройств, разделяющих одну линию запроса (и следовательно, общий вектор прерывания), должны быть выстроены в цепочку. В процессе обработки прерывания очередной обработчик в цепочке чтением известного ему регистра своего устройства должен определить, не это ли устройство вызвало прерывание. Если это, то обработчик должен выполнить необходимые действия и сбросить сигнал запроса прерывания от своего устройства, после чего передать управление следующему обработчику в цепочке; в противном случае он просто передает управление следующему обработчику.
Разделяемые прерывания для разнотипных устройств в общем случае работоспособными считать нельзя. Во-первых, у каждого устройства факт прерывания программно обнаруживается по-своему, и этот способ знает только драйвер этого устройства. Так что программно для совместного использования прерываний их обработчики должны уметь выстраиваться в цепочки, что на практике выполняется не всегда корректно. Во-вторых, возможны потери прерываний от устройств, требующих быстрой реакции. Это может происходить, если обработчик такого устройства окажется в конце цепочки, а предшествующие ему обработчики окажутся «нерасторопными» (не самым быстрым способом обнаружат, что прерывание — не их). Поведение системы в такой ситуации может меняться в зависимости от порядка загрузки драйверов. Для нескольких однотипных устройств (например, сетевых адаптеров на одном и том же кристалле), пользующихся одним драйвером, разделяемые прерывания работают вполне успешно.
Чтобы прерывания, одновременно возникающие от нескольких устройств, не терялись, контроллер прерываний должен быть чувствительным к уровню, а не к перепаду на входе запроса. В соответствие со схемотехникой логики ТТЛ и КМОП активным уровнем должен быть низкий; выходной формирователь сигнала запросов у адаптеров — с открытым коллектором (ТТЛ) или открытым стоком (КМОП); вход запроса у контроллера должен быть «подтянут» к высокому уровню резистором. Тогда непосредственное соединение этих выходов со входом контроллера («Монтажное И») даст требуемый результат в аппаратном плане, а в программном плане необходимо корректно выстроить обработчики в цепочку.
Поясним, почему надежное разделение прерываний при чувствительности к перепаду на линии запроса невозможно. Если устройство 1 выработает сигнал запроса после того, как его выработает (но еще не снимет) устройство 2, то контроллер обработает только один запрос. Цепочка программных обработчиков окажется ненадежной: если обработчик устройства 1 в этой цепочке будет проверять свое устройство до возникновения прерывания, то прерывание будет потеряно. Поскольку прерывания по своей природе обычно асинхронны, работа этих устройств совместно с поддерживающими программами будет загадочно нестабильной.
Как уже говорилось, в шине ISA прерывание вырабатывается по положительному перепаду сигнала на линии запроса. Стандартный контроллер 8259A позволяет задавать чувствительность — уровень или перепад — только для всех входов одновременно, поэтому разделяемые прерывания на шине ISA неработоспособны. Тем не менее некоторые чипсеты, реализующие контроллеры прерываний, допускают индивидуальное управление чувствительностью каждого входа. Тогда при соответствующих возможностях CMOS Setup, адаптеров и их ПО разделяемые прерывания технически реализуемы.
Для шины PCI, казалось бы, проблема разделения прерываний решена — здесь активным уровнем запроса является низкий, так что, запрограммировав входы контроллера на чувствительность к уровню, создается аппаратная база совместного использования. Однако на практике разделяемые прерывания работают не всегда, и иногда приходится подбирать положение карт расширения в слотах PCI, при которых устройства не конфликтуют друг с другом по прерываниям. Виной конфликтов могут быть как сами карты расширения, так и их драйверы, неспособные выстраиваться в корректную цепочку.
Если карта PCI использует одну линию запроса прерываний, то этой линией по умолчанию является INTR А. Если все четыре карты PCI используют по одной линии запроса, то, как это видно на рис. 12.1, каждая линия занимается монопольно. Однако если сложная карта нуждается в большем числе линий запроса, то ей придется разделять линии с соседними картами. На современных системных платах часто устанавливают более четырех слотов PCI, при этом, естественно, «угроза» совместного использования линий запросов «нависает» и над картами с одной линией запроса. Порт AGP в плане прерываний следует рассматривать наравне со слотами PCI.
Проявления конфликтов и ошибок назначения прерываний могут быть разнообразными. Сетевая карта при ошибке в прерываниях не сможет принимать кадры из сети (при этом она может их успешно посылать). У устройств хранения доступ к данным будет поразительно медленным (иногда можно минутами ожидать, например, появления информации о файлах и каталогах) или вообще невозможным. Звуковые карты будут молчать или «заикаться», на видеопроигрывателях изображение будет дергаться и так далее. Конфликты могут приводить и к внезапным перезагрузкам компьютера, например по приходу кадра из сети или сигналу от модема.
12.4. Прямой доступ к памяти — DMA
Прямой доступ к памяти (Direct Memory Access, DMA) позволяет выполнять пересылку данных между регистрами устройств и памятью, минуя центральный процессор. Для устройств, использующих DMA, различают два типа доступа.
♦ Пассивный доступ, он же Slave DMA, — устройство пользуется общим контроллером DMA, расположенным на системной плате.
♦ Активный доступ, он же Bus Master DMA, — устройство само является ведущим на своей шине и способно генерировать обращение к памяти (как правило, системной). Реализация активного DMA зависит от типа шины расширения, к которой подключается устройство (см. главу 6). Примером устройств с активным DMA являются контроллеры ATA, расположенные на современных системных платах.
Процессор при обмене по DMA занят только инициализацией контроллера, которая сводится к записи в его регистры нескольких байт, задающих начальный адрес и размер пересылаемого блока памяти, направление и режим обмена. В самом обмене данных занят только контроллер DMA, память, к которой он обращается, и связующие их шины. Во время операций DMA процессор может продолжать работу, если выбранный режим обмена не занимает всей пропускной способности шин, используемых процессором в данный момент (шины памяти, шины PCI, через которые подключается ISA в современных компьютерах). Контроллер DMA можно считать простейшим сопроцессором ввода-вывода, разгружающим центральный процессор от рутинных операций обмена.
Обмен по DMA не всегда дает выигрыш в скорости обмена, в ряде случаев быстрее работает программированный ввод-вывод (PIO). Однако PIO занимает процессор полностью, а во время DMA процессор может заниматься полезной работой. Поскольку для инициализации контроллера DMA требуется выполнение ряда инструкций ввода-вывода, передача коротких блоков по каналу DMA нецелесообразна. Пассивный DMA реализуется стандартизованным контроллером, который первоначально был ориентирован на шину ISA. Для интерфейса ПУ каждый канал DMA представляется парой сигналов: запрос обмена — DRQx и подтверждение обмена — DACKx#. В PC/AT доступны 7 каналов DMA — четыре 8-битных (номера 0–3) и три 16-битных (5–7), — подключенные к первичному и вторичному контроллерам соответственно. Канал 4 используется для каскадирования (соединения контроллеров). В PC/XT были только три 8-битных канала, канал 0 использовался для регенерации памяти. Контроллеры DMA программно совместимы с системами i8237, применяемыми в первых моделях PC/XT и AT. Стандартные каналы и адреса регистров приведены в табл. 12.3.
Таблица 12.3. Стандартные каналы прямого доступа к памяти
Номер канала DMA# | 0¹ | 1 | 2 | 3 | 4² | 5 | 6 | 7 | |
Стандартное назначение | XT | MRFR | - | FDD | HDD | Отсутствуют | |||
AT | - | - | FDD | - | Каскад | - | - | - | |
Разрядность, байт | 1 | 2 с четного адреса | |||||||
Макс, размер блока | 64 Кбайта | 128 Кбайт, четный | |||||||
Граница блока | Кратна 1000h | Кратна 2000h | |||||||
Регистр страниц | 8 бит A16-A23 | 7 бит A17-A23 | |||||||
Адреса регистров: | |||||||||
— страниц | 087 | 083 | 081 | 082 | 08F | 08В | 089 | 087 | |
— адреса | 000 | 002 | 004 | 006 | 0C0 | 0C4 | 0C8 | 0CE | |
— счетчика | 001 | 003 | 005 | 007 | 0C2 | 0C6 | 0СА | 0СЕ |
¹ Канал 0 в XT использовался для регенерации памяти (MRFR).
² Канал 4 доступен только в PC/2 MCA.
16-битные каналы DMA 5–7 могут быть использованы интеллектуальными устройствами для прямого управления шиной ISA (bus mastering), при этом контроллер DMA фактически лишь играет роль арбитра шины.
Устройства, использующие стандартные каналы DMA, могут располагаться лишь в слотах ISA/EISA или на системной плате (контроллер НГМД, LPT-порт в режиме ECP или Fast Centronics, аудиокодек). Если эти устройства системной платы используют каналы DMA, то данные каналы становятся недоступными для абонентов шины ISA.
На время переходного периода, связанного с «изживанием» шины ISA, потребовалась возможность эмуляции каналов DMA для устройств шины PCI. Существует два механизма эмуляции каналов DMA: PC/PCI и DDMA. Механизм PC/PCI (см. п. 6.2.7) был разработан фирмой Intel для обеспечения возможности использования слотов ISA блокнотными ПК, подключаемыми к док-станции по шине PCI. Альтернативное решение — механизм DDMA (Distributed DMA — распределенный DMA) позволяет «расчленить» стандартный контроллер и отдельные его каналы эмулировать средствами карт PCI. Оба этих механизма реализуемы только как часть моста между первичной шиной PCI и шиной ISA, поэтому их поддержка может обеспечиваться (или не обеспечиваться) только на системной плате и разрешаться в CMOS Setup.
12.4.1. Контроллер прямого доступа 8237A
Микросхема 8237A, применявшаяся в PC вплоть до первых моделей AT, представляет собой четырехканальный контроллер прямого доступа к памяти, допускающий каскадирование. Вторичный контроллер (8237#2) каскадно соединен с первичным, при этом теряется возможность использования одного канала вторичного контроллера. Контроллер 8237А имеет 16-разрядные регистры адреса и счетчики, что обеспечивает возможность программирования передачи блока данных размером до 64 Кбайт или слов. Назначение регистров контроллеров DMA, применительно к их адресам в пространстве ввода-вывода компьютера, приведено в табл. 12.4. Контроллер допускает довольно гибкое конфигурирование. Корректное оперативное управление отдельными каналами не затрагивает общих настроек. Общее конфигурирование контроллеров (запись в регистры 008 и 0D0) выполняет BIOS при инициализации во время теста POST; в XT тогда же программируется и канал 0, применяемый для регенерации памяти. Для использования каналов устройствами шины ISA запись в регистры 008 и 0D0 не рекомендуется. Обмен с регистрами контроллера выполняется только однобайтными операциями ввода-вывода. Для загрузки 16-битных значений задействуется триггер младшего/старшего байта. По сбросу контроллера или записи любого байта по адресу 00Ch (0D8h для второго контроллера) этот триггер сбрасывается, и контроллер готовится к приему младшего байта. После приема этого байта триггер меняет состояние, и контроллер воспринимает старший байт, после которого триггер опять переключается.
Таблица 12.4. Регистры контроллера DMA 8237A
8237#1 | 8237#2 | R/W, Назначение регистров |
000, 002, 004, 006 | 0C0, 0C4, 0C8, 0CC | W — регистры начального адреса для каналов 0–3 (8237#1) и 4–7 (8237#2). R — регистры текущего адреса тех же каналов |
001, 003, 005, 007 | 0С2, 0C6, 0CA, 0СЕ | W — начальное значение счетчика передач для каналов 0–3 (8237#1) и 4–7 (8237#2). R — текущее значение счетчика передач тех же каналов |
008 | 0D0 | W, Command Register — конфигуратор контроллера . Бит 7: 1 — активный уровень (DACK# — высокий, 0 — низкий); бит 6: 1 — активный уровень (DRQ — низкий, 0 — высокий); бит 5: 1 — режим расширенной записи (должен быть 0); бит 4: 0 — фиксированный приоритет, 1 — циклический; бит 3: 1 — укороченный цикл обмена (должен быть 0); бит 2: 1 — запрет работы контроллера; бит 1: 1 — фиксация адреса 0 канала (должен быть 0); бит 0: 1 — передача память-память (в PC не используется, должен быть 0) |
008 | 0D0 | R, Status Register — состояние каналов . Биты 4–7: запросы каналов 0–3; биты 0–3: завершение цикла каналов 0-3 |
009 | 0D2 | W, Request Register — регистр программных запросов . Биты 7–3 не используются; бит 2: 1 — установка, 0 — сброс бита запроса; биты 1–0: выбор канала (00 — 0; 01 — 1; 10 — 2; 11 — 3) |
00А | 0D4 | W, Single Mask Bit Register — управление масками. Биты 7–3 не используются; бит 2:1 — установка, 0 — сброс бита маски; биты 1–0: выбор канала (00 — 0; 01 — 1; 10 — 2; 11 — 3) |
00B | 0D6 | W, Mode Register — режимы работы каналов . Биты 7–6: режим передачи (00 — по запросу, 01 — одиночный, 10 — блочный, 11 — каскадирование); бит 5: 0 — инкремент, 1 — декремент адреса; бит 4: 1 — разрешение автоматической реинициализации |
00B | 0D6 | Биты 3–2; тип передачи (00 — холостой, проверка канала, 01 — запись в память, 10 — чтение памяти, 11 — недопустимо); биты 1–0: выбор канала (00 — 0; 01 — 1; 10 — 2; 11 — 3) |
00C | 0D8 | W, Clear Byte Pointer Flip/Flop — сброс триггера младшего/старшего байта |
00D | 0DA | W, Master Clear — общий сброс 8237 (вывод любого байта в регистр вызывает сброс) |
00E | 0DC | W, Clear Mask Register — общий сброс масок всех каналов (вывод любого байта в регистр вызывает сброс) |
00F | 0DE | W, All Mask Register Bits — регистр масок всех каналов . Биты 0–3: маски каналов 0–3 (0 — канал разрешен, 1 — замаскирован); биты 4–7 не используются |
Программирование контроллера для каждого канала определяет начальный адрес, направление его модификации (инкремент/декремент), количество пересылаемых байт (слов), режим работы канала. Регистры адреса контроллеров 8237A — 16-разрядные, и для расширения разрядности адреса для каждого канала имеются специальные регистры страниц (DMA page register), внешние по отношению к контроллерам 8237A. В отличие от адресных регистров контроллера 8237A регистры страниц при выполнении циклов DMA не модифицируются — в них по команде процессора до начала обмена по каналу загружается требуемое значение. В PC/AT регистры страниц хранят биты A[23:16] для 8-битных каналов и A[23:17] — для 16-битных. В PC/XT регистры страниц хранили только 4 бита A[19:16]. Контроллер 16-битных каналов подключен к шине адреса со смещением на 1 бит, так что линией А0 он не управляет. При передаче по 16-битным каналам всегда А0=0 (передачи слов по четным адресам). Счетчики циклов каналов — 16-разрядные, что позволяет передавать блоки до 64 К байт (для 8-битных каналов) или слов (для 16-битных каналов). При инициализации в счетчик загружается число, на единицу меньшее требуемого числа циклов, так что FFFF соответствует 65 534 передачам (216). В последнем цикле передачи (когда счетчик отсчитает требуемое количество циклов) контроллер вырабатывает сигнал завершения TC, общий для всех каналов. Этот сигнал устройство может использовать для выработки сигнала прерывания, а программа может определить, какой канал «отстрелялся», прочитав регистр состояния каналов в контроллере DMA. В зависимости от выбранного режима по окончании счета контроллер либо остановит работу данного канала, либо выполнит автоматическую реинициализацию (автозагрузку) — восстановит прежде записанные значения регистра адреса и счетчика циклов и будет снова готов к пересылке такого же блока данных.
ВНИМАНИЕ
При достижении регистром-счетчиком адреса значения FFFFh следующее его значение будет 0000h, а внешний регистр адреса страницы, естественно, останется неизменным. Таким образом, если блок начинается не с границы 64 Кбайт страницы памяти, возможно его «сворачивание» в кольцо. Но если для процессоров 80x86 в реальном режиме сегменты, также «сворачиваемые» в кольца, могут начинаться с адреса любого 16-байтного параграфа (границы кратны 10h), то при прямом доступе эти границы кратны 10000h. Этот эффект обязательно необходимо учитывать при программировании прямого доступа — блок, пересекающий данную границу, должен пересылаться за два сеанса циклов DMA, между которыми канал (включая и регистр страниц) должен быть реинициализирован. Эффект «сворачивания» сегментов в 16-битных каналах аналогичен, только для каналов. 5–7 эти «кольца» имеют размер 64 Кбайт слов и границы, кратные 20000h.
Разрядность передаваемых данных по каналу DMA должна соответствовать типу канала — 16-битный канал всегда пересылает данные словами, и расщепление их на одиночные байты невозможно.
Каждый канал может работать в одном из трех логических режимов.
♦ Режим одиночной передачи (single transfer mode) — получив подтверждение DACKx#, устройство сразу снимает сигнал запроса DRQx, а контроллер DMA организует один цикл передачи. Счетчик адреса в контроллере модифицируется, счетчик циклов декрементируется.
♦ Режим блочной передачи (block transfer mode) — получив подтверждение DACKx#, устройство сразу снимает сигнал запроса DRQx, а контроллер DMA организует последовательность циклов передачи до обнуления счетчика циклов. Если разрешена автозагрузка канала, то для пересылки следующего блока требуется повторная подача DRQx. На время передачи всего блока контроллер монопольно захватывает шину, при этом не выполняется регенерация памяти.
♦ Режим передачи по запросу (demand transfer mode) — получив подтверждение DACKx#, устройство не снимает сигнал запроса DRQx до тех пор, пока у него есть потребность в передаче. При наличии этого сигнала контроллер DMA организует последовательность циклов передачи вплоть до обнуления счетчика циклов. Если сигнал запроса снят до обнуления счетчика, контроллер DMA отдает управление шине, а при последующем появлении этого запроса продолжит обмен с того места, на котором остановился.
ВНИМАНИЕ
Используя DMA в режимах, отличных от одиночного, следует соблюдать осторожность, чтобы длительность непрерывной передачи не превышала 15 мкс.
Стандартный контроллер DMA на шине ISA с частотой 8 МГц работает на половинной частоте и требует для одиночной передачи не менее пяти своих тактов. Длительность одиночного цикла составляет 1,125 мкс. В блочных передачах пропускная способность DMA достигает 1 Мбайт/с для 8-битных каналов и 2 Мбайт/с для 16-битных (время цикла составляет 1 мкс). На современных компьютерах контроллер DMA реализуется чипсетом системной платы; при сохранении программной совместимости с 8237А он может работать на шине гораздо быстрее. Количество тактов шины на один цикл может программироваться опциями BIOS Setup.
12.5. Процессоры х86
Все программы в IBM PC-совместимом компьютере исполняются центральным процессором, принадлежащим к семейству х86. Любое устройство для процессора представляет собой лишь набор регистров (ячеек), отображенных в пространство памяти и (или) ввода-вывода, и необязательно источник аппаратных прерываний. Современные процессоры х86, работающие в защищенном режиме, имеют довольно сложные механизмы виртуализации памяти, ввода-вывода и прерываний, из-за которых приходится различать физические и логические пространства (адреса памяти и ввода-вывода) и события (операции ввода-вывода, прерывания). Физический адрес ячейки памяти или порта ввода- вывода — это адрес, формируемый для обращения к данной ячейке на физических шинах компьютера (системной шине процессора, шине PCI, ISA). Логический адрес — это тот адрес, который формируется исполняемой программой (по замыслу программиста) для доступа к требуемой ячейке. Физическая операция ввода-вывода или обращения к памяти — это процесс (шинный цикл), во время которого генерируются электрические сигналы, обеспечивающие доступ к данной ячейке (порту). Логическая операция — это исполнение программной инструкции (команды) обращения к интересующей ячейке. Логическая операция не всегда порождает ожидаемую физическую операцию: при определенных условиях она может блокироваться средствами защиты процессора, вызывая даже принудительное завершение программы, или же эмулироваться, создавая иллюзию физического исполнения.
Безопасность в защищенном режиме базируется на 4-уровневой системе привилегий. В большинстве современных ОС ради упрощения и экономии процессорного времени используются только два крайних уровня — нулевой (supervisor), с неограниченными возможностями, и третий (user), с самыми жесткими ограничениями. Смена уровней привилегий при исполнении программы занимает много тактов процессора, но это вынужденная плата за реализацию защиты, без которой устойчивую ОС не построить. Более подробно механизмы защиты и виртуализации памяти, ввода-вывода и прерываний в процессорах х86 описаны в литературе [6, 7], здесь же изложены лишь некоторые прикладные аспекты их работы.
12.5.1. Возможности адресации памяти процессорами различных поколений
Сложность обращения к памяти в PC обусловлена свойствами процессоров х86 разных поколений и требованием обратной совместимости новых процессоров и компьютеров со старым ПО.
Процессорам 8086/88 было доступно адресное пространство 1 Мбайт с диапазоном адресов 0-FFFFFh, причем физический 20-битный адрес вычислялся с помощью двух 16-битных компонентов по формуле Addr = Seg×16 + Offset, где Seg — содержимое сегментного регистра (CS, DS, SS или ES), a Offset — исполнительный адрес, формируемый из одного или нескольких слагаемых в соответствии с выбранным режимом адресации. Эта сегментная модель адресации позволяет программам оперировать с непрерывными блоками памяти (сегментами) размером не более 64 Кбайт. Для манипуляций с памятью большего размера требовалось переключение сегментов с помощью специальных инструкций процессора, что усложняло программирование. Заметим, что при Seg = FFFFh и Offset = FFFFh данная формула дает адрес 10FFEFh, но ввиду 20-битного ограничения на шину адреса эта комбинация в физической памяти указывает на 0FFEFh. Таким образом, адресное пространство как бы сворачивается в кольцо с небольшим «нахлестом».
В процессоре 80286 шина физического адреса была расширена до 24 бит, и введен новый режим работы — защищенный (Protected Mode), в котором программа может обращаться к 16-мегабайтному пространству физической памяти через логическое пространство виртуальной памяти. Здесь виртуальная память строилась на основе той же сегментной модели памяти с 16-разрядными регистрами. Физический адрес формировался суммированием 16-разрядного исполнительного адреса (смещения внутри сегмента) с 24-разрядным базовым адресом сегмента.
Кроме защищенного режима, в процессоре 80286 имеется и реальный режим, в котором процессор ведет себя почти так же, как и 8086 (но более быстрый). Здесь физический адрес вычисляется так же, как и в 8086/88, но из-за ошибки разработчиков та самая единица в бите A20, которая отбрасывалась в процессорах 8086/88, теперь попадает на шину адреса, и в результате максимально доступный физический адрес в реальном режиме достиг 10FFEFh. Для обеспечения полной совместимости с процессором 8086/88 в схему PC ввели вентиль линии A20 шины адреса — GateA20, который либо пропускает сигнал от процессора, либо принудительно обнуляет линию A20 системной шины адреса. Этот вентиль должен быть открыт при работе в защищенном режиме, а также когда в реальном режиме нужны дополнительные (64 К-16) байт памяти. Вентиль управляется через контроллер клавиатуры (см. п. 8.1.2) или иным специфическим способом.
В 32-разрядных процессорах, начиная с 80386, сохранена та же идея обращения к памяти с участием сегментных регистров (16-разрядных), но регистры процессора, участвующие в формировании адреса, позволяют адресовать уже 2³² = 4 Гбайт памяти в каждом сегменте. Базовый адрес сегмента берется из специальных структур данных — дескрипторов сегментов. Кроме базового адреса в дескрипторе описывается его лимит (длина), назначение (код или данные), возможность записи и чтения, а также уровень привилегий программы, позволяющий обращаться к данному сегменту. Дескрипторы предварительно программно формируются в памяти, где их наборы хранятся в виде таблиц дескрипторов. Процессор имеет средства защиты памяти, контролирующие использование сегментов. Программа может обращаться лишь к тем сегментам памяти, описание которых имеется в доступных дескрипторах. Виртуальное адресное пространство, доступное программе, имеет объем до (16 К-2) сегментов (число возможных дескрипторов), каждый из которых может иметь размер до 4 Гбайт. Дескриптор выбирается с помощью селектора, загружаемого в сегментный регистр (CS, DS, SS, ES, FS или GS). Однако это виртуальное адресное пространство отображается блоком сегментации в логическое адресное пространство с опять-таки 32-разрядным линейным адресом, то есть объемом 4 Гбайт. По замыслу разработчиков процессора, это отображение с подкачкой требуемых сегментов с диска и выгрузкой неиспользуемых должно выполняться диспетчером виртуальной памяти операционной системы. Практически такая виртуализация применялась на процессорах 80286 (с 16-разрядными регистрами), поскольку иных механизмов не существовало.
Для виртуализации памяти (и защиты) в 32-разрядных процессорах применяется иной механизм, основанный на блоке страничной переадресации — принципиальной новинке 32-разрядных процессоров х86. В его задачу входит отображение 32-разрядного линейного адреса (продукта блока сегментации) на 32- или 36-разрядный физический адрес, формируемый на системной шине процессора при его обращениях к памяти. В отличие от блока сегментации, оперирующего блоками разного размера (сегментами), блок страничной переадресации оперирует страницами одинакового размера. Переадресация выполняется на основе таблиц страниц, где для каждой страницы логической памяти имеется свой описатель. В этом описателе имеется признак присутствия страницы в физической памяти, и для присутствующих страниц указывается базовый адрес физического отображения. Кроме того, имеются биты, управляющие доступом к странице по чтению и записи с различных уровней привилегий, возможностью ее кэширования, и некоторые служебные биты. При обращении программы к отсутствующей странице процессор вырабатывает исключение, обработчик которого занимается подкачкой нужной страницы из внешней памяти (с диска) в ОЗУ. Этот обработчик и реализует виртуальную память с подкачкой страниц по запросу (Demand-Paged Virtual Memory), которая в настоящее время обычно и подразумевается под виртуальной памятью. При недостатке свободного места в физической памяти обработчик выполняет и замещение страниц, по его мнению, наименее нужных, выгружая их на диск. Создав несколько наборов описателей страниц, можно получить несколько виртуальных адресных пространств, каждое из которых имеет размер до 4 Гбайт, причем страницы разных пространств могут быть полностью изолированы друг от друга, а могут и частично пересекаться. В многозадачной ОС каждая задача (виртуальная машина) имеет собственное (как ей представляется) адресное пространство.
Первоначально блок страничной переадресации работал со страницами размером 4 Кбайт. В дополнение к этому базовому механизму в процессор Pentium ввели возможность работы и со страницами размером 4 Мбайт (режим PSE). В ряде процессоров P6 разрядность физического адреса увеличена до 36 бит, и все процессоры P6 имеют возможность включение режима переадресации РАЕ, позволяющего отображать страницы размером 4 Кбайт и 2 Мбайт с расширением физического адреса. С процессорами Pentium III появился режим преобразования PSE-36, в котором блок оперирует 4-Мбайтными страницами в 36-битном физическом пространстве и сохраняется возможность работы со стандартными 4-Кбайтными страницами базового режима. Это позволяет довольно эффективно управляться с современными объемами физической памяти компьютера.
В стандартном реальном режиме 32-разрядные процессоры работают с памятью так же, как и 80286, с возможностью адресации в диапазоне 0-10FFEFh, причем вентиль Gate A20 ввели уже в сам процессор. Физический адрес вычисляется с участием сегментных регистров, размер непрерывного сегмента — 64 Кбайт. По умолчанию в реальном режиме адреса формируются с использованием только младших 16 бит 32-разрядных регистров, правда, для каждой инструкции можно с помощью префиксов изменить разрядность адресных компонентов на 32 бита. Однако и при этом невозможно пересечь границу 64-Кбайтного сегмента — сработает исключение защиты. В стандартном реальном режиме блок страничной переадресации не работает, и физический адрес совпадает с линейным. С помощью временного переключения в защищенный режим можно настроить таблицы страниц, разрешить преобразование и далее в реальном режиме задействовать страничное преобразование. Этот трюк используется менеджерами памяти типа EMM386 для работы со свободными блоками UMA.
Есть и еще один режим, неофициальный, но тоже работающий на всех 32-разрядных процессорах х86, — «нереальный» (unreal), он же «большой реальный» (big real). Он позволяет процессору в реальном режиме обращаться к данным, расположенным в любом месте 4-Гбайтного пространства линейных (и физических) адресов. Этот режим базируется на логике блока сегментации, которая при вычислении линейного адреса во время обращений к памяти пользуется скрытыми программно-недоступными регистрами дескрипторов сегментов. Из этих регистров берется базовый адрес, из них же берется и лимит, который используется схемой защиты. В этих регистрах кэшируются дескрипторы сегментов, загружаемые из памяти во время исполнения инструкций, переопределяющих значения сегментных регистров (CS, DS, SS, ES, FS и GS) в защищенном режиме. По аппаратному сбросу в эти скрытые регистры заносятся «неинтересные» параметры стандартного реального режима, с лимитом 64 Кбайт. В реальном режиме при переопределении сегментных регистров значение базового адреса берется как 16-кратное значение, загружаемое в соответствующий сегментный регистр, а лимит устанавливается в 64 Кбайт. Тем не менее, если в защищенном режиме в сегментный регистр загрузить селектор дескриптора, в котором описан сегмент размером 4 Гбайт с нулевым базовым адресом и возможностью полного доступа на любом уровне привилегий, переключиться в реальный режим и не трогать этот сегментный регистр, то далее процессор будет иметь доступ ко всему этому сегменту в данной модификации реального режима. Однако такая «благодать» распространяется только лишь на доступ к данным через сегментные регистры FS и GS, которые используются в инструкциях обращений к памяти, снабженных префиксами замены сегмента. Эти сегментные регистры появились только с 32-разрядными процессорами, и никакие традиционные сервисы BIOS (и DOS) их не затрагивают. Остальные сегментные регистры настолько часто используются, что «время жизни» описания большого сегмента в их кэширующих регистрах будет слишком коротким. Программный код, увы, исполняется только из сегмента, которым командует CS, поэтому для него остается лишь первый мегабайт с 64-Кбайтными сегментами. Так что большие программные модули приходится подгружать в эту область по мере надобности, но это можно выполнять довольно быстро пересылками данных из любого места «большого сегмента». Большой реальный режим широко используется менеджерами памяти, а также игровыми DOS-программами, всецело захватывающими ресурсы компьютера.
Итак, самые широкие возможности адресации имеются в защищенном 32-разрядном режиме, наиболее естественном для современных процессоров. В этом режиме может использоваться как плоская, так и сегментная модели памяти. Под плоской (flat) понимается модель, в которой все сегментные регистры указывают на один и тот же сегмент памяти (как правило, начинающийся с нулевого адреса), и его лимит может достигать 4 Гбайт, что позволяет адресовать этот немалый (даже по нынешним меркам) объем памяти без манипуляций сегментными регистрами. Однако при этом теряются все возможности виртуализации памяти на основе сегментов, а также отсутствует сегментная защита. В сегментной модели памяти сегментные регистры кода, стека и данных настраиваются на разные, возможно и не пересекающиеся сегменты. Здесь имеются все возможности сегментной защиты и сегментной виртуализации памяти. Поскольку современным приложениям пока достаточно 4 Гбайт памяти (надолго ли?), сегментную модель ради упрощения диспетчера памяти стараются не использовать. Защита памяти имеется и на уровне страниц, правда, не такая развитая и надежная, как сегментная.
12.5.2. Проблемы страничной переадресации
В реальном режиме (при отключенной страничной переадресации) логический адрес, формируемый прикладной программой, совпадает с физическим адресом, фигурирующим на шинах расширения. Тут все просто, правда, в стандартном (а не большом) реальном режиме доступен только первый мегабайт адресов (только устройства в области UMA).
В защищенном режиме в принципе доступно все физическое адресное пространство, но появляются проблемы, связанные с отображением логических адресов на физические. Отображением (поддержкой таблиц переадресации) ведает ОС, приложения могут только узнать карту отображений (получить список физических адресов страниц для какой-то области своей виртуальной памяти). Какие-то области могут в данный момент и не присутствовать в ОЗУ (они могут быть выгруженными на диск). У драйверов устройств возможностей больше — они могут запросить блок памяти с последовательными физическими страницами и потребовать фиксации определенных страниц (запретить их выгрузку из ОЗУ).
При организации прямого доступа к памяти, как по стандартным каналам DMA, так и используя ведущие устройства шин ISA и PCI, возникает проблема пересечения границ страниц. Если приложение хочет выполнить обмен по DMA с областью доступной ей памяти непосредственно, то оно должно запросить у ОС физический адрес, которому соответствует логический адрес предполагаемого буфера обмена. Именно этот физический адрес должен задаваться устройству, выполняющему DMA, при инициализации сеанса обмена (указании начального адреса, длины блока и запуске канала). В каждом сеансе обмена не должна пересекаться граница страницы, которой оперирует блок страничной переадресации, поскольку следующая логическая страница может иметь физическое отображение в произвольном (относительно предыдущей страницы) месте. Чаще всего ОС оперирует страницами по 4 Кбайт, при этом пересылка больших блоков данных ведется «короткими перебежками», между которыми процессор должен выполнять повторную инициализацию DMA. Эта проблема решается усложнением контроллеров DMA — применением «разбросанной записи» в память (scatter write) и «собирающего чтения» памяти (gather read). Контроллеру DMA задается список описателей блоков (начальный адрес и длина). Отработав очередной блок памяти, контроллер переходит к следующему, и так до конца списка. Такие возможности имеет, например, стандартный контроллер PCI IDE (см. п. 9.2.1). Стандартный контроллер DMA имеет и другую «страничную проблему», связанную с реализацией регистров страниц (см. п. 12.4).
Проблема пересечения границ может решаться и иначе, без усложнения контроллера DMA. Для этого в памяти резервируется буфер значительного размера, отображенный на непрерывную область физической памяти, и обмен данными физическое устройство выполняет только с этим буфером. Однако такой буфер рядовое приложение создать не может; он может быть организован лишь драйвером устройства. Приложения могут только получать указатели на этот буфер и обмениваться с ним данными. Таким образом, по пути от приложения к устройству появляется дополнительная «перевалочная база» (буфер драйвера) и дополнительная пересылка данных, что приводит к дополнительным затратам времени.
12.5.3. Инструкции ввода-вывода
Для обращения программы к пространству ввода-вывода предназначены всего четыре инструкции процессора: IN (ввод из порта в регистр процессора), OUT (вывод в порт из регистра процессора), INS (ввод из порта в элемент строки памяти) и OUTS (вывод элемента из строки памяти в порт). Последние две инструкции, появившиеся с процессором 80286, могут использоваться с префиксом повтора REP, что обеспечивает быструю пересылку блоков данных между портом и памятью. Обмен данными с портами, при котором применяют строковые инструкции ввода-вывода, получил название PIO (Programmed Input/Output — программированный ввод-вывод). Скорость такого обмена превышает скорость стандартного канала прямого доступа (DMA), правда, DMA в отличие от PIO почти не занимает процессорного времени.
Разрядность слова, передаваемого за одну инструкцию ввода-вывода, может составлять 8, 16 или 32 бита. В зависимости от «выровненности» адреса по границе слова и разрядности данных используемой шины это слово может передаваться за один или несколько циклов шины с указанием соответствующего нарастающего адреса в каждом цикле обращения к памяти. Инструкции ввода-вывода порождают шинные циклы обмена, в которых вырабатываются сигналы чтения порта/записи в порт. На шине ISA это сигналы IORD# и IOWR# соответственно; они и отличают пространство ввода-вывода от пространства памяти, где соответствующие операции чтения и записи вырабатывают сигналы MEMRD# и MEMWR#. На шине PCI разделение памяти и пространства ввода-вывода происходит иначе — здесь тип операции кодируется четырехбайтной командой, в зависимости от типа инструкции, выполняемой процессором.
Во избежание недоразумений и для экономии шинных циклов рекомендуется выравнивать адреса 16-битных портов по границе слова, а 32-битных — по границе двойного слова. Обращения по выровненным адресам выполняется за один цикл системной шины. Обращение по невыровненным адресам выполняется за несколько циклов, причем однозначная последовательность адресов обращений (которая зависит от модели процессора) не гарантируется. Так, например, одна инструкция вывода слова по нечетному адресу приведет к генерации двух смежных шинных циклов записи. При программировании обращений следует учитывать специфику устройств ввода-вывода. Если, например, устройство допускает только 16-разрядные обращения, то старший байт его регистров будет доступен лишь при вводе-выводе слова по четному адресу.
Некоторую сумятицу в стройную систему адресации вводят регистры ATА. Здесь регистр 1F0 (1 канал) является 16-битным регистром данных, но в то же время есть и совершенно независимый от него 8-битный регистр 1F1. В Serial ATA эта тема развита — здесь имеются еще четыре 16-битных регистра с адресами (относительно базового адреса блока командных регистров) 2, 3, 4 и 5, которые раньше были 8-битными.
В реальном режиме процессора программе доступно все пространство адресов ввода- вывода. В защищенном режиме 32-разрядных процессоров (частным случаем которого является и виртуальный режим V86) имеется возможность программного ограничения доступного пространства ввода-вывода, определяя его максимальный размер (начиная с нулевого адреса и в пределах 64 К), а внутри разрешенной области доступ может быть разрешен или запрещен для каждого конкретного адреса. Размер области и карта разрешенных портов (IO Permission Bitmap) задается операционной системой в дескрипторе сегмента состояния задачи (TSS). При обращении по неразрешенному адресу вырабатывается исключение процессора, а поведение его обработчика определяется операционной системой. Возможно снятие задачи-нарушителя (знаменитое сообщение «приложение… выполнило недопустимую операцию и будет закрыто»). Возможен и другой вариант, когда по обращению к порту монитор операционной системы выполняет некоторые действия, создавая для программы иллюзию реальной операции ввода-вывода. Таким образом виртуальная машина по операциям ввода-вывода может общаться с виртуальными устройствами. Заметим, что ОС Windows 9x не особо заботится о виртуализации и защите ввода-вывода; здесь, например, из DOS-окна можно обращаться к любым портам, даже к портам устройств, занятых операционной системой.
12.5.4. Прерывания
В процессорах х86 используются аппаратные прерывания, программные прерывания и исключения. Аппаратные прерывания были описаны выше; кроме того, к ним относится и специфичное (и неиспользуемое прикладными программами) прерывание SMI для входа в режим системного управления (SMM). Программные прерывания по сути прерываниями и не являются — это лишь короткая форма дальнего вызова ограниченного количества процедур, выполняемая инструкцией Int N (N=0-255). Программные прерывания, в частности, используются для вызовов сервисов BIOS и DOS. Исключения генерируются процессором и сопроцессором, когда при исполнении инструкций возникают особые условия (например, деление на ноль или срабатывание защиты). Исключения занимают векторы прерываний 0-31, которые частично пересекаются с векторами аппаратных прерываний ведущего контроллера и NMI, а также с векторами сервисов BIOS. В процессорах 8086/88 исключения назывались внутренними прерываниями, их было совсем мало. По мере «взросления» процессоров добавлялись новые исключения; исключениями особо богаты современные процессоры при работе в защищенном режиме. На исключениях строится защита и виртуальная память в многозадачных ОС защищенного режима.
В реальном режиме прерывания работают довольно просто, и их обработчики могут находиться в любом месте физически адресуемой памяти (ОЗУ или ПЗУ). В таблице прерываний, начинающейся с нулевого адреса, каждый вектор прерываний представляется дальним указателем на процедуру обработки (16-байтные смещение и сегмент). Внедрение собственных обработчиков прерываний представляет собой несложную задачу, если прерывание используется монопольно одним устройством и соответствующим ему единственным модулем ПО. В реальном режиме любая программа может управлять флагом разрешения аппаратных прерываний; некорректное управление флагом может приводить к различным неприятностям — от сбоя системного времени до «зависания» компьютера.
В защищенном режиме прерывания работают гораздо сложнее. Таблица прерываний здесь содержит 8-байтные дескрипторы прерываний. Их обработчики должны быть подключены к ядру ОС, постоянно присутствующему в физической памяти. Иначе возможна ситуация, когда, например, аппаратное прерывание вызовет обработчик, выгруженный в данный момент на диск менеджером виртуальной памяти. Обработка такого прерывания будет чрезвычайно долгой (потребуется подкачка страницы). Позволять любой программе управлять флагом разрешения прерываний для многозадачных ОС нельзя из соображений общей устойчивости системы. Сам процесс обработки прерываний (и исключений) в защищенном режиме существенно отличается от прерываний реального режима, и в современных процессорах и ОС имеются средства виртуализации прерываний, о чем подробнее можно прочитать в [6, 7]. Заметим, что в ОС Windows 9x каждое окно MS-DOS представляет собой отдельную виртуальную машину с собственной таблицей прерываний «реального» вида, и работа с прерываниями в ней практически не отличается от работы в «чистой» MS-DOS. Для установки обработчиков прерываний, требуемых программам защищенного режима, используются вызовы специальных сервисов ОС, и обработчик оформляется особым образом в соответствии с соглашениями этой ОС (не так, как для MS-DOS).
12.6. Аппаратные средства измерения времени
В IBM PC/AT имеются аппаратные средства для измерения времени. Трехканальный счетчик-таймер, программно совместимый с i8254 (в XT — 8253), выполняет следующие функции:
♦ канал 0: — генерация аппаратных прерываний (IRQ0) каждые 54,936 мс (частота 18,206 Гц), вызывающих инкремент системного таймера (счетчика в ячейке 40:006Е BIOS Data Area);
♦ канал 1 — генерация запросов на регенерацию памяти;
♦ канал 2 — генерация звуковых сигналов или измерение времени.
Внутренние счетчики микросхемы имеют разрядность 16 бит, но общение с ними возможно только 8-битными операциями. При этом можно задавать значение только младшего байта счетчика (LSB), только старшего (MSB) или обоих (LSB/MSB), причем сначала передается младший, а потом старший байт. Программирование микросхемы осуществляется записью байт в управляющий регистр по отдельности для каждого канала. Назначение регистров счетчиков- таймеров приведено в табл. 12.5. Входная частота для всех каналов 1,19318 МГц. Штатно все каналы работают в режиме генерации импульсов. Счет для каналов 0 и 1 разрешен постоянно. В канале 2 используется управляющий вход GATE, разрешающий счет, который управляется битом 0 (T2G, R/W) системного порта AT (061h). Выходной сигнал канала 2 может быть программно считан (Т20, бит 5 того же порта). При использовании канала 2 для измерения времени необходимо отключить формирование звука (обнулив бит SPK, R/W, бит 1 порта 061h).
Таблица 12.5. Регистры счетчиков-таймеров
Порт, R/W | Назначение |
040 RW | Счетчик 0 — системные часы. Режим 011, LSB/MSB, Binary, константа счетчика равна 0 (соответствует коэффициенту деления 65 536) |
041 RW | Счетчик 1 — регенерация памяти. Режим 010, LSB, Binary, константа счетчика равна 12h (18) |
042 RW | Счетчик 2 — генератор звука, измерение времени. Вход GATE от бита 0 порта В 8255 (061). Режим 011, LSB/MSB, Binary, значение счетчика определяет высоту тона |
043 W | Управляющий регистр . Биты 7, 6 — выбор счетчика 0, 1, 2. Биты 5, 4 — режим обращения: 00 — защелка текущего значения; 01 — LSB — только младший байт; 10 — MSB — только старший байт; 11 — LSB/MSB — сначала младший, затем старший байты. Биты 3–1 — режим счетчика: 000 — прерывание по счетчику; 001 — ждущий мультивибратор (одновибратор, у 8254 несколько отличается от 8253); x10 — генератор коротких импульсов заданной частоты; x11 — генератор меандра; 100 — счетчик событий с разрешением; 101 — счетчик событий с перезапуском. Бит 0 — 0=Bin (двоичный счет), 1=BCD — (двоично-десятичный счет) |
Часы-календарь CMOS RTC являются частью комбинированной микросхемы МС146818 с батарейным питанием, используемой в IBM PC/AT для хранения ряда аппаратных настроек. Часы синхронизируются от собственного генератора (32,768 кГц), они содержат:
♦ часы-календарь (год, месяц, число, час, минута, секунда);
♦ будильник, подающий сигнал в назначенный час, минуту и секунду;
♦ генератор меандра, позволяющий формировать запросы прерываний с задан ной частотой (как правило, 1024 Гц).
CMOS RTC является источником аппаратных прерываний (IRQ8). Прерывания могут возникать от будильника, генератора меандра и после смены времени в часах. Отдельные источники прерывания идентифицируются чтением ячейки 0Ch и разрешаются записью в ячейку 0Bh.
Доступ к ячейкам CMOS RTC осуществляется через порты ввода-вывода 070h (индекс ячейки) и 071h (данные). Заметим, что бит 7 порта 70h используется и для блокировки NMI (см. п. 12.4), так что диапазон адресов памяти CMOS ограничен пределами 0-7Fh. Поскольку эта память имеет быстродействие порядка единиц микросекунд, между командами записи адреса и чтения-записи данных необходима программная задержка. Во время изменения состояния часов данные, считываемые из ячеек 0–9, могут оказаться некорректными. Признаком этой ситуации является единичное значение бита 7 ячейки 0Ah. Для определения момента окончания смены состояния часов можно пользоваться и разрешением соответствующего источника прерывания. Назначение ячеек CMOS RTC, относящихся к таймерной части, приведено в табл. 12.6 (полное определение ячеек см. в [1]).
Таблица 12.6. Назначение ячеек таймерной части CMOS RTC
Индекс | Назначение |
00h-09h, 32h (37 в PS/2) | Ячейки РТС в BCD-формате : 00 — секунды; 01 — секунды будильника; 02 — минуты; 03 — минуты будильника; 04 — часы; 05 — часы будильника; 06 — день недели; 07 — день месяца; 08 — месяц; 09 — год (2 младшие цифры); 32h — век-1 (2 старшие цифры года); 37h — век-1 (2 старшие цифры года) в PS/2 |
0Ah | RTC Status Register А (регистр статуса А) : бит 7 — обновление времени (0 — готов к чтению); биты [6:4] — делитель частоты (для кварца на 32,768 кГц — 010); биты [3:0] — 0110 — выходная частота меандра 1024 Гц |
0Bh | RTC Status Register В (регистр статуса В) : бит 7 — остановка часов (0 — нормальный ход); бит 6 — разрешение периодических прерываний (0 — запрещено); бит 5 — разрешение прерывания от будильника (0 — запрещено); бит 4 — разрешение прерывания по окончании смены времени (0 — запрещено); бит 3 (см. также регистр 0Ah) — разрешение выходного меандра (0 — запрещено); бит 2 — формат BCD/BIN (0 — BCD); бит 1 — 12/24-часовой режим (1 — 24-часовой); бит 0 — зимнее/летнее время (0 — переключение запрещено) |
0Ch | RTC Status Register С (регистр статуса С) : чтение флагов идентификаторов прерывания: бит 7 — IRQF (общий запрос прерывания); бит 6 — PF (периодические прерывания); бит 5 — AF (прерывание от будильника); бит 4 — UF (прерывание по окончании смены времени); биты [3:0] — зарезервированы |
0Dh | RTC Status Register D (регистр статуса D) : бит 7 — питание (1 — норма, 0 — разряд батареи); биты [6:0] — зарезервированы |
Аппаратные таймеры имеют поддержку функциями BIOS (подробнее см. [1, 8, 9]). Сервисы BIOS Int 1Ah позволяют считывать и модифицировать значения системного таймера (ячейки 40:006Eh в BIOS Data Area), а также даты, времени и будильника CMOS RTC.
Функции BIOS Int 15h позволяют с помощью CMOS RTC вводить задержку или запускать таймер установки флага (через заданное время установить бит 7 указанной ячейки памяти). Время задается в микросекундах, но минимальная выдержка зависит от производительности ПК (достижимы единицы миллисекунд), максимальная выдержка — около 70 часов.
Начиная с процессоров Pentium, появилась возможность измерения времени с точностью до такта ядра процессора. Для этого процессоры имеют внутренний 64-битный счетчик TSC (Time Stamp Counter), обнуляющийся по аппаратному сбросу (сигналом RESET#). Разрядность позволяет считать без переполнения в течение нескольких столетий. Для доступа к счетчику имеется специальная инструкция RDTSC, правда, установкой флага TSD в управляющем регистре CR4 (процессора) ОС может сделать ее привилегированной (доступной только на нулевом уровне привилегий). В этом случае приложение, исполняемое на уровне 3, может аварийно завершаться по отказу исполнения инструкции. ОС может и позволить обращение к этому регистру, но «подсовывая» программе угодное ей значение времени. Заметим, что из-за внутреннего умножения частоты в процессоре результат чтения счетчика может отставать от реального времени на число, достигающее коэффициента умножения частоты. Правда, такая точность никому и не нужна (она потеряется в измеряющих программах).
12.7. Способы запуска программ
Традиционным способом запуска программ является загрузка их с какого-либо устройства хранения (диска) в оперативную память и исполнение в ОЗУ. До того как пользователь получает возможность такого запуска, требуется множество предварительных действий. По включении питания (и аппаратному сбросу) процессор начинает исполнять процедуру POST (начальный запуск и самотестирование) из ROM BIOS, причем большая часть кода исполняется прямо в ПЗУ. POST инициализирует стандартное оборудование ПК (о котором «знает» ROM BIOS системной платы), а также обнаруживает модули расширения ROM BIOS и запускает их процедуры инициализации. Далее POST определяет загрузочное устройство (обычно диск), ищет на нем загрузочную запись (сектор), загружает этот сектор в фиксированную область ОЗУ и передает управление на его начальный адрес. С этого момента, как правило, начинается процесс загрузки операционной системы с того же носителя: сначала базовой системы, а затем и всех необходимых дополнительных компонентов в виде драйверов и автоматически загружаемых программ. Только после этого пользователь может запускать требуемые программы с любого доступного устройства хранения (в том числе и через сеть). Программы могут загружаться и автоматически, без участия пользователя, по предварительно составленному и сохраненному сценарию (файлы config.sys, autoexec.bat и т. п. средства).
Для ряда специальных применений ПК приходится нарушать эти традиции. Для сравнительно простых систем можно отказаться от использования операционных систем. Программу функционирования компьютера можно «зашить» в ПЗУ, оформив в виде модуля расширения BIOS, и эта программа получит управление от POST. Можно и не связываться с ПЗУ, а загружать программу с устройства хранения простым загрузчиком, первая ступень которого должна совпадать со стандартным начальным загрузчиком. Однако не стоит отказываться от операционной системы без веских причин, поскольку она обеспечивает не только удобное операционное окружение, но и средства разработки и отладки программ. Операционную систему и необходимые программы можно загружать не только с привычных дисков (гибких, жестких, оптических), но и с компактных твердотельных носителей (см. п. 9.3). Эти носители могут подключаться к обычным интерфейсам устройств хранения.
Интересный вариант «твердотельного диска» — DiskOnChip — для микрокомпьютеров и микроконтроллеров, не имеющих стандартных интерфейсов устройств хранения, предлагает фирма M-Systems. Это микросхема, имеющая интерфейс 8/16-битной статической памяти, легко подключаемый к шине ISA (или локальной шине). Модель Millenium Plus объемом 32 Мбайт содержит массив флэш-памяти архитектуры NAND, модуль статической памяти SRAM (1 Кбайт), интерфейсные схемы, логику защиты записи и чтения и схемы обнаружения и исправления ошибок. Микросхема отображается на 8-Кбайтную страницу пространства памяти компьютера в области C8000-EFFFFh. По сигналу аппаратного сброса начальный блок из флэш-памяти выгружается в SRAM; если обнаруживается ошибка, то берется следующий (резервный) блок. Этот блок содержит процедуру инициализации «диска», которая обнаруживается тестом POST как модуль расширения BIOS. Процедура загружает из флэш-массива в системное ОЗУ драйвер своего «электронного диска» (блочного устройства), которое становится первым или последним логическим жестким диском (по выбору при конфигурировании). Далее к этому «диску» можно обращаться обычным способом (через Int 13h), c него же может и загружаться ОС. Интерфейс допускает каскадирование — объединение в единый диск до 4 микросхем, увеличивая его объем до 128 Мбайт, при этом все микросхемы отображаются через общее окно памяти (используют общий сигнал выборки). Встроенное ПО обеспечивает полную эмуляцию диска с прозрачным исправлением ошибок и переназначением дефектных секторов. Микросхема поддерживает длительную скорость записи 750 Кбайт/с, считывания — 2,4 Мбайт/с. Пиковая скорость считывания/записи достигает 20 Мбайт/с. В устройстве имеется уникальный идентификационный номер, область для однократного программирования (OTP), возможность защиты от записи отдельных зон и возможность ограничения доступа по паролю (нечитаемому).
12.8. Сервисы и прерывания BIOS
Системная BIOS предоставляет ряд сервисов низкого уровня, в основном предназначенных для обслуживания ввода-вывода и имеющих отношения к стандартным аппаратным интерфейсам. Традиционные сервисы BIOS обычно вызываются в реальном режиме или V86 посредством инструкций программных прерываний (Int xx). Большинство сервисов может быть вызвано и через фактически стандартизованные точки входа (адреса в области ROM BIOS) дальними вызовами процедур (CALL Far) с предварительным помещением в стек регистра флагов (сервисы построены как обработчики прерываний). Все традиционные сервисы BIOS работают в 16-разрядном режиме процессора, и ими можно пользоваться в реальном режиме, V86 и малопривлекательном 16-разрядном защищенном режиме.
Для процессоров 386+ оптимальным по эффективности является 32-разрядный защищенный режим. Для того чтобы из этого режима можно было пользоваться сервисами BIOS (правда, не всеми) без промежуточных переключений, по инициативе фирмы Phoenix ввели 32-разрядные вызовы BIOS32. Адрес точки входа BIOS32 заранее не известен, но известен способ его нахождения: в диапазоне адресов памяти 0E0000-0FFFFFh на границе параграфов (младшие 4 бита адреса нулевые) ищется строка-сигнатура "_32_" (число 325F5F33h) заголовка, за которой следует физический адрес точки входа. Сами сервисы вызываются дальними вызовами точки входа в сервис. Номер, параметры вызываемых функций и результаты передаются на регистрах процессора.
Прерывания, обслуживаемые системной BIOS, перечислены ниже. Кроме них несколько векторов используются как указатели на различные структуры данных.
Внутренние прерывания:
♦ Int 00h — деление на 0;
♦ Int 01h — пошаговый режим;
♦ Int 03h — точка останова;
♦ Int 04h — переполнение;
♦ Int 06h — недопустимая команда 286+;
♦ Int 07h — вызов отсутствующего NPU.
Аппаратные прерывания:
♦ Int 02h — немаскируемое прерывание;
♦ Int 08h — таймер 8253/8254;
♦ Int 09h — клавиатура;
♦ Int 0Ah — IRQ2/9;
♦ Int 0Bh — IRQ3;
♦ Int 0Ch — IRQ4;
♦ Int 0Dh — IRQ5;
♦ Int 0Eh — IRQ6 — контроллер гибких дисков;
♦ Int 0Fh — IRQ7;
♦ Int 70h — CMOS-таймер;
♦ Int 71h — IRQ9 (перенаправлено на Int 0Ah);
♦ Int 72h — IRQ10;
♦ Int 73h — IRQ11;
♦ Int 74h — IRQ12 (контроллер мыши PS/2);
♦ Int 75h — IRQ13 — исключение сопроцессора;
♦ Int 76h — IRQ14 — контроллер жестких дисков;
♦ Int 77h — IRQ15.
ПРИМЕЧАНИЕ
Прерывания Int 70h - 77h имеют место только в AT.
Функции ROM BIOS (16-битные сервисы):
♦ Int 05h (F000:FF54h) — печать экрана;
♦ Int 10h — видеосервис;
♦ Int 11h — чтение списка оборудования (слово из BDA 0040:0010h), возвращает в АХ:
• биты 15:14 — число обнаруженных LPT-портов: 00 — 0, …, 11 — 3;
• бит 13 — резерв;
• бит 12 — обнаружен игровой адаптер;
• биты 11:9 — число обнаруженных СОМ-портов: 000 — 0, …, 111 — 7;
• бит 8 — наличие контроллера DMA;
• биты 7:6 — число обнаруженных НГМД: 00 — 1, …, 11 — 4;
• биты 5:4 — активный видеорежим: 00 — резерв, 10 — 80-колоночный цветной, 01 — 40-колоночный цветной, 11 — монохромный;
• биты 3:2 — размер ОЗУ на системной плате (теперь обычно 00);
• бит 1 — присутствие математического сопроцессора;
• бит 0 — присутствие дисководов;
♦ Int 12h — размер непрерывной памяти;
♦ Int 13h — дисковый сервис (блочный ввод-вывод);
♦ Int 14h — обслуживание СОМ-портов;
♦ Int 15h — AT-функции (системный сервис, функции определяются значением АН/АХ):
• 00-03h — управление и обмен данными с кассетным магнитофоном (были когда-то и такие «стриммеры»!) на старых PC;
• 4fh — перехват клавиатуры;
• 53xxh — сервисы управления потреблением АРМ (Advanced Power Management);
• 8300h — запуск таймера, устанавливающего флаг в заданной ячейке;
• 8301h — сброс того же таймера;
• 84h — джойстик (см. п. 8.6);
• 86h — программируемая задержка;
• 87h — перемещение блока расширенной памяти;
• 88h — получение размера расширенной памяти;
• 89h — переключение в режим V86;
• C0h — получение системной конфигурации, при успешном выполнении (CF=0, AH=0) ES:BX указывает на таблицу данных конфигурации;
• 80-82h, 85h, 90h, 91h — функции многозадачных ОС (BIOS устанавливает заглушки);
♦ Int 16h — клавиатурный ввод-вывод;
♦ Int 17h — обслуживание LPT-портов;
♦ Int 18h — процедура восстановления при неудаче начальной загрузки (прежде — ROM-Basic);
♦ Int 19h — начальная загрузка (вызов процедуры Bootstrap);
♦ Int 1Ah — системное время, дата, будильник и 16-битные вызовы сервисов PCI;
♦ Int 1Bh — обработчик нажатия клавиш Ctrl+Break;
♦ Int 1Ch — User Timer Interrupt, процедура, вызываемая обработчиком Int 08h каждые 55 мс; BIOS устанавливает простую заглушку (IRET), но программы могут перехватывать это прерывание; на время отработки этой процедуры все аппаратные прерывания запрещены (кроме NMI).
♦ Int 33h — поддержка мыши;
♦ Int 4Ah — обработчик будильника пользователя, установленного функцией BIOS Int 1Ah(6); прерывание вызывается асинхронно, так что при возврате из процедуры все регистры и флаги должны быть в том же состоянии, что и при входе; BIOS ставит заглушку (IRET);
♦ Int 67h — EMS-функции.
Указатели на таблицы:
♦ Int 1Dh — видеопараметры;
♦ Int 1Eh — параметры дискет;
♦ Int 1Fh — знакогенератор СGA;
♦ Int 41h — параметры HDD 0;
♦ Int 46h — параметры HDD 1;
♦ Int 43h — знакогенератор EGA.
12.8.1. Int 09h, Int 16h — поддержка клавиатуры
Поддержка клавиатуры заключается в обработке прерываний от устройства ввода и предоставлении сервисов ввода прикладным программам.
Прерывания, вызванные приходом кодов нажатия и отпускания клавиш, обрабатывает BIOS Int 9h. Каждый принятый скан-код (или цепочка) обрабатывается с учетом состояния клавиатурных флагов. Результат обработки (как правило, ASCII-символ в младшем байте и скан-код в старшем) помещается в клавиатурный буфер, расположенный в ОЗУ. По приему каждого символа указатель головы буфера увеличивается. Буфер организован в виде кольца, после достижения конца области буфера указатель головы установится на начало области. В случае переполнения буфера (указатель головы «догнал» указатель хвоста) очередное слово не записывается, и подается звуковой сигнал. Размер позволяет хранить описание шестнадцати фактов нажатий клавиш. Нажатие клавиш Ctrl, Shift, Alt и некоторых комбинаций в буфере не отмечается, но приводит к модификации бит ячеек флагов клавиатуры. Нажатие «системной» комбинации Ctrl+Alt+Del, клавиши PrintScreen (SysRq) и некоторых других к записи в клавиатурный буфер не приводит, а вызывает специальные процедуры.
Для обслуживания клавиатуры используются ячейки ОЗУ из области данных BIOS (BIOS Data Area):
♦ 0:0417, 0:418 — флаги клавиатуры;
♦ 0:0419 — аккумулятор кода Alt-набора;
♦ 0:041А — указатель головы буфера (Buffer Head), 2 байта (модифицируется при помещении символа в буфер);
♦ 0:041C — указатель хвоста буфера (Buffer Tail), 2 байта (модифицируется при извлечении символа из буфера);
♦ 0:041E-0:042D — область кольцевого буфера (16 слов).
Обработчик аппаратного прерывания до обработки принятого скан-кода вызывает прерывание BIOS Int 15h с AH=4Fh, а в AL находится принятый скан-код. Стандартный обработчик Int 15h(4Fh) просто выполняет возврат с CF=0, но его можно заменить специальным обработчиком, который будет при необходимости подменять принятые скан-коды на какие-либо иные (оставляя их в AL), что должно отмечаться установкой CF=1. В старых версиях BIOS такой возможности перехвата не было, ее наличие можно определить вызовом Int 15h(C0h).
Для клавиатуры USB или иного устройства ввода, заменяющего клавиатуру в качестве консоли, прерывание Int 9h должно вызываться программно при обработке каждого клавиатурного события. Обработчик этого прерывания должен выполнять те же действия: скан-код пропускать через Int 15h(4Fh) и помещать в клавиатурный буфер, а также модифицировать флаги клавиатуры.
Интерфейс прикладного уровня для клавиатуры представляет BIOS Int 16h. Его основное назначение — извлечение слов из клавиатурного буфера. Функция задается в регистре АН при вызове, результат помещается в регистр АХ.
♦ АН = 00h — чтение (с ожиданием готовности) и выборка слова из буфера (меняется указатель хвоста). Индикаторы клавиатуры обновляются в соответствии с состоянием флагов. Если буфер пуст, то на AT выполняется прерывание Int 15h (подфункция 90), что может использоваться ОС, например, для переключения задач. Чтобы программа не «зависала» на ожидании символа, предварительно стоит проверить готовность функцией 01h. Символы расширенной клавиатуры фильтруются — преобразуются в их аналоги 83-клавишной клавиатуры.
♦ АН = 01h — проверка готовности, чтение без выборки (указатели не изменяются). Признак наличия символа в буфере — установленный флаг ZF.
♦ АН = 02h — чтение состояния флагов (в AL — байт 0:417h, см. выше).
♦ АН = 03h — установка задержки и частоты автоповтора: BL — код задержки (00=250, 01=500, 02=750, 03=1000 мс), ВН — код частоты (см. п. 9.2.1).
♦ АН = 05h — запись слова из регистра СХ в буфер (меняется указатель головы). Признак успешной записи — AL=0, если в буфере нет места, то AL=1.
♦ АН = 10h и AH = 11h — функции, аналогичные 00h и 01h, но предназначены специально для 101/102-клавишных клавиатур — в них не выполняется фильтрация символов расширенной клавиатуры. Для ряда клавиш, отсутствующих в клавиатуре АТ-84, эти функции дадут результаты, отличающиеся от вызовов 00h и 01h.
♦ AH=12h — чтение расширенного состояния флагов (в АХ — слово KbdShiftFlags101Rec), в котором младший байт совпадает с тем, что дает функция 02h (слово из 0:417h), а старший байт похож на слово из 0:418h. Назначение бит АХ:
• бит 0 — клавиша Shift (правая) нажата;
• бит 1 — клавиша Shift (левая) нажата;
• бит 2 — клавиша Ctrl (любая) нажата;
• бит 3 — клавиша Alt (любая) нажата;
• бит 4 — включен индикатор Scroll Lock;
• бит 5 — включен индикатор Num Lock;
• бит 6 — включен индикатор Caps Lock;
• бит 7 — включен режим Insert;
• бит 8 — клавиша Ctrl (левая) нажата;
• бит 9 — клавиша Alt (левая) нажата;
• бит 10 — клавиша Ctrl (правая) нажата;
• бит 11 — клавиша Alt (правая) нажата;
• бит 12 — клавиша Scroll Lock нажата;
• бит 13 — клавиша Num Lock нажата;
• бит 14 — клавиша Caps Lock нажата;
• бит 15 — клавиша SysReq нажата.
Функции чтения буфера (00 и 10h) в регистре AL возвращают ASCII-код символа, в АН — скан-код. Символы, полученные нестандартным способом (в русском регистре или Alt-набором), сопровождаются нулевым скан-кодом. Alt-набор позволяет ввести в буфер любой символ — для этого его код в десятичной системе набирается на цифровой клавиатуре при нажатой клавише Alt, результат заносится в буфер при отпускании клавиши Alt.
При AL=0 регистр АН содержит расширенный ASCII-код (Extended ASCII Keystroke). Дополнительные клавиши 101/102 клавиатур при использовании функций 10h-12h генерируют код E0h в младшем байте и скан-код, соответствующий аналогичным управляющим клавишам 83/84-клавишных клавиатур.
Функция записи (05h), несколько неожиданная для клавиатуры, позволяет легко имитировать работу оператора для различных демонстрационных программ. Если прикладная программа не перехватывает обслуживание клавиатуры на уровне аппаратного прерывания (Int 9h), то резидентная программа может ей «подбрасывать» слова в буфер, которые будут восприниматься как нажатие клавиш.
ASCII-коды буфера, соответствующие нажатию клавиш, приведены в [1, 7]. При русификации (или другой локализации) клавиатуры отслеживание переключения регистров (языков) ложится на обработчик аппаратного прерывания клавиатуры.
12.8.2. Int 10h — видеосервис
Int 10h — видеосервис — предназначен для работы с графическим адаптером. Его первичной задачей является управление видеорежимом (BIOS Video Mode), определяющим формат экрана. BIOS адаптера должна выполнять программирование всех стандартных и специфических управляющих регистров для установки (смены) требуемого видеорежима и выбранных параметров развертки — кроме нее о способах этих переключений остальное ПО может и не знать.
В пределах возможностей установленного видеорежима видеосервис предоставляет возможности отображения информации на различных уровнях. Простейший для программиста телетайпный режим позволяет посылать поток символов, которые будут построчно отображаться на экране с отработкой символов возврата каретки, перевода строки, обеспечивая «прокрутку» изображения при заполнении экрана. Есть функции и для полноэкранной работы с текстом, при которой доступны и атрибуты символа. В графическом режиме имеется возможность чтения и записи пиксела с указанными координатами. Однако видеосервисом Int 10h программисты пользуются далеко не всегда, поскольку работает он довольно медленно. Подробно рассматривать функции видеосервиса не будем (этому посвящены отдельные книги), отметим особо лишь функцию телетайпного вывода Int 10h(0Eh). При вызове AH=0Eh, в AL — код выводимого символа, в BL — цвет (только для графического режима). Символ выводится в текущую позицию курсора, и курсор сдвигается на следующую, переходя на новую строку после конца предыдущей и прокручивая экран при его заполнении. Специальные символы вызывают возврат на начало строки (CR, код 0Dh), перевод строки (LF, 0Ah) и короткий гудок (BEL, 07h). Этой функцией часто пользуются для вывода сообщений программами, работающими на нижнем уровне (например, модули инициализации ПЗУ расширений BIOS, загрузчики и другие, не имеющие еще доступа к сервисам операционных систем). Программа вывода получается простейшей, работает на всех адаптерах и во всех режимах, но довольно медленно.
12.8.3. Int 13h — поддержка дисков
Функции дискового сервиса вызываются программным прерыванием Int 13h.
Традиционно дисковый сервис подразделяет физические диски на дискеты (diskette) и фиксированные диски (fixed disk). Набор функций (табл. 7.8) для этих классов устройств несколько различается как по составу, так и по реализации. Классы различаются по диапазонам номеров физических устройств: для дискет отводятся номера 0-7Fh (реально только 0–3), а для фиксированных дисков — 80h-FFh.
Контроллеры дисковых интерфейсов, имеющие в своем составе дополнительные модули BIOS, перехватывают вектор Int 13h, беря на себя обслуживание своих устройств. Когда в IBM PC/XT появились жесткие диски со своим контроллером, модуль BIOS этого контроллера, инициализирующийся во время теста POST, вставал на место Int 13h, а указатель на исходный обработчик дискового сервиса (драйвер НГМД из системной BIOS) сохранялся на месте Int 40h. Хотя поддержка жестких дисков давно уже включена в системную BIOS, ради совместимости возможность использования прерывания Int 40h для вызова драйвера гибких дисков сохраняется. Интерфейс этого вызова совпадает с Int 13h, но номер устройства (в регистре DL) не должен превышать 7Fh.
Кроме функций дискового сервиса (Int 13h) c дисковыми устройствами связаны еще и векторы, обслуживающие аппаратные прерывания от контроллера НГМД — Int 0Eh (линия IRQ 6) и от контроллера жестких дисков — Int 76h (линия IRQ 14). При наличии двухканального порта ATA второй канал обычно задействует линию IRQ 15 (вектор 77h). В XT контроллер жестких дисков занимал линию IRQ 5 (вектор 0Dh). Дополнительные контроллеры дисков могут использовать и другие прерывания. Аппаратные прерывания вырабатываются контроллерами по завершении (нормальному и аварийному) внутренних операций. На эти прерывания BIOS не реагирует, а при инициализации их векторы направляются на программную заглушку (инструкцию IRET).
Стандартные драйверы дисковых функций BIOS (включая и расширенный сервис) имеют однозадачное происхождение. Во время выполнения функции значительное процессорное время может затрачиваться на ожидание завершения операции устройством. Драйверы многозадачного режима построены иначе: у них есть вызывающая часть, инициализирующая начало операции, и обработчик аппаратного прерывания от контроллера, сообщающий операционной системе о выполнении операции и результате.
Традиционный сервис BIOS
Традиционный дисковый сервис работает в 16-разрядном режиме процессора, все параметры вызова передаются через регистры процессора. Адрес сектора задается в системе CHS и размещен весьма специфично. Сервис вызывается программным прерыванием Int 13h, при вызове принимаются следующие соглашения:
♦ номер функции задается в регистре АН и не должен превышать 3Fh;
♦ логический номер диска задается в регистре DL (бит 7 = 0 — признак обращения к НГМД);
♦ номер цилиндра (0-1023) задается в регистре СН (младшие 8 бит) и CL[7:6] (старшие 2 бита);
♦ номер головки (0-255) задается в регистре DH;
♦ номер начального сектора (1-63) задается в регистре CL[5:0];
♦ количество секторов, участвующих в операции, 8 бит — в регистре AL (0-255);
♦ указатель на начало буфера оперативной памяти для считываемых и записываемых данных (address of buffer) — в регистрах ЕS:BX;
♦ результат выполнения операции определяется по флагу переноса: СF = 0 — успешное выполнение операции, CF = 1 — обнаружены ошибки (код состояния возвращается в регистре АН, код завершения последней операции с дискетами хранится по адресу 40:41h, с жесткими дисками — 40:74h);
♦ таблица параметров диска для дискет (DPT) задана указателем в памяти по адресу 0:78h, для жестких дисков (HDPT) — 0:104h или 0:118h.
Список функций традиционного сервиса приведен в табл. 12.7, подробнее они описаны в [4, 9]. Устройства могут не поддерживать некоторые функции, о чем драйверы должны «честно сообщить» кодом возврата 01h.
Таблица 12.7. Функции традиционного дискового сервиса
Номер функции АН | Назначение параметров | Использование регистров указателей и таблиц | ||||
DL | DH, CL, CH | AL | ES: BX | DPT/HDPT | ||
00h | Reset Disk System — сброс дисковой системы (всех контроллеров и устройств), позиционирование на нулевой цилиндр | - | - | - | - | - |
01h | Read Status of Last Operation — чтение состояния последней операции | + | - | - | - | - |
02h | Read Sectors into Memory — чтение секторов с диска в память | + | + | + | + | + |
03h | Write Sectors from Memory — запись секторов из памяти на диск | + | + | + | + | |
04h | Verify Sectors — верификация секторов (холостое чтение без записи в память и проверка CRC/ECC) | + | + | + | - | + |
05h | Format Desired Track — форматирование трека | + | + | + | + | + |
08h | Get Drive Parameters — получение параметров диска | +³ | +³ | +³ | - | +³ |
09h¹ | Initialize Drive Parameters — инициализация таблиц параметров диска | + | - | - | - | + |
0Ah¹ | Read Long — «длинное» чтение (сектор и поле ЕСС) | + | + | + | + | + |
0Bh¹ | Write Long — «длинная» запись (сектор и поле ЕСС) | + | + | + | + | + |
0Ch¹ | Seek — поиск цилиндра | + | + | - | - | - |
0Dh¹ | Alternative Disk Reset — альтернативный сброс (не затрагивая контроллера дискет) | + | - | - | - | - |
10h¹ | Test Drive Ready — проверка готовности | + | - | - | - | - |
11h¹ | Recalibrate — рекалибровка (позиционирование на нулевой цилиндр) | + | - | - | - | - |
14h¹ | Controller Internal Diagnostics — диагностика контроллера жестких дисков | - | - | - | - | - |
15h | Read DASD Туре — получение типа диска: АН=0 — нет диска; АН=1 — дискета, без датчика смены диска; АН=2 — дискета, с датчиком смены диска; АН=3 — жесткий диск; иные значения — код ошибки. CX: DX содержат число 512-байтных секторов на диске | + | - | - | - | - |
16h² | Diskette Change Line Status — проверка статуса смены дискеты: CF=0: АН=0 — смены носителя не было; CF=1: AH=1 — недопустимый номер диска; АН=6 — была смена диска или определение смены не поддерживается; AH=80h — дисковод не готов или не установлен; иные значения — код ошибки | + | - | - | - | - |
17h² | Set Diskette Type for Format — установка типа дискеты для форматирования (перед форматированием) | + | +³ | |||
18h² | Set Media Type for Format — установка типа носителя (для форматирования) | + | +³ | - | - | - |
20h² | Get Media Type — получение типа установленного носителя | + | - | - | - | - |
24h¹ | Set Multiple Mode — установка параметров режима многосекторного обращения (в AL — число секторов за операцию) | + | - | + | - | - |
25h¹ | Identify Drive ATA — идентификация накопителя (только для ATA-дисков) | + | - | - | + | - |
¹ Только для фиксированных дисков.
² Только для дискет и других сменных носителей.
³ Назначение отличается от обычного.
Формально традиционный сервис позволяет работать с дисками, имеющими до 1024×256×63 = 16 515 072 секторов (около 8,4 Гбайт). Ряд операционных систем имеет ошибку, не позволяющую использовать полный объем, допустимый данным сервисом. Для дисков объемом более 15 481 935 секторов следует пользоваться только функциями расширенного сервиса (см. ниже). Однако при работе с устройствами ATA имеется еще и барьер в 528 Мбайт. Дело в том, что контроллер жесткого диска ATA, на который ориентированы драйверы Int 13h, имеет только 4-битный регистр номера головки (а в BIOS — 6 бит). Правда, этот же контроллер способен принимать 16-битный номер цилиндра (в BIOS — 10 бит). Понятно, что непосредственно без искажений через эти два фильтра (формат вызова и формат регистров контроллера) может пройти только вызов с самыми жесткими ограничениями по каждой координате. Тогда ограничение, полученное тем же перемножением диапазонов координат, получается около 528 миллионов байт:
(210 = 1024 цилиндра) × (24 = 16 головок) × (26 – 1 = 63 сектора) × 512 байт = 528 482 304 байт.
Для преодоления 528-мегабайтного барьера дисков ATA, не трогая программного интерфейса, в BIOS ввели расширение традиционного дискового сервиса. Интерфейс ATA в трехмерной геометрии позволяет реализовать довольно большой (но уже не запредельный) объем диска:
(216 = 65 536 цилиндров) × (24 = 16 головок) × (28 – 1 = 255 сектора) × 512 байт = 136,9 Гбайт.
Чтобы достичь хотя бы интерфейсного ограничения BIOS (8,4 Гбайт), стали применять трансляцию параметров вызова функций Int 13h, которые будем теперь называть логическими, в физические параметры, передаваемые контроллерам ATA-дисков. В функции, которая сообщает параметры диска (функция 8), производится обратная трансляция, так что на стороне вызова программного интерфейса Int 13h присутствуют только логические параметры. Естественно, логический объем диска не может превышать физического: (С × H × S)ЛОГ ≤ (С × H × S)ФИЗ.
Подробнее о преодолении барьеров и способах трансляции (LBA, Large Disk, ECHS) см. в [1, 4, 9]
Расширенный сервис BIOS
Чтобы получить возможность работы через BIOS с дисками объема более 8,4 Гбайт, потребовалось ввести новые функции дискового сервиса.
Расширенный дисковый сервис BIOS, Enhanced Disk Drive Services (EDD), продвигаемый фирмой Phoenix Technologies LTD, реализуется многими разработчиками BIOS и устройств массовой памяти. Он позволяет работать с устройствами, имеющими объем до 264 секторов, эффективно используя архитектуру процессоров IA-32 и IA-64. Сервис оперирует линейным логическим адресом сектора (LBA). Вместо традиционных таблиц параметров дисков в нем используются новые, дающие исчерпывающую информацию об устройствах, их физической организации и интерфейсе. Устройства могут иметь сменные носители и сами быть съемными в процессе работы компьютера (например, подключенные к шине USB или IEEE 1394), так что понятие «сменяемость носителя» несколько размывается. Такие устройства должны поддерживать механизм уведомления о смене носителя и программное блокирование смены носителя. По прогнозам емкости данного интерфейса должно хватить на 15–20 лет.
Расширения BIOS Int 13h используют ОС Windows 95, Windows 98, Windows 2000. Правда, это использование ограничено лишь начальной загрузкой и процессом установки (FDISK, FORMAT), поскольку в регулярной работе применяются собственные 32-разрядные драйверы. Расширения BIOS Int 13h не используют DOS (все версии), Windows 3.1x, Windows NT, Novell NetWare, OS/2 Warp, Linux, Unix.
В настоящее время определены три набора функций:
♦ доступ к фиксированным дискам (fixed disk access subset) — функции 41-44h, 47h и 48h;
♦ блокировка и смена носителя (device locking and ejecting subset) — функции 41h, 45h, 46h, 48h и 49h;
♦ поддержка расширенных дисков (enhanced disk drive (EDD) support subset) — функции 41h и 48h.
Расширенный сервис, как и традиционный, вызывается программным прерыванием Int 13h с номерами функций свыше 3Fh (регистр АН); номер устройства (регистр DL) допустим в диапазоне 80h-FFh. Основные параметры вызова — начальный адрес блока, число секторов для передачи и адрес буфера — передаются через адресный пакет (device address packet). Формат пакета в сравнении с передачей параметров традиционного сервиса через регистры процессора довольно просторный.
Поскольку расширение BIOS может и отсутствовать, имеется функция проверки его наличия (номер 41h). Расширение может действовать избирательно (не для всех устройств), так что проверку надо производить для конкретного устройства, интересующего программу. Проверка дает номер версии расширения и карту поддерживаемых наборов функций. Функции расширенного чтения, записи, верификации и поиска (42h, 43h, 44h и 47h) по смыслу не отличаются от их аналогов из традиционного сервиса. Для работы со сменными носителями введены функции отпирания/запирания, извлечения и проверки факта смены носителя (45h, 46h и 49h). От идеологии традиционного сервиса сильно отличается функция получения параметров устройства (48h). Она возвращает в ОЗУ буфер с набором параметров и детальным описанием устройства, позволяющим ОС и приложениям работать с ним, минуя BIOS. Функция установка аппаратной конфигурации (4Eh) позволяет управлять режимом передачи (PIO, DMA), а также предварительной выборкой (поиском).
Для эмуляции дисков на загружаемых CD-ROM к сервисам BIOS Int 13h добавляется несколько новых функций:
♦ начать/завершить эмуляцию диска (4Ah/4Bh), начать эмуляцию диска и выполнить загрузку (4Ch);
♦ прочитать секторы загрузочного каталога (4Dh); функции 41-48h позволяют обращаться к любым логическим секторам CD-ROM (в режиме LBA с размером сектора 2048 байт), когда для данного привода включена эмуляция.
Подробнее расширенный сервис рассмотрен в [4].
12.8.4. Int 14h — поддержка СОМ-портов
СОМ-порты поддерживаются сервисом BIOS Int 14h, который обеспечивает описанные ниже функции.
♦ 00h — инициализация (установка скорости обмена и формата посылок, заданных регистром AL; запрет источников прерываний). На сигналы DTR и RTS влияния не оказывает (после аппаратного сброса они пассивны).
♦ 01h — вывод символа из регистра AL (без аппаратных прерываний). Активируются сигналы DTR и RTS, и после освобождения регистра THR в него помещается выводимый символ. Если за заданное время регистр не освобождается, фиксируется ошибка тайм-аута и функция завершается.
♦ 02h — ввод символа (без аппаратных прерываний). Активируется только сигнал DTR (RTS переходит в пассивное состояние), и ожидается готовность принятых данных, принятый символ помещается в регистр AL. Если за заданное время данные не получены, функция завершается с ошибкой тайм-аута.
♦ 03h — опрос состояния модема и линии (чтение регистров МSR и LSR). Эту гарантированно быструю функцию обычно вызывают перед функциями ввода-вывода во избежание риска ожидания тайм-аута.
При вызове Int 14h номер функции задается в регистре АН, номер порта (0–3) — в регистре DX (0 — COM1, 1 — COM2…). При возврате из функций 0, 1 и 3 регистр АН содержит байт состояния линии (регистр LSR), AL — байт состояния модема (MSR). При возврате из функции 2 нулевое значение бита 7 регистра АН указывает на наличие принятого символа в регистре AL; ненулевое значение бита 7 — на ошибку приема, которую можно уточнить функцией 3.
Байт состояния линии (регистр АН) имеет следующий формат:
♦ бит 7 — ошибка тайм-аута (после вызова функции 2 — признак любой ошибки);
♦ бит 6 — регистр сдвига передатчика пуст (пауза передачи);
♦ бит 5 — промежуточный регистр передатчика пуст (готов принять символ для передачи);
♦ бит 4 — обнаружен обрыв линии;
♦ бит 3 — ошибка кадра (отсутствие стоп-бита);
♦ бит 2 — ошибка паритета принятого символа;
♦ бит 1 — переполнение (потеря символа);
♦ бит 0 — регистр данных содержит принятый символ.
Байт состояния модема (регистр AL при возврате из функций 0, 1, 3) имеет следующий формат:
♦ бит 7 — состояние линии DCD;
♦ бит 6 — состояние линии RI;
♦ бит 5 — состояние линии DSR;
♦ бит 4 — состояние линии CTS;
♦ бит 3 — изменение состояния DCD;
♦ бит 2 — изменение огибающей RI;
♦ бит 1 — изменение состояния DSR;
♦ бит 0 — изменение состояния CTS.
При инициализации порта биты регистра AL имеют следующее назначение:
♦ биты [7:5] — скорость обмена:
• 000=110; 100=1200; 001=150; 101=2400;
• 010=300; 110=4800; 011=600; 111=9600 бит/с;
♦ биты [4:3] — контроль паритета:
• 01 — число единиц нечетное;
• 11 — четное;
• 0 и 10 — без контроля;
♦ бит 2 — количество стоп-бит: 0–1 бит, 1–2 бита (на скорости 110 бит/с — 1,5 стоп-бит);
♦ биты [1:0] — длина посылки: 00 — 5 бит, 01 — 6 бит, 10 — 7 бит, 11 — 8 бит.
В процессе начального тестирования POST BIOS проверяет наличие последовательных портов (регистров UART 8250 или совместимых) по стандартным адресам и помещает базовые адреса обнаруженных портов в ячейки BIOS Data Area 0:0400, 0402, 0404, 0406. Эти ячейки хранят адреса портов с логическими именами COM1-СОМ4. Нулевое значение адреса является признаком отсутствия порта с данным номером. В ячейки 0:047С, 047D, 047Е, 047F заносятся константы, задающие тайм-аут для портов.
Обнаруженные порты инициализируются на скорость обмена 2400 бит/с, 7 бит данных с контролем на четность (even), 1 стоп-бит. Управляющие сигналы интерфейса DTR и RTS переводятся в исходное состояние («выключено» — положительное напряжение).
12.8.5. Int 17h — поддержка принтера
Сервисы BIOS Int 17h: обеспечивают инициализацию, вывод байта данных и опрос состояния принтера, подключенного к LPT-порту. При вызове функция задается в регистре АН, номер LPT-порта — в регистре DX.
♦ АН = 00h — вывод байта из регистра AL по протоколу Centronics (без аппаратных прерываний). Данные помещаются в выходной регистр, и, дождавшись готовности принтера (снятия сигнала Busy), формируется строб.
♦ АН = 01h — инициализация интерфейса и принтера (установка исходных уровней управляющих сигналов, формирование импульса Init#, запрет аппаратных прерываний и переключение на вывод двунаправленного интерфейса).
♦ АН = 02h — опрос состояния принтера (чтение регистра состояния порта).
При возврате регистр АН содержит байт состояния, который собирается из бит регистра состояния SR[7:3] и программно формируемого флага тайм-аута. Биты 6 и 3 относительно байта, считанного из регистра состояния, инвертированы. Назначение бит байта состояния:
♦ бит 7 — не занято (сигнал Busy); нулевое значение означает, что принтер занят (буфер полон или состояние Off-Line, или ошибка);
♦ бит 6 — подтверждение (сигнал Ack#); единичное значение означает, что принтер подключен;
♦ бит 5 — конец бумаги (сигнал PaperEnd);
♦ бит 4 — принтер готов (сигнал Select); нулевое значение означает, что принтер в состоянии Off-Line;
♦ бит 3 — ошибка принтера (сигнал Error#); единичное значение соответствует ошибке;
♦ биты 2:1=00 (не используются);
♦ бит 0 — флаг тайм-аута, устанавливается при неудачной попытке вывода символа, если сигнал Busy не снимается в течение времени, определенного для данного порта в ячейках тайм-аута (в BIOS Data Area); в этом случае согласно протоколу Centronics строб данных не вырабатывается.
Перехват прерывания Int 17h является удобным способом внедрения собственных драйверов принтера. Потребность в них может возникать при подключении к порту принтера с интерфейсом ИРПР или необходимости перекодировки символов. Если разрабатываемый драйвер предназначен не только для перекодировки, но и изменения протокола (через Int 17h можно организовать вывод через LPT-порт по протоколу ИРПР и даже через СОМ-порт), следует внимательно отнестись к битам возвращаемого байта состояния. При их неправильном формировании попытки вывода на печать могут приводить к ошибочным сообщениям.
12.8.6. Int 1Ah и Int 15h — поддержка таймеров
Сервисы BIOS Int 1Ah позволяют считывать и модифицировать значения системного таймера, даты и времени, а также установки будильника часов реального времени CMOS RTC. Перечисленные ниже номера функций указываются при вызове в регистре АН.
1. АН=0 — чтение системного таймера (двойного слова по адресу 40:006Eh в BIOS Data Area, инкрементируемого по прерываниям от канала 0 счетчика- таймера 8253/8254 примерно раз в 55 мс. Таймер обнуляется при выполнении теста POST после аппаратного сброса). Возвращает значение таймера, в СХ — старшую часть, в DX — младшую. AL=0, если за последние 24 часа не было переполнения таймера. В современных версиях сброс AL возвращает счетчик переполнений таймера, хранящийся в ячейке 40:0070h (в старых версиях это был флаг).
2. АН=1 — установка системного таймера (СХ — старшая часть, в DX — младшая) и сброс флага (счетчика) переполнения таймера в ячейке 40:0070h. В случае ошибки устанавливается флаг CF=1.
3. АН=2 — чтение времени из RTC. Возвращает в упакованном BCD-формате час (в регистре СН), минуту (CL), секунду (DH) и признак коррекции летнего/зимнего времени (DL=1 — коррекция используется, DL=0 — нет). Признаком успешной операции является флаг CF=0. Во избежание ошибок некоторых BIOS при вызове флаг CF должен быть сброшен.
4. АН=3 — установка времени в RTC, назначение регистров и признак результата аналогичен функции 2.
5. АН=4 — чтение даты из RTC. Возвращает в упакованном BCD-формате век (в регистре СН), две старшие цифры года (CL), месяц (DH) и день (DL). Признаком успешной операции является флаг CF=0. Во избежание ошибок некоторых BIOS при вызове флаг CF должен быть сброшен.
6. АН=5 — установка даты в RTC, назначение регистров и признак результата аналогичен функции 4.
7. АН=6 — установка времени срабатывания будильника RTC. Возвращает в упакованном BCD-формате час (в регистре СН), минуту (CL) и секунду (DH). Если будильник уже установлен, переустановка не производится и возвращается флаг CF=1. При срабатывании будильник вызывает прерывание Int 4Ah.
8. АН=7 — отмена установки будильника.
Функции BIOS Int 15h позволяют программировать таймер CMOS RTC — вводить задержку или запускать таймер установки флага, указывая время в микросекундах (СХ — старшее слово, DX — младшее). Нулевое значение интервала не вызывает никаких действий. Достижимое разрешение в зависимости от производительности ПК может достигать единиц миллисекунд, максимальная выдержка — около 70 часов. Перечисленные ниже номера функций указываются при вызове в регистре АН или АХ.
9. AH=86h — задержка на заданное время. Управление будет возвращено вызвавшему процессу только через указанный интервал. По окончании задержки будет установлен бит 7 в ячейке BDA 0040:00A0. Таймер может оказаться занятым, тогда вызов сразу возвратит флаг CF=1 (при успехе CF=0, а в AL окажется маска, записанная в 8259А#2).
10. AX=8300h — запуск таймера, устанавливающего флаг после указанной задержке бит 7 в ячейке, заданной регистрами ES:BX. При успешном запуске CF=0; если таймер занят (он один) — CF=1 и AL=0. Управление возвращается процессу сразу, а флаг будет установлен через заданное время. Перед завершением программа, запускавшая таймер, должна его сбросить функцией 8301h (во-первых, чтобы освободить; во-вторых, чтобы снять «адскую машинку», которая неожиданно сама может изменить значение ячейки памяти, вполне возможно уже задействованную другим, ничего не «подозревающим» процессом).
11. AX=8301h — сброс того же таймера.
12.8.7. PCI BIOS
Функции PCI BIOS используются только для поиска и конфигурирования устройств PCI — процедур, требующих доступа к их конфигурационному пространству (см. п. 8.2). Регулярная работа с этими устройствами выполняется через обращения к регистрам устройств по адресам, полученным при конфигурировании, и обработке известных номеров прерываний от этих устройств. Для 16-битного интерфейса реального режима, V86 и 16-битного реального режима, функции PCI BIOS вызываются через прерывание Int 1Ah; номер функции задается при вызове в регистре АХ. Возможна и программная имитация прерывания дальним вызовом по физическому адресу 000FFE6EH (стандартная точка входа в обработчик Int 1Ah) с предварительным занесением в стек регистра флагов.
Признаком нормального выполнения является CF=0 и АН=0; при CF=1 АН содержит код ошибки:
♦ 81h — неподдерживаемая функция;
♦ 83h — неправильный идентификатор производителя;
♦ 86h — устройство не найдено;
♦ 87h — неправильный номер регистра PCI.
Вызовы требуют глубокого стека (до 1024 байт). Для 32-разрядных вызовов защищенного режима все эти же функции вызываются через точку входа, найденную через каталог 32-разрядных сервисов (см. выше), при этом назначение входных и выходных регистров и флага CF сохраняется. До использования 32-разрядного интерфейса следует сначала найти его каталог и убедиться в наличии сервисов PCI. Функции PCI BIOS перечислены ниже:
♦ АХ = B101h — проверка присутствия PCI BIOS. При наличии PCI BIOS возвращает CF=0, АН=0 и EDX=20494350h (строка символов "PCI "); проверяться должны все три признака. При этом в AL находится описатель аппаратного механизма доступа к конфигурационному пространству и генерации специальных циклов PCI:
• Бит 0 — поддержка механизма № 1 для доступа к конфигурационному пространству;
• Бит 1 — поддержка механизма № 2 для доступа к конфигурационному пространству;
• Биты 2:3=00 (резерв);
• Бит 4 — поддержка генерации специального цикла по механизму № 1;
• Бит 5 — поддержка генерации специального цикла по механизму № 2;
• Биты 6:7=00 (резерв).
В регистрах ВН и BL возвращается старший и младший номер версии (BCD-цифры), в CL — максимальный номер шины PCI, присутствующий в системе (число шин +1, поскольку они нумеруются с нуля последовательно). В регистре EDI может возвращаться линейный адрес точки входа 32-разрядных сервисов BIOS. Этот адрес возвращается не всеми версиями BIOS (некоторые не изменяют EDI); для проверки можно при вызове обнулять EDI и проверять на нуль возвращенное значение.
♦ АХ = B102h — поиск устройства по идентификатору. При вызове в СХ указывается идентификатор устройства, в DX — идентификатор производителя, в SI — индекс (порядковый номер) устройства. При успешном возврате в ВН — номер шины, в BL[7:3] — номер устройства, BL[2:0] — номер функции. Для нахождения всех устройств с указанными идентификаторами вызовы выполняют, последовательно инкрементируя SI от 0 до получения кода возврата 86h.
♦ AX = B103h — поиск устройства по коду класса. При вызове в ЕСХ[23:16] указывается код класса, в ЕСХ[15:8] — подкласса, в ЕСХ[7:0] — интерфейс, в SI — индекс устройства (аналогично предыдущему). При успешном возврате в ВН — номер шины, в BL[7:3] — номер устройства, BL[2:0] — номер функции.
♦ АХ = B106h — генерация специального цикла PCI. При вызове в BL указывается номер шины, в EDX — данные специального цикла.
♦ АХ = В108h — чтение байта конфигурационного пространства устройства PCI. При вызове в ВН — номер шины, в BL[7:3] — номер устройства, BL[2:0] — номер функции, в DI — номер регистра (0-FFh). При успешном возврате в CL — считанный байт.
♦ АХ = B109h — чтение слова конфигурационного пространства устройства PCI. При вызове в ВН — номер шины, в BL[7:3] — номер устройства, BL[2:0] — номер функции, в DI — номер регистра (0-FFh, четный). При успешном возврате в СХ — считанное слово.
♦ АХ = В10Ah — чтение двойного слова конфигурационного пространства устройства PCI. При вызове в ВН — номер шины, в BL[7:3] — номер устройства, BL[2:0] — номер функции, в DI — номер регистра (0-FFh, кратный 4). При успешном возврате в ЕСХ — считанное двойное слово.
♦ АХ = B10Bh — запись байта конфигурационного пространства устройства PCI. При вызове в ВН — номер шины, в BL[7:3] — номер устройства, BL[2:0] — номер функции, в DI — номер регистра (0-FFh), в CL — записываемый байт.
♦ АХ = B10Ch — запись слова конфигурационного пространства устройства PCI. При вызове в ВН — номер шины, в BL[7:3] — номер устройства, BL[2:0] — номер функции, в DI — номер регистра (0-FFh, четный), в СХ — записываемое слово.
♦ АХ = B10Ah — запись двойного слова конфигурационного пространства устройства PCI. При вызове в ВН — номер шины, в BL[7:3] — номер устройства, BL[2:0] — номер функции, в DI — номер регистра (0-FFh, кратный 4), в ЕСХ — записываемое двойное слово.
12.9. Расширения ROM BIOS
В микросхеме ROM BIOS, установленной на системной плате, поддерживаются только стандартные (по назначению и реализации) устройства. При необходимости дополнительные устройства, устанавливаемые в слоты шин расширения (ISA, PCI, PCMCIA), могут иметь микросхемы ПЗУ своей программной поддержки — Additional ROM BIOS (дополнительные модули ROM BIOS), они же Expansion ROM. Эта необходимость возникает, когда программная поддержка устройств требуется до загрузки ОС и прикладного ПО. В таком модуле может содержаться и вся программа функционирования специализированного бездискового контроллера на базе PC. Расширения ROM BIOS используют графические адаптеры EGA/VGA/SVGA, некоторые контроллеры жестких дисков, контроллеры SCSI, сетевые адаптеры с удаленной загрузкой и другие периферийные устройства. Для модулей расширения устройств с шиной ISA в пространстве памяти зарезервирована область C8000h-F4000h. POST сканирует эту область с шагом 2 Кбайт в поисках дополнительных модулей BIOS на завершающем этапе выполнения (после загрузки векторов прерываний указателями на собственные обработчики). Дополнительный модуль BIOS графического адаптера (EGA, VGA, SVGA…) имеет фиксированный адрес C0000 и инициализируется раньше (на шаге инициализации видеоадаптера). Устройства с шиной PCI в своем конфигурационном пространстве содержат лишь признак использования модуля расширения, а его приписку к адресам памяти назначает POST.
Дополнительный модуль ROM BIOS должен иметь заголовок, выровненный по границе 2-килобайтной страницы памяти, формат заголовка ПЗУ иллюстрирует табл. 12.8.
Таблица 12.8. Заголовок модуля дополнительного ПЗУ
Смещение | Длина | Назначение |
0 | 2 | Сигнатура (признак начала модуля): байт 0=55h, байт 1=AAh |
2 | 1 | Длина, указанная в блоках по 512 байт |
3 | 3 | Точка входа процедуры инициализации, заканчивающейся дальним возвратом Ret Far (вызывается инструкцией Far Call во время POST). Обычно здесь располагается трехбайтная инструкция JMP, указывающая на начало процедуры |
6-17h | Резерв | |
18h | 2 | Указатель на структуру данных PCI (только для карт PCI), см. ниже п. 12.9.1 |
1Ah | 2 | Указатель на структуру расширенного заголовка карт ISA PnP, см. ниже п. 12.9.2 |
В традиционном заголовке присутствовали только первые 3 поля, указатели на структуры PCI и ISA PnP ввели позже. Корректным считается модуль, начинающийся с признака AA55h (значения слова с учетом порядка байтов) и нулевой суммой (по модулю 256) всех байтов в объявленной области (реальная длина модуля может превышать объявленную, но байт контрольной суммы, естественно, должен входить в объявленную область).
В случае обнаружения корректного модуля POST дальним вызовом (Call Far) вызывает процедуру инициализации модуля, начинающуюся с 3-го адреса заголовка модуля. Ответственность за ее корректность полностью ложится на разработчика. Процедура может переопределять векторы прерываний, обслуживаемых BIOS. Переопределив на себя Bootstrap (Int 19h), можно получить управление при загрузке, что и используется, например, для удаленной загрузки компьютеров через локальную сеть (Remote Boot Reset). Если стандартное продолжение процедуры загрузки не требуется, а дополнительный модуль представляет собой(например, управляющую программу для какого-либо оборудования, вместо процедуры инициализации в ПЗУ может находиться и основная программа, не возвращающая управление системной последовательности POST.
Процедура инициализации и программная поддержка устройства в ПЗУ должны быть написаны таким образом, чтобы им были безразличны абсолютные адреса, по которым они размещаются в пространстве памяти. На картах расширения, как правило, имеются аппаратные средства изменения базового адреса, а иногда и размера ПЗУ (джамперы или программно-управляемые переключатели). Это позволяет бесконфликтно разместить модули ПЗУ нескольких установленных карт.
По сравнению с традиционным способом использования ПЗУ, когда оно, будучи разрешенным, постоянно присутствует в области памяти, имеется более рациональный способ подключения расширений ROM BIOS, основанный на модели DDIM (Device Driver Initialization Model — модель инициализации драйвера устройств). POST определяет наличие ПЗУ по найденному заголовку и копирует его содержимое (по объявленной длине) в свободное пространство верхней памяти (ОЗУ), оставляя разрешенной запись в эту область. Далее в этой копии (в ОЗУ) вызывается процедура инициализации (по адресу 3). Эта процедура, написанная в соответствии с моделью DDIM, должна определить, каким образом ее запустили: традиционным (в ПЗУ) или в соответствии с DDIM (в ОЗУ). Определить это она может просто — попыткой модификации области ее «тела», которая в ПЗУ, естественно, не приведет к изменению содержимого памяти. Обнаружив режим DDIM (память модифицируема), процедура выполняет все необходимые действия по инициализации. Далее она определяет, какую часть копии (начиная от начала заголовка) требуется оставить в памяти на время загрузки и регулярной работы системы, отсекая не нужное в дальнейшем тело процедуры инициализации. Попутно она может в оставляемом модуле установить какие-либо параметры, требуемые для работы драйвера устройства. Наконец, она модифицирует поле длины в заголовке и контрольную сумму так, чтобы фрагмент модуля оставался корректным, и дальним возвратом отдает управление тесту POST. Теперь POST снова анализирует заголовок (но уже копии в ОЗУ) и запрещает запись в область ОЗУ (страницу с размером, кратным 4 К), которую «попросила» оставить процедура инициализации. Далее POST, по возможности, запрещает работу (отображение в область UMA) исходного модуля ПЗУ и продолжает свой путь к вызову процедуры начальной загрузки. Основное преимущество данного метода — возможность более рационального использования памяти в UMA (обычные ПЗУ «висят» в ней в полном объеме, невзирая на реальные потребности). Второе преимущество — возможность сохранения параметров, вычисляемых процедурой инициализации (она может задействовать параметры, полученные в процессе выполнения теста POST), в «замораживаемой» области памяти. Кроме того, как правило, медленные микросхемы ПЗУ на все время исполнения подменяются быстрым системным ОЗУ (не используя впрямую механизма теневой памяти). Процедура инициализации ПЗУ карт ISA с моделью DDIM должна проверять окружение, в котором она работает (см. выше); безусловная работа DDIM гарантируется только для карт PCI.
Для более эффективной работы DDIM желательно использовать не только стандартную, но и расширенную память (за пределами первого мегабайта), в то время как POST работает в реальном режиме процессора. Решить эту проблему помогает режим «Big Real Mode», который поддерживают все 32-разрядные процессоры (см. п. 12.3.1). Специально для предоставления доступа ко всей памяти процедурами инициализации фирмы Phoenics и Intel разработали спецификацию PMM (POST Memory Manager Specification), версия 1.01 была опубликована в конце 1997 г. Эта спецификация определяет несколько дополнительных сервисов BIOS, позволяющих выделять, находить и освобождать блоки в любой, в том числе и расширенной памяти. Клиенты этого сервиса запрашивают блок памяти требуемого размера, a BIOS возвращает физический 32-разрядный адрес начала выделяемого блока (если она способна его выделить). Клиент помечает свой блок 32-битным индексом (handle), по которому его в дальнейшем можно найти функцией поиска. Анонимный блок (индекс FFFFFFFFh) поиску не поддается. Этими сервисами можно пользоваться только до начала процедуры начальной загрузки (Int 19h), работу с вентилем Gate A20 они берут на себя. Перед начальной загрузкой BIOS освобождает и обнуляет все блоки расширенной памяти, занятые с помощью этих сервисов. Сервисами PMM могут пользоваться процедуры инициализации карт расширения, а также процедуры BCV, описанные в заголовке ПЗУ карт PnP (см. ниже). Процедуры, на которые указывает BEV, ими пользоваться не могут, поскольку вызываются после входа в Int 19h. Наличие сервисов PMM определяется по контрольной структуре, начинающейся со строки-сигнатуры $PMM и расположенной на границе параграфа в области E0000-FFFF0h. Программный интерфейс можно найти в вышеуказанном документе, который доступен на сайте http://www.phoenix.com/techs.
12.9.1. ROM BIOS карт ISA PnP
Для поддержки технологии PnP и расширения возможностей управления начальной загрузкой в спецификации PnP BIOS ввели дополнительный указатель на структуру расширенного заголовка (Expansion Header Structure). Расширенный заголовок имеет формат, приведенный в табл. 12.9. В одном ПЗУ может находиться несколько расширенных заголовков (это требуется для многофункциональных карт расширения), связанных в цепочку. В каждом расширенном заголовке может указываться смещение следующего заголовка относительно начала стандартного заголовка. Наличие и действительность расширенного заголовка проверяется по его сигнатуре и контрольной сумме. Сумма всех байтов расширенного заголовка, включая байт контрольной суммы, должна быть нулевой.
Таблица 12.9. Расширенный заголовок ROM BIOS карт ISA PnP
Смещение | Длина | Назначение |
0h | 4 байта | Сигнатура, строка $PnP (символы ASCII) |
04h | байт | Версия структуры (01h) |
05h | байт | Длина (в параграфах по 16 байт) |
06h | слово | Смещение следующего заголовка (0000h, если нет больше) |
08h | байт | Резерв(0) |
09h | байт | Контрольная сумма |
0Ah | двойное слово | Идентификатор устройства PnP |
0Eh | слово | Указатель на строку идентификатора производителя (0, если нет) |
10h | слово | Указатель на строку названия продукта (0, если нет) |
12h | 3 байт | Код типа устройства |
15h | байт | Индикаторы устройства |
16h | слово | Вектор подключения BCV (Boot Connection Vector) — 0, если нет |
18h | слово | Вектор отключения (Disconnect Vector) — 0, если нет |
1Ah | слово | Точка входа для загрузки BEV (Bootstrap Entry Point) — 0, если нет |
1Ch | слово | Резерв (0) |
1Eh | слово | Вектор получения информации о статических ресурсах (Static Resource Information Vector) — Real/Protected mode (0 если нет) |
Расширенный заголовок позволяет определить идентификатор устройства PnP, его название и код производителя. Код типа состоит из байта общего типа, байта подтипа и байта идентификатора программного интерфейса, по которым система может узнать знакомые устройства.
Байт индикаторов устройства имеет следующее назначение битов:
♦ бит 7 — ПЗУ поддерживает модель инициализации устройства (Device Driver Initialization Model);
♦ бит 6 — ПЗУ может затеняться оперативной памятью;
♦ бит 5 — ПЗУ может кэшироваться по чтению;
♦ бит 4 — ПЗУ требуется лишь для загрузки с данного устройства;
♦ бит 3 — резерв (0);
♦ бит 2 — является устройством загрузки (IPL-устройство);
♦ бит 1 — устройство ввода (может заменять клавиатуру);
♦ бит 0 — устройство вывода (дисплей).
Вектор подключения BCV (Boot Connection Vector, он же Interrupt Connection Vector) указывает смещение для процедуры, дальний вызов которой приведет к перехвату векторов прерываний первичных устройств ввода, вывода или загрузки (сервисов Int 9h, Int 10h или Int 13h соответственно), в зависимости от параметров, переданных в регистрах процессора. При вызове этой процедуры в регистре АХ единицы в битах 0, 1 и 2 запрашивают перехват сервисов Int 9h, Int 10h или Int 13h соответственно (остальные биты нулевые), ES:DI указывает на контрольную структуру PnP BIOS (System BIOS PnP Installation Check Structure), BX содержит селективный номер (CSN) карты ISA PnP (для других карт FFFFh); DX содержит адрес порта чтения ISA PnP (для других карт FFFFh).
Вектор отключения указывает на процедуру, восстанавливающую старое значение векторов при безуспешной попытке загрузки с данного устройства.
Точка входа для загрузки BEV требуется, если устройство может использоваться в качестве загрузочного, но не обеспечивает блочных функций сервиса Int 13h. Тогда системная микросхема BIOS может дальним вызовом вызвать эту процедуру вместо выполнения сервиса Int 19h. Таким образом, например, может выполняться удаленная загрузка (Remote Programm Loading, RPL) по сети.
Вектор получения информации о статических ресурсах задает смещение процедуры, вызов которой выгрузит в память дескрипторы занимаемых ресурсов (в форматах, аналогичных структурам для ISA PnP). Адрес буфера размером не менее 1024 байт задается регистрами ES: DI при вызове данной процедуры.
Процедура инициализации, которая начинается со смещения 3 в заголовке ПЗУ, для карт PnP должна подчиняться определенным требованиям (до этой спецификации специальных требований не было), принимать параметры и сообщать код возврата.
♦ При вызове процедуры ЕS: DI указывает на контрольную структуру PnP BIOS, BX содержит CSN карты ISA PnP (для других карт FFFFh); DX — адрес порта чтения ISA PnP (для других карт FFFFh).
♦ При исполнении процедура может переопределять любые векторы прерываний и изменять данные в BDA и EBDA, но перед возвратом она обязана восстановить прежние указатели для Int 9h, Int 10h, Int 13h и все прежние значения связанных с ними переменных в BDA и EBDA.
♦ При возврате в АХ возвращаются признаки проинициализированного устройства:
• бит 8 — устройство начальной загрузки, поддерживающее блочные функции INT 13h;
• бит 7 — устройство вывода, поддерживающее символьный вывод («телетайпный» режим) INT 10h;
• бит 6 — устройство ввода, поддерживающее символьный ввод INT 9h;
• биты 5:4 — состояние подключения загрузочного устройства: 00 — не подключено, 01 — неизвестно, 10 — подключено (для устройства RPL соединение установлено), 11 — резерв;
• биты 3:2 — состояние подключения устройства вывода (аналогично предыдущему);
• биты 1:0 — состояние подключения устройства ввода (аналогично предыдущему).
Как видно из данного описания, расширенный заголовок и правила поведения процедуры инициализации позволяют системной BIOS более гибко пользоваться функциями дополнительных модулей BIOS — традиционные дополнительные модули со стороны системной BIOS были практически неуправляемыми. Заголовок данного вида может использоваться и картами ISA без поддержки PnP. Если эти карты будут передавать информацию о своих статических ресурсах, они окажут большую услугу для распределения ресурсов системой BIOS с поддержкой PnP. Таким образом, приспособить карту для работы в среде PnP можно всего лишь модификацией содержимого ее ПЗУ расширения BIOS.
Карта ISA PnP может быть установлена в разные системы, имеющие BIOS как с поддержкой PnP, так и без. Процедура инициализации должна исполняться адекватно обнаруженной среде: без PnP BIOS она должна работать традиционным способом, при необходимости загрузки перехватывая INT 19h, а в среде PnP BIOS она должна вести себя скромнее, лишь предоставляя системной BIOS требуемые интерфейсы и точки входа.
12.9.2. Expansion ROM карт PCI
Для содержимого ПЗУ расширения BIOS, установленных на картах PCI, принят стандарт, несколько отличающийся от традиционных дополнительных модулей ROM BIOS. Заголовок ПЗУ соответствует традиционному, но дополнительно имеет указатель на структуру данных PCI (табл. 12.10). Идентификаторы производителя и устройства, а также код класса совпадают с описанными в конфигурационном пространстве устройства PCI. Поскольку шина PCI используется не только в PC, в ПЗУ карты может храниться несколько модулей. Каждый модуль начинается со структуры данных, сам модуль следует сразу за структурой. За ним начинается структура для следующего модуля (если у предыдущего не установлен признак последнего модуля) и так далее. Тип платформы (процессора) указывается в заголовке модуля, и при инициализации BIOS активизируется только нужный. Такой механизм позволяет, например, один и тот же графический адаптер устанавливать и в IBM PC, и в Power PC.
Таблица 12.10. Структура данных PCI
Смещение | Длина, байт | Назначение |
0 | 4 | Сигнатура, строка символов "PCIR" |
4 | 2 | Идентификатор производителя |
6 | 2 | Идентификатор устройства |
8 | 2 | Резерв¹ |
Ah | 2 | Длина структуры (байт), начиная с сигнатуры |
Ch | 1 | Версия структуры (0 для данной версии) |
Dh | 3 | Код класса |
10h | 2 | Длина образа |
12h | 2 | Версия кода/данных |
14h | 1 | Тип кода: 0 — х86 для PC-АТ, 2 — HP PA-RISC |
15h | 1 | Индикатор: 1 — последний образ, 0 — не последний |
16h | 2 | Резерв |
¹ До спецификации PCI 2.2 здесь помещался указатель на строку Vital Product Data (важные сведения о продукте).
Применительно к дополнительному ПЗУ карты PCI имеется три параметра, относящихся к размерам. Размер ПЗУ определяется чтением конфигурационного пространства. Размер, указанный во 2-м байте заголовка, указывает на длину модуля на этапе инициализации. Этот модуль POST загружает в ОЗУ перед тем, как вызвать процедуру инициализации (точка входа со смещением 3). Контрольная сумма, расположенная обычно в конце модуля, обеспечивает нулевую сумму всех байт. Длина образа, указанная в структуре данных PCI (слово со смещением 10h), описывает размер области, которая должна оставаться в памяти в режиме нормального функционирования (она может быть меньше, поскольку код процедуры инициализации уже не требуется). Эта область также защищается контрольной суммой. Структура данных PCI должна оставаться в памяти все время.
Работа с модулями ПЗУ для карт PCI выполняется в соответствии с моделью DDIM (см. выше). POST определяет наличие ПЗУ по полю Expansion ROM Base Address в конфигурационном пространстве и назначает ему адрес в свободном пространстве памяти. После этого программированием регистра команд разрешается считывание ПЗУ, и в нем ищется сигнатура заголовка АА55h. Когда сигнатура найдена, POST ищет подходящий образ (по типу кода и совпадающий по идентификаторам с обнаруженными устройствами PCI) и загружает его в ОЗУ (в область C0000-DFFFFh), оставляя разрешенной запись в эту область. Далее чтение ПЗУ запрещается (записью в поле Expansion ROM Base Address), и вызывается процедура инициализации (по адресу 3). При вызове процедуры POST сообщает номер шины (в регистре АН), номер устройства (AL[7:3]) и номер функции (AL[2:0]), благодаря чему процедура узнает точные координаты аппаратных средств. После этого определяется размер области, которую следует оставить в памяти (по байту 2, который может быть модифицирован процедурой инициализации), и для этой области запрещается запись. Если процедура инициализации «урезает» занимаемую память, она должна позаботиться о достоверности контрольной суммы области, описанной байтом 2. Если память освобождается полностью (процедура обнуляет байт 2), то контрольная сумма, естественно, не нужна. Расширение для VGA (определяется по коду класса) обрабатывается особым образом — загружается по адресу C0000h. Процедура инициализации может определить наличие PnP BIOS в системе, проверив значение контрольной структуры PnP по адресу, указанному в ES: DI, и исполняться в зависимости от обнаруженного системного окружения.