linux键盘IO探究和实验[基于哈工大操作系统实验]

来源:互联网 发布:淘宝手机端图片不清晰 编辑:程序博客网 时间:2024/06/05 19:51

    我们使用的键盘,看似非常简单自然,但是其功能的实现却相当有学问,本文将以哈工大操作系统IO设备实验为基础,讲解一下linux0.11下键盘功能的实现,和简单修改的方法。

一,实现原理

键盘功能主要由如下几个程序实现:

keyboard.S     : 大S,引入c++预编译,使得汇编程序可以用预处理命令。接受键盘中断反馈的键盘码。

tty_io.c           :读汇编程序吃剩下的东西,嚼完往下扔。

console.c       :对了,嚼完的被他接住了....他再嚼两下,吐到您的屏幕上。

 

也就是说,一个字符从敲击至到达屏幕,经过的路程简要来说是这样的:

keyboard.S   ---read_queue---->  tty_io.c   --------write_queue----->  console.c  ----调用__asm__()---> 屏幕。

不关心这些东西,想直接过实验的同学可以直接跳到五

二,keyboard.S 程序和 f12 功能键

先看一下keyboard.s程序:

 

/* *  linux/kernel/keyboard.S * *  (C) 1991  Linus Torvalds *Thanks to Alfred Leung for US keyboard patches *Wolfgang Thiel for German keyboard patches *Marc Corsini for the French keyboard */#include <linux/config.h>.text.globl keyboard_interrupt/* * these are for the keyboard read functions */size= 1024/* must be a power of two ! And MUST be the same   as in tty_io.c !!!! */head = 4tail = 8proc_list = 12buf = 16mode:.byte 0/* caps, alt, ctrl and shift mode */leds:.byte 2/* num-lock, caps, scroll-lock mode (nom-lock on) */e0:.byte 0/* *  con_int is the real interrupt routine that reads the *  keyboard scan-code and converts it into the appropriate下方的中断服务函数,将按键扫描码,转换成ASCII码 *  ascii character(s). */keyboard_interrupt:/*这个是键盘中断函数,没几行代码,每次按键盘,就进入这里*/pushl %eaxpushl %ebxpushl %ecxpushl %edxpush %dspush %esmovl $0x10,%eaxmov %ax,%dsmov %ax,%esxor %al,%al/* %eax 寄存器放的,就是这次按键按下的按钮编码 */inb $0x60,%alcmpb $0xe0,%al     /* 简单比较处理一下 */je set_e0cmpb $0xe1,%alje set_e1call key_table(,%eax,4)/* 将 eax 按钮号码交给 【key_table】 映射到相应处理函数。keytable 在程序末尾*/movb $0,e0e0_e1:inb $0x61,%aljmp 1f1:jmp 1f1:orb $0x80,%aljmp 1f1:jmp 1f1:outb %al,$0x61jmp 1f1:jmp 1f1:andb $0x7F,%aloutb %al,$0x61movb $0x20,%aloutb %al,$0x20pushl $0call do_tty_interruptaddl $4,%esppop %espop %dspopl %edxpopl %ecxpopl %ebxpopl %eaxiretset_e0:movb $1,e0jmp e0_e1set_e1:movb $2,e0jmp e0_e1/* * This routine fills the buffer with max 8 bytes, taken from * %ebx:%eax. (%edx is high). The bytes are written in the * order %al,%ah,%eal,%eah,%bl,%bh ... until %eax is zero. */put_queue:               /*写队列函数,调用时,把接收到的一组按钮吐到read_queue里面给tty_io*/pushl %ecxpushl %edxmovl table_list,%edx# read-queue for consolemovl head(%edx),%ecx1:movb %al,buf(%edx,%ecx)incl %ecxandl $size-1,%ecxcmpl tail(%edx),%ecx# buffer full - discard everythingje 3fshrdl $8,%ebx,%eaxje 2fshrl $8,%ebxjmp 1b2:movl %ecx,head(%edx)movl proc_list(%edx),%ecxtestl %ecx,%ecxje 3fmovl $0,(%ecx)3:popl %edxpopl %ecxret                          /*控制特殊键盘按钮的处理函数 ,alt shift ctrl 什么的*/ctrl:movb $0x04,%aljmp 1falt:movb $0x10,%al1:cmpb $0,e0je 2faddb %al,%al2:orb %al,moderetunctrl:movb $0x04,%aljmp 1funalt:movb $0x10,%al1:cmpb $0,e0je 2faddb %al,%al2:notb %alandb %al,moderetlshift:orb $0x01,moderetunlshift:andb $0xfe,moderetrshift:orb $0x02,moderetunrshift:andb $0xfd,moderetcaps:testb $0x80,modejne 1fxorb $4,ledsxorb $0x40,modeorb $0x80,modeset_leds:call kb_waitmovb $0xed,%al/* set leds command */outb %al,$0x60call kb_waitmovb leds,%aloutb %al,$0x60retuncaps:andb $0x7f,moderetscroll:xorb $1,ledsjmp set_ledsnum:xorb $2,ledsjmp set_leds/* *  curosr-key/numeric keypad cursor keys are handled here. *  checking for numeric keypad etc. */cursor:                    /*光标处理,不用管,代码省略*/......cur2:/* e0 forces cursor movement */...cur:...ok_cur:...#if defined(KBD_FR)num_table:.ascii "789 456 1230."#elsenum_table:.ascii "789 456 1230,"#endifcur_table:.ascii "HA5 DGC YB623"/* * 下面这个函数有意思了,他就是处理function1-12的函数,从下面的映射表key_table可以看出,任意F被按下都跳到这里处理 */func:pushl %eaxpushl %ecxpushl %edxcall show_stat  /*这里调用了一个位于【sched.c】中的c语言系统调用函数,打开sched.c可以看到,这是输出进程状态的函数【show_stat()】,也就是说,linux0.11中,不管是f几,都要show_stat*/popl %edxpopl %ecxpopl %eaxsubb $0x3B,%aljb end_funccmpb $9,%aljbe ok_funcsubb $18,%alcmpb $10,%aljb end_funccmpb $11,%alja end_funcok_func:cmpl $4,%ecx/* check that there is enough room */jl end_funcmovl func_table(,%eax,4),%eaxxorl %ebx,%ebxjmp put_queueend_func:ret/* * function keys send F1:'esc [ [ A' F2:'esc [ [ B' etc.  这里是【F1到F12的扫描码表】,可见 F12其实是一个esc [[ L 信号 如果处理不当,L就会变成字符溢出  很显然,这里Linus先生压根没处理F12按键,所以L字符溢出到了显示屏幕上*/func_table:.long 0x415b5b1b,0x425b5b1b,0x435b5b1b,0x445b5b1b.long 0x455b5b1b,0x465b5b1b,0x475b5b1b,0x485b5b1b.long 0x495b5b1b,0x4a5b5b1b,0x4b5b5b1b,0x4c5b5b1b#ifdefined(KBD_FINNISH)   /*此处省略 外文键盘处理的具体代码*/key_map:......shift_map:......alt_map:......#elif defined(KBD_US)key_map:......shift_map:......alt_map:......#elif defined(KBD_GR)key_map:.........shift_map:......alt_map:......#elif defined(KBD_FR)key_map:......shift_map:......alt_map:......#else#error "KBD-type not defined"#endif/* * do_self handles "normal" keys, ie keys that don't change meaning * and which have just one character returns.下面这个函数,被大多普通按键调用。 */do_self:lea alt_map,%ebxtestb $0x20,mode/* alt-gr */jne 1flea shift_map,%ebxtestb $0x03,modejne 1flea key_map,%ebx1:movb (%ebx,%eax),%alorb %al,%alje nonetestb $0x4c,mode/* ctrl or caps */je 2fcmpb $'a,%aljb 2fcmpb $'},%alja 2fsubb $32,%al2:testb $0x0c,mode/* ctrl */je 3fcmpb $64,%aljb 3fcmpb $64+32,%aljae 3fsubb $64,%al3:testb $0x10,mode/* left alt */je 4forb $0x80,%al4:andl $0xff,%eaxxorl %ebx,%ebxcall put_queuenone:ret/* * minus has a routine of it's own, as a 'E0h' before  减号按钮得到了李刚的特殊待遇,单独处理 * the scan code for minus means that the numeric keypad * slash was pushed. */minus:cmpb $1,e0jne do_selfmovl $'/,%eaxxorl %ebx,%ebxjmp put_queue/* * 这是【按键处理映射表】,这里你可以看到他们的编码,和对应的实际按键字母。 * 大部分按键对应do_self普通处理。 * func按键映射在下面 */key_table:.long none,do_self,do_self,do_self/* 00-03 s0 esc 1 2 */.long do_self,do_self,do_self,do_self/* 04-07 3 4 5 6 */.long do_self,do_self,do_self,do_self/* 08-0B 7 8 9 0 */.long do_self,do_self,do_self,do_self/* 0C-0F + ' bs tab */.long do_self,do_self,do_self,do_self/* 10-13 q w e r */.long do_self,do_self,do_self,do_self/* 14-17 t y u i */.long do_self,do_self,do_self,do_self/* 18-1B o p } ^ */.long do_self,ctrl,do_self,do_self/* 1C-1F enter ctrl a s */.long do_self,do_self,do_self,do_self/* 20-23 d f g h */.long do_self,do_self,do_self,do_self/* 24-27 j k l | */.long do_self,do_self,lshift,do_self/* 28-2B { para lshift , */.long do_self,do_self,do_self,do_self/* 2C-2F z x c v */.long do_self,do_self,do_self,do_self/* 30-33 b n m , */.long do_self,minus,rshift,do_self/* 34-37 . - rshift * */.long alt,do_self,caps,func/* 38-3B alt sp caps f1 */.long func,func,func,func/* 3C-3F f2 f3 f4 f5 这里映射F按键 , 用func 处理*/.long func,func,func,func/* 40-43 f6 f7 f8 f9 */.long func,num,scroll,cursor/* 44-47 f10 num scr home */.long cursor,cursor,do_self,cursor/* 48-4B up pgup - left */.long cursor,cursor,do_self,cursor/* 4C-4F n5 right + end */.long cursor,cursor,cursor,cursor/* 50-53 dn pgdn ins del */.long none,none,do_self,func/* 54-57 sysreq ? < f11 */.long func,none,none,none/* 58-5B f12 ? ? ? 这里映射了F12 用func处理,下面没有好玩的了*/.long none,none,none,none/* 5C-5F ? ? ? ? */...        ... 

三,tty_io.c程序

关于按键处理,这个程序中仅一个函数有意思

/* *  linux/kernel/tty_io.c * *  (C) 1991  Linus Torvalds *//* * 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};/*copy_to_cooked函数处理从按键读出来的东西,在read_q中,放到要写入屏幕的队列write_q中*//*函数中那一堆PUTCH 就把字符转移到write_q了*/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=='L'){printk("F12或者L被按下了");}*/、/*if(c=='L') continue;*//*下面都是比较常规的处理代码了,主要功能是将read_q 中的东西放到write_q中*/...... 

四,console.c程序

这个程序从write_q中拿出字母,放(tù)到您的屏幕上。

/* *  linux/kernel/console.c * *  (C) 1991  Linus Torvalds *//* *console.c * * 本程序实现了如下的函数 *'void con_init(void)' *'void con_write(struct tty_queue * queue) 这个是我们主要讨论的 *  */#include <linux/sched.h>#include <linux/tty.h>#include <asm/io.h>#include <asm/system.h>/* * These are set up by the setup-routine at boot-time: */#define ORIG_X(*(unsigned char *)0x90000)#define ORIG_Y(*(unsigned char *)0x90001)#define ORIG_VIDEO_PAGE(*(unsigned short *)0x90004)#define ORIG_VIDEO_MODE((*(unsigned short *)0x90006) & 0xff)#define ORIG_VIDEO_COLS (((*(unsigned short *)0x90006) & 0xff00) >> 8)#define ORIG_VIDEO_LINES(25)#define ORIG_VIDEO_EGA_AX(*(unsigned short *)0x90008)#define ORIG_VIDEO_EGA_BX(*(unsigned short *)0x9000a)#define ORIG_VIDEO_EGA_CX(*(unsigned short *)0x9000c)#define VIDEO_TYPE_MDA0x10/* Monochrome Text Display*/#define VIDEO_TYPE_CGA0x11/* CGA Display */#define VIDEO_TYPE_EGAM0x20/* EGA/VGA in Monochrome Mode*/#define VIDEO_TYPE_EGAC0x21/* EGA/VGA in Color Mode*/#define NPAR 16extern void keyboard_interrupt(void);static unsigned charvideo_type;/* Type of display being used*/static unsigned longvideo_num_columns;/* Number of text columns*/static unsigned longvideo_size_row;/* Bytes per row*/static unsigned longvideo_num_lines;/* Number of test lines*/static unsigned charvideo_page;/* Initial video page*/static unsigned longvideo_mem_start;/* Start of video RAM*/static unsigned longvideo_mem_end;/* End of video RAM (sort of)*/static unsigned shortvideo_port_reg;/* Video register select port*/static unsigned shortvideo_port_val;/* Video register value port*/static unsigned shortvideo_erase_char;/* Char+Attrib to erase with*/static unsigned longorigin;/* Used for EGA/VGA fast scroll*/static unsigned longscr_end;/* Used for EGA/VGA fast scroll*/static unsigned longpos;static unsigned longx,y;static unsigned longtop,bottom;static unsigned longstate=0;static unsigned longnpar,par[NPAR];static unsigned longques=0;static unsigned charattr=0x07;static void sysbeep(void);/* * 此处省略一堆函数 *  */#define RESPONSE "\033[?1;2c"/* 下面这个这个函数就是控制台打印函数(console_write)*它的功能是从 待写队列write_q 中取出字母简单处理,然后打印到屏幕上*它的运作原理叫做“循环匹配”,如果直接遇到了一个普通字符,就_asm_()打印出来。如果遇到了屏幕处理命令(回删,翻页,光标移动),就连续吃掉下一个字符来匹配命令*如果匹配到了,就执行,如果吃了相应长度的字符但是没有命令匹配,就当白吃了,那些字符也不会吐出来再显示了。*/void con_write(struct tty_struct * tty){int nr;char c;nr = CHARS(tty->write_q);while (nr--) {GETCH(tty->write_q,c);/*每次循环,在这里读取一个char,如果你在这里把c赋值成别的了,那么屏幕就只会显示这一种字符了,比如全是‘*’ *//********if(c=='L')continue;//这几句是我写的,原程序没有if((c>='a'&&c<='z')||(c>='A'&&c<='Z')||(c>='0'&&c<='9'))if(f12){c='*';}*********/switch(state) {case 0:if (c>31 && c<127) {/*普通字符就打印*/if (x>=video_num_columns) {x -= video_num_columns;pos -= video_size_row;lf();}__asm__("movb attr,%%ah\n\t""movw %%ax,%1\n\t"::"a" (c),"m" (*(short *)pos));pos += 2;x++;} else if (c==27)/*如果是escape功能字符,就进入读命令模式*/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 (c=='7')save_cur();else if (c=='8')restore_cur();/*举个例子,"escape 8" 就是光标退行的意思*/break;case 2:/*长命令读取*/for(npar=0;npar<NPAR;npar++)par[npar]=0;npar=0;state=3;/*从长命令读取转到长命令处理模式*/if ((ques=(c=='?')))/*如果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();}......

五,实现F12按键功能的改变

现在我们知道了这些按键字符的处理流程,我们要做的就是设置一个标志flag,在识别到F12的地方翻转flag,在写屏幕的地方判断flag,来决定是否要输出'*'

那么只要这样就可以了:

1,在大家都有的头文件中加入一个全局变量的外部引用:

asm\system.h 末尾加入:

extern int f12;
然后在console.c中定义这个变量的本体:

int f12=0;
这样就搞定了全局变量。

2,然后在:

keyboard.S: func:子函数中,每一次F12就会进入这里,每一次进入这里就会调用show_stat(),那么直接把sched.c改了:

sched.c:

void show_stat(void){int i;if(f12)f12=0;else f12=1;/*实现标志翻转*//****for (i=0;i<NR_TASKS;i++)原来的显示进程信息都不要了,没什么实际用处,看着闹心。if (task[i])show_task(i,task[i]);******/}

3,最后在console.c中判断标志进行输出:

void con_write(struct tty_struct * tty){int nr;char c;nr = CHARS(tty->write_q);while (nr--) {GETCH(tty->write_q,c);if(c=='L')continue;/*将f12按钮产生的多余输出字符屏蔽*/if((c>='a'&&c<='z')||(c>='A'&&c<='Z')||(c>='0'&&c<='9'))/*用星号代替普通字符*/if(f12){c='*';}........

编译内核:make clean(清理工程)     make all(强制重建工程)

恭喜你,大功告成。

实验主要目的是要分的同学可以飘走做实验了。


六,高端的实验方案

上面提出的办法可以说是实现基本功能最简单的办法了,实际上只修改了3个文件。(实验要求规定可以修改任意文件,数量小于7个即可)。

但是这种方法比较简陋,如果不屏蔽F12按钮按下自动产生的L字符,虽然能过,但是比较不好看。

然而如果按照如上方法屏蔽了,则L字符就不会再出现了,即使你按下L也不显示。

而且,按下F12后,输出队列中仍然有一个L,虽然看不见,这时如果打ls命令回车,其实是Lls,所以第一次敲入的命令是无效的,之后就正常了。

怎么能让这个L问题处理得好一点呢,我们可以这么做:
通过增加一个标志位int block(如法炮制);来跟踪f12。目的是:仅仅屏蔽按下f12之后紧接着输出的L,其他的不屏蔽。

在show_stat()中:

void show_stat(void){int i;block=1;/*加入一句按下标志*/if(f12)f12=0;else f12=1;...

在console.c中不再判断L:

void con_write(struct tty_struct * tty){int nr;char c;nr = CHARS(tty->write_q);while (nr--) {GETCH(tty->write_q,c);if((c>='a'&&c<='z')||(c>='A'&&c<='Z')||(c>='0'&&c<='9'))if(f12){c='*';}......

在tty_io.c:copy_to_cooked()中:

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=='L'&&block){block=0;continue;}/*在这里做的修改*/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;elsecurrent->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);}


,大气的解决方案

高端的整改之后,按下F12不会再向缓冲区搞出L了,(虽然搞出也没什么关系),但是你可能发现,不管按下F几,都能实现*转换的功能,这可怎么办。

首先,这是因为我们的标志置位操作是在show_stat中做得,原代码中,只要按下F键就都执行show_stat,那么你只要比较一下得到的F码,然后再决定是否跳入show_stat就行了。

func:        ;;;不需要保护现场了subb $0x3B,%aljb end_funccmpb $9,%aljbe ok_funcsubb $18,%alcmpb $10,%aljb end_funccmpb $11,%alja end_func  ;;;如果不是F12就跳走了;;保护现场        pushl %eaxpushl %ecxpushl %edxcall show_stat    ;;;;如果是f12,就执行这个函数popl %edx   ;;;恢复现场popl %ecx popl %eaxok_func:cmpl $4,%ecx /* check that there is enough room */jl end_funcmovl func_table(,%eax,4),%eaxxorl %ebx,%ebxjmp put_queueend_func:ret

八,上档次的解决方法

事实上,经过高端大气的解决办法之后,我们已经实现了F12改状态,非F12不改,且L字符输入输出都无影响的效果。

但是有些时候就很有意思,比如实验要求说:“上传修改后的4个系统文件,没修改的上传原文件,修改其他文件也一并上传,总数小于7即可”。

然后大家做完了检查的时候又说:”包含其他文件的都不行啊,都算错,扣分。”

asm/system.h 这个头文件是没办法了,必须包含,否则没有全局变量,根本无法跨文件处理,怎么样才能不使用shed.c呢?

其实改了show_stat后,它唯一作用就是改了flag12标志位,赋值语句而已,几条汇编即可:

在keyboard.S中:

#include<asm/system.h> ;上述包含写在keyboard.S的最上边就行,其中包含了你定义的C语言变量  int  f12。func:;;此处不需保护现场了 subb $0x3B,%al jb end_func cmpb $9,%al jbe ok_func subb $18,%al cmpb $10,%al jb end_func cmpb $11,%al ;;;比较F12ja end_func;;保护现场        pushl %eaxpushl %ecxpushl %edx        cmpb _f12, $0x01   ;;;比较f12和1jne fp1        movb $0x00,_f12    ;;;如果f12==1 就f12=0        jmp fp2fp1:movb $0x01,_f12    ;;;如果f12==0 就 f12=1fp2:   popl %edx   ;;恢复现场popl %ecxpopl %eaxok_func:cmpl $4,%ecx /* check that there is enough room */jl end_funcmovl func_table(,%eax,4),%eaxxorl %ebx,%ebxjmp put_queueend_func:ret

这样就完成了高大上的改造,大部分用汇编完成。
其实看到这里的同学你真的很厉害,治学精神很值得敬佩。
关于键盘IO实验,其实现方法多种多样,又在read_write中改的,有在tty_io中改的,也可以像这样直接几行汇编解决的,也可以全部用汇编在keyboard.S中解决,相互组合近十余种方法。
最后要告诉同学们的是,我们做实验,并不需拘泥于这些方法,更不必为了实验的分数来和实验课老师较劲,会的东西都是你的,以后都可以变成钱,就这么简单。



讲技术,说人话
Aurora极光城



0 0
原创粉丝点击