目次
1. 実験の目的
1. オペレーティング システムのデバイス管理の基本原理の理解を深め、キーボード割り込みやスキャン コードなどの概念を実践します。
2. Linux 0.11のキーボード端末やモニタ端末の処理プロセスを実践的に習得します。
2. 実験内容
この実験の基本的な内容は、Linux 0.11の端末装置の処理コードを改変して、従来とは異なる方法でキーボード入力や文字表示を制御するというものです。
初期状態、すべて通常通りです。ユーザーが F12 を 1 回押した後、アプリケーションが端末に出力するすべての文字を * に置き換えます。ユーザーがもう一度 F12 を押すと、通常の状態に戻ります。出力を再度置換するには、F12 を 3 回押します。その後も続きます。
ls コマンドを例に挙げます。
通常は ls と入力します。
# ls
hello.c hello.o hello
まず F12 を押してから、ls と入力します。
# **
*****.* *****.* *****
もう一度 F12 を押して、「ls」と入力します。
# ls
hello.c hello.o hello
F12 を 3 回押して、「ls」と入力します。
# **
*****.* *****.* *****
【実験のヒント】
この実験では、Linux 0.11の端末装置の処理コード(ファイル)を修正し、キーボード入力や文字表示などに従来とは異なる制御を行う必要があります。 kernel/chr_drv/console.c
3. 実験の準備
1. キーボード入力処理
キーボード I/O は通常、次のファイルで割り込み駆動されます。 kernel/chr_drv/console.c
void con_init(void) //控制台的初始化
{
// 键盘中断响应函数设为 keyboard_interrupt
set_trap_gate(0x21, &keyboard_interrupt);
}
この関数はキー押下にアクションがあるたびに呼び出されkeyboard_interrupt
、 kernel/chr_drv/keyboard.S
ファイルに実装されます (拡張子が大文字の S であることに注意してください)。
キーボード入力に関連するすべての機能がこのファイルに実装されているため、この実験の一部の機能もこのファイルに実装できます。
簡単に言えば、keyboard_interrupt
呼び出された後、キーボードのスキャン コードが添字として使用され、 key_table
配列に格納されているキーに対応する応答関数が呼び出されます。
2. 出力文字の制御
printf()
最終的な出力関数は write()
システムコールを呼び出しているので、これをうまく制御すれば write()
出力文字を制御することができます。
4. 実験プロセス
実験の考え方を理解するには、この記事を読むことをお勧めします。オペレーティングシステム実験 7 端末デバイス制御
1. F12キーボード機能処理を追加
(1)kernel/chr_drv/tty_io.c
ファイルを変更し、ファイルの末尾にコードを追加します。
int switch_show_char_flag = 0;
void press_f12_handle(void)
{
if (switch_show_char_flag == 0)
{
switch_show_char_flag = 1;
}
else if (switch_show_char_flag == 1)
{
switch_show_char_flag = 0;
}
}
(2)include/linux/tty.h
ファイルを変更し、ファイルの末尾にコードを追加します。
extern int switch_show_char_flag;
void press_f12_handle(void);
(3)kernel/chr_drv/keyboard.S
ファイルを変更し、525 行目の関数をコメントアウトして次func
のように置き換えます press_f12_handle
。
/* .long func,none,none,none 58-5B f12 ? ? ? */
.long press_f12_handle,none,none,none
2. * 文字の表示処理を追加
ファイルを変更しkernel/chr_drv/console.c
、その中の関数を変更しますcon_write
。
void con_write(struct tty_struct * tty)
{
……
case 0:
if (c>31 && c<127) {
if (x>=video_num_columns) {
x -= video_num_columns;
pos -= video_size_row;
lf();
}
/* 添加开始 */
if (switch_show_char_flag == 1)
{
if((c>='A'&&c<='Z')||(c>='a'&&c<='z')||(c>='0'&&c<='9'))
c = '*';
}
/* 添加结束 */
__asm__("movb attr,%%ah\n\t"
"movw %%ax,%1\n\t"
::"a" (c),"m" (*(short *)pos)
);
pos += 2;
x++;
……
}
上記のコードは、while ループを通じて文字を 1 つずつ処理し、ビデオ メモリに格納します。
したがって、文字がビデオ メモリに書き込まれる前にフィルタを実行でき F12_flag == 1
、その時点ですべての文字が* に変換されます。
3. カーネルを再コンパイルします
// linux-0.11 目录下
make all
4. Linux 0.11 の実行
Linux 0.11 を入力すると、テスト結果は次のようになります。
5. 実験報告
1. 元のコードで F12 を押すと、割り込みが応答した後、割り込みサービス ルーチンが func? を呼び出します。どのような機能を果たしますか?
[回答] F12 を押した後、 func 関数は F12 をエスケープ文字シーケンス [ [ L にエスケープします。(F1~F12の処理は[[A~[[L]と同様です)
2. 実装では、ファイルに出力される文字もフィルタリングしますか? 「はい」の場合、端末に出力される文字だけをフィルタリングするにはどうすればよいでしょうか? そうでない場合、ファイルに出力される文字をフィルタリングするにはどうすればよいでしょうか?
【回答】 今回の実験では、ファイルに出力する文字をフィルタリングするのではなく、端末に出力する文字をフィルタリングするだけであり、con_write
関数を修正することで実現しています。ファイルに出力される文字をフィルタリングしたい場合は、file_write
それを実現するように関数を変更する必要があります。
特定の変更については、以下を参照してください。
while (c–>0)
{
tmp = get_fs_byte(buf++);
if(f12_flag == 1)
{
if((tmp>='A'&&tmp<='Z')||(tmp>='a'&&tmp<='z')||(tmp>='0'&&tmp<='9'))
tmp = '*';
}
*(p++) = tmp;
}