Как отправить NMI на той же системе - PullRequest
1 голос
/ 15 сентября 2011

Мне нужно отправить nmi в систему, над которой я работаю. Я хочу протестировать несколько вещей, которые я реализовал. Есть ли какая-нибудь программа для работы с Windows, которая позволяет нам это делать? Я думаю, что могу написать в порт, используя __outword. Есть ли другой способ сделать это?

У меня есть еще один вопрос. Существуют ли какие-либо конкретные сценарии, которые вызывают NMI? (Тем не менее, я не хочу, чтобы система BSOD или тройной сбой.)

Спасибо

1 Ответ

4 голосов
/ 15 сентября 2011

Из Руководство по разработке программного обеспечения Intel: Руководство по системному программированию :

Немаскируемое прерывание (NMI) может быть сгенерировано двумя способами:

  • Внешнее оборудование поддерживает вывод NMI.
  • Процессор получает сообщение на системной шине (процессоры Pentium 4, Intel Core Duo, Intel Core 2, Intel Atom и Intel Xeon) или последовательной шине APIC (Семейство P6 и процессоры Pentium) с режимом доставки NMI.

и

Возможно выдать маскируемое аппаратное прерывание (через вывод INTR) длявектор 2 для вызова обработчика прерываний NMI;однако это прерывание не будет действительно прерыванием NMI.Истинное прерывание NMI, которое активирует аппаратные средства обработки NMI процессоров, может быть доставлено только через один из перечисленных выше механизмов.

Итак, если все, что вы хотите сделать, это запустить обработчик NMI, вы можете простоиспользуйте int $2 (int 02h в синтаксисе Intel).Но если вам необходимо убедиться, что он не маскируется, вам потребуется либо внешнее оборудование для его запуска, либо использование APIC.


Если вы решите использовать APIC для отправки NMI,Самый простой способ сделать это - послать межпроцессорное прерывание.Для этого вам потребуется доступ к локальным регистрам APIC, которые по умолчанию отображаются в физической памяти по адресу 0xFEE00000, хотя это можно изменить.Вам нужно будет найти физическую страницу, содержащую регистры APIC, и отобразить ее в виртуальной памяти, чтобы вы могли получить к ним доступ.

Чтобы отправить IPI, необходимо записать в регистр конфигурации прерываний.Младшие 32 бита ICR расположены в 0x300 на странице APIC, а верхние 32 бита - в 0x310.Чтобы отправить NMI, вам необходимо:

  1. Получить идентификатор APIC процессора, на который вы хотите отправить NMI.Если вы хотите отправить его на процессор, на котором вы работаете, это просто, поскольку вы можете прочитать его из APIC в 0x20 в битах 24-31.
  2. Записать идентификатор APIC в поле назначения, биты 24-31 регистра высокой ICR.
  3. Запишите значение 0x4400 в регистр низкой ICR.Биты 8-10 этого значения указывают, что вы отправляете NMI, а бит 14 указывает, что вы используете режим триггера assert.

При записи в регистр APIC вы должны записать полное значение 32.битовое значение.Кроме того, биты 13, 16-17 и 20-55 в ICR зарезервированы, поэтому вы не должны изменять их значения.Вы также должны записывать в старшие биты ICR перед младшими битами, так как IPI инициируется записью в младшие биты.

Вот пример отправки NMI текущему процессору в C.

#define APIC_ID_OFFSET 0x20
#define ICR_LOW_OFFSET 0x300
#define ICR_HIGH_OFFSET 0x310
// Convenience macro used to access APIC registers
#define APIC_REG(offset) (*(unsigned int*)(apicAddress + offset))

void *apicAddress; // This should contain the virtual address that the APIC registers are mapped to

// Get the current APIC ID. Leave it in the high 8 bits since that is where it needs to be written anyway
unsigned int apicID = APIC_REG(APIC_ID_OFFSET) & 0xFF000000;
unsigned int high = APIC_REG(ICR_HIGH_OFFSET) & 0x00FFFFFF;
high |= apicID;
unsigned int low = APIC_REG(ICR_LOW_OFFSET) & 0xFFF32000;
low |= 0x4400;
APIC_REG(ICR_HIGH_OFFSET) = high;
APIC_REG(ICR_LOW_OFFSET) = low;
...