Как получить номер прерывания от обработчика прерываний в x86?

Когда прерывание запускается в защищенном режиме на x86, можно ли выяснить, какой номер прерывания был запущен? Например, скажем, я вызвал int 0xFF. В обработчике можно узнать, что вызывался int 0xFF?


person user1454902    schedule 02.09.2012    source источник
comment
IDT хранит все обработчики прерываний, и каждому обработчику должен быть назначен только один номер прерывания. то есть: никогда не должно быть одного обработчика прерывания, назначенного нескольким прерываниям.   -  person Jay    schedule 03.09.2012
comment
Я планировал иметь массив указателей на функции, если бы мое ядро ​​могло назначать разные обработчики. Я собирался иметь один обработчик, который будет вызывать обработчик из массива, но что бы ни случилось, у меня будут отдельные обработчики для каждого....   -  person user1454902    schedule 03.09.2012


Ответы (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, но с несколькими уникальными точками входа, каждая из которых сохраняет уникальный номер (= номер вектора) в стеке. Затем общий код извлечет это число и сделает то, что необходимо для этого вектора прерывания.

person Alexey Frunze    schedule 03.09.2012

Создание заглушек, которые помещают значение в стек, — отличный способ справиться с этим, и он используется на 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 */

Это также имеет дело с кодом ошибки.

person Ciro Santilli 新疆再教育营六四事件ۍ    schedule 09.11.2015

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

person Neil    schedule 02.09.2012
comment
Предыдущий адрес не имеет ничего общего с номером прерывания. Возможно, когда вы говорите об исключении или ловушке, это может помочь, но для внешнего прерывания совсем нет. - person Sam Liao; 03.09.2012
comment
@arsane В своем примере он назвал int 0xFF. Не похоже, чтобы он использовал внешние прерывания. - person Neil; 05.09.2012