kernel源码(七)设置8259A
1 8259A芯片
外部引脚和内部结构
IR0-IR7:中断源
IRR:中断请求寄存器,8位,每一位对应一个中断请求,某一位置1表示对应有中断请求
IMR:中断屏蔽寄存器,8位,每一位对应一个中断,某一位置1表示屏蔽某个中断源(比如IR3被屏蔽,则CPU将不会收到IR3的中断请求)
PR判优电路:中断请求冲IRR过来后,如果IRR有多个位置1,则这里判断优先级,先处理哪个中断
ISR:内部服务寄存器,经过PR判优电路,最高优先级的请求被送到ISR中,保存正在服务的中断请求
INT:连接CPU的中断输入端
/INTA:CPU请求中断后的结果回送到这里
ICW:初始化命令字寄存器,共4个,ICW1-ICW4,每一个寄存器都是8位
OCW:写入操作命令字寄存器,共3个,OCW1-OCW3,每一个寄存器都是8位
8259A工作过程:
当系统通电后,首先应对8259A初始化,也就是由CPU执行一段程序,向8259A写入若干控制字,指定它的工作方式。初始化完成后,8259A就准备好了,随时可以接受外设的中断请求信号,当外设发出请求后,8259A对外部中断请求的处理过程如下:
1. 哪条IR线上的数据有效,IRR相应位置就置1。
2. 8259A由INT引脚向CPU发INTR信号。
3. CPU完成当前指令后,用/INTR信号响应,告诉8259A收到了中断请求。
4. 8259A接收到CPU发出的第一个/INTA脉冲后,把最高优先权的ISR置1,并使相应的IRR复位0。
5. 第二个中断响应周期中,CPU再输出一个/INTA脉冲,这时8259A就把刚才选定的中断源所对应的8位中断类型码放到数据总线上,CPU读取该中断类型码并乘以4,就是中断服务子程序在中断向量表中的入口地址。找到执行。
6. 若8259A工作在自动中断结束AEOI方式,在第二个/INTA脉冲结束时,把中断源所对应的ISR中相应位复位。对于非自动中断结束方式,则由CPU在中断服务子程序结束时向8259A写入EOI命令,才能使ISR中的相应位复位
2 8259A和CPU的连接方式
3 setup.s
上一篇我们讲解了setup.s。但是对8259A的设置代码,我们一笔带过,这里我们再看一下这一段代码
in和out指令是专门用于累加器ax的指令。out指令表示通过外部设备的I/O端口号发送数据到外设。这里的端口号指的是内存地址,Linux给8259A设置的内存地址是0x20,,0x21和0xA0,0xA1
8259A规定0x20和0xA0:我们通过这两个端口写入ICW1,OCW2,OCW3并能够读取IRR和ISR。0xA0和0xA1:我们通过这两个端口写入ICW2,ICW3,ICW4并能够读写IMR寄存器。
! well, that went ok, I hope. Now we have to reprogram the interrupts :-( ! we put them right after the intel-reserved hardware interrupts, at ! int 0x20-0x2F. There they won't mess up anything. Sadly IBM really ! messed this up with the original PC, and they haven't been able to ! rectify it afterwards. Thus the bios puts interrupts at 0x08-0x0f, ! which is used for the internal hardware interrupts as well. We just ! have to reprogram the 8259's, and it isn't fun. mov al,#0x11 ! initialization sequence out #0x20,al ! send it to 8259A-1,通过端口号发送数据0x11到8259A-1,用于设置ICW1,这里我们发送的是00010001,对照代码下面的图片我们可以知道其意思。 .word 0x00eb,0x00eb ! 和jmp $+2, jmp $+2指令作用相同,这里直接使用机器码。$表示当前指令位置,jmp无条件转移,即转移到当前指令+2的位置,作用是延时两条指令的时间,给IO端口一个反应时间 out #0xA0,al ! and to 8259A-2,设置从芯片的ICW1,也设置为00010001.表示中断请求是边沿触发、多片8259A级联并且需要发送ICW4 .word 0x00eb,0x00eb mov al,#0x20 ! start of hardware int's (0x20) out #0x21,al !初始化ICW2为0010 0000,参考下面3.2小节说明,可知我么这里设置了IR0~IR7的中断号 .word 0x00eb,0x00eb mov al,#0x28 ! start of hardware int's 2 (0x28) out #0xA1,al !初始化从片的ICW2,也就是设置从片的中断号高5位 .word 0x00eb,0x00eb mov al,#0x04 ! 8259-1 is master out #0x21,al !初始化主片ICW3,设置为0000 0100 .word 0x00eb,0x00eb mov al,#0x02 ! 8259-2 is slave out #0xA1,al !初始化从片ICW3,设置为0000 0010 .word 0x00eb,0x00eb mov al,#0x01 ! 8086 mode for both out #0x21,al !初始化主片ICW4,设置为0000 0001 .word 0x00eb,0x00eb out #0xA1,al !初始化从片ICW4,设置为0000 0001 .word 0x00eb,0x00eb mov al,#0xFF ! 设置OCW1寄存器,该寄存器用于设置IMR以屏蔽中断。这里设置为1111 1111表示全屏蔽,待外部设备准备好后会开启。 out #0x21,al .word 0x00eb,0x00eb out #0xA1,al !设置从片OCW1,屏蔽所有中断
3.1 初始化ICW1
(参考https://blog.csdn.net/longintchar/article/details/79439466):
3.2 初始化ICW2
Linux-0.11 系统把主片的 ICW2 设置为 0x20,表示主片中断请求0~7级对应的中断号是 0x20~0x27;把从片的 ICW2 设置成 0x28,表示从片中断请求8~15级对应的中断号是 0x28~0x2f
3 初始化ICW3
4 初始化ICW4
Linux-0.11内核送往8259A主芯片和从芯片的 ICW4 命令字的值均为 0x01。表示 8259A 芯片被设置成普通全嵌套、非缓冲、非自动结束中断方式,并且用于 8086 及其兼容系统。
5 初始化OCW1
OCW1 用于对 8259A 中中断屏蔽寄存器 IMR 进行读/写操作。