目录
一、实验目的
二、实验内容
三、实验准备
1. 键盘输入处理过程
2. 输出字符的控制
四、实验过程
1. 添加 F12 键盘功能处理
2. 添加 * 字符的显示处理
3. 重新编译内核
4. 运行 Linux 0.11
五、实验报告
一、实验目的
1、加深对操作系统设备管理基本原理的认识,实践键盘中断、扫描码等概念。
2、通过实践掌握 Linux 0.11 对键盘终端和显示器终端的处理过程。
二、实验内容
本次实验的基本内容是修改 Linux 0.11 的终端设备处理代码,对键盘输入和字符显示进行非常规的控制。
初始状态,一切如常。用户按一次 F12 后,把应用程序向终端输出所有字母都替换为 * 。用户再按一次 F12,又恢复正常。第三次按 F12,再次进行输出替换。之后依此类推。
以 ls 命令为例
正常情况下输入 ls:
# ls
hello.c hello.o hello
第一次按 F12,然后输入 ls:
# **
*****.* *****.* *****
第二次按 F12,然后输入 ls:
# ls
hello.c hello.o hello
第三次按 F12,然后输入 ls:
# **
*****.* *****.* *****
【实验提示】
本次实验需要修改 Linux 0.11 的终端设备处理代码( kernel/chr_drv/console.c
文件),对键盘输入和字符显示进行非常规的控制。
三、实验准备
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()
,就能控制好输出字符。
四、实验过程
建议看看这篇文章理解实验的思路,写的很详细:操作系统实验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 循环一个个地取字符进行处理,然后放入显存。
所以可以在字符放入显存之前进行一次过滤,当 F12_flag == 1
时将字符都转变为 * 。
3. 重新编译内核
// linux-0.11 目录下
make all
4. 运行 Linux 0.11
进入 Linux 0.11 ,测试结果如下:
五、实验报告
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;
}