(内容が乱雑だったので訂正しました。)
IDTのゲートディスクリプタにはaaa関数を登録します。
c
1void protect_puts(char*,int,int,int); 2void set_intr_gate(); 3void aaa(); 4void loop(); 5 6/* メイン関数 */ 7 8void main_kernel(){ 9 10 set_intr_gate(); 11 12 __asm__( 13 "int $0x00\n\t" 14 ); 15 loop(); 16 17} 18 19void loop(){ 20 21 for(; ; ) { 22 23} 24} 25 26void aaa(){ 27 char ptr[] = "abcdefghigk"; 28 char *a = ptr; 29 protect_puts(a,11,5,5); 30} 31 32/* 文字表示関数 */ 33 34void protect_puts(char *char_address,int bytes,int side_size,int height_size){ /* 1=文字アドレス,2=バイト */ 35 36/* message */ 37/* 本来ポインタを使いたいがエラーが起こるのでいまは保留 */ 38 int vram_address = 0xA0000; 39 int font_address = 0x0500; 40 int byte_count = bytes; 41 int yoko = side_size; 42 int tate = height_size; 43 char *ptrr = char_address; 44 45 __asm__ __volatile__( 46 /* 横設定 */ 47 "mov %7,%%eax\n\t" 48 "mov %5,%%ebx\n\t" 49 "add %%eax,%%ebx\n\t" 50 "mov %%ebx,%2\n\t" 51 52 53 "mov %8,%%eax\n\t" 54 "mov $1280,%%ebx\n\t" 55 "mul %%ebx\n\t" 56 "mov %5,%%ebx\n\t" 57 "add %%eax,%%ebx\n\t" 58 "mov %%ebx,%2\n\t" 59 60 61 "mov %6,%%eax\n\t" /* eax = 文字があるアドレス */ 62 "mov %3,%%ebx\n\t" /* %0 ebx = バイト数 */ 63 ".protect_puts_loop2:\n\t" 64 "cmp $0,%%ebx\n\t" 65 "jz .endd\n\t" 66 67 "xor %%esi,%%esi\n\t" 68 "mov (%%eax),%%esi\n\t" /* esiレジスタにASCII1文字 */ 69 /* "mov $97,%%esi\n\t" */ 70 "and $0b00000000000000000000000011111111,%%esi\n\t" 71 "shl $4,%%esi\n\t" 72 73 "xor %%ebx,%%ebx\n\t" 74 "mov %4,%%ebx\n\t" 75 "add %%ebx,%%esi\n\t" 76 77 78 "mov %5,%%edi\n\t" 79 80 "mov $16,%%ecx\n\t" /* 1文字 縦16bitだから */ 81 82 ".protect_puts_loop:\n\t" 83 "movsb\n\t" 84 "add $80 - 1,%%edi\n\t" 85 "loop .protect_puts_loop\n\t" 86 87 "inc %%eax\n\t" 88 89 "xor %%ebx,%%ebx\n\t" 90 91 "mov %5,%%ebx\n\t" 92 "add $1,%%ebx\n\t" 93 "mov %%ebx,%2\n\t" 94 95 "mov %3,%%ebx\n\t" /* バイトカウント 0かどうか確認 */ 96 "sub $1,%%ebx\n\t" 97 "mov %%ebx,%0\n\t" 98 "mov %3,%%ebx\n\t"/* 変更 */ 99 100 "jmp .protect_puts_loop2\n\t" 101 102 103 ".endd:\n\t" 104 105 106 : "=m" (byte_count), /* %0 バイト数 */ 107 "=m" (font_address), 108 "=m" (vram_address) 109 110 : "m" (byte_count), /* %0 バイト数 %4*/ 111 "m" (font_address), 112 "m" (vram_address), 113 "m" (ptrr), 114 "m" (yoko), 115 "m" (tate) 116 ); 117 118 } 119 120 121#define _set_gate(gate_addr,type,dpl,addr,seg) \ 122do { \ 123 int __d0, __d1; \ 124 __asm__ __volatile__ ("movw %%dx,%%ax\n\t" \ 125 "movw %4,%%dx\n\t" \ 126 "movl %%eax,%0\n\t" \ 127 "movl %%edx,%1" \ 128 :"=m" (*((long *) (gate_addr))), \ 129 "=m" (*(1+(long *) (gate_addr))), "=&a" (__d0), "=&d" (__d1) \ 130 :"i" ((short) (0x8000+(dpl<<13)+(type<<8))), \ 131 "3" ((char *) (addr)),"2" ((seg) << 16)); \ 132} while (0) 133 134void set_intr_gate() 135{ 136 void(* a)(); 137 a = aaa; 138 139 _set_gate(0x8400,14,0,&a,0x08); 140} 141
ブートローダープログラムと上記のカーネル(?)プログラムをrawバイナリ形式に変換し
くっつけてVirtualbox上で動かします。
_set_gate(0x8400,14,0,&a,0x08);
これでIDTにゲートディスクリプタの登録を行っています。
このプログラムを使ってaaa関数(ポインタaにaaa関数のアドレスが入っている。)
をソフトウエア割り込みで呼び出せるようにしたいです。
aaa関数の中で画面に文字を表示させる関数を読んでいるので
ソフトウエア割り込み(INT 0x00)
↓
登録したゲートディスクリプタ(aaa関数への)が参照されaaa関数が呼ばれる。
↓
aaa関数内部で画面に文字が表示される関数が呼ばれ
画面上に文字が表示される。
以上のことを期待しています。
試験的に メモリ0x8600上に
jmp $(無限ループ)
この命令を配置し、
_set_gate(0x8400,14,0,0x8600,0x08);
とやってINT 0x00でソフトウエア割り込みを起こしたところ正常に動作しました。
なので、・・・
void(* a)();
a = aaa;
_set_gate(0x8400,14,0,&a,0x08);
このようにしてaaa関数へのゲートディスクリプタを作成してINT 0x00で呼び出したのですが
エラーこそ起こらないものの画面に何も表示されず
期待通りの動作になりません。
0x8600に配置したループ処理が呼べたことから
割り込み処理ルーチンのアドレス設定は問題なくできているものと思われます。(たぶん)
なので、どちらかと言えば
aaa関数 あるいは aaa関数内で呼ばれているprotect_puts(文字表示関数)のほうに問題があると思うのですが・・・
何がいけないんでしょうか?
アセンブリ言語でいうところのret命令みたいのが必要なのでしょうか?
(いや、それだったらエラーになるはずだが・・・)
c
1/* プロトタイプ宣言 0x1060 */ 2void loop(); 3void protect_puts(char*,int,int,int); 4void set_intr_gate(); 5void aaa(); 6 7/* メイン関数 */ 8 9void main_kernel(){ 10 11 set_intr_gate(); 12 13 14 __asm__( 15 "int $0x32\n\t" 16 ); 17 18 loop(); 19 20} 21 22 23 24 25void aaa(){ 26 char ptr[] = "abcdefghigk"; 27 char *a = ptr; 28 protect_puts(a,11,5,5); 29 30} 31 32/* 文字表示関数 */ 33 34void protect_puts(char *char_address,int bytes,int side_size,int height_size){ /* 1=文字アドレス,2=バイト */ 35 36 37 int vram_address = 0xA0000; 38 int font_address = 0x0500; 39 int byte_count = bytes; 40 int yoko = side_size; 41 int tate = height_size; 42 char *ptrr = char_address; 43 44 __asm__ __volatile__( 45 /* 横設定 */ 46 "mov %7,%%eax\n\t" 47 "mov %5,%%ebx\n\t" 48 "add %%eax,%%ebx\n\t" 49 "mov %%ebx,%2\n\t" 50 51 52 "mov %8,%%eax\n\t" 53 "mov $1280,%%ebx\n\t" 54 "mul %%ebx\n\t" 55 "mov %5,%%ebx\n\t" 56 "add %%eax,%%ebx\n\t" 57 "mov %%ebx,%2\n\t" 58 59 60 "mov %6,%%eax\n\t" /* eax = 文字があるアドレス */ 61 "mov %3,%%ebx\n\t" /* %0 ebx = バイト数 */ 62 ".protect_puts_loop2:\n\t" 63 "cmp $0,%%ebx\n\t" 64 "jz .endd\n\t" 65 66 "xor %%esi,%%esi\n\t" 67 "mov (%%eax),%%esi\n\t" /* esiレジスタにASCII1文字 */ 68 /* "mov $97,%%esi\n\t" */ 69 "and $0b00000000000000000000000011111111,%%esi\n\t" 70 "shl $4,%%esi\n\t" 71 72 "xor %%ebx,%%ebx\n\t" 73 "mov %4,%%ebx\n\t" 74 "add %%ebx,%%esi\n\t" 75 76 77 "mov %5,%%edi\n\t" 78 79 "mov $16,%%ecx\n\t" /* 1文字 縦16bitだから */ 80 81 ".protect_puts_loop:\n\t" 82 "movsb\n\t" 83 "add $80 - 1,%%edi\n\t" 84 "loop .protect_puts_loop\n\t" 85 86 "inc %%eax\n\t" 87 88 "xor %%ebx,%%ebx\n\t" 89 90 "mov %5,%%ebx\n\t" 91 "add $1,%%ebx\n\t" 92 "mov %%ebx,%2\n\t" 93 94 "mov %3,%%ebx\n\t" /* バイトカウント 0かどうか確認 */ 95 "sub $1,%%ebx\n\t" 96 "mov %%ebx,%0\n\t" 97 "mov %3,%%ebx\n\t"/* 変更 */ 98 99 "jmp .protect_puts_loop2\n\t" 100 101 102 ".endd:\n\t" 103 104 105 : "=m" (byte_count), /* %0 バイト数 */ 106 "=m" (font_address), 107 "=m" (vram_address) 108 109 : "m" (byte_count), /* %0 バイト数 %4*/ 110 "m" (font_address), 111 "m" (vram_address), 112 "m" (ptrr), 113 "m" (yoko), 114 "m" (tate) 115 ); 116 117 } 118 119 120 121/* IDT登録関数 */ 122 123#define _set_gate(gate_addr,type,dpl,addr,seg) \ 124do { \ 125 int __d0, __d1; \ 126 __asm__ __volatile__ ("movw %%dx,%%ax\n\t" \ 127 "movw %4,%%dx\n\t" \ 128 "movl %%eax,%0\n\t" \ 129 "movl %%edx,%1" \ 130 :"=m" (*((long *) (gate_addr))), \ 131 "=m" (*(1+(long *) (gate_addr))), "=&a" (__d0), "=&d" (__d1) \ 132 :"i" ((short) (0x8000+(dpl<<13)+(type<<8))), \ 133 "3" ((char *) (addr)),"2" ((seg) << 16)); \ 134} while (0) 135 136void set_intr_gate() 137{ 138 void(* a)() = aaa; 139 _set_gate(0x8590,14,0,&a,0x08); /* 0x8600 */ 140} 141 142 143 144 145 146/* ループ関数 */ 147 148 void loop(){ 149 150 for(; ; ) { 151 152} 153} 154
文字制限のためPIC初期化関数とかは省略しました。main_kernelから処理がスタートします。
INT 0x32(10進数50)でaaa関数を呼び出そうとしています。
(何やら長いですが原因が全く分からないのでお願いします・・・。)
やってみたこと
IDTアドレスの指定が間違えている可能性がある。
なので・・・
ブートローダーからカーネルへ制御が移行する際に
push IDT
とすることでスタックにIDTアドレスを保管し
カーネルに制御が移ったらスタックに積まれたアドレスを回収する。
c
1/* プロトタイプ宣言 0x1060 */ 2void loop(); 3void protect_puts(char*,int,int,int); 4void set_intr_gate(int); 5void aaa(); 6void test(); 7 8 9/* メイン関数 */ 10 11void main_kernel(){ 12 int idt_address = 0x00000000; 13 __asm__( 14 "mov 4(%%esp),%%eax\n\t" 15 "mov %%eax,%1\n\t" 16 :"=m" (idt_address) 17 :"m" (idt_address) 18 ); 19 20 set_intr_gate(idt_address); 21} 22 23void set_intr_gate(int idt_address) 24{ 25 void(* a)() = aaa; 26 _set_gate(idt_address,14,0,&a,0x08); /* 0x8600 */ 27} 28 29
こちらも結果は同様に変わりませんでした。(1万文字をこえるので変更点以外は省略しました。)
そもそもIDTにトラップゲートを設置する以前に何か設定するものでもあるのでしょうか?
何か知っておられましたら教えていただけると助かります。
lidt [IDTR] mov eax,int_handler mov [IDT+49*8],ax mov word [IDT+49*8+2],0x08 mov word [IDT+49*8+4],0x8E00 shr eax,16 mov [IDT+49*8+6],ax int 49
ブートローダーで上記のプログラムでIDTに登録したところうまくできましたが
カーネル以降での登録はまだうまくいっていません。
ブートローダーはアセンブリ言語で書き
カーネル以降はC言語で記述しており
アセンブリ言語で定義した関数を登録しソフトウエア割り込みで呼び出す分には何も問題なく作動するのですが
カーネルつまりC言語で定義された関数を登録すると呼び出した時点でエラー・暴走が起こります。
呼び出した時点で暴走するので関数から復帰する際に~ってわけではなさそうです。
void function(){}
なにもしなってのはこのようなやつです。
_set_gate(idt_address,14,0,ブートローダーアセンブリ言語レベルで定義した関数アドレス,0x08);
この場合はうまくいき
_set_gate(idt_address,14,0,カーネルCC言語レベルで定義すた関数アドレス,0x08);
この場合エラーになります。(内容に関係なしに)
アセンブリ言語内で定義した関数は割り込みハンドラとして登録し実行することができる。
これを利用して解決案として
アセンブリ言語内で割り込みハンドラを登録。
そのハンドラ内でC言語関数アドレスに向けてJMPする。
・・・この方法を試そうと思いましたが
アセンブリ言語で書かれたブートローダーと
C言語で書かれたカーネルをそれぞれ
別々にリンクしrawバイナリ形式にしたところで繋げているのでこの方法は使えません・・・。
なんか解決策はないでしょうか?
回答1件
あなたの回答
tips
プレビュー