NMI немаскируемое прерывание это последний рубеж связи с процессором, когда вся остальная система прерываний уже нема. Обычные аппаратные запросы IRQ проходят через контроллер прерываний, их можно маскировать по одному или гасить все разом инструкцией cli, сбрасывающей флаг IF в регистре EFLAGS. NMI этой дисциплины не признаёт: линия заводится на процессор напрямую, вне маршрутизации APIC, и доставляется всегда, в том числе когда IF равен нулю и код ядра находится в критической секции со снятыми прерываниями. Именно поэтому NMI называют аварийной кнопкой паники в железе: когда операционная система глуха ко всему, этот сигнал всё равно пробивается внутрь и заставляет процессор перейти на вектор номер два таблицы IDT. Системный архитектор относится к NMI как к пожарному извещателю: он не участвует в обычной жизни здания, но когда срабатывает, вопрос уже не о комфорте, а о том, уцелеет ли конструкция.

Отличие NMI от обычных запросов IRQ на уровне железа

Обычный IRQ рождается в устройстве, попадает на контроллер прерываний, там маскируется, приоритизируется и перенаправляется процессору, который волен отложить обслуживание, пока флаг IF сброшен. Устройство копит запрос, драйвер до него доберётся, когда планировщик позволит. Такая архитектура даёт ядру управляемость: можно запретить прерывания на время обхода списка страниц, можно поднять IRQL и вытеснить низкоприоритетные источники. Цена управляемости в том, что система умеет молчать. Если ядро ушло в бесконечный цикл с запрещёнными прерываниями, ни клавиатура, ни сетевой адаптер, ни таймер не способны прервать затвор.

NMI устроен принципиально иначе. Сигнал идёт по выделенной линии мимо контроллера, и логика маскирования его не касается. Процессор принимает NMI по фронту, причём само ядро выставляет внутренний запрет только на время обработки первого NMI, чтобы избежать вложенного входа, и снимает его инструкцией iret. Точка входа фиксирована: вектор два, обработчик ядра. Никакой драйвер не может его перехватить на пользовательском уровне, никакой антивирус не встанет в цепочку раньше ядра. Это и делает NMI честным механизмом: его путь короче всех остальных, он не зависит от состояния шины контроллера прерываний и не требует, чтобы ОС была в добром здравии.

Второе отличие в семантике. IRQ сообщает: "устройство просит обслуживания". NMI сообщает: "произошло нечто, что нельзя игнорировать ни тактовом цикле дольше". Поэтому содержимое обычного прерывания всегда связано с драйвером устройства, а содержимое NMI почти всегда связано с целостностью системы целиком.

Источники NMI от сторожевого таймера до кнопки на передней панели

На серверном железе источников NMI накопилось несколько, и все они объединены одним свойством: это сигналы о состояниях, при которых продолжать работу опаснее, чем остановиться. Первый классический источник это машинные проверки. Machine Check Exception технически имеет собственный вектор восемнадцать, но контроллеры наблюдения за ошибками памяти и инфраструктура MCA на некоторых платформах маршрутизируют фатальные события через линию NMI, особенно когда требуется разбудить все ядра одновременно. Некорректируемая ошибка ECC, повреждение данных на шине, отказ кэш-контроллера это те события, при которых железо кричит через NMI.

Второй источник это сторожевой таймер. Аппаратный watchdog это независимый счётчик на материнской плате или в BMC, который ОС обязана периодически перезапускать. Если система зависла и перестала обслуживать таймер, счётчик дотикает до нуля и платформа выдаёт NMI либо холодный сброс, в зависимости от настройки. Таймер не верит никаким программным заверениям, что система жива: он верит только регулярному стуку.

Третий источник это физическая кнопка NMI, которая присутствует на серверных шасси, иногда спрятанная под скрепку. Нажатие замыкает линию, и платформа генерирует NMI на все процессоры. Это осознанное решение производителей: дать инженеру в дата-центре инструмент принудительного вмешательства в зависшую машину, не выдёргивая питание.

Четвёртый источник это удалённая инициация через IPMI. Команда контроллеру управления платой может поднять NMI по сети, без физического доступа к стойке. Инженер сидит за сотни километров, система не отвечает ни на консоль, ни на сетевой стек, но BMC живёт отдельной жизнью на собственном питании и выполняет приказ диагностировать:

  1. убедиться, что система действительно не отвечает на обычные каналы;
  2. проверить, что дамп памяти настроен и целевой том доступен;
  3. отправить NMI через интерфейс управления платой;
  4. дождаться завершения записи аварийного дампа;
  5. перезагрузить машину и передать дамп аналитикам.

Каждый из этих источников по сути говорит одно и то же: наступила ситуация, в которой надёжнее остановиться, чем доверять дальнейшему выполнению.

Поведение ядра при входе в обработчик NMI

Когда процессор принимает NMI, выполнение текущей инструкции завершается, состояние сохраняется на стек, и управление передаётся обработчику вектора два. Это происходит немедленно, вне очередей и планировщиков. Ядро в обработчике NMI работает в жёстких ограничениях: нельзя обращаться к страничной памяти, которая может быть выгружена, нельзя захватывать большинство спин-блокировок, нельзя вызывать процедуры, способные уснуть. Контекст непредсказуем: NMI мог настичь систему где угодно, вплоть до середины переключения контекста. Поэтому обработчик пишут коротким, оборонительным, опирающимся только на резидентную память.

В Windows классическое назначение NMI это немедленный аварийный останов. Традиционный путь ведёт к bugcheck с кодом NMI_HARDWARE_FAILURE, шестнадцатеричное значение 0x80, которое читается как сто двадцать восемь в десятичной записи. Ядро гасит остальные процессоры, собирает минимальный контекст, рисует синий экран и пишет дамп памяти на сконфигурированный том. С точки зрения операционной системы это не сбой, а исполнение протокола безопасности: причина, по которой NMI пришёл, обычно означает, что данным в памяти больше нельзя доверять.

На Linux поведение гибче: вектор два обслуживает цепочка зарегистрированных обработчиков, и NMI используется не только для паники, но и для рабочих механизмов вроде perf-профилирования, где таймер производительности бьёт через NMI, чтобы сэмплировать стеки даже в критических секциях. Но и там некорректируемая аппаратная ошибка завершается паникой ядра по той же логике честной остановки.

Bugcheck 0x80 и настройка CrashOnNMI для тестирования зависаний

Серверные инженеры давно приручили NMI как диагностический инструмент. Классическая задача выглядит так: продакшн-серверWindows "висит", консоль чёрная, сеть молчит, но блок питания работает, и виноват явно софт, а не железо. Обычные средства диагностики бессильны, потому что все они работают поверх IRQ, а система глуха к IRQ. Решение это намеренная инициация NMI, чтобы ядро само выронило дамп памяти зависшего состояния.

Для этого в реестре Windows существует параметр CrashOnNMI в ветви параметров аварийного управления памятью, значение один включает реакцию на немаскируемое прерывание. В сочетании с настроенным полным или ядерным дампом и доступным файлом подкачки это превращает кнопку NMI или команду IPMI в дистанционный спуск дампа. Сценарий применения отработан годами: система зависла, инженер через интерфейс управления платой посылает NMI, ядро входит в обработчик, усредняет регистры всех процессоров, формирует bugcheck, пишет дамп и перезагружается. После загрузки дамп уходит в анализ стеков, и в нём видно, какой драйвер крутился в цикле со сброшенным IF, какой спин-лок был захвачен и кем.

Без CrashOnNMI тот же NMI на современных Windows может быть поглощён платформой как событие сторожевого таймера без остановки, и драгоценное состояние зависания исчезнет при следующей перезагрузке питанием. Поэтому на серверах, где зависания регулярны и требуют разбора, параметр включают заранее, до инцидента, а не во время него.

Диагностика зависшего живого сервера через NMI

Особая ценность NMI обнаруживается в пограничном состоянии, когда сервер формально жив, а фактически мёртв. Вентиляторы шумят, сетевые индикаторы мигают, BMC рапортует, что питание в норме, но ОС не отвечает ни на что. Такое зависание почти всегда означает, что ядро ушло в состояние с запрещёнными прерываниями: бесконечный цикл на спин-блокировке на высоком IRQL, взаимная блокировка в ядре, драйвер, который забыл выйти из критической секции. Все обычные механизмы опроса работают через IRQ и потому немы.

NMI пробивает эту немоту, потому что ему не нужен ни контроллер прерываний, ни флаг IF, ни планировщик. Сигнал доходит до каждого ядра, обработчик фиксирует регистры и стеки, и дамп показывает точный кадр зависания: на каком адресе крутится каждый процессор текущий, какие потоки ждут какие объекты, какой драйвер владеет блокировкой. Это единственный неразрушающий способ получить посмертную фотографию зависания: перезагрузка кнопкой питания стирает всё, а NMI останавливает систему, сохраняя улику.

Инженеры ценят и вторичное свойство: через NMI можно проверить сам диагностический контур. Если после нажатия кнопки дамп не появился, значит, что-то сломано в цепочке BMC, настройках дампа или файле подкачки, и это лучше узнать в тесте, чем в час ночи на боевом инциденте.

История NMI от ошибок чётности PC XT до Machine Check Architecture

Родословная NMI восходит к первым персональным компьютерам. На IBM PC XT немаскируемое прерывание обслуживало ошибку чётности памяти: каждый байт DRAM сопровождался девятым битом чётности, и контроллер памяти при несовпадении поднимал NMI. Пользователь видел печальное сообщение об ошибке чётности, и машина останавливалась. Логика была безжалостной и правильной: если память возвращает не то, что в неё записали, любое дальнейшее вычисление отравлено.

Современные машины развили эту идею в Machine Check Architecture. Процессор содержит банки машинных проверок, регистры фиксируют адрес, тип и источник ошибки, а ошибки делятся на скорректированные и некорректируемые. Скорректированная ошибка ECC исправлена ещё в контроллере памяти, ОС получает о ней уведомление через corrected machine check interrupt, обычный прерывание, и просто журналирует событие. Некорректируемая ошибка это тот случай, когда данные потеряны безвозвратно, и тогда включается тяжёлая артиллерия вплоть до NMI на все ядра.

В Windows вся эта телеметрия собирается инфраструктурой WHEA, и инженер видит в журнале событий записи об аппаратных ошибках с указанием банка, статусного регистра и типа источника. Регулярные скорректированные ошибки на одном модуле DIMM это ранний сигнал его деградации: система ещё работает, но разумный администратор уже заказывает замену. Журналы WHEA превратили то, что на PC XT было одним смертным приговором, в градуированную систему наблюдения за здоровьем железа.

Почему синий экран от NMI защищает целостность памяти и когда включать CrashOnNMI

Взгляд непосвящённого видит в синем экране после NMI отказ системы. Взгляд архитектора видит в нём выполнение контракта целостности. Если NMI пришёл от некорректируемой ошибки памяти, то какая-то область ОЗУ уже содержит искажённые данные, и процессор мог успеть их прочитать, оперировать ими и разнести яд dismiss дальше по структурам ядра, страницам БД, буферам диска. Продолжать работу означает тихо портить данные, возможно необратимо, возможно в финансовых записях или медицинских системах. Остановиться честнее: bugcheck фиксирует состояние, дамп рассказывает причину, перезагрузка возвращает машину в чистое состояние. Потеря минут простоя есть плата за гарантию, что система никогда не работала на битых данных.

Практические советы по CrashOnNMI строятся на простом балансе. Включать параметр стоит на продакшн-серверах, где диагностируются периодические зависания и требуется снимать дамп удалённо, через IPMI или кнопку на корпусе. Включать его стоит на эталонных стендах и в стресс-лабораториях, где зависание это ожидаемый исход эксперимента. Обязательное условие это настроенный и проверенный дамп памяти: целевой том с достаточным местом, корректный файл подкачки, автоматическая перезагрузка. Не стоит включать CrashOnNMI на площадках, где доступ к BMC не контролируется строго, потому что любой, кто может послать NMI, может уронить машину. И не стоит забывать выключать тестовый контур после завершения расследования, если политика площадки этого требует.

NMI остаётся одним из немногих механизмов x86, который за сорок лет не потерял смысла. От девятибитной памяти PC XT до банков машинных проверок серверных процессоров идея неизменна: у системы должна быть линия, по которой железо может сказать правду в лицо, минуя все фильтры. Инженер, который понимает NMI, получает в руки инструмент честной остановки, точной диагностики и гарантии целостности, и это редкое сочетание делает немаскируемое прерывание обязательной частью профессии.