实验内容
本实验的基本内容是修改Linux 0.11的终端设备处理代码,对键盘输入和字符显示进行非常规的控制。
在初始状态,一切如常。用户按一次F12后,把应用程序向终端输出所有字母都替换为“*”。用户再按一次F12,又恢复正常。第三次按F12,再进行输出替换。依此类推。
以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/keyboard.S
func:
/*程序210行子函数处理功能键
将功能键转化成转义字符存取到读队列中*/
pushl %eax
pushl %ecx
pushl %edx
//call show_stat //将该行注释掉,调用显示各任务的状态函数,我们不需要显示
popl %edx
popl %ecx
popl %eax
linux-0.11/kernel/chr_drv/tty_io.c
修改copy_to_cooked函数
增加字符判断,由于按下F12时,判断是否为F1-F12的扫描码,若是,则将查func_table中的4个字节的转义字符序列放入缓冲队列中。
若不是,则不处理并返回。例如:功能键发送的扫描码,F12键为:‘esc [ [ L’。
具体参考:Linux0.11完全注释keyboard.S文件238行左右的代码。
/*
* linux/kernel/tty_io.c
*
* (C) 1991 Linus Torvalds
*/
/*
* 'tty_io.c' gives an orthogonal feeling to tty's, be they consoles
* or rs-channels. It also implements echoing, cooked mode etc.
*
* Kill-line thanks to John T Kohl.
*/
#include <ctype.h>
#include <errno.h>
#include <signal.h>
#define ALRMMASK (1<<(SIGALRM-1))
#define KILLMASK (1<<(SIGKILL-1))
#define INTMASK (1<<(SIGINT-1))
#define QUITMASK (1<<(SIGQUIT-1))
#define TSTPMASK (1<<(SIGTSTP-1))
#include <linux/sched.h>
#include <linux/tty.h>
#include <asm/segment.h>
#include <asm/system.h>
#define _L_FLAG(tty,f) ((tty)->termios.c_lflag & f)
#define _I_FLAG(tty,f) ((tty)->termios.c_iflag & f)
#define _O_FLAG(tty,f) ((tty)->termios.c_oflag & f)
#define L_CANON(tty) _L_FLAG((tty),ICANON)
#define L_ISIG(tty) _L_FLAG((tty),ISIG)
#define L_ECHO(tty) _L_FLAG((tty),ECHO)
#define L_ECHOE(tty) _L_FLAG((tty),ECHOE)
#define L_ECHOK(tty) _L_FLAG((tty),ECHOK)
#define L_ECHOCTL(tty) _L_FLAG((tty),ECHOCTL)
#define L_ECHOKE(tty) _L_FLAG((tty),ECHOKE)
#define I_UCLC(tty) _I_FLAG((tty),IUCLC)
#define I_NLCR(tty) _I_FLAG((tty),INLCR)
#define I_CRNL(tty) _I_FLAG((tty),ICRNL)
#define I_NOCR(tty) _I_FLAG((tty),IGNCR)
#define O_POST(tty) _O_FLAG((tty),OPOST)
#define O_NLCR(tty) _O_FLAG((tty),ONLCR)
#define O_CRNL(tty) _O_FLAG((tty),OCRNL)
#define O_NLRET(tty) _O_FLAG((tty),ONLRET)
#define O_LCUC(tty) _O_FLAG((tty),OLCUC)
int flag = -1;
int flag1 = 0;
int flag2 = 0;
int flag3 = 0;
int flag4 = 0;
struct tty_struct tty_table[] = {
{
{ICRNL, /* change incoming CR to NL */
OPOST|ONLCR, /* change outgoing NL to CRNL */
0,
ISIG | ICANON | ECHO | ECHOCTL | ECHOKE,
0, /* console termio */
INIT_C_CC},
0, /* initial pgrp */
0, /* initial stopped */
con_write,
{0,0,0,0,""}, /* console read-queue */
{0,0,0,0,""}, /* console write-queue */
{0,0,0,0,""} /* console secondary queue */
},{
{0, /* no translation */
0, /* no translation */
B2400 | CS8,
0,
0,
INIT_C_CC},
0,
0,
rs_write,
{0x3f8,0,0,0,""}, /* rs 1 */
{0x3f8,0,0,0,""},
{0,0,0,0,""}
},{
{0, /* no translation */
0, /* no translation */
B2400 | CS8,
0,
0,
INIT_C_CC},
0,
0,
rs_write,
{0x2f8,0,0,0,""}, /* rs 2 */
{0x2f8,0,0,0,""},
{0,0,0,0,""}
}
};
/*
* these are the tables used by the machine code handlers.
* you can implement pseudo-tty's or something by changing
* them. Currently not done.
*/
struct tty_queue * table_list[]={
&tty_table[0].read_q, &tty_table[0].write_q,
&tty_table[1].read_q, &tty_table[1].write_q,
&tty_table[2].read_q, &tty_table[2].write_q
};
void tty_init(void)
{
rs_init();
con_init();
}
void tty_intr(struct tty_struct * tty, int mask)
{
int i;
if (tty->pgrp <= 0)
return;
for (i=0;i<NR_TASKS;i++)
if (task[i] && task[i]->pgrp==tty->pgrp)
task[i]->signal |= mask;
}
static void sleep_if_empty(struct tty_queue * queue)
{
cli();
while (!current->signal && EMPTY(*queue))
interruptible_sleep_on