终于把int 8h调通了

摘要:
---------------------------------------------------------------------------------------
 

最近一直在折腾int8h,明明已经把中断处理程序的入口地址注册到0000:0020处,显式调用int8h可以正常转移到中断处理程序,但就是不可以自动中断。
 后来还是在于渊前辈的书里找到答案,“说起EOI,如果你有过在实模式下的编程经验,那么对它因该不会陌生。当每一次中断处理结束,需要发送一个EOI给8259A,以便继续接受中断”。
  于是我在程序中加了两行代码:
  mov al,20h
  out 20h,al
  编译测试,果然每秒18.2次的中断跑起来了。
 ---------------------------------------------------------------------------------------

讲讲经过
下面是那段存在错误的代码:
-------------------------------------------------
%include "echoinit.mac"
%include "./echon.mac";这两个头文件是我自己写的多行宏,用来实现类似c语言printf的功能,已专门测试过,没有问题
org 0x7c00
enter:jmp start
handler:echon 'hello oranges world'
iret ;handler标签处是int 8h的中断处理程序,预期的效果是屏幕从上向下重复打印出'hello orangesworld'
     ;但实际运行起来什么现象也没有
start:echoinit ;这个宏是echon宏的初始化,都是我自己定义的,不用管它
setup:
mov ax,0 ;在8*4内存地址处注册中断处理程序的入口地址
mov ds,ax
mov bx,32
mov word [bx],handler-$$
mov word [bx+2],07c0h
;int 8h ;这一行不注释的话,会出现附图1效果--->这说明8h中断的处理程序安装成功
jmp $
times 510-($-enter) db 0
dw 0aa55h
-------------------------------------------------
终于把int <wbr>8h调通了
附图1(上图)

  我预期的效果是屏幕从上向下重复打印出'hello orangesworld‘,现在什么现象都没有。显然是cpu并没有响应8253A的0通道所不断发出的8号中断。
 最先想到的(确切说是从网上查到的)是忘了加sti,导致全局中断屏蔽,于是我加上一句sti打开中断,编译测试,出现下图画面:

终于把int <wbr>8h调通了
附图2(上图)
  跟附图1一模一样是不是?但别忘了:图1是手动调用int8h得到的结果,图2对应的代码已经将int 8h注释掉了,并且加了一句sti。这说明sti产生了效果,它的确使cpu响应了int8h中断!但效果不佳:cpu只响应了1次就熄火儿了。
 我琢磨了一下:大概是bochs虚拟机的问题,它为了实现单步调试,可能不断的用cli指令屏蔽中断。于是我就用不带调试功能的bochs测试了一下,依然是同样画面。
 我不死心,心想可能不带调试功能的bochs也有问题,于是在bochs上装了freedos,另外写了一段程序(因为我那个echon宏在com文件里不能用),编译成boot.com文件来做测试。下面是那段代码:
---------------------------------------------------------------------------------------
entrance:jmp setup
handler: 
    movax,0xb800
    moves,ax
    mov byte[es:di],dl
    adddi,2                       ;es:di指向屏幕下一个字符对应的内存地址
    inc dl                      ;dl自增1,即产生a,b,c,d,e...的效果 
    iret
setup:  mov dl,'b'
    movdi,0                      ;初始化es:di指向屏幕第一个字符对应的内存地址
    movbx,32                   ;8h中断的中断表项在0000h:0020h处
    movax,0
    movds,ax
   mov  word [ds:bx],handler-entrance+100h;将中断处理程序的入口地址登记到中断向量表
    movax,cs
    movword  [ds:bx+2],ax
    sti
jmp $
---------------------------------------------------------------------------------------
  代码想实现的效果是:从屏幕左上角,从左到右一次显示a,b,c,d,e.....
  编译nasm -o boot.com boot.asm
  dos下测试,画面如下:
终于把int <wbr>8h调通了
很悲据吧!只有第一个字母变成了b,然后画面就一动不动了!显然cpu又是只相应了一次8h中断就哑火了。

 这一连串的失败让我重新怀疑问题出现在自己的代码上,于是我就大致看了看8259A中断控制器的原理:IR0接8253A的0通道的时钟中断,优先级最高,bios开机即将IR0的中断码设为8H....IMR的8个位分别对应IR0~IR7的开关...
  难道是IMR的对应位将int 8h屏蔽掉了,因为IMR的端口是21h,我在代码中加了一条inal,21h,编译之后bochs调试,这条指令执行之后,info cpu显示:al=b8即IMR的值是10111000  IR0对应的0,说明int8h中断未被屏蔽!哎,当时真是很绝望,我可不想再把微机原理8259A彻头彻尾学一遍!
  这时翻了翻于渊前辈的书,竟然得知世界上还有EOI这个东西...
  算是比较幸运吧...
  程序正常跑起来之后是这样:
  终于把int <wbr>8h调通了

上图是dos下那个程序,开头正是我想要的b,c,d,e....后面的乱码是可以理解的:al超过256后,就不再是ascii有效值了(其实是个动态的逐渐打印的过程,可惜做成gif文件太麻烦)
终于把int <wbr>8h调通了

上图是bochs下那个程序,前面写掉了个h,但哪里在乎这!等了这么长时间的画面一下子跳到眼前,赶忙抓下来了。
 现在回想一下之前的怪异现象:cpu响应一次8h中断就熄火儿。原因无非是中断处理程序结束的时候,并没有发送一个EOI到8259A,于是它便无法继续接受中断...于是哑火儿了。嘀咕一句,这个EOI不知道跟cpu的INTA信号有关系没(我现在是懒得学更多了,弄不懂先放着,原先只是想在另一个程序里用一下int8h,结果费了这么大周折)
遇到的一个介绍8259A的视频,是吉大的微机原理,讲的还可以:http://www.xuexun.com/C_23660.shtml
原文地址:https://www.cnblogs.com/weiweishuo/p/3082642.html