На сегодня, у многих специалистов, использование ACPI ассоциируется в первую очередь с функциями управления электропитанием и минимизацией энергопотребления. Вместе с тем, данная спецификация разработана как альтернатива устаревающему стандарту Plug and Play, и сферы ее применения значительно шире.
Спецификация ACPI содержит огромное количество определений, протоколов и форматов, поэтому в рамках одной статьи можно изложить только основные принципы ее функционирования. Для подробного изучения вопроса рекомендуется обратиться к документам [1], [2], [8]. Предлагаемый материал позиционируется как практический пример, интересный для специалистов, уже имеющих некоторые базовые знания в данной области. На уровне ассемблерных инструкций и схемотехники материнской платы рассматривается процедура программного выключения питания. К статье прилагаются также протоколы ручного дизассемблирования таблиц ACPI с подробными комментариями.
Как это работает?
Рассмотрим абстрактный пример. Пусть для выполнения заданного действия необходимо записать в регистр по адресу X данные Y. При использовании подхода, основанного на вызове сервисных процедур BIOS, в выполняемом блоке BIOS будет размещена процедура, которая осуществляет указанную запись. Задача операционной системы — просто вызвать эту процедуру. В данном случае, особенности реализации конкретного чипсета, если таковые имеются, скрыты внутри BIOS и не являются заботой разработчика ОС.
Второй вариант — ОС не обращается к BIOS и выполняет указанную запись самостоятельно. В этом случае, драйвер напрямую взаимодействует с регистрами чипсета, распознает и эффективно использует его возможности. Но расплата за это — усложнение и ограниченная совместимость. Как известно, под каждый чипсет нужен свой драйвер.
Разработчикам ACPI удалось придумать третий вариант. Численные значения X и Y, отражающие особенности реализации конкретной платформы, хранятся в специальных таблицах, которые генерирует BIOS при старте и размещает в оперативной памяти. Для этого, как правило, используется последний мегабайт верхней памяти. Операционная система находит и считывает эти параметры. Процедура записи в регистр по адресу X данных Y является частью ОС, а не BIOS, но параметры X и Y предоставляет BIOS посредством таблиц ACPI.
Какие преимущества это дает? Таблицы ACPI, в отличие от сервисных процедур BIOS, не содержат выполняемого кода, поэтому независимо от архитектуры процессора и режима его работы, можно использовать одни и те же таблицы. Чтобы оценить это преимущество, вспомним о неудобствах, связанных с тем, что большинство функций BIOS могут быть вызваны только в реальном режиме процессора (Real Mode). Функции, доступные в защищенном режиме (Protected Mode) должны иметь несколько точек входа (для Real Mode, Protected Mode 16, Protected Mode 32).
Так как процедура взаимодействия с оборудованием является частью ОС, для настройки на конкретную платформу, можно совместно использовать данные, полученные от BIOS (из таблиц ACPI) и данные, размещенные в драйвере при его разработке. Это дает дополнительную гибкость.
Таким образом, таблицы ACPI обеспечивают эффективное использование BIOS для информирования программного обеспечения об особенностях конкретной платформы. При этом отсутствуют неудобства, связанные с использованием сервисных процедур BIOS.
Таблицы и структуры ACPI
Операционная система, или программа, желающая воспользоваться интерфейсом ACPI, сначала должна выполнить его детектирование и определить расположение таблиц. Для этого, в области адресов выполняемого блока BIOS (E0000h-FFFFFh) необходимо найти структуру RSDP (Root System Description Pointer). Структура имеет размер 36 байт, может быть расположена в произвольном месте внутри указанного 128-Кбайтного блока и обнаруживается по последовательности символов «RSD PTR». Если структура не обнаружена или ее контрольная сумма неверна, детектирующая программа делает вывод, что ACPI не поддерживается. Если структура обнаружена и имеет правильную контрольную сумму, из нее считывается 32-битный адрес таблицы RSDT (Root System Description Table), содержащей каталог таблиц ACPI. В реализациях ACPI версии 2.0 и выше, доступен также 64-битный адрес таблицы XSDT (Extended System Description Table). Функции этой таблицы, такие же, как у таблицы RSDT, но за счет использования 64-битных указателей, таблица XSDT, а также таблицы, на которые она ссылается, могут быть расположены выше 4 Гб.
Ниже перечислены основные таблицы ACPI, полная номенклатура таблиц приведена в [1].
Таблица FADT (Fixed ACPI Description Table) содержит набор параметров, описывающих платформу и чипсет. ОС использует эти параметры при взаимодействии с оборудованием. Таблица FADT форматирована, то есть назначение каждого поля определяется его адресом внутри таблицы. Здесь содержатся константы, характеризующие платформу, адреса структур в оперативной памяти, используемых для взаимодействия BIOS и ОС, адреса регистров чипсета, используемых для передачи заданных команд (регистры управления) и опроса текущего состояния (регистры статуса), номера линий запросов на прерывание, используемых для оповещения ОС о заданных событиях в подсистеме ACPI и другая информация.
Структура FACS (Firmware ACPI Control Structure) используется для управления переходом в спящий режим и выходом из него. Она содержит вектор для передачи управления на процедуру, запускаемую при выходе из спящего режима. Также здесь находится 32-битная сигнатура оборудования или Hardware Signature, используемая для контроля изменений конфигурации, произошедших за время нахождения системы в спящем режиме, например удаления или подключения каких-либо устройств. Это переменная, вычисляемая как функция от текущей конфигурации оборудования. После выхода из спящего режима, значение этой переменной вычисляется повторно и сравнивается с образцом, хранящимся в структуре FACS.
Таблица DSDT (Differentiated System Description Table) является самой сложной. Она содержит описание методов выполнения типовых системных операций (например, считывание температуры процессора или изменение номера линии запроса на прерывание, используемой заданным устройством), информацию об устройствах, шинах, всех системных объектах и методах взаимодействия с ними. Декларации системных устройств (объекты System Plug and Play Nodes), также продублированы в этой таблице, при этом номенклатура описанных устройств существенно расширена. Таблица DSDT, в отличие от FADT, не форматирована, то есть доступ к заданной записи осуществляется не по фиксированному адресу, а последовательным сканированием и детектированием требуемой записи. Исходный код таблицы DSDT пишется программистом на языке ASL (ACPI Source Language), который преобразуется компилятором в код AML (ACPI Machine Language). Интерпретатор языка AML, входящий в состав операционной системы, обеспечивающий обработку DSDT, обычно называется виртуальной машиной ACPI.
Таблицы SSDT (Secondary System Description Table) используются как модули расширения таблицы DSDT. В системе может присутствовать несколько таблиц SSDT. Мотивация применения таблиц SSDT состоит в том, что отдельные порции AML кода (например, выбираемые в зависимости от типа установленного процессора или состояния BIOS Setup) удобно выделить в виде отдельных таблиц, а не размещать в главной таблице DSDT.
Таблица MADT (Multiple APIC Description Table) используется для информирования операционной системы о логических и физических процессорах и контроллерах прерываний I/O APIC (Input-Output Advanced Programmable Interrupt Controller). Подобно старой таблице MPT (Multiprocessing Table), расположенной в выполняемом блоке BIOS, таблица MADT содержит последовательность информационных структур, описывающих процессоры, контроллеры прерываний, а также соответствие между номерами линий запросов на прерывание и входами контроллеров прерываний. В большинстве систем, использующих технологию Hyper Threading, в таблице MPT декларированы только физические процессоры или ядра, а в таблице MADT перечислены все логические процессоры. Это дает операционной системе дополнительную возможность для распознавания типа мультипроцессорной системы.
Первые 36 байт каждой таблицы образуют заголовок, назначение полей которого одинаково для всех таблиц. Далее следует основной блок, это информация, структура которой определяется типом таблицы. Полная номенклатура и детальное описание всех таблиц и структур, а также формат указателя RSDP приводится в [1].
Протоколы дизассемблирования таблиц ACPI
В прилагаемом каталоге DISASM содержатся протоколы ручного дизассемблирования некоторых таблиц ACPI и их фрагментов с детальными комментариями (текстовые файлы в кодировке DOS). Разумеется, существует возможность для автоматизированного выполнения этой задачи, например, дизассемблер фирмы Phoenix Technologies — AD.EXE (ACPI Dump). Вместе с тем, для получения некоторых сведений, необходимых для написания собственной виртуальной машины ACPI и других исследовательских работ, автор посчитал уместным «копнуть глубже», несмотря на очевидную трудоемкость данного подхода.
Примечание. В комментариях к дизассемблированным таблицам ACPI, используются ссылки на страницы и пункты документов, указанных в файле README.TXT. Для того чтобы ссылки оставались верными, необходимо использовать именно те версии документов, которые указаны. Например, вместо доступной на сегодня спецификации ACPI 3.0 (документ [1]), во время выполнения данных работ использовалась спецификация ACPI 2.0.
Описание работы программы
Как и в ранее опубликованных статьях данного цикла, в целях монопольного и беспрепятственного взаимодействия программы с оборудованием, автор применил древнюю технологию отладки под DOS. Аргументация такого шага и рекомендации по организации рабочего места приведены в ранее опубликованной статье «64-битный режим под DOS: исследовательская работа №1».
В качестве примера взаимодействия с оборудованием посредством интерфейса ACPI, рассмотрена процедура программного выключения питания компьютера (для систем с блоком питания ATX).
Предлагаемый пример является полуфабрикатом, и совместим не со всеми реализациями таблиц DSDT. Текущая версия программы способна находить объекты _S5, только в таких реализациях, где указанные объекты расположены в начале таблицы DSDT. Для универсального решения такой задачи, необходима полноценная реализация виртуальной машины ACPI, так как чтобы добраться до объекта _S5, потребуется интерпретировать AML код, расположенный до требуемого объекта. В случае несовместимости выдается сообщение Incompatible version of AML code.
На базе данного примера, заинтересованный читатель может самостоятельно реализовать полнофункциональную виртуальную машину ACPI. Автор также ведет работы в данном направлении и при наличии читательского интереса, планирует представить такую разработку в последующих публикациях.
Прилагаемый каталог WORK содержит следующие файлы:

Рассмотрим выполнение основного модуля. Нумерация пунктов данного описания соответствует нумерации пунктов комментариев в исходном тексте - файле WORK\atx_off.asm.
- Устанавливаем адрес стека.
- Выводим сообщение о начале выполнения программы.
- Проверяем режим работы процессора. Данная программа требует Real Mode, так как взаимодействует с оборудованием. Если процессор в Protected Mode, выходим с сообщением об ошибке.
- Разрешаем адресную линию A20 и включаем Big Real Mode. Эти действия необходимы, так как таблицы ACPI расположены выше 1 MB.
- Детектируем поддержку ACPI. Подпрограмма Scan_ACPI_RSDP сканирует 128-Кбайтный блок E0000h-FFFFFh на предмет обнаружения сигнатуры - последовательности символов «RSD PTR», с которой начинается структура RSDP. Если сигнатура найдена и контрольная сумма RSDP верна, из RSDP считывается 32-битный адрес таблицы RSDT, содержащей каталог таблиц ACPI. Иначе, выходим с сообщением об ошибке. Далее, используя подпрограмму Get_ACPI_Table, находим таблицу FADT по сигнатуре "FACP". Из таблицы FADT, по фиксированным адресам считываем адреса портов для регистров управления контроллера Power Management: PM1a_CNT_BLK и PM1b_CNT_BLK (Power Management Control Blocks). Использование этих регистров описано в пункте 7. Сохраняем прочитанные значения.
- Используя подпрограмму Get_ACPI_Table, находим таблицу DSDT по сигнатуре «DSDT». Используя подпрограмму Scan_AML_Name, находим в таблице DSDT декларацию объекта NAME содержащего имя _S5. Этот объект содержит значения S5a_Value, S5b_Value, использование которых описано в пункте 7. Сохраняем значения, полученные при интерпретации содержимого объекта.
Стандартное для ACPI имя переменной _S5, используемой в процедуре выключения питания, обусловлено тем, что дежурный режим, при котором на блок питания ATX подается напряжение сети, но система выключена (блок питания выдает только напряжение +5V Standby и сигнал PS_ON=1) классифицируется спецификацией ACPI как состояние S5=Soft-Off.
- Выполняем запись заданных значений в заданные порты, что приводит к выключению питания (переводу сигнала PS_ON в состояние логической «1»). Предварительно выводим дамп значений, полученных на шагах 5 и 6. Считываем порт PM1a_CNT_BLK, в прочитанном значении, бит 13 (Sleep Enable) устанавливаем в «1», биты 12-10 (поле Sleep Type) устанавливаем в состояние, равное содержимому объекта S5a_Value, остальные биты не изменяем. Значение, с модифицированными битами 13-10 записываем обратно в порт PM1a_CNT_BLK. Считываем порт PM1b_CNT_BLK, в прочитанном значении, бит 13 (Sleep Enable) устанавливаем в «1», биты 12-10 (поле Sleep Type) устанавливаем в состояние, равное содержимому объекта S5b_Value, остальные биты не изменяем. Значение, с модифицированными битами 13-10 записываем обратно в порт PM1b_CNT_BLK. После задержки, связанной с прохождением сигналов через Power Management контроллер, питание должно выключиться. Запрещаем прерывания и останавливаем процессор. В типовой платформе, инструкции CLI и HLT, расположенные после процедуры записи регистров, успеют выполниться до выключения питания, так как существует задержка срабатывания контроллера Power Management и инерционность блока питания. Вместе с тем, вариант, при котором питание выключится раньше, также допускается.
Использование двух портов управления PM1a_CNT_BLK и PM1b_CNT_BLK обусловлено тем, что спецификация ACPI поддерживает описание нетипичных платформ, у которых для выключения питания требуется выполнить запись в два порта, имеющие различные адреса и физически расположенные в разных микросхемах (Северном и Южном мостах чипсета). В типичной платформе такая возможность избыточна, так как для рассматриваемого действия достаточно записи в один порт, расположенный в составе Южного моста чипсета. При этом переменная PM1a_CNT_BLK содержит адрес этого порта, а переменная PM1b_CNT_BLK содержит нуль, что соответствует отсутствию порта. Программа, выполняющая запись значений в указанные регистры, пропускает операцию записи, если адрес нулевой.
- Сюда передается управление, если требуется аварийное завершение программы после того, как разрешена линия A20 и включен режим Big Real Mode. Восстанавливаем состояние линии A20, выключаем режим Big Real Mode и переходим к пункту 9 для выхода из программы.
- Выход из программы с генерацией сообщения об ошибке.
Управление блоком питания ATX
Рассмотрим процессы, происходящие при выполнении вышеописанной программы, на уровне принципиальной электрической схемы. Разумеется, в каждой материнской плате, в зависимости от модели чипсета, микросхемы MIO (Multi Input/Output) и других факторов, рассматриваемый узел реализован по-своему.

Для определенности возьмем частный случай - материнские платы, использующие Южный мост Intel ICH6, описанный в [6] (это платы на чипсетах Intel 915 и 925) и микросхему MIO Winbond W83627THF, описанную в [12].

Ядро Power Management контроллера, а именно, логика, принимающая решение о включении и выключении питания находится в составе Южного моста чипсета. Здесь же расположен программно-доступный регистр PM1_CNT_BLK, используемый в приведенном примере для выключения питания. Обеспечение интерфейса Power Management контроллера с внешним миром входит в обязанности микросхемы MIO. В ее составе находится схема опроса кнопки Power Switch, которая, получив сигнал от кнопки, транслирует его Power Management контроллеру (ICH6). Также в составе MIO находится формирователь сигнала PS_ON для блока питания ATX. При получении соответствующего приказа от ICH6, микросхема MIO выдает сигнал PS_ON=0, что приводит к включению блока питания.

Что происходит при выполнении нашей программы? Запись в регистр PM1_CNT_BLK 16-битного слова, у которого бит 13 (Sleep Enable) установлен в «1», а значение битового поля Sleep_Type соответствует ACPI-состоянию S5 (состояние Soft-Off) является приказом для ICH6 начать процедуру выключения питания. ICH6 выдает сигнал SLP_S3# (контакт с координатами T4). Он приходит на вход SLP_Sx (контакт 73) микросхемы MIO W83627THF. В результате микросхема W83627THF выдает логическую «1» на выход PWCTL# (контакт 72) и блок питания выключается. Этот выход подключен к линии PS_ON блока питания. В зависимости от схемотехники платы, подключение выполняется напрямую или через буферный повторитель.
Другие примеры реализаций микросхем Южных мостов и MIO приведены в [7], [9], [10], [11], [13].
При рассмотрении работы блока питания, не следует путать сигналы PS_ON и PWR_OK. Сигнал PS_ON (Power Supply On) используется для включения блока питания ATX. Это входной сигнал для блока питания и выходной сигнал для материнской платы. При логическом «1» на этой линии, блок питания выключен (работает только дежурный источник +5V Standby, необходимый для схемы управления питанием). При логическом «0» на этой линии блок питания включен, выдаются все выходные напряжения. Сигнал PWR_OK (Power OK, синоним Power Good) используется для запуска материнской платы при включении питания и блокировки работы ее устройств на время переходных процессов при включении и выключении питания. Это входной сигнал для материнской платы и выходной сигнал для блока питания. Логический «0» на этой линии равносилен нажатию кнопки RESET. При этом все устройства зафиксированы в состоянии сброса. При включении питания, в течение нескольких миллисекунд, сигнал PWR_OK=0, это обеспечивает запуск компьютера и препятствует выполнению каких-либо операций до стабилизации питания. При выключении питания, во время переходного процесса, сигнал PWR_OK также переходит в состояние логического «0». Во время рабочего сеанса на этой линии присутствует логическая «1». Подробности в [3], [4].
Источники информации
Электронные документы, доступные на сайте ACPI
- Advanced Configuration and Power Interface Specification. Revision 3.0
Электронные документы, доступные на сайте Intel
- Instantly Available Power Managed Desktop PC Design Guide. Revision 1.1
- ATX Specification. Version 2.03
- ATX / ATX12V Power Supply Design Guide. Version 1.0 (Public Release)
- ATX Balanced Technology Extended (BTX) Interface Specification. Version 1.0
- Intel I/O Controller Hub 6 (ICH6) Family Datasheet. Document Number 301473-001
- Intel I/O Controller Hub 7 (ICH7) Family Datasheet. Document Number 307013-002
Электронные документы, доступные на сайте AMD
- Open Platform Management Architecture Specification. Publication # 32200
- AMD-8111 HyperTransport I/O Hub Data Sheet. Publication # 24674
Электронные документы, доступные на сайте datasheetarchive.com
- VIA VT82C686A South Bridge Datasheet. Revision 1.54
- VIA VT82C686B South Bridge Datasheet. Revision 1.71
Электронные документы, доступные на сайте Winbond
- Winbond LPC I/O W83627THF
Электронные документы, доступные на сайте ITE
- IT8712F Environment Control - Low Pin Count Input/Output (EC-LPC I/O)
Загрузить ZIP-архив
с примером программирования
на ассемблере
можно здесь.