2012-05-14 5 views
6

Piszę jądro samodzielnie, a po pierwszej stronie obsługi przerwań błędów, po wykonaniu IRET, powoduje przerwanie 13 (ogólna ochrona), a kod błędu to 0x18. Nie wiem, co jest nie tak, zawartość pchana na stos pochodzi z procesora.Dlaczego funkcja iret z procedury obsługi błędów strony generuje przerwanie 13 (ogólny błąd ochrony) i kod błędu 0x18?

Oto stan rejestru, gdy wystąpi przerwanie, oraz pamięć, w której przechowywane były rejestry. Ponadto IRET jest zwracany z obsługi przerwania błędu strony.

Jest pewne, że% ESP jest taki sam przed wykonaniem IRET i przerwaniem.

enter image description here

enter image description here

Odpowiedz

7

Jeśli wyjątek jest od IRET sama, to najprawdopodobniej IRET nie udaje się przywrócić jedną z zapisanych rejestrów segmentowych, ale wartość (8 lub 0x18, btw?) Jest w jakiś sposób źle. To może być nie tak, bo nigdy nie (re) zainicjowany rejestru w trybie chronionym lub Twój obsługi ustawić go na złą wartością przed wykonaniem IRET czy coś się stało z GDT ...

EDIT: Z rysunku to oczywiste że program obsługi błędów stronicowania nie usunął kodu wyjątku (wartość 4 pod adresem w ESP) przed wykonaniem IRET. I tak IRET zinterpretował 4 jako nową wartość dla EIP, 0x1000018 jako nową wartość dla CS i 0x23 jako nową wartość dla EFLAGS, podczas gdy dla tych trzech rejestrów powinna być używana 0x1000018, 0x23 i 0x3206. Oczywiście, selektor segmentu danych (który 0x1000018 jest interpretowany jako po obcięciu do 0x0018) nie może być załadowany do CS i to powoduje #GP (0x18).

+0

„To może być nie tak, bo nigdy nie (re) zainicjowany rejestru w trybie chronionym”, który rejestr powinien zainicjować? –

+0

Wszystkie rejestry segmentów powinny być poprawnie zainicjowane w trybie chronionym (CS, DS, ES, SS, FS, GS). Właściwie to w tej chwili trudno powiedzieć, co jest nie tak, nie wiedząc więcej o kodzie. Opublikuj kod. –

+0

Opis 'IRET' powinien dać ci kilka wskazówek, co może być nie tak. Spójrz na wszystkie warunki prowadzące do '#GP (selektor)'. –

2

Rozszerzając Alexey:

Kiedy niektóre przerwania zdarzyć (ale nie inne), automatycznie pchania kod błędu 4 bajtów na stosie. Błąd strony jest jednym z nich.

Ten kod błędu zawiera dodatkowe informacje o przerwie.

Intel Manual Volume 3 System Programming Guide - 325384-056US September 2015 Tabela 6-1. Kolumna "Kod błędu" w "Protected-Mode Exceptions and Interrupts" dokładnie informuje, które przerwania powodują wypychanie kodu błędu, a które nie.

38.9.2.2 "Kody błędów strony" wyjaśnia, co oznacza błąd.

Więc trzeba będzie albo:

pop %eax 
/* Do something with %eax */ 
iret 

Lub jeśli chcesz zignorować kod błędu:

add $4, %esp 
iret 

za niewielką przykład patrz this page handler i spróbuj zakomentowałeś pop.

Porównaj powyższe z Division error exception, który nie musi otwierać stosu.

Zauważ, że jeśli zrobisz po prostu int $14, dodatkowy bajt nie zostanie zepchnięty: dzieje się tak tylko w przypadku rzeczywistego wyjątku.

Dobrym sposobem radzenia sobie z tym jest wypychanie na stosie fałszywego kodu błędu 0 dla przerwania, które nie powodują, że rzeczy są jednolite. Samouczek Jamesa Molloya: does exactly that.

Jądro 4.2 wydaje się robić coś podobnego. Pod arch/x86/entry/entry64.S modeli przerywa z has_error_code:

trace_idtentry page_fault do_page_fault has_error_code=1 

a następnie wykorzystuje je na tym samym pliku jako:

.ifeq \has_error_code 
pushq $-1 /* ORIG_RAX: no syscall to restart */ 
.endif 

który robi push gdy has_error_code=0.

pytanie pokrewne: Do I have to pop the error code pushed to stack by certain exceptions before returning from the interrupt handler?

Powiązane problemy