时钟中断是一个非常重要的硬中断,计算机体系中有一个叫作8253/54的芯片(PIT)。在PIT 芯片上有3个计数器,它可以按预先设定好的方式每隔一小段时间触发一次中断。在早期的Linux系统内核中采用了10ms触发一次,这也被称作是Linux的心跳。在后续章节中我们也要利用这个中断来实现系统内核的多任务处理机制。但在这一节里,只是来学习如何使用8253和使用时钟中断。
PIT 芯片有1个控制寄存器和3个计数器。控制寄存器的访问端口为0x43。计数寄存器的访问端口为0x40、0x41和0x42。每个寄存器可以以6个不同模式计数,并可以选择用BCD或者二进制计数。先将控制字写入控制寄存器,告诉它我们选择哪个计数寄存器、写入方式和计数模式等。再向选定的计数寄存器写入计数初值。这3个计数器的输入频率都是 1.19318Mhz。1193180是所有计数器都使用的作为时钟频率的固定值,计数器0作为定时器为系统时钟提供计时基准。计数器0的输出端与中断控制器8259A的IRQ0相连。假如需要计数器0的中断频率为N每秒,则divisor = 1193180/N,然后将divisor的低8位和高8位分别输入计数器0的访问端口:
//计算divisor u32 divisor = 1193180 / TIMER_FREQUENCY; //写入8253的控制寄存器 outb_p(0x36, 0x43); //写入频率低8位到计数器0 outb_p(divisor & 0xff, 0x40); //写入频率高8位到计数器0 outb_p(divisor >> 8, 0x40);
设定了计数器之后,并打开PIC中断控制器IRQ0的0位来打开时钟中断:
//打开PIC的时钟中断IRQ0 outb_p(inb_p(0x21) & 0xfe, 0x21);
在int.S文件中的_int_0x20处加入调用时钟中断代码:
//时钟中断 _int_0x20: cli pushal pushfl //调用时钟中断处理函数 call int_timer popfl popal sti iret
在sys_call.c中加入一个int_timer的处理函数,让它在显示器的右下角显示一个不断变化的字符(ascii从32到126这些是可显字符),每有一个时钟中断,就让它的ascii码加1:
/* * int_timer : 时钟中断 * return : void */ void int_timer() { char *p = (char *) 0xb8000; p += ((23 * 80 + 77)) * 2; *p = i; if (++i >= 127) { i = 32; } //通知PIC可以接受新中断 outb_p(0x20, 0x20); }
最后在start_kernel中安装时钟中断:
//安装时钟中断 install_timer();
编译并查看运行结果:
源代码的下载地址为:
https https://github.com/magicworldos/lidqos.git git git@github.com:magicworldos/lidqos.git subverion https://github.com/magicworldos/lidqos branch v0.12
Copyright © 2015-2023 问渠网 辽ICP备15013245号