戏说BIOS之Keyboard

戏说BIOSKeyboard

 

1. Introduction

    

    Keyboard System看起来好像挺简单,但事实上它远比想象中的复杂,硬件上Keyboard System需要两颗cpu完成key stroke的转换以及和Host的通信过程,一颗用于处理keyboardmake&break过程,另一颗作为keyboard controllerhost交换信息。一次按键过程在软件的层面上也要经过多次转化才能成为最终被用户理解的ASCII码。这个过程通常需要经历ma=>mv=>set2=>Set1=>ASCIIKeyboard System的架构框图如下图1所示:

 

 戏说BIOS之Keyboard_第1张图片   

 

 这是MB中常见的架构,在NB中这部分已经被放入EC之中成为EC

 一个部分KBC,但是工作原理依旧如此。

 

2. How It Works

 

    那么当我们按下一个键,需要做哪些动作,才能让我们看到最终的字符呢? 听我慢慢道来。当我们按下一个键‘k’时(make),键盘内部的8031会将kset2 scan code2Ch 通过上图1的串行连接送给80428042查一张set2set1的表将该set2 scan code转成 set1的‘14h’,而且8042会引发IRQ1通知host,表示有按键事件发生。Host将会读取60Port获取set1scancode14h’,而后host会将‘14h’转化为ASCII码‘k’,当我们松开一个键时过程同按下比较像了,不过键盘内部的8031会先送‘F0h’,然后再送‘2Ch’给80428042看到‘f0h’会将Set1的‘14h’的bit7设置为194h,以表示这是一个breakHost端也会收到中断IRQ1,可是host通常不处理break codeMake&Break    key也被称之为通码和断码。最终host会将set1以及ASCII码放在BDA 之中。Host端对于键盘系统处理分为以下几类:a.字符键b.功能键c.控制d.双态键e.特殊功能键,对于这几种不同按键host处理方式也会有所不同对于c&d host会在BDA中置flag;对于a host会保存set1ASCII码在BDA之中(大小写根据控制键的flag确定);b会影响到set1的值;对于e host可能会通过中断调用相关的function下图2显示host的处理流程:

          戏说BIOS之Keyboard_第2张图片

 

 

   接下来我将分别用CASM演示BIOS处理keyboard system的大致过程代码的原理是通过hook int9接管BIOS的中断处理过程,然后读取EC6064 port获得kbcdatastatus,并转为ASCII码显示出来,有一个要注意的地方就是EOIEOI是特指8259或者8259兼容设备的中断清除指令。需要在中断服务程序结束之前向8259发送EOI令,如果在中断程序一开始就发送EOI指令的话,中断服务程序一旦比较大,运行时间较长,可能会产生中断嵌套,严重会造成死机。如果中断服务程序结束之后还没有发送EOI指令的话,那么以后将屏蔽该IRQ以及优先级低于该IRQ的所有中断。我最初就没有送EOI,害得我调试了好久。

 

C代码如下所示:

 

#include

#include

#include

#include

#include

#include

 

void interrupt new_int9_handler(); /* interrupt prototype */

void interrupt (*old_int9_handler)(); /* interrupt function pointer */

unsigned char ESC_Press_Flag = 0;

unsigned char fifo[0x10]={0};

unsigned char start=0;

unsigned char stop=0;

 

int main(void)

{

          printf("Used to test keyboard set1 scancode/n");

          printf("@author:peterhu/t/t@Version 1.0/n");

          printf("Copyright(C) LGPL/t[ESC] to Quit/n");

 

          /* store old interrupt vector */

          old_int9_handler = getvect(9);

          /* set up new interrupt handler */

          setvect(0x09,new_int9_handler);

 

          while(1)

          {

                   if(ESC_Press_Flag)

                             break;

 

                   while(stop != start)

                   {

                             printf("[%.2x],",fifo[stop]);

                             stop = (++stop)%0x10;

                   }

          }

 

          setvect(0x09,old_int9_handler);

          clrscr();

          return 1;

}

 

void interrupt new_int9_handler()

{

          unsigned char status;

          unsigned char set1;

          disable();

 

          status = inportb(0x64);

          if(status & 0x01)

          {

                   set1 = inport(0x60);

                   fifo[start] = set1;

                   start = (++start) % 0x10;

                   if(set1 == 0x01)

                    ESC_Press_Flag = 1;

 

             //printf("[%.2x],",set1);

          }

          outportb(0x20,0x20);

 

          enable();

}

 

asm代码如下所示:

data   segment       

                   SET1  db 0

                   H2A            db  '[','0','0',']','$'

                   MSG            db      'Used to test keyboard set1 scancode',0Ah,0Dh,'@author:peterhu',09h,09h,'@Version 1.0',0Ah,0Dh,'Copyright(C) LGPL',09h,'[ESC] to Quit',0Ah,0Dh,'$'

                   OLDINT9    dd      0

                   ESCPR         db      0

data   ends

 

code   segment

          assume cs:code,ds:data

         

start:

                   mov    ax,data

                   mov    ds,ax

                  

                   mov    ax,1ch

                   call hex2asi

                   call show_set1                 

                   call show_title

                  

                   call back_int9

                   call install_int9                                 

                  

l0:

                   xor     cx,cx

                   mov    cl,SET1

                   jcxz   nokey

                   xor     ax,ax

                   mov    al,SET1

                   call hex2asi

                   call show_set1

                   mov    SET1,00h

nokey:

                   mov    cl,ESCPR

                   jcxz l0

                  

                   call restore_int9                                         

                   mov    ax,4c00h

                   int 21h

                  

                  

                  

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;  sub routine for store and show set1 scancode

;;  for keybord  strok maybe something error :/    

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

 

int9_handler:

 

          cli

          in       al,64h

          and     al,01h

          cmp al,01h

          jne     exit9

          in       al,60h

          mov ah,00h

          cmp al,01h

          je       escp

          jmp    exit9

         

escp:

          mov    ESCPR,01h

exit9:

          mov SET1,al

          mov    al,20h

          out     20h,al

          sti

          iret

                  

back_int9:

         

          push   ax     

          xor     ax,ax

          mov    es,ax

          mov    ax,es:[24h]

          mov    word ptr OLDINT9,ax

          mov    ax,es:[26h]

          mov    word ptr OLDINT9+2,ax

          pop    ax

          ret

 

restore_int9:

 

          push   ax     

          xor     ax,ax

          mov    es,ax

          mov    ax,es:[24h]

          mov    ax,word ptr OLDINT9

          mov    ax,es:[26h]

          mov    ax,word ptr OLDINT9+2

          pop    ax

          ret

 

install_int9:

         

          push   ax

          push   ds

          push   bx

         

          mov    ax,0

          mov    ds,ax

          mov    bx,24h

          cli

          mov    word ptr[bx],offset int9_handler

          mov    word ptr[bx+2],seg int9_handler

          sti

                  

          pop    bx

          pop    ds

          pop    ax

          ret

         

show_title:

 

                   push   dx

                   mov    dx,offset MSG

                   mov    ah,9

                   int      21h

                   pop              dx

                   ret

                  

show_set1:

 

                   push   dx

                   mov    dx,offset H2A

                   mov    ah,9

                   int      21h

                   pop              dx

                   ret

                  

hex2asi:

                   push   dx

                   push   cx

                   push   si

                   push   bx

                  

                   mov    bx,0

                   mov    si,offset H2A

                   mov byte ptr [si+1],'0'

                   mov    byte ptr [si+2],'0'

ha1:   

                   mov    cx,10h

                   mov    dx,0

                   div     cx

                   mov    cx,ax

                   jcxz   ha3

                   cmp dx,10d

                   jnb     ha2   

                  

                   add dx,30h

                   push   dx

                   inc     bx

                   jmp short ha1

ha2:            

                   sub     dx,10d

                   add    dx,'A'

                   push   dx

                   inc     bx

                   jmp    ha1    

                                     

ha3:

                   cmp dx,10d

                   jnb     ha4

                   add dx,30h

                   push dx

                   inc bx

                   mov cx,bx

                   jmp    ha5

ha4:            

                   sub     dx,10d

                   add    dx,'A'

                   push   dx

                   inc     bx

                   mov cx,bx

                   jmp    ha5

 

ha5:

                   pop    ax

                   mov    [si+1],al

                   inc     si

                   loop    s4

 

ok:

                   pop    bx

                   pop    si

                   pop    cx

                   pop    dx

                   ret              

                  

code   ends

end              start

上述程序运行状况如下图3所示,一旦有按键动作该程序就会显示set1scancode(没有给出相应的ASCII码,凑合着用吧J)上述代码可以在这里下载

 

 戏说BIOS之Keyboard_第3张图片

 

REFF:

<>

 

Enjoy it!

 

That’s all

 

Peter

你可能感兴趣的:(BIOS,Internals)