美文网首页
哈工大操作系统实验(五)I/O设备管理

哈工大操作系统实验(五)I/O设备管理

作者: 寒夏凉秋 | 来源:发表于2017-07-02 11:06 被阅读0次

    本次实验内容:
    本实验的基本内容是修改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的文件

    首先我们得知道 在修改之前,按下F12什么功能;
    键盘I/O是典型的中断驱动,在kernel/chr_drv/console.c文件中:

    void con_init(void) //控制台的初始化
    {
    set_trap_gate(0x21,&keyboard_interrupt); //键盘中断响应函数设为keyboard_interrupt
    }
    所以每次按键有动作,keyboard_interrupt函数就会被调用,它在文件kernel/chr_drv/keyboard.S

    func:
        /*程序210行子函数处理功能键
          将功能键转化成转义字符存取到读队列中*/
        pushl %eax
        pushl %ecx
        pushl %edx
        call show_stat  
        popl %edx
        popl %ecx
        popl %eax
    
    调用 show_stat 函数,显示当前 进程状态
    
    屏蔽了 call  show_stat的功能再改成我们自己的的功能就好了
    func:
        /*程序210行子函数处理功能键
          将功能键转化成转义字符存取到读队列中*/
        pushl %eax
        pushl %ecx
        pushl %edx
        //call show_stat  
        popl %edx
        popl %ecx
        popl %eax
    

    (二)修改tty_io.c文件

    linux-0.11/kernel/chr_drv/tty_io.c

    键盘每次输入一个字符,操作系统都会将这个字符送到字符缓冲区进行处理.
    f12是一个功能键,它的扫描码是 esc,[,[,L
    分别对应ascii码的27,91,91,76
    所以要连续判断四次 字符呀
    你说 那我判断这几个字符的时候输出了一个其他的字符,它应该显示这个其他字符啊.
    所以这段处理程序就应该写在 操作系统判断字符做出功能的代码之前.

    判断字符的代码是copy_to_cooked函数

    增加的全局变量
    int judge=-1;
    int f1=0,f2=0,f3=0;
    long j=0;
    
    void copy_to_cooked(struct tty_struct * tty)
    {
        signed char c;
    //now用来判断当前时间戳 
        long now;
         
        while (!EMPTY(tty->read_q) && !FULL(tty->secondary)) {
            GETCH(tty->read_q,c);
    //开始添加代码
            if(c==27)
        {   
            f1=1;
            j=jiffies;
    //获取当前 函数的CPU心跳数,用来计时
        }
                
            else if(f1==1&&f2==0&&c==91)
                f2=1;
            else if(f1==1&&f2==1&&c==91)
                f3=1;
            else if(f1==1&&f2==1&&f3==1&&c==76)
            {
                now=jiffies;
                if((now-j)>10)
    //比如人为的输入esc,[,[,J 也会认为是F12,所以要根据四个字符的到达的时间判断是一次输入还是多次输入的~
            {
                printk("%ld \t %ld \n",j,now);
                break;
            }
                
                judge*=-1;
                continue;
            }
            else
                f1=f2=f3=0;
    //添加代码结束
            if (c==13)
                if (I_CRNL(tty))
                    c=10;
                else if (I_NOCR(tty))
                    continue;
                else ;
            else if (c==10 && I_NLCR(tty))
                c=13;
            if (I_UCLC(tty))
                c=tolower(c);
            if (L_CANON(tty)) {
                if (c==KILL_CHAR(tty)) {
                    /* deal with killing the input line */
                    while(!(EMPTY(tty->secondary) ||
                            (c=LAST(tty->secondary))==10 ||
                            c==EOF_CHAR(tty))) {
                        if (L_ECHO(tty)) {
                            if (c<32)
                                PUTCH(127,tty->write_q);
                            PUTCH(127,tty->write_q);
                            tty->write(tty);
                        }
                        DEC(tty->secondary.head);
                    }
                    continue;
                }
                if (c==ERASE_CHAR(tty)) {
                    if (EMPTY(tty->secondary) ||
                       (c=LAST(tty->secondary))==10 ||
                       c==EOF_CHAR(tty))
                        continue;
                    if (L_ECHO(tty)) {
                        if (c<32)
                            PUTCH(127,tty->write_q);
                        PUTCH(127,tty->write_q);
                        tty->write(tty);
                    }
                    DEC(tty->secondary.head);
                    continue;
                }
                if (c==STOP_CHAR(tty)) {
                    tty->stopped=1;
                    continue;
                }
                if (c==START_CHAR(tty)) {
                    tty->stopped=0;
                    continue;
                }
            }
            if (L_ISIG(tty)) {
                if (c==INTR_CHAR(tty)) {
                    tty_intr(tty,INTMASK);
                    continue;
                }
                if (c==QUIT_CHAR(tty)) {
                    tty_intr(tty,QUITMASK);
                    continue;
                }
            }
            if (c==10 || c==EOF_CHAR(tty))
                tty->secondary.data++;
            if (L_ECHO(tty)) {
                if (c==10) {
                    PUTCH(10,tty->write_q);
                    PUTCH(13,tty->write_q);
                } else if (c<32) {
                    if (L_ECHOCTL(tty)) {
                        PUTCH('^',tty->write_q);
                        PUTCH(c+64,tty->write_q);
                    }
                } else
                    PUTCH(c,tty->write_q);
                tty->write(tty);
            }
            PUTCH(c,tty->secondary);
        }
        wake_up(&tty->secondary.proc_list);
    }
    

    修改后的tty_io.c文件

    /*
     *  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)
    long j;
    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(&queue->proc_list);
        sti();
    }
    
    static void sleep_if_full(struct tty_queue * queue)
    {
        if (!FULL(*queue))
            return;
        cli();
        while (!current->signal && LEFT(*queue)<128)
            interruptible_sleep_on(&queue->proc_list);
        sti();
    }
    
    void wait_for_keypress(void)
    {
        sleep_if_empty(&tty_table[0].secondary);
    }
    
    int judge=-1;
    int f1=0,f2=0,f3=0;
    
    void copy_to_cooked(struct tty_struct * tty)
    {
        signed char c;
        long now;
         
        while (!EMPTY(tty->read_q) && !FULL(tty->secondary)) {
            GETCH(tty->read_q,c);
            if(c==27)
        {   
            f1=1;
            j=jiffies;
        }
                
            else if(f1==1&&f2==0&&c==91)
                f2=1;
            else if(f1==1&&f2==1&&c==91)
                f3=1;
            else if(f1==1&&f2==1&&f3==1&&c==76)
            {
                now=jiffies;
                if((now-j)>10)
            {
                printk("%ld \t %ld \n",j,now);
                break;
            }
                
                judge*=-1;
                continue;
            }
            else
                f1=f2=f3=0;
    
            if (c==13)
                if (I_CRNL(tty))
                    c=10;
                else if (I_NOCR(tty))
                    continue;
                else ;
            else if (c==10 && I_NLCR(tty))
                c=13;
            if (I_UCLC(tty))
                c=tolower(c);
            if (L_CANON(tty)) {
                if (c==KILL_CHAR(tty)) {
                    /* deal with killing the input line */
                    while(!(EMPTY(tty->secondary) ||
                            (c=LAST(tty->secondary))==10 ||
                            c==EOF_CHAR(tty))) {
                        if (L_ECHO(tty)) {
                            if (c<32)
                                PUTCH(127,tty->write_q);
                            PUTCH(127,tty->write_q);
                            tty->write(tty);
                        }
                        DEC(tty->secondary.head);
                    }
                    continue;
                }
                if (c==ERASE_CHAR(tty)) {
                    if (EMPTY(tty->secondary) ||
                       (c=LAST(tty->secondary))==10 ||
                       c==EOF_CHAR(tty))
                        continue;
                    if (L_ECHO(tty)) {
                        if (c<32)
                            PUTCH(127,tty->write_q);
                        PUTCH(127,tty->write_q);
                        tty->write(tty);
                    }
                    DEC(tty->secondary.head);
                    continue;
                }
                if (c==STOP_CHAR(tty)) {
                    tty->stopped=1;
                    continue;
                }
                if (c==START_CHAR(tty)) {
                    tty->stopped=0;
                    continue;
                }
            }
            if (L_ISIG(tty)) {
                if (c==INTR_CHAR(tty)) {
                    tty_intr(tty,INTMASK);
                    continue;
                }
                if (c==QUIT_CHAR(tty)) {
                    tty_intr(tty,QUITMASK);
                    continue;
                }
            }
            if (c==10 || c==EOF_CHAR(tty))
                tty->secondary.data++;
            if (L_ECHO(tty)) {
                if (c==10) {
                    PUTCH(10,tty->write_q);
                    PUTCH(13,tty->write_q);
                } else if (c<32) {
                    if (L_ECHOCTL(tty)) {
                        PUTCH('^',tty->write_q);
                        PUTCH(c+64,tty->write_q);
                    }
                } else
                    PUTCH(c,tty->write_q);
                tty->write(tty);
            }
            PUTCH(c,tty->secondary);
        }
        wake_up(&tty->secondary.proc_list);
    }
    
    int tty_read(unsigned channel, char * buf, int nr)
    {
        struct tty_struct * tty;
        char c, * b=buf;
        int minimum,time,flag=0;
        long oldalarm;
    
        if (channel>2 || nr<0) return -1;
        tty = &tty_table[channel];
        oldalarm = current->alarm;
        time = 10L*tty->termios.c_cc[VTIME];
        minimum = tty->termios.c_cc[VMIN];
        if (time && !minimum) {
            minimum=1;
            if ((flag=(!oldalarm || time+jiffies<oldalarm)))
                current->alarm = time+jiffies;
        }
        if (minimum>nr)
            minimum=nr;
        while (nr>0) {
            if (flag && (current->signal & ALRMMASK)) {
                current->signal &= ~ALRMMASK;
                break;
            }
            if (current->signal)
                break;
            if (EMPTY(tty->secondary) || (L_CANON(tty) &&
            !tty->secondary.data && LEFT(tty->secondary)>20)) {
                sleep_if_empty(&tty->secondary);
                continue;
            }
            do {
                GETCH(tty->secondary,c);
                if (c==EOF_CHAR(tty) || c==10)
                    tty->secondary.data--;
                if (c==EOF_CHAR(tty) && L_CANON(tty))
                    return (b-buf);
                else {
                    put_fs_byte(c,b++);
                    if (!--nr)
                        break;
                }
            } while (nr>0 && !EMPTY(tty->secondary));
            if (time && !L_CANON(tty)) {
                if ((flag=(!oldalarm || time+jiffies<oldalarm)))
                    current->alarm = time+jiffies;
                else
                    current->alarm = oldalarm;
            }
            if (L_CANON(tty)) {
                if (b-buf)
                    break;
            } else if (b-buf >= minimum)
                break;
        }
        current->alarm = oldalarm;
        if (current->signal && !(b-buf))
            return -EINTR;
        return (b-buf);
    }
    
    int tty_write(unsigned channel, char * buf, int nr)
    {
        static int cr_flag=0;
        struct tty_struct * tty;
        char c, *b=buf;
    
        if (channel>2 || nr<0) return -1;
        tty = channel + tty_table;
        while (nr>0) {
            sleep_if_full(&tty->write_q);
            if (current->signal)
                break;
            while (nr>0 && !FULL(tty->write_q)) {
                c=get_fs_byte(b);
                if (O_POST(tty)) {
                    if (c=='\r' && O_CRNL(tty))
                        c='\n';
                    else if (c=='\n' && O_NLRET(tty))
                        c='\r';
                    if (c=='\n' && !cr_flag && O_NLCR(tty)) {
                        cr_flag = 1;
                        PUTCH(13,tty->write_q);
                        continue;
                    }
                    if (O_LCUC(tty))
                        c=toupper(c);
                }
                b++; nr--;
                cr_flag = 0;
                PUTCH(c,tty->write_q);
            }
            tty->write(tty);
            if (nr>0)
                schedule();
        }
        return (b-buf);
    }
    
    /*
     * Jeh, sometimes I really like the 386.
     * This routine is called from an interrupt,
     * and there should be absolutely no problem
     * with sleeping even in an interrupt (I hope).
     * Of course, if somebody proves me wrong, I'll
     * hate intel for all time :-). We'll have to
     * be careful and see to reinstating the interrupt
     * chips before calling this, though.
     *
     * I don't think we sleep here under normal circumstances
     * anyway, which is good, as the task sleeping might be
     * totally innocent.
     */
    void do_tty_interrupt(int tty)
    {
        copy_to_cooked(tty_table+tty);
    }
    
    void chr_dev_init(void)
    {
    }
    
    

    (三)修改linux-0.11/kernel/chr_drv/console.c

    tty_io.c文件只是捕捉到了按下f12的状态
    我们需要在控制程序中添加 改变输出的代码,最简单的方法是只要按下F12就把所有的字符都变成"*"号输出就行了
    我们只要在con_write()函数中添加一行代码:

    extern int judge;//引用代码tty_io.c中的judge变量
    
    if(judge==1)
        c='*';
    

    con_write函数:

    extern int judge;
    
    void con_write(struct tty_struct * tty)
    {
        int nr;
        char c;
    
        nr = CHARS(tty->write_q);
        while (nr--) {
            GETCH(tty->write_q,c);
            switch(state) {
                case 0:
                    if (c>31 && c<127) {
                        if (x>=video_num_columns) {
                            x -= video_num_columns;
                            pos -= video_size_row;
                            lf();
                        }
                        if(judge==1)
                                c='*';
                        __asm__("movb attr,%%ah\n\t"
                            "movw %%ax,%1\n\t"
                            ::"a" (c),"m" (*(short *)pos)
                            );
                        pos += 2;
                        x++;
                    } else if (c==27)
                        state=1;
                    else if (c==10 || c==11 || c==12)
                        lf();
                    else if (c==13)
                        cr();
                    else if (c==ERASE_CHAR(tty))
                        del();
                    else if (c==8) {
                        if (x) {
                            x--;
                            pos -= 2;
                        }
                    } else if (c==9) {
                        c=8-(x&7);
                        x += c;
                        pos += c<<1;
                        if (x>video_num_columns) {
                            x -= video_num_columns;
                            pos -= video_size_row;
                            lf();
                        }
                        c=9;
                    } else if (c==7)
                        sysbeep();
                    break;
                case 1:
                    state=0;
                    if (c=='[')
                        state=2;
                    else if (c=='E')
                        gotoxy(0,y+1);
                    else if (c=='M')
                        ri();
                    else if (c=='D')
                        lf();
                    else if (c=='Z')
                        respond(tty);
                    else if (x=='7')
                        save_cur();
                    else if (x=='8')
                        restore_cur();
                    break;
                case 2:
                    for(npar=0;npar<NPAR;npar++)
                        par[npar]=0;
                    npar=0;
                    state=3;
                    if ((ques=(c=='?')))
                        break;
                case 3:
                    if (c==';' && npar<NPAR-1) {
                        npar++;
                        break;
                    } else if (c>='0' && c<='9') {
                        par[npar]=10*par[npar]+c-'0';
                        break;
                    } else state=4;
                case 4:
                    state=0;
                    switch(c) {
                        case 'G': case '`':
                            if (par[0]) par[0]--;
                            gotoxy(par[0],y);
                            break;
                        case 'A':
                            if (!par[0]) par[0]++;
                            gotoxy(x,y-par[0]);
                            break;
                        case 'B': case 'e':
                            if (!par[0]) par[0]++;
                            gotoxy(x,y+par[0]);
                            break;
                        case 'C': case 'a':
                            if (!par[0]) par[0]++;
                            gotoxy(x+par[0],y);
                            break;
                        case 'D':
                            if (!par[0]) par[0]++;
                            gotoxy(x-par[0],y);
                            break;
                        case 'E':
                            if (!par[0]) par[0]++;
                            gotoxy(0,y+par[0]);
                            break;
                        case 'F':
                            if (!par[0]) par[0]++;
                            gotoxy(0,y-par[0]);
                            break;
                        case 'd':
                            if (par[0]) par[0]--;
                            gotoxy(x,par[0]);
                            break;
                        case 'H': case 'f':
                            if (par[0]) par[0]--;
                            if (par[1]) par[1]--;
                            gotoxy(par[1],par[0]);
                            break;
                        case 'J':
                            csi_J(par[0]);
                            break;
                        case 'K':
                            csi_K(par[0]);
                            break;
                        case 'L':
                            csi_L(par[0]);
                            break;
                        case 'M':
                            csi_M(par[0]);
                            break;
                        case 'P':
                            csi_P(par[0]);
                            break;
                        case '@':
                            csi_at(par[0]);
                            break;
                        case 'm':
                            csi_m();
                            break;
                        case 'r':
                            if (par[0]) par[0]--;
                            if (!par[1]) par[1] = video_num_lines;
                            if (par[0] < par[1] &&
                                par[1] <= video_num_lines) {
                                top=par[0];
                                bottom=par[1];
                            }
                            break;
                        case 's':
                            save_cur();
                            break;
                        case 'u':
                            restore_cur();
                            break;
                    }
            }
        }
        set_cursor();
    }
    
    

    (四)大功告成,编译运行把~

    报告:

    (1)在原始代码中,按下F12,中断响应后,中断服务程序会调用func?它实现的是什么功能?
    将F12转义成转义字符序列 [ [ L , 对F1-F12处理类似 [ [ A -> [ [ L

    (2) 在你的实现中,是否把向文件输出的字符也过滤了?如果是,那么怎么能只过滤向终端输出的字符?如果不是,那么怎么能把向文件输出的字符也一并进行过滤?

    实现中并没有把向文件输出的字符也过滤,在copy_to_cooked函数处理中并不是将字符放到write_q,然后调用con_write来显示到控制台。
    而是shell通过上层的sys_write系统调用将tty->secondary队列中的字符显示出来的。而在sys_write的实现过程中调用了tty_write函数。
    所以只修改tty_write后,按键回显当然也变成’*’,第二次按的时候回复原来的样子;

    因此要想将向文件输出的字符一并进行过滤,需要修改file_write函数。设置Flag,如果为F12按下状态,将从内核态读出的数据转为‘*’赋给用户空间即可

    相关文章

      网友评论

          本文标题:哈工大操作系统实验(五)I/O设备管理

          本文链接:https://www.haomeiwen.com/subject/iligcxtx.html