2012-02-14 5 views
2

Я пытаюсь обрабатывать прерывания ядра через IDT. Я работаю на Intel x86 под Linux.x86: цикл обработчика прерываний

Я установил свои IDT и мои записи прерываний, и я запустил несколько тестов для просмотра обработчиков прерываний.

Когда я пытаюсь использовать int $0x0, он отлично работает: мой обработчик вызывается, но когда я пытаюсь сделать какое-то исключение с нажатым кодом ошибки, я вхожу в бесконечный цикл.

Схема выглядит следующим образом:

Когда приходит исключение, первая часть моего обработчика в ASM и вызывает общую C часть.

my_handler.c

void handler(int i) 
{ 
    printf("Exception %d caught\n", i); 
} 

my_handlers.S

common: 
    pushal 

    pushl %ds 
    pushl %es 
    pushl %fs 
    pushl %gs 

    addl $48, %esp     // 4 4-bytes segments pushed 
            // + 8 4-bytes registers (pushal) 
`         // esp points on exception code 

    call handler     // call the C handler with exception code 

    subl $48, %esp 

    popl %gs 
    popl %fs 
    popl %es 
    popl %ds 

    popal 

    addl $8, %esp     // 4-byte error code + 4-byte exception number 
    iret 


exception_de_handler: 
    pushl $0      // Fake error code 
    pushl $0      // interrupt number 
    jmp common 

exception_gp_handler: 
    // error code is pushed by µproc. 
    pushl $13      // interrupt number 
    jmp common 

exception_pf_handler: 
    // error code is pushed by µproc. 
    pushl $14      // interrupt number 
    jmp common 

Если я пытаюсь запустить код followig:

int* a = 0x0; 
*a = 42; 

Он работает, то exceution возобновляется после *a = 42;

Но если я стараюсь:

int* a = 0x0; 
*a = 42; 
*a = 1337; 

Он идет в бесконечном цикле:

Exception 14 caught 
Exception 13 caught 
Exception 13 caught 
Exception 13 caught 
Exception 13 caught 
     ..... 
Exception 13 caught 
Exception 13 caught 
Exception 13 caught 
     ..... 

Почему первое исключение ошибки страницы (14) обрабатывались затем цикл по общей защите (13)?

Благодарим за ответы.

+1

Почему вы вручную манипулируете IDT из-под Linux? Это не может закончиться хорошо. Вы должны использовать API-интерфейсы драйверов устройств Linux для прерывающихся прерываний. (Также я не уверен, как вам удается вызывать 'printf' из режима ядра - нам может понадобиться дополнительное объяснение того, что вы на самом деле сделали.) – zwol

+0

@ Zack - хорошая точка – Stewart

ответ

2

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

код ошибки Нажмите (может быть сделана с помощью CPU) Push-регуляр регса сегмента Push-

добавить 0x48 к указателю стеки, наматывать из стека всего пути назад, чтобы он указывал на код ошибки.

называют вашу функцию C

Что это фактически делает это «освобождение» часть своего стека, что сегментные регистры были сохранены. В самом деле вы даже не нужно беспокоиться о функции C в все потому, что адрес возврата попадает в стек в команде вызова и сдувает вашу запись ds и es, прежде чем вы даже доберетесь до C-вызова. Когда вы вернетесь из вызова C, вы пытаетесь привести в порядок стоп-колл, но вы не понимаете это правильно - отчасти потому, что вы уже испортили его, а отчасти потому, что вы не очищаете стек после вызов функции (при условии, что обработчик использует соглашение о вызове _cdecl).

Это приводит к появлению фиктивного значения для ds. Когда вы загружаете это в ds, CPU проверяет значение против GDT и обнаруживает, что он недействителен. В этот момент он вызывает GPF (исключение 13), которое вы используете. Это, в определенной степени, восстанавливает стек (процессор ищет SS для вас) и оставляет старое значение ds set - поэтому вы никогда не меняете ds, что позволяет снова запускать printf.

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

 Смежные вопросы

  • Нет связанных вопросов^_^