使用无限循环时,x86中断处理程序被阻止

时间:2017-12-20 16:49:54

标签: c assembly x86

我正在尝试学习x86程序集和c语言。现在我已经完成了一个简单的计时器和键盘中断。第一个可以每隔几个刻度打印一行,第二个可以打印你在键盘上按下的内容。代码就像:

timer.c中:

print();
return;

keyboard.c中:

print();
return;

main.c中:

while(1);

这两个处理程序都在IDT中。因此,当发生中断时,IF标志被清除。 CPU将忽略其他中断。 初始化了main函数中的所有配置后,我用无限循环完成了它,就像:while(1)。 好的,这很好,我可以在屏幕上看到这两个处理程序正常工作 但是,当我想让它成为嵌套中断时,我做了以下事情:

timer.c中:

sti();      //set IF to 1 to enable interrupt 
print();
while(1); // wait here to test if the keyboard interrupt can  occur
return;

keyboard.c中:

print();
return;

main.c中:

while(1);

接下来发生的事情真正吸引了我:使用Bochs,我可以看到我的程序只是在timer.c中执行while循环。此时,我检查了标志,它显示IF标志已经设置,但是当我尝试输入某个东西来测试另一个interrut时,它失败了。似乎所有的中断都被阻止或忽略了。

问题是,这两个循环之间有什么区别,一个只是在一个中断处理程序中,我也不知道如何解决这个问题。我在我的vmware和virtualbox中仔细检查了我的代码,但结果是一样的。

我知道在遇到这个问题之前一定已经发生了这个问题,但是,我找不到任何与这个问题有关的问题。

2 个答案:

答案 0 :(得分:2)

定时器中断(IRQ0)优先于键盘中断(IRQ1)。

因此,即使您在定时器中断处理程序中通常(使用sti指令)启用中断,主中断控制器(PIC)也只会启用更高优先级的中断,直到您的定时器/ IRQ0服务程序完成为止

有关其他说明,请参阅:https://groups.google.com/forum/#!topic/comp.lang.asm.x86/7coo0px-BU4

  

是的,就是这样。中断控制器(主要的   一个,在这种情况下),它将向CPU发出定时器中断信号   在CPU之前不允许任何相同或较低优先级的中断   通过EOI告诉它定时器中断已经完成   指令(outportb(0x20, 0x20)表示主中断   控制器)。

可能在技术上向PIC发出EOI指令,告诉它已完成对IRQ0的处理,但你可能会为一些非常混乱的场景和竞争条件做好准备。

让中断处理程序只处理它们的特定中断并保存相关状态会更加清晰。然后,让您的主程序监视您需要的序列(例如计时器,然后是键盘)

答案 1 :(得分:1)

通过在中断处理程序中启用中断,您不能仅启用&#34;其他&#34;中断,但所有中断。包括定时器中断。 (这太笼统了,payne在评论中指出,在x86上可能有不同的IRQ信号源,并且特定的PIC / APIC芯片可以配置为优先于其他...不会改变任何有关<重新进入IRQ处理的原则,但您可以微调哪些IRQ具有优先级,这可能意味着如果您的配置阻止它,最终根本不需要重新进入锁定)

您的代码看起来不像是可重入的处理程序,所以如果这就是处理程序代码的完成方式,那么您的计时器会按照配置继续启动新的计时器中断,并且因为您有{{1}在那里,他们不断重新输入处理程序代码,填充缓慢的堆栈空间直到它会溢出(或环绕,我不确定你是否处于实际或保护模式,以及你的堆栈是如何设置的) 。只有最后一个当然正在运行,休息是休眠的(永远,如果最后一个没有返回)。

长时间中断处理程序通常是错误代码体系结构的标志(针对最短+最快的中断处理程序,通常只是用数据填充一些队列,在中断处理程序之外以异步方式处理)。但是如果你确实需要一个,并且你不能禁用其他中断,你必须将处理程序编写为可重入的中断。

sti

附录:还有一句话,可能是#34;显而易见的&#34;一,但只是为了确保它清楚。单CPU核心可以同时运行单个&#34;线程&#34;指令,即它在Re-entrant timer interrupt handler { if (locked) return; // already handling previous IRQ // which means the new IRQ is **IGNORED**! (price for slow handler) locked = true; // lock to prevent further re-entry sti(); //set IF to 1 to enable interrupts // do the slow stuff here (but not infinite loop of course!) // "print();" is not an excellent idea either, for interrupt handler // while(1); // this would never ever end at all, so NO. // slow stuff finished, ready for next request locked = false; // allow next timer IRQ to process the slow stuff again return; } 内执行无限循环,或者它正在执行一个中断处理程序。当新的IRQ信号进入CPU并启用中断时,当前的CPU状态存储在堆栈中(无论是在主机,还是定时器或键盘,都无关紧要),CPU将切换到所需的中断处理程序。因此,如果你发出的IRQ比你的处理程序完成并返回到前面的代码更快,你将慢慢地用存储的CPU状态来阻塞堆栈内存,它将永远不会返回到底部的原始线程({{1}内的无限循环})。

相关问题