实验内容
当按下F12时,控制端所有字母 变成* ,再按一次则恢复,以此类推…
实验目的
- 加深对操作系统设备管理基本原理的认识,实践键盘中断、扫描码等概念
- 通过实践掌握Linux0.11对键盘终端和显示器终端的处理过程。
实验需要具备的基本知识
键盘I/O是一种典型的中断驱动事件,既然是中断就对应需要:1. 中断号 2. 中断处理函数。中断号实验手册已经通过set_trap_gate 函数告诉我们是0x21 (十进制的33) ,中断处理函数也已经告诉我们是keyboard_interrupt 函数。因此我们就搞清楚了我们需要进行修改的地方。
键盘输入与显示器显示整体流程
这里先给出一张图(来源Linux内核0.11完全注释),这张图展示了整个过程。
当用于在键盘上键入一个字符时,随即引起键盘中断,中断处理程序负责从键盘控制器读取对应的键盘扫描码,然后采用映射表译成相应字符并放入tty读队列read_q 。 然后通过中断处理程序do_tty_interrupt() 调用copy_to_cooked() 对该字符进行过滤处理,并放到tty辅助队列secondary 中,同时也把字符放入tty写队列write_q 当中并调用写控制台函数con_write() ,此时如果该终端的回显(echo )属性是设置了的,那么会直接显示到屏幕上。
do_tty_interrupt() 以及copy_to_cooked() 函数在tty_io.c 中实现。
con_write() 函数是在console.c 文件当中实现
总结来说:
主要涉及两个程序:键盘中断处理程序(keyboard.S )负责把用户键入的字符放到read_q 缓冲队列当中;另外一个是屏幕显示处理程序(console.c )用于从write_q 队列当中取出字符并显示到屏幕上。
基于以上认识,你就能明白大部分教程里面都有一张图,这张图展示了三个缓冲队列以及函数之间的关系,如下所示:
从键盘键入的数据可以写入文件,也可以回显到屏幕当中。我们只关心回显那条路。通过图中分析可知,我们只需要对console.c 文件(/linux/kernel/chr_drv 目录下)当中负责给终端写入字符的con_write 函数加以修改就OK。那么如何修改?
con_write() 函数往屏幕缓冲区写入的数据取决于是否按下f12, 因此我们需要时时刻刻监控是否按下f12。为此,我们可以定义一个全局变量switch_show_char_flag 来检测当前f12的状态,以及一个能够修改这个全局变量的回调函数。(这个回调函数不就是我们按下f12之后的中断相应函数么?)
在keyboard.S 当中定义了f12响应函数:
.long none,none,do_self,func
.long func,none,none,none
.long none,none,none,none
.long none,none,none,none
我们可以把func 函数替换成我们自定义的函数用于更新全局变量switch_show_char_flag 。
自此实验思路就有了!
实验过程
通过以上分析,我们可以将实验分为以下几个步骤。
- 设置监控变量S
- 重写f12响应函数
func 用来修改S - 根据S判断
con_write 函数是否写入*
-
在include/linux/tty.h当中声明监控变量S以及响应函数(这个可以自定义,比如我定义为press_f12_handle ) extern int switch_show_char_flag;
void press_f12_handle(void);
-
在kernel/chr_drv/tty_io.c 末尾添加,用来定义设置监控变量S以及响应函数 int switch_show_char_flag=0;
void press_f12_handle(void)
{
switch_show_char_flag=1-switch_show_char_flag;
}
-
在linux 0.11/chr_drv/keyboard.S 中将我们自定义的响应函数替代默认的func 函数 .long none,none,do_self,func
.long press_f12_handle,none,none,none
.long none,none,none,none
.long none,none,none,none
-
最后在Linux 0.11/kernel/chr_drv/console.c 当中修改con_write 函数 ......
......
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++;
}
......
......
实验结束,编译运行看看结果吧!
|