質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.49%
アセンブリ言語

アセンブリ言語とは、機械語を人間にわかりやすい形で記述した低水準言語です。

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

x86

x86はIntel 8086 CPU シリーズの命令セットアルキテクチャーです。

VirtualBox

VirtualBoxは、現在米オラクル社が開発している、 x86仮想化ソフトウェア・パッケージの一つです。

Q&A

解決済

2回答

1858閲覧

IDT登録処理 どこが誤りがあるのかわからないので教えてください

kazuyakazuya

総合スコア193

アセンブリ言語

アセンブリ言語とは、機械語を人間にわかりやすい形で記述した低水準言語です。

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

x86

x86はIntel 8086 CPU シリーズの命令セットアルキテクチャーです。

VirtualBox

VirtualBoxは、現在米オラクル社が開発している、 x86仮想化ソフトウェア・パッケージの一つです。

0グッド

0クリップ

投稿2020/11/13 13:49

編集2020/11/14 09:45

割り込みゲートディスクリプタの設置がうまくいっていないようです。
どこに誤りがあるのかわからないので教えてください。

プロテクトモードです。

参考:
0から作るos
How to use LIDT from inline assembly to load an interrupt vector table?

手順として
"割り込み"ゲートディスクリプタテーブルを0x00000000に設置。
ベクタ0x00だけ初期化します。
int 0x00にてソフトウエア割り込みを起こして
登録した割り込みハンドラが呼び出されるか見て
適切に設置されているかを確認する。

以下が作成したコードです。
ソフトウエア割り込み(0x00)を呼び出したとたんにVMがエラーで落ちるので
適切に割り込みゲートを設置できていないと思われます。

///_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ //          1 // // typedef struct { unsigned short size; void * base; } __attribute__ ((packed)) IDTR; IDTR idtr; idtr.size = 128 * 8; idtr.base = 0x00000000; __asm__ ("lidt %0" :: "m"(*(&idtr))); // // // ///_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ ///_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ //          2 // // int IDT_LOW; int IDT_HIGH; void (*p)() = Display_Rotation; int *GateAddress_Low = 0x00 * 8 + 0; int *GateAddress_High = 0x00 * 8 + 4; __asm__ __volatile__( "MOV %%DX,%%AX\n\t" "MOV %%EAX,%0\n\t" "MOV %2,%%DX\n\t" "MOV %%EDX,%1\n\t" :"=b" (IDT_LOW),"=c" (IDT_HIGH) :"i" ((short)(0x8000 + (0 << 13) + (0b110 << 8))),"a" ((0x08)<<16),"d" (p) ); *GateAddress_Low = IDT_LOW; *GateAddress_High = IDT_HIGH; // // // ///_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ __asm__("int $0x00\n\t");

1
LIDT命令でIDTRレジスタに読み込ませています。
[フォーマット](http://softwaretechnique.jp/OS_Development/Image/Kernel_Development02/IDTR.png
割り込みゲートディスクリプタのサイズは8バイト
それを128個配置するので 128 * 8。
IDT設置アドレスは0x00000000にしています。


割り込みテーブル ベクタ0x00のゲートディスクリプタをセットしています。
割り込みハンドラには Display_Rotation関数を登録します。

割り込みゲートフォーマット(図の中央)

IDT_LOWに割り込みディスクリプタに格納する値の下位32bitを。
IDT_HIGHに割り込みディスクリプタに格納する値の上位32bitを
__asm__の処理で入れるようにしています(のつもり・・・)。

その後、
*GateAddress_Low = IDT_LOW;
*GateAddress_High = IDT_HIGH;
にて IDT ベクタ0x00の割り込みディスクリプタに対応するアドレスに
IDT_LOW IDT_HIGHを格納しています。

もしかしたら初歩的なミスをしているかもしれませんが・・・
どこのコードに誤りがあるのか分からないのでお願いします

アセンブリ出力結果(こっちでは都合上 LOOP関数を割り込みハンドラとして登録します。)

void loop(); void main_kernel(){ ///_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ //          1 // // typedef struct { unsigned short size; void * base; } __attribute__ ((packed)) IDTR; IDTR idtr; idtr.size = 128 * 8; idtr.base = 0x00000000; __asm__ ("lidt %0" :: "m"(*(&idtr))); // // // ///_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ ///_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ //          2 // // int IDT_LOW; int IDT_HIGH; void (*p)() = loop; int *GateAddress_Low = 0x00 * 8 + 0; int *GateAddress_High = 0x00 * 8 + 4; __asm__ __volatile__( "MOV %%DX,%%AX\n\t" "MOV %%EAX,%0\n\t" "MOV %2,%%DX\n\t" "MOV %%EDX,%1\n\t" :"=b" (IDT_LOW),"=c" (IDT_HIGH) :"c" ((short)(0x8000 + (0 << 13) + (0b110 << 8))),"a" ((0x08)<<16),"d" (p) ); *GateAddress_Low = IDT_LOW; *GateAddress_High = IDT_HIGH; // // // ///_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ __asm__("int $0x00\n\t"); } void loop(void){ for(;;){} }
pushl %ebx subl $32, %esp //スタック32バイト確保 movw $1024, -30(%ebp) //-30(ebp)に 構造体変数idtr.size = 128 * 8 movl $0, -28(%ebp) //-30(ebp)に 構造体変数idtr.base = 0 lidt -30(%ebp)

こちらがLIDT命令付近と思われる処理です。

/NO_APP movl $_loop, -8(%ebp) //-8(ebp) LOOP関数開始アドレス movl $0, -12(%ebp) //-12 = IDT_Address下位 0x0000000 (つまりセグメントディスクリプタ下位32bit) movl $4, -16(%ebp) // -16 = IDT_Address 上位 0x00000004 (つまりセグメントディスクリプタ上位32bit) movl $-31232, %ecx // ECX == ((short)(0x8000 + (0 << 13) + (0b110 << 8))) たぶん16BIT movl $524288, %eax // EAX == (0x08)<<16 movl -8(%ebp), %edx //EDX == LOOP関数開始アドレス /APP # 52 "project1.c" 1 MOV %DX,%AX //EAXの下位16BITにloop関数開始アドレス EAXの上位16BITにセグメントセレクタ MOV %EAX,%ebx //さきほどのEAXをEBXにコピー MOV %cx,%DX //EDX上位にlooP関数開始アドレス EDX下位に ((short)(0x8000 + (0 << 13) + (0b110 << 8)))←サイズ16bit MOV %EDX,%ecx //先ほどのEDXをECXにコピー # 0 "" 2 /NO_APP movl %ecx, %eax     //さきほどEAXからEBXにコピーしたものをまたEAXにコピー movl %ebx, %edx     //さきほどEDXからECXにコピーしたものをまたEDXにコピー movl %edx, -20(%ebp) //-20(EBP)に  合計32BIT [下位16BITにloop関数開始アドレス 上位16BITにセグメントセレクタ] を保存 movl %eax, -24(%ebp) //-24(EBP)に  合計32BIT [上位にlooP関数開始アドレス 下位に((short)(0x8000 + (0 << 13) + (0b110 << 8)))]を保存 movl -12(%ebp), %eax //35行目 IDT_Address下位 0x0000000 (つまりセグメントディスクリプタ下位32bit)をEAXにコピー movl -20(%ebp), %edx //[下位16BITにloop関数開始アドレス 上位16BITにセグメントセレクタ] をEDXに movl %edx, (%eax)     movl -16(%ebp), %eax // 36行目 IDT_Address 上位 0x00000004 (つまりセグメントディスクリプタ上位32bit)をEAXにコピー movl -24(%ebp), %edx //[上位にlooP関数開始アドレス 下位に((short)(0x8000 + (0 << 13) + (0b110 << 8)))]をEDXにコピー movl %edx, (%eax)

こちらがゲート設置処理です。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

自己解決

どこに問題があったのか?

問題1
割り込みハンドラの関数を定義する際は
コンパイラに割り込み専用に関数を作らせる必要があります。
(未解決)

問題2
関数のアドレスを正しく取得できていていませんでした。
その関数ポインタは生成されたrawバイナリの先頭アドレスから
関数の配置アドレスまでのオフセットが入っています。
(逆に言えば、アドレス0x0000からrawバイナリを配置すれば問題なく動く)

なので、[関数ポインタ + バイナリ配置アドレス]とやることで解決しました。

投稿2020/11/16 10:03

編集2020/11/26 10:26
kazuyakazuya

総合スコア193

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

GCCのオプションでアセンブリコードを出力させて、それでチェックしていけばどうでしょ。

投稿2020/11/13 13:53

y_waiwai

総合スコア87747

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kazuyakazuya

2020/11/13 13:59

コードの生成がうまくいっていないか確認しろってことでしょうか? それとも上記のCコードが明らかにおかしいからアセンブリにして見てみろってことでしょうか?
y_waiwai

2020/11/13 14:01

アセンブルコードを出せば、なにしてるかわからんってことにはならんでしょう。 まずはそれ出して、あなたの思うようなことをやってるのかを見てみましょうよ
kazuyakazuya

2020/11/13 15:04

アセンブリを確認したところ以下のようなものがありました。 movl $-31232, %ecx この -31132は以下の結果だと思われますが 何でマイナスになっているんでしょうか? ((short)(0x8000 + (0 << 13) + (0b110 << 8))) (見た感じ今のところこれ以外おかしなところはありませんでした。)
y_waiwai

2020/11/13 15:10

たんに最上位ビットが1だから、という以外の理由はないです 最終的に目的の値になればいいんですw
kazuyakazuya

2020/11/13 15:13

数値がすべて符号付10進数としてみなされるということでしょうか?
y_waiwai

2020/11/13 15:16

コンパイラさんがすることですんで、そういうことなんでしょうね
y_waiwai

2020/11/13 15:18

いろいろコード書いてアセンブリリスト出してみてみるとおもしろいですよ 最適化をするとどう省略されるとか、あなた好みじゃないですかねw
kazuyakazuya

2020/11/13 15:21

今のところ 最適化なし だけでおなか一杯です(笑)
kazuyakazuya

2020/11/14 02:19

https://hogehoge.tk/tool/number.html このサイトで-31232を2進数にすると 1111111111111111 1000011000000000 となりました。 short型って符号付整数2バイトなのに32BITあるのはなぜでしょうか?
y_waiwai

2020/11/14 02:24

そりゃそこでは32bit前提で変換してるってだけでしょう
kazuyakazuya

2020/11/14 02:45

あ、見落としていました すみません。 ディスクリプタのDフィールドに1(32BIT)ではなく0(16BIT)をセットするというミスを発見しました。 ただ、訂正後もエラーが起こるのでまだ間違いがあるようです・・・
kazuyakazuya

2020/11/14 03:45

IDTのゲート設置 GDTの設置 上記2つが問題なく設定できたとして他にソフトウエア割り込みを起こしてエラーが起こる原因なんてありますか?
y_waiwai

2020/11/14 03:50

まあちょっと気になったのは、その設定中は割り込みは禁止にしないといけないってのがあるけど、 そもそものはなし、VirtualBoxがそこまできちんとエミュレートしてるのかって心配もありますわな。 実機でやってみたらどうなるでしょ
kazuyakazuya

2020/11/14 04:10

cli命令で割り込み禁止にしているのでそこは大丈夫だと思われます。
kazuyakazuya

2020/11/14 11:28

う~ん プロテクトモードに移行してから割り込みを使いたい場合 IDT,GDTのセットアップ以外何か必要なものありましたですっけ? 20回くらい見ましたが間違えていると思われるところは見つけられませんでしたし ブートローダー(アセンブリ)の段階でIDTのセットアップもしてみましたが そちらでもエラーになります。。。
y_waiwai

2020/11/14 11:38

あと気になるところといえば、 > IDT設置アドレスは0x00000000にしています。 とありますが、アドレス0x00000000にはちゃんとIDTのテーブルデータをおいてるんですよね? それがないと割り込みで暴走します まあ、このレベルになるとデバッガも使えないし、どうやって追いかけるかが問題ですねー
kazuyakazuya

2020/11/14 11:53

質問で載せたコードですと *GateAddress_Low = IDT_LOW; *GateAddress_High = IDT_HIGH; ここで0x00000000にIDTのベクタ1つのみ設置しています。 LIDT [SAMPLE_IDT] INT 0 SAMPLE_IDT: dw 割り込みハンドラ下位アドレス dw 0x08 dw 0b0000000011010001 dw 割り込みハンドラ上位アドレス アセンブリで上記のようなものも作って実行してみましたがこちらでもエラーになります。 こちらも私が見た限りコードは正しそうなのですが・・・
y_waiwai

2020/11/14 12:35

んで、その0番地にはメモリがきちんとあって、その書き込んだデータが見えてるんですよね。 そこらへんは確認してますか
kazuyakazuya

2020/11/14 13:55

MOV EAX,LOOP MOV EBX,SAMPLE_IDT MOV [EBX],AX SHR EAX,16 MOV EBX,SAMPLE_IDT_LOW MOV [EBX],AX     LIDT [SAMPLE_IDT]   INT 0    SAMPLE_IDT: dw 0x00 dw 0x08 dw 0b0000000011010001 SAMPLE_IDT_LOW: dw 0x00 LOOP: JMP $ SAMPLE_IDTから始まるアドレスをIDT開始アドレスとします。 上記のようにベクタ0のみを設定します。 LOOPラベルに定義されている処理を割り込みハンドラとして登録します というコードを作成し、実際にSAMPLE_IDTにLOOPのアドレスが格納されているかというのを 確認しましたが適切に入っていました。 やっぱ、IDTの設定以外に問題があるのかな・・・?
kazuyakazuya

2020/11/15 09:08

あらかじめ決めておいたアドレスに無限ジャンプ命令(0xebfe)を配置して 割り込みハンドラに登録して呼び出したところうまく動作しました。 呼び出す関数または呼び出す関数のアドレスに問題があるようです。 そういえばC言語では 割り込みハンドラを作成するとき特別な宣言が必要だってのをどこかで見た記憶があるのですが 何か知っておられますか?
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.49%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問