Когда прерывание запускается в защищенном режиме на x86, можно ли выяснить, какой номер прерывания был запущен? Например, скажем, я вызвал int 0xFF. В обработчике можно узнать, что вызывался int 0xFF?
Как получить номер прерывания от обработчика прерываний в x86?
Ответы (3)
Если у вас есть уникальные обработчики прерываний (или, по крайней мере, уникальные точки входа и код пролога), то, конечно, вы можете отличить int 0xFF
, скажем, от int 0x30
. Адреса ISR хранятся в IDT
, так что это место, где начинается дифференциация.
Нет хорошей альтернативы уникальным ISR. Вот почему...
В ISR вы можете проверить стек вызывающей стороны, увидеть адрес возврата и проверить код прямо перед адресом возврата, чтобы увидеть, является ли это 2-байтовой инструкцией int n
(закодированной как байты: 0xCD, n) или чем-то еще. Проблема в том, что существуют также int 3
и into
1-байтовые инструкции (закодированные как 0xCC и 0xCE соответственно). Как отличить 0xCD+0xCC (int 0xCC
) или 0xCD+0xCE (int 0xCE
) от просто 0xCC (int 3
) или 0xCE (into
)? До 0xCC или 0xCE может быть что угодно. Переменная длина инструкций не позволяет легко и надежно анализировать/дизассемблировать код в обратном направлении.
Как насчет других способов запуска прерываний/исключений, таких как ud2
? Или инструкции, запускающие #GP, #PF? Это могут быть произвольные инструкции.
Также вы должны иметь в виду, что исключения не обрабатываются точно так же. Некоторые из них поставляются с дополнительной информацией, сохраняемой ЦП в стеке перед входом в ISR, это код ошибки. У других нет этого кода ошибки, и ваш ISR должен удалить его перед выполнением iret
. Ошибка в определении вектора исключения приведет к сбою или зависанию вашего кода.
Теперь об аппаратных прерываниях... Возможно, вы сможете определить, какое аппаратное прерывание обслуживается. PIC
имеет in-service register
(ISR
), где бит, установленный в 1 (AFAIR), указывает IRQ
, но если вы позволяете прерываниям с более высоким приоритетом вытеснять ISR, обрабатывающие прерывания с более низким приоритетом (разрешая прерывания внутри ISR), то идентификация прерывания быстро становится сложнее, чем необходимо.
Итак, просто используйте уникальные ISR для всех ваших IRQ, исключений и системных вызовов. Или используйте один общий ISR, но с несколькими уникальными точками входа, каждая из которых сохраняет уникальный номер (= номер вектора) в стеке. Затем общий код извлечет это число и сделает то, что необходимо для этого вектора прерывания.
Создание заглушек, которые помещают значение в стек, — отличный способ справиться с этим, и он используется на 5_irq/interrupt.asm#L8" rel="nofollow noreferrer">учебник Джеймса Моллоя:
%macro ISR_NOERRCODE 1
global isr%1
isr%1:
cli ; Disable interrupts firstly.
push byte 0 ; Push a dummy error code.
push byte %1 ; Push the interrupt number.
jmp isr_common_stub ; Go to our common handler code.
%endmacro
%macro ISR_ERRCODE 1
global isr%1
isr%1:
cli ; Disable interrupts.
push byte %1 ; Push the interrupt number
jmp isr_common_stub
%endmacro
ISR_NOERRCODE 0
ISR_NOERRCODE 1
ISR_NOERRCODE 2
ISR_NOERRCODE 3
ISR_NOERRCODE 4
ISR_NOERRCODE 5
ISR_NOERRCODE 6
ISR_NOERRCODE 7
ISR_ERRCODE 8
ISR_NOERRCODE 9
ISR_ERRCODE 10
ISR_ERRCODE 11
ISR_ERRCODE 12
ISR_ERRCODE 13
ISR_ERRCODE 14
ISR_NOERRCODE 15
/* More entries */
Это также имеет дело с кодом ошибки.
Я не эксперт по обработчикам прерываний, но у них должен быть где-то обратный адрес, чтобы исходный код мог возобновить выполнение. Если вы можете получить старый адрес этого адреса, вы можете проверить предыдущий адрес, который предположительно будет содержать номер прерывания.
int 0xFF
. Не похоже, чтобы он использовал внешние прерывания.
- person Neil; 05.09.2012