购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

2.4.4 时钟中断实验

设置完GDT以后,接下来就可以做一个简单的时钟中断实验。为了使能时钟中断,需要将时钟中断的屏蔽位打开,打开的方式很简单,代码如下:

1 movb $0xfe,%al

2 outb%al,$0x21

3

4 movb $0xff,%al

5 outb%al,$0xA1

只需要修改setup.S中设置OCW1的语句,即向0x21端口写入0xfe(11111110b),这样就把主8259A的IRQ0打开了,IRQ0对应的外部中断正好是时钟中断,同时向0xA1端口继续写入0xff(11111111b),表示屏蔽来自8259A的全部中断。

中断打开之后,需要为其设置中断服务程序,并同时修改IDT。时钟中断服务程序如下:

1  .code32

2  .text

3  .globl startup_32

4  startup_32:

5   ...

6

7   call setup_idt

8   call set_clock_idt

9   int $0x80

10   sti

11

12 loop:

13   jmploop

14

15 setup_idt:

16...

17

18 ignore_int:

19...

20

21 set_clock_idt:

22   leal clock_handle,%edx

23   movl $0x00080000, %eax

24   movw %dx,%ax

25   movw $0x8e00,%dx

26   leal idt,%edi

27   addl $0x100,%edi

28   movl %eax,(%edi)

29   movl%edx,4(%edi)

30   ret

31 clock_handle:

32   movl $0x96,%edi

33   incb%gs:(%edi)

34   /* 向0x20端口发送EOI */

35   movb $0x20,%al

36   outb%al,$0x20

37   iret

38

39 .align 4

40 .word 0

41 idt_descr:

42   .word 256 *8-1

43   .long idt

44

45 idt:

46   .fill 256,8,0

从31行开始是中断服务程序,主要用于将%gs:(%edi)内置位置的一个字节值加1,而%gs中的选择子对应GDT的第三项,它的段基地址为显存的基地址,即0xb8000。在第9行的软中断触发之后,会在屏幕的右上角打印一个红色字母I,而clock_handle的功能是将这个字节加1。也就是说,时钟中断到来之后红色字母将变成J,下一次时钟中断到来之后将变成K,依此类推。clock_handle处理程序向20h端口写入了0x20,也就是OCW2的EOI标识,通知8259A将当前处理程序结束,并且通过执行iret指令返回,这样8259A就可以继续接收下一个中断。

第21~30行对IDT进行了设置,并且设置了其中一个表项(第29行),它相对idt的偏移为0×100(256),因为一个IDT占用8个字节,所以这里设置的中断向量号为256/8=32=0×20,正是主8259A的IRQ0对应的时钟中断向量号。还需要注意的是第22行、23行对中断描述符中服务程序入口的设置,对照图2-10可以推断,set_clock_idt程序的作用是将第32号中断的中断处理程序设置为clock_handle。它所对应的中断描述符的8字节的最终内容为:

❑第0~15位保存了中断处理程序clock_handle的低16位。

❑第16~31位保存了段选择子0x0008表示的是代码段。

❑第32~47位保存了0x8E00,设置了IDT的类型、特权级等信息。

❑第48~63位保存了中断处理程序clock_handle的高16位。如此一来,在初始化所有IDT之后,调用set_clock_idt,就成功设置了时钟中断的处理程序,虽然已经打开了时钟中断的屏蔽位,但是还需要一个条件,时钟中断才能被8259A成功接收,那就是中断标识位IF(Interrupt Flag,中断标志)。

通过第10行的sti指令,可以将IF打开,这次时钟中断就可以被CPU响应并处理。如果一切都顺利的话,重新编译内核会发现原本红色字符I出现的位置会不停地加1,呈现出字符不断跳动的状态。 4R7G6hm0KsRubqkNIKAc08rzmk01mvFKAeD8eu5CaE89QCrWZdghFBuanGBtnPIp

点击中间区域
呼出菜单
上一章
目录
下一章
×