实验7-终端设备的控制
实验内容请查看实验指导手册
绪论
根据题目的要求,可以想到一共需要改两个地方:
第一个地方:我们首先需要把F12
原有的功能屏蔽掉,然后改成我们要用到的“开关”功能,即设定一个变量flag表示开关标记,按一次F12后flag变成1,再按一次flag变成0,再按又变成1。
第二个地方:在字符输出到显示器前,根据flag
的值来决定显示正常字符或者显示*字符。
一、实验内容
(1)修改linux-0.11/kernel/chr_drv/keyboard.S文件
正常情况下在linux0.11中,当按下F1~F12的功能键后会调用show_stat
函数来显示系统中当前进程状态,对应代码在kernel/chr_drv/keyboard.S文件中,第210行func
函数中:
func:
push %eax
push %ecx
push %edx
call show_stat
pop %edx
pop %ecx
pop %eax
将语句call show_stat
删除掉,因为我们不需要原有的F12
所对应的按键功能了。
(2)修改tty_io.c文件
该文件中的copy_to_cooked
函数是处理ASCII
字符的函数。先在该函数的定义外面增加全局变量如下,flag
即开关标志,f1~f3
是等会判断要用到的一些中间变量。
int flag = 0;
int f1=0,f2=0,f3=0;
然后在copy_to_cooked
函数中添加一部分内容,使其识别到F12
对应的那四个ASCII字符后(F12
这个功能键的扫描码是ESC、[、[、L,它们对应的ASCII码是27,91,91,76),改变flag
的值,然后continue
跳过本轮循环(否则会继续执行后面的代码从而导致按下F12
时会显示一个字符L),如下:
void copy_to_cooked(struct tty_struct * tty)
{
signed char c;
while (!EMPTY(tty->read_q) && !FULL(tty->secondary)) {
GETCH(tty->read_q,c);
//下面开始添加代码
if(c==27){
f1 = 1;
f2=f3=0;
}
else if(f1==1 && f2==0 && c==91){
f2 = 1;
}
else if(f2==1 && f3==0 && c==91){
f3 = 1;
}
else if(f3==1 && c==76 && flag==0){
flag = 1;
f1=f2=f3=0;
continue;
}
else if(f3==1 && c==76 && flag==1){
flag = 0;
f1=f2=f3=0;
continue;
}
else{
f1=f2=f3=0;
}
//添加代码结束
(3)修改console.c文件
在(kernel/chr_drv/console.c)文件中定义的con_write()
函数中,它对队列中的字符进行了一些处理后,最终放入显存。如下是将字符变量c
放入显存的代码:
__asm__("movb attr,%%ah\n\t"
"movw %%ax,%1\n\t"
::"a" (c),"m" (*(short *)pos)
);
所以我们只需要在这段代码之前加上一条if语句,判断flag
如果是1,则把要放入显存中的字符变成星号,修改后如下(需要在该函数中先通过extern int flag
这条语句来声明外部变量 ,因为flag
在现在的这个文件中还没有定义过):
/* 在文件的头部添加变量声明语句 */
extern int flag;
/* ... */
//添加开始
while(nr--){
/* ... */
if(flag == 1){
c = '*';
}
//添加结束
__asm__("movb attr,%%ah\n\t"
"movw %%ax,%1\n\t"
::"a" (c),"m" (*(short *)pos)
);
/* ... */
(4)编译测试
保存所有修改过的文件,使用make all
指令重新编译内核。编译成功后,返回上一级菜单,使用./run
启动Bochs:
(1)启动Bochs:
(2)第一次按F12
:
(3)第二次按F12
:
二、回答问题
1.在原始代码中,按下 F12,中断响应后,中断服务程序会调用 func,它实现的是什么功能?
正常情况下打开模拟器中,按下功能键F12即可显示内核栈中各个进程的状态信息,而当把func中的call show_stat屏蔽掉后,再按下F12就什么也没有了,可见func实现的功能就是调用show_stat函数来显示内核栈中各个进程的状态信息。
2.在你的实现中,是否把向文件输出的字符也过滤了?
只过滤了向终端输出的字符,向文件输出的字符没有被过滤。
因为我们最后修改的是控制向显存输出的con_write()函数,使其当flag=1的时候向显存输出星号。
如果要过滤掉向文件输出的字符的话,需要找到对应的那个控制向文件输出的函数并修改。