Когда мой ноутбук начал показывать некорректный заряд батареи после обновления Windows 11, я столкнулся с необходимостью глубокого погружения в мир ACPI. Проблема оказалась в несовместимости таблиц BIOS с новыми механизмами управления питанием. Решение потребовало использования специализированных инструментов и понимания внутренней работы ACPI в ядре Windows.

Архитектура ACPI и роль драйвера Acpi.sys

В основе управления питанием Windows лежит драйвер Acpi.sys, который выступает виртуальной машиной для интерпретации AML кода. Этот драйвер загружается ядром при старте системы и парсит фиксированные таблицы RSDT (Root System Description Table) или XSDT (Extended System Description Table). Через эти таблицы система находит указатели на DSDT и множественные SSDT таблицы, содержащие описания устройств и методов управления ими.

Особенность Windows в том, что она требует строгого соответствия спецификации ACPI версии 6.5 для корректной работы батарей. Каждый аккумулятор должен иметь HID PNP0C0A для control method батарей или ACPI0002 для Smart Battery Subsystems. Источники питания описываются через HID ACPI0003 с обязательным методом _PSR для определения наличия внешнего питания.

Я обнаружил, что многие производители ноутбуков, особенно ASUS в моделях ROG Strix, допускают ошибки в реализации методов ECLV(), добавляя функции Sleep() в прерываниях. Это вызывает характерные латентные спайки и проблемы с GPU power cycles. Исправление требует не только правки DSDT, но и понимания работы EmbeddedControl регионов.

Инструментарий для парсинга и декомпиляции

Для работы с ACPI таблицами я использую комплект утилит Intel ACPICA и Microsoft ASL Compiler из Windows Driver Kit. Процесс начинается с извлечения таблиц из системы:

acpidump -b

Эта команда создает файл acpi.dat со всеми таблицами в бинарном виде. Далее использую acpixtract для разделения:

acpixtract -a acpi.dat

Получаю отдельные файлы DSDT.dat, SSDT1.dat и другие. Для декомпиляции в читаемый ASL применяю Intel iASL:

iasl -d DSDT.dat

Microsoft компилятор имеет свой синтаксис:

asl /u DSDT.AML

Он создает исходный .ASL файл, но отличается большей лояльностью к ошибкам по сравнению с Intel версией. Это часто приводит к ситуации, когда код компилируется в Microsoft ASL, но не проходит проверку в iASL.

Отладка через WinDbg и AMLI Debugger

Настройка отладки ACPI требует включения специальных параметров в загрузчике Windows. Сначала активирую режим отладки:

bcdedit /debug {default} on
bcdedit /set {default} nx autoenable

После перезагрузки подключаюсь через WinDbg и использую специализированные расширения. Команда !acpicache выводит список всех ACPI таблиц, закешированных HAL. Команда !acpiinf показывает конфигурацию ACPI включая местоположение системных таблиц. Для просмотра RSDT использую !rsdt, а полный список расширений доступен через !acpikd.help.

При возникновении AML брейкпоинтов система может перейти в AMLI режим в проверяемых сборках Windows. Это позволяет построчно просматривать выполнение AML кода и модифицировать переменные прямо в процессе исполнения. Такая возможность критична при отладке сложных проблем с батареями.

Типичные проблемы батарей и их диагностика

Наиболее распространенная проблема, с которой я сталкивался, это исчезновение драйвера Microsoft ACPI-Compliant Control Method Battery из диспетчера устройств. Без этого драйвера Windows не может общаться с контроллером батареи. Решение часто простое: удалить драйвер через диспетчер устройств и выполнить поиск изменений оборудования. Windows переустановит ACPI драйвер автоматически.

Более сложные случаи требуют анализа методов _BST (Battery Status) и _BIF или _BIX (Battery Information Extended). В одном из проектов я обнаружил, что методы возвращают жестко закодированные значения вместо реальных данных от контроллера. Код выглядел примерно так:

Method (_BST, 0, NotSerialized)
{
    Return (Package() {0x00, 0x1000, 0x1000, 0x0BB8})
}

Вместо обращения к EmbeddedControl для получения актуальных данных. После исправления метод стал корректно читать регистры EC:

Method (_BST, 0, NotSerialized)
{
    Store (B1ST, Local0)
    Store (B1CR, Local1)
    Store (B1RC, Local2)
    Store (B1VT, Local3)
    Return (Package() {Local0, Local1, Local2, Local3})
}

Редактирование DSDT и распространенные ошибки

При правке DSDT часто встречаюсь с ошибкой 4105 Invalid object type for reserved name. Метод _PLD должен возвращать Package, а не Buffer напрямую. Исправление выглядит так:

// Было:
Name (_PLD, Buffer (0x10) { ... })

// Стало:
Name (_PLD, Package() { Buffer (0x10) { ... } })

Аналогичные правки требуются для методов _CRS, _PRT и других зарезервированных имен. Каждый имеет свои требования к типу возвращаемых данных согласно спецификации ACPI.

Критически важно увеличивать OEMRevision в DefinitionBlock после любых изменений. Если оставить прежнее значение, ядро Windows может проигнорировать модифицированную таблицу:

DefinitionBlock ("DSDT.aml", "DSDT", 2, "VENDOR", "MODEL", 0x00000001)

Для мультибатарейных систем добавляю метод _SBS для объявления количества батарей и проверяю, что _PCL корректно перечисляет все потребители энергии. В ноутбуках с Smart Battery часто требуется валидация SMBus адресов, где 0x0B используется для батареи, а протокол AttribWord для чтения данных.

Компиляция и загрузка модифицированных таблиц

После внесения правок компилирую ASL обратно в AML используя разные флаги в зависимости от цели:

iasl -sa DSDT.dsl  // генерирует .aml файл
iasl -tc DSDT.dsl  // создает .aml и .hex для включения в ядро

Для тестирования использую acpiexec, который загружает таблицу в пользовательский интерпретатор:

acpiexec DSDT.aml
evaluate _SB.BAT0._BST

Это позволяет проверить работу методов без риска повредить систему. Если метод _STA возвращает 0x0F, устройство считается присутствующим и функционирующим.

В Windows загрузка кастомных таблиц возможна через registry override используя команду:

asl /loadtable your.aml

Но это требует совпадения сигнатуры таблицы, отключенного SecureBoot и включенного test mode. Без выполнения этих условий Windows откажется загружать модифицированную таблицу.

Практические кейсы и решения

В моей практике был случай с Dell Inspiron, где после обновления Windows 11 батарея застряла на 55% и не заряжалась. Проблема решилась переустановкой драйвера батареи, но анализ DSDT показал некорректную реализацию метода _BTP (Battery Trip Point), который не генерировал SCI события при низком заряде.

Для ноутбуков Lenovo часто встречаю проблему с неправильным кодированием информации батареи в методах _BIF. Инженер Richard Hughes описывал похожий случай, где пришлось переписывать методы для реального обращения к контроллеру батареи через EC вместо использования статических значений.

При работе с ASUS ROG требуется особое внимание к методу ECLV(). Удаление Sleep() из прерываний и добавление MUX проверок предотвращает циклы переключения питания GPU. Также важно реализовать метод _BMC для калибровки батареи с возможностью разряда при подключенном питании.

Для отладки латентных проблем использую ETW трacing через logman или firescope для удаленного логирования. При зависаниях ядра netconsole захватывает вывод отладки. Добавление Printf в ASL код помогает точно определить место возникновения проблемы.

Работа с ACPI таблицами требует методичного подхода и глубокого понимания спецификации. Всегда создаю резервные копии оригинальных таблиц и документирую каждое изменение. Помню, что неправильные модификации могут привести к невозможности загрузки системы, поэтому держу под рукой загрузочную флешку и план восстановления.

Мой опыт показывает, что большинство проблем с батареями в Windows решаются без правки DSDT. Но когда стандартные методы не помогают, умение работать с ACPI таблицами становится незаменимым инструментом. Главное подходить к процессу системно, тестировать каждое изменение в эмуляторе и всегда иметь путь отката.