8

カーネルを自作していますが、最初のページエラー割り込みハンドラのあと、IRETを実行すると割り込み13(一般保護)が発生し、エラーコードは0x18です。何が問題なのかわかりません。スタックにプッシュされたコンテンツはCPUからのものです。

割り込みが発生したときのレジスタの状態と、レジスタが格納されていたメモリは次のとおりです。さらに、ページ エラー割り込みハンドラから IRET が返されます。

%ESP が IRET 実行前と割り込み発生前と同じであることは確かです。

ここに画像の説明を入力

ここに画像の説明を入力

4

2 に答える 2

9

例外がIRETそれ自体からのものである場合IRET、保存されたセグメントレジスタの1つを復元できない可能性がありますが、値(8または0x18、ところで?)はどういうわけか間違っています。保護モードでレジスタを(再)初期化したことがないIRETか、GDTに何かが起こった前にハンドラーがレジスタを不正な値に設定したため、間違っている可能性があります...

編集ESP:図から、ページフォールトハンドラーが実行前に例外コード(のアドレスの値4)を削除しなかったことがわかりIRETます。したがって、IRET4をの新しい値EIP、0x1000018をの新しい値CS、0x23をの新しい値として解釈しますEFLAGSが、これら3つのレジスタには0x1000018、0x23、および0x3206を使用する必要があります。明らかに、データセグメントセレクター(0x1000018は0x0018への切り捨て後と解釈されます)をロードできずCS、これにより#GP(0x18)が発生します。

于 2012-05-14T14:39:43.607 に答える
5

アレクセイの拡張:

一部の割り込みが発生すると (他の割り込みは発生しません)、4 バイトのエラー コードが自動的にスタックにプッシュされます。ページ フォールトもその 1 つです。

このエラー コードには、割り込みに関する追加情報が含まれています。

Intel Manual Volume 3 System Programming Guide - 325384-056US 2015 年 9 月表 6-1. 「プロテクト モードの例外と割り込み」列の「エラー コード」では、どの割り込みがエラー コードをプッシュし、どの割り込みがプッシュしないかを正確に示します。

38.9.2.2「ページ・フォルト・エラー・コード」では、エラーの意味を説明しています。

したがって、次のいずれかが必要になります。

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

または、エラー コードを無視する場合:

add $4, %esp
iret

最小限の例については、このページ ハンドラーを参照して、pop.

上記を、スタックをポップする必要のない分割エラー例外と比較してください。

int $14単純に を実行すると、余分なバイトがプッシュされないことに注意してください。これは実際の例外でのみ発生します。

これに対処する適切な方法は、0これを行わない割り込みのスタックにダミーのエラー コードをプッシュして、物事を統一することです。James Molloy のチュートリアルはまさにそれを行います。

Linux カーネル 4.2 も同様のことをしているようです。arch/x86/entry/entry64.S の下では、次のように割り込みをモデル化しhas_error_codeます。

trace_idtentry page_fault do_page_fault has_error_code=1

次に、同じファイルで次のように使用します。

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

と押しhas_error_code=0ます。

関連する質問:割り込みハンドラから戻る前に、特定の例外によってスタックにプッシュされたエラー コードをポップする必要がありますか?

于 2015-10-28T17:46:40.113 に答える