System Interruption

Jun 15th, 2020

BIOS 调用

  • 在主板内存较高地址区内的ROM(只读存储器)中,固化了PC机的基本输入/输出系统BIOS(Basic Input/Output System)。 BIOS 提供了系统加电自检、引导并装人操作系统、主要I/O设备的控制等功能。主要的外部设备,如键盘、显示系统、磁盘(软盘和硬盘)、打印机、系统时钟等,都有相应的中断调用。主要的BIOS中断类型如下表所示。

中断号

功能

中断号

功能

0H

除法出错

10H

显示器

1H

单步中断

11H

设备校验

2H

不可屏蔽中断

12H

内存大小检查

3H

断点中断

13H

磁盘

4H

溢出中断

14H

异步通信

5H

打印屏幕中断

15H

I/O系统扩充

8H

8254系统定时中断

16H

键盘

9H

键盘中断

17H

打印机

BH

异步通信串口1中断

18H

驻留BIOS

CH

异步通信串口0中断

19H

引导

DH

硬件中断

1AH

时钟

EH

软盘中断

1BH

键盘Break

FH

并行打印机中断

1CH

定时器

  • 左侧栏中的中断号都小于10H,为系统的硬中断,所谓硬中断,是由I/O硬件事件触发的,一般不由程序调用(尽管可以调用它们)。这类中断提供的是真正面向I/O硬件的中断例程。

  • 右侧栏中的中断号大于等于10H的,为软中断,它不由I/O硬件事件触发,是供系统软件和用户程序调用的一组功能。

  • 一些主要的I/O设备,如键盘、显示器、打印机、磁盘、异步通信口、时钟等都拥有这两种中断

DOS中断调用

  • DOS是磁盘操作系统(Disk Operating System)的简称.DOS是由BIOS在开机后装入内存的,它提供了任务管理、设备管理、用户界面管理、文件管理等各种服务。

  • 本来DOS是一套标准的软件,不会产生什么中断。但DOS借用了BIOS用软中断提供功能调用的方法,将它为编程者准备的API(应用程序编程接口)都以中断调用方式来提供。这些功能调用也不仅仅是1/O设备的功能调用。

  • 大多数为用户提供的功能调用都位于软中断21H中,但还有其他一些DOS中断调用。主要的DOS中断调用如下表所示。

中断号

功能

20H

程序终止

21H

主要的DOS功能调用

22H

结束地址

23H

Ctrl+Break出错地址

24H

严重出错处理

25H

绝对磁盘读

26H

绝对磁盘写

27H

终止并驻留内存

28H~3EH

DOS内部使用的中断

2FH

补充的DOS中断

30H~3FH

保留给DOS

  • 对编程者来说,使用的主要是21H中断调用。

  • DOS在21H中断调用中给出了绝大多数用户编程所需的功能,所以有时也将对21H的调用称为DOS功能调用。

  • 对DOS21H功能的调用,只需将AH置成功能号,其他寄存器置上该功能号所规定的参数,即可完成所需的功能。

  • 例如,要从应用程序中返回DOS的功能调用方法是:

    MOV AH, 4CH
    MOV AL, 返回码
    INT 21H

    平时我们直接使用 MOV AX, 4C00H 就是返回码为0的返回到DOS。

键盘I/O调用

  • 这里大部分使用栗子进行说明。

IBM键盘的扫描码表

键盘缓冲区

  • 用户每按下一个键,都会产生一个键盘中断(如果允许中断的话)。

  • 键盘的中断处理程序会根据用户按下的键,决定是否求出所按键的ASCII码,否则,将只给出该键的扫描码。

  • 由于所按键并不会马上被用户程序读取,所以在BIOS的参数区中,定义了一个键盘输人缓冲区KB_ BUFFER。它的位置在内存0040: 001A处,结构如下:

地址

属性

空间定义

说明

0040:001A

BUFF_HEAD

DW ?

首指针

0040:001C

BUFF_TAIL

DW ?

尾指针

0040:001E

KB_BUFFER

DW 16 DUP(?)

16个字的缓冲区

0040:003E

KB_BUFFER_END

LABEL, WORD

尾地址

上述缓冲区是一个先进先出的循环队列,BUFF_HEAD及BUFF_TAIL是缓冲区的两个指针。这两个指针相等,缓冲区为空。程序调用BIOS获取键盘输人时,BIOS就会从缓冲区中取出内容,同时移动指针。缓冲区满,会响铃告警。

键盘状态及键盘状态字节

  • 用户按下Shift ,Ctrl, Alt ,NumLock ,Scroll,Ins及CapsLock键时, BIOS并不返回扫描码, 而是置上一种状态。

  • 程序可通过查询状态字节获知这些键的状态。

  • 利用 INT 16H 的 AH=2 功能可以返回此状态字节。

  • 下图为键盘状态对应的字节:

BIOS键盘功能调用

BIOS提供给键盘的调用为16H,有三个功能,分别为:

AH号

功能

结果

说明

0

从键盘读

AH为键盘扫描码 AL为对应的ASCII(如果可以转换为ASCII)

该功能为强制读 若用户没有按键则一直等待

1

从缓冲区读

ZF=0时:AH=键盘扫描码,AL=对应的ASCII或0 ZF=1时:表示无键被按下,KB_BUFFER为空

该功能为探测读 若用户已按键,则与0相同 若用户未按键,则直接返回

2

取键盘状态字节

AL=键盘状态字节

参见上图的键盘状态字节

实用栗子:

  • 输入汉字:

      hanzibuff dw ?
      mov ah, 0
      int 16h
      cmp al, 0
      jz exit
      test ah, 80h
      jz exit ;输入后ah首位为0,al为0才是汉字
      mov byte ptr hanzibuff, ah
      mov ah, 0
      int 16h
      mov byte ptr hanzibuff+1, ah
      jmp exit
  • 在程序运行过程中检测是否有键按下:

      ...
      mov ah, 1 ;从缓冲区读
      int 16h
      jz continue
      cmp ah, xx
      ; do something

    在一个长时间运行的程序中,可以加入上面的语句序列控制程序的运行,比如按下ESC时终止程序运行,则将 cmp ah,xx 中 xx 替换为 01 即可。

DOS键盘功能调用

BIOS使用的是16h进行调用,DOS的21h也为键盘提供了一些列的功能如下:

AH

功能说明

输入参数

返回结果

1

从键盘读入并回显

AL=字符

6

测试读键盘

DL=0FFH

AL=字符(如有输入)

7

从键盘输入一个字符并不回显

AL=字符

8

从键盘输入一个字符并不回显,检测Ctrl+Break

A

读字符至缓冲区

DS:DX=缓冲

字符及计数已经设置好

B

读键盘状态

AL=0FFH(有输入) AL=00H(无输入)

C

清除键盘缓冲区并调用一种功能

AL=功能号(1,6,7,8,A)

下面以栗子来说明A和C功能:

  • 清除键盘缓冲区:

    注意是键盘的缓冲区,不是设置的DS:DX内存的缓冲区

    mov ah, 0ch ; 清除缓冲区
    mov al, 08h ; 并再读一个字符
    int 21h
  • 读入字符串,实现将其中的所有小写转大写的功能

      ------------------------------------------
      data:
      len equ 121
      in_buf db len-1 ; 第一个byte:最多能够输入的字符长度
             db ? ; 第二个byte:实际输入的字符长度(空格分割)
             db len dup(?) ; 缓冲区存储字符空间
      ------------------------------------------
      code: 
      buf_read:
          mov dx, offset in_buf
          mov ah, 0ah
          int 21h
    
          mov cl, in_buf+1 ; +1可以使得出循环的时候直接在'$'的位置
          xor ch, ch
          mov si, offset in_buf+2
      lp1:
          mov al, [si]
          cmp al, 'a' ; 小于'a'不是小写字母
          jb lp2
          cmp al, 'z' ; 大于'z'不是小写字母
          ja lp2
          add al, 'A'-'a' ; 小写转大写
          mov [si], al ; 存回内存
    
      lp2:
          inc si ; 字符串指针+1
          loop lp1
    
          mov byte ptr[si], '$' ; si指向末尾的下一个,直接写入字符串终止符
    
          mov ah, 2
          mov dl, 0dh ; 回车
          int 21h
          mov ah, 2
          mov dl, 0ah ; 换行
          int 21h
    
          mov dx, offset in_buf+2 ; in_buf+2 为字符串首地址
          mov ah, 09h ; 输出以'$'为结尾的字符串
          int 21h
    
          jmp exit
    • 运行实例:

      • in_buf 位于 DS:46,输入 huiH231-

      • 第一个byte为78H,十进制为120

      • 第二个byte为08H,为实际输入的字符个数

      • in_buf+2 开始为实际存储,如果要直接输出需要在末尾加'$'

Last updated