Linux-0.11操作系统实验7-终端设备的控制
实验环境:终端设备的控制实验任务:修改 Linux 0.11 的终端设备处理代码,对键盘输入和字符显示进行非常规的控制。在初始状态,一切如常。用户按一次F12 后,把应用程序向终端输出所有字母都替换为“*”。用户再按一次F12,又恢复正常。第三次按 F12,再进行输出替换。依此类推。实验本质:IO的使用:让外设工作起来表现为CPU给外设的硬件寄存器发送指令,控制器完成真正的工作,向CPU发...
实验环境:终端设备的控制
实验任务:修改 Linux 0.11
的终端设备处理代码,对键盘输入和字符显示进行非常规的控制。在初始状态,一切如常。用户按一次F12
后,把应用程序向终端输出所有字母都替换为“*”
。用户再按一次F12
,又恢复正常。第三次按 F12
,再进行输出替换。依此类推。
实验本质:
- IO的使用:让外设工作起来表现为CPU给外设的硬件寄存器发送指令,控制器完成真正的工作,向CPU发中断信号,然后CPU进行中断处理。操作系统要给用户提供一个简单视图-----文件视图,将CPU与外设链接起来。
实验思路:
-
键盘中断初始化
键盘中断的初始化在
boot/main.c
文件的init()
函数中,在这个函数中会调用tty_init()
函数对显卡的变量等进行设置(如:video_size_row
,vide_mem_start
,video_port_reg
,video_port_val
,video_mem_end
等等),并对键盘中断0x21
设置,将中断过程指向keyboard_interrupt
函数(这是通过set_trap_gate(0x21, &keyboard_interrupt)
语句来实现的。 -
键盘中断发生
当键盘中断发生时,
intb $0x60,%al
指令会取出键盘的扫描码,放在al
寄存器中,然后查key_table表进行扫描码处理,key_table
表中定义了相关所有扫描码对应键的处理函数(如do_self
,func
,alt
,ctrl
,none
等),比如f1-f12
键的处理则要先运行一段处理函数func
,调用sched.c
中定义的show_stat
函数显示当前进程情况,默认情况linux-0.11
中所有的功能键都进行这样的动作,然后下一步将控制键以及功能键进行转义,比如ctrl_a
将会被转义为^a
,f1
会被转义为esc[[A
,f2
被转义为esc[[B
,而其他键也经过类似处理,处理完毕后将跳到put_queue
,将扫描码放在键盘输入队列中,当然如果没有对应的扫描码被找到,则会通过none
标签直接退回,不会被放入队列。然后再调用do_tty_interrupt
函数进行最后的处理。do_tty_interrupt
直接调用copy_to_cooked
函数对队列中的字符进行判断处理,最后调用con_write
函数将其输出到显卡内存。在此同时,也会将字符放入辅助队列中,以备缓冲区读写程序使用。 -
字符输出流程
无论是输出字符到屏幕上还是文件中,系统最终都会调用
write
函数来进行,而write
函数则会调用sys_write
系统调用来实现字符输出,如果是输出到屏幕上,则会调用tty_write
函数,而tty_write
最终也会调用con_write
函数将字符输出;如果是输出到文件中,则会调用file_write
函数直接将字符输出到指定的文件缓冲区中。所以无论是键盘输入的回显,还是程序的字符输出,那只需要修改con_write
最终写到显存中的字符就可以了。但如果要控制字符输出到文件中,则需要修改file_write
函数中输出到文件缓冲区中的字符即可。
读队列read_q
用于存放从键盘或串行终端输入的原始( raw )
字符序列;写队列write_q
用于存放写到控制台显示屏或串行终端去的数据;辅助队列secondary
用于存放经过行规则程序处理(过滤)过的数据,或称为熟(cooked)
模式数据。上层终端读函数tty_read
用于读取secondary
队列中的字符。
对于一个控制台,当用户在键盘上键入了一个字符时,会引起键盘中断响应(中断请求信号 IRQ1, 对应中断号 INT 33 ),此时键盘中断处理程序就会从键盘控制器读入对应的键盘扫描码,然后根据使用的键盘扫描码映射表译成相应字符,放入tty
读队列read_q
中。然后调用中断处理程序的 C函数do_tty_interrupt()
,它又直接调用行规则函数copy_to_cooked()
对该字符进行过滤处理,并放入 tty 辅助队列secondary
中,同时把该字符放入tty
写队列write_q
中,并调用写控制台函数con_write()
。此时如果该终端的回显( echo )属性是设置的,则该字符会显示到屏幕上。do_tty_interrupt()
和copy_to_cooked()
函数在tty_io.c
中实现。有关控制台终端操作的驱动程序,主要涉及两个程序。一个是键盘中断处理程序
keyboard.S
,主要用于读入用户键入的字符并放入read_q
缓冲队列中;另一个是屏幕显示处理程序console.c
,用于从write_q
队列中取出字符并显示在屏幕上。
添加F12
功能键盘处理
-
修改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; } }
-
修改/include/linux/tty.h文件,在末尾添加:
extern int switch_show_char_flag; void press_f12_handle(void);
-
修改kernel/chr_drv/keyboard.S文件,修改key_table代码如下:
/* .long func,none,none,none 58-5B f12 ? ? ? */ .long press_f12_handle,none,none,none
添加字符*
显示处理
-
修改linux-0.11/kernel/chr_drv/console.c文件,修改con_write函数:
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++;
-
重新编译内核,make all
-
运行bochs,测试结果如下:
实验问题
- 在原始代码中,按下 F12,中断响应后,中断服务程序会调用 func?它实现的是什么功能?
将F12转义成转义字符序列 [ [ L , 对F1-F12处理类似 [ [ A -> [ [ L
- 在你的实现中,是否把向文件输出的字符也过滤了?如果是,那么怎么能只过滤向终端输出的字符?如果不是,那么怎么能把向文件输出的字符也一并进行过滤?
没有把向文件输出的字符过滤,只过滤向终端输出的字符是通过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;
}
参考链接:
https://blog.csdn.net/Watson2016/article/details/72188549
https://blog.csdn.net/realfancy/article/details/90544792
更多推荐
所有评论(0)