8259A驱动编写

简介: 8259A驱动编写

引言

  • 这一章节我们要来实现 8259A 驱动代码的实现
  • 驱动,听起来很难得样子,其实复杂在硬件的了解,其代码本身是非常简单的。所以,有了上一章节对 8259A 的介绍,本章内容就变得非常简单了

x86 中的 8259A 级联

  • 前面我们比较的对 8259A 级联方式进行通用性地介绍,现在我们有针对性的看看其在我们具体的 x86 系统中的级联

  • 不要问 IRQ 为什么这么排列,当时就这么约定的吧,你非要不按照这么排列也行,就是你做出的系统只能运行在你自己的硬件平台上,无法运行在通用的硬件平台上

8259A 驱动编写

  • 在 8259A 内部有两组寄存器,一组是初始化命令寄存器组,用来保存初始化命令字(Initialization Command Words,ICW),ICW 共 4 个,ICW1~ICW4。另一组寄存器是操作命令寄存器组,用来保存操作命令字(Operation Command Word,OCW),OCW 共 3 个,OCW1~OCW3。所以,我们对 8259A 的编程,也分为初始化和操作两部分

8259A 初始化

  • 先来介绍一下 ICW1~ICW4 寄存器
  • ICW1:用来初始化 8259A 的连接方式和中断信号的触发方式。其格式如下:
7 6 5 4 3 2 1 0
0 0 0 1 LTIM ADI SNGL IC4
  • ICW1 需要写入到主片的 0x20 端口和从片的 0xA0 端口
  • IC4 表示是否要写入 ICW4,并不是所有的 ICW 初始化控制字都需要用到。IC4 为 1 时表示需要在后面写入 ICW4,为 0 则不需要。注意,x86 系统 IC4 必须为 1
  • SNGL 表示 single,若 SNGL 为 1,表示单片,若 SNGL 为 0,表示级联
  • ADI 表示 call address interval,用来设置 8085 的调用时间间隔,x86 不需要设置
  • LTIM 表示 level/edge triggered mode,用来设置中断检测方式,LTIM 为 0 表示边沿触发,LTIM 为 1 表示电平触发
  • 第 4 位的 1 是固定的
  • 第 5~7 位专用于 8085 处理器,x86 不需要,直接置为 0 即可
  • ICW2:用来设置起始中断向量号,只设置 IRQ0 的中断向量号即可,IRQ1,IRQ2...中断向量号依次 +1。其格式如下:
7 6 5 4 3 2 1 0
T7 T6 T5 T4 T3 ID2 ID1 ID0
  • ICW2 需要写入到主片的 0x21 端口和从片的 0xA1 端口
  • 只需要填写高 5 位 T3~T7,ID0~ID2 这低 3 位不用咱们负责。由于咱们只填写高 5 位,所以任意数字都是 8 的倍数,这个数字表示的便是设定的起始中断向量号
  • ICW3:ICW3 仅在级联的方式下才需要(如果 ICW1 中的 SNGL 为 0),用来设置主片和从片用哪个 IRQ 接口互连。由于主片和从片的级联方式不一样,对于这个 ICW3,主片和从片都有自己不同的结构
  • 主片 ICW3 格式
7 6 5 4 3 2 1 0
S7 S6 S5 S4 S3 S2 S1 S0
  • 对于主片,ICW3 中置 1 的那一位对应的 IRQ 接口用于连接从片,若为 0 则表示接外部设备。比如,若主片 IRQ2 接有从片,则主片的 ICW3 为 00000100
  • 从片 ICW3 格式
7 6 5 4 3 2 1 0
0 0 0 0 0 ID2 ID1 ID0
  • 不光是作为主片需要设置 ICW3,作为从片也需要设置 ICW3,而从片 ICW3 只用到低 3 位,低 3 位能表示的数值范围是 0~7,正好可以对应连接到主片IRQ0~IRQ7。比如,若从片级联到主片的 IRQ2,则从片的 ICW3 为 00000010
  • ICW3 需要写入主片的 0x21 端口及从片的 0xA1 端口
  • ICW4:设置 8259A 的中断嵌套方式。其格式如下:
7 6 5 4 3 2 1 0
0 0 0 SFNM BUF M/S AEOI μPM
  • ICW4 需要写入主片的 0x21 及从片的 0xA1 端口
  • ICW4 有些低位的选项基于高位,所以咱们从高位开始介绍
  • 第 7~5 位未定义,直接置为 0 即可
  • SFNM 表示特殊全嵌套模式(Special Fully Nested Mode),若 SFNM 为 0,则表示全嵌套模式,若 SFNM 为 1,则表示特殊全嵌套模式。全嵌套模式,中断服务程序执行时不响应其它同优先级级或低优先级级中断,必须等中断服务程序执行完毕方可响应其它同优先级中断,而特殊全嵌套模式在中断服务程序正在执行时也响应其它同优先级中断,低优先级中断依旧是不响应的
  • BUF 表示本 8259A 芯片是否工作在缓冲模式。BUF 为 0,则工作非缓冲模式,BUF 为 1,则工作在缓冲模式
  • 如果工作在缓冲模式下(BUF=1),M/S 用来规定本 8259A 是主片,还是从片。若 M/S=1:主片,若 M/S=0:从片;若工作在非缓冲模式(BUF=0)下,M/S 无效
  • AEOI 表示自动结束中断(Auto End Of Interrupt)。AEOI=0:非自动结束中断,AEOI=1:自动结束中断
  • μPM 表示微处理器类型(microprocessor),此项是为了兼容老处理器。若 μPM 为 0,则表示 8080 或 8085 处理器,若 μPM 为 1,则表示 x86 处理器
  • 代码实现
; 初始化可编程中断控制器 8259A - 级联
pic_init:
    push ax
.8259a_m_init:  ; 8259A 主片初始化
    mov al, 0x11  ; ICW1:边沿触发,级联,需要 ICW4
    out 0x20, al
    mov al, 0x20  ; ICW2:起始中断向量号为 0x20
    out 0x21, al
    mov al, 0x04  ; ICW3:IRQ2 接从片
    out 0x21, al
    mov al, 0x11  ; ICW4:8086模式,正常 EOI,非缓冲模式,特殊全嵌套模式
    out 0x21, al
.8259a_s_init:  ; 8259A 从片初始化
    mov al, 0x11  ; ICW1:边沿触发,级联,需要 ICW4
    out 0xA0, al
    mov al, 0x28  ; ICW2:起始中断向量号为 0x28
    out 0xA1, al
    mov al, 0x02  ; ICW3:设置从片连接到主片 IRQ2 引脚
    out 0xA1, al
    mov al, 0x01  ; ICW4:8086模式,正常 EOI,非缓冲模式,全嵌套模式
    out 0xA1, al
    pop ax
    ret

8259A 操作

  • 学了 ICW 寄存器,现在再来学习几个 OCW 寄存器吧
  • OCW1:用来屏蔽连接在 8259A 上的外部设备的中断信号,实际上就是把 OCW1 写入了 IMR 寄存器
  • 注意了,由于外部设备的中断都是可屏蔽中断,所以最终还是要受标志寄存器 eflags 中的 IF 位的管束,若 IF=0,可屏蔽中断全部被屏蔽,也就是说,若 IF=0,即使 8259A 把外部设备的中断向量号发过来,CPU 也置之不理
  • OCW1 格式如下:
7 6 5 4 3 2 1 0
M7 M6 M5 M4 M3 M2 M1 M0
  • OCW1 要写入主片的 0x21 或从片的 0xA1 端口
  • M0~M7 对应 8259A 的 IRQ0~IRQ7,某位为 1,对应的 IRQ 上的中断信号就被屏蔽了。否则某位为 0 的话,对应的 IRQ 中断信号则被放行
  • OCW2:用来设置中断结束方式和优先级模式,其格式如下:
7 6 5 4 3 2 1 0
R SL EOI 0 0 L2 L1 L0
  • OCW2 要写入到主片的 0x20 及从片的 0xA0 端口
  • 如果 R=0,表示固定优先级方式,即 IRQ 接口号越低,优先级越高
  • 如果 R=1,表明用循环优先级方式,这样优先级会在 0~7 内循环。如果 SL=0,初始的优先级次序为 IR0>IR1>IR2>IR3>IR4>IR5>IR6>IR7。当某级别的中断被处理完成后,它的优先级别将变成最低,将最高优先级传给之前较之低一级别的中断请求,其他依次类推。可循环方式多用于各中断源优先级相同的情况,优先级通过这种循环可以实现轮询处理。该循环可总结为如果 IR(i)优先级最低,IR(i+1)则优先级最高,其优先级关系如下图所示:

  • 在 R=1 且 SL=1 时,还可以通过 L2~L0 指定最低优先级是哪个 IRQ 接口,举个例子,若想指定 IRQ5 为最低优先级,则需要设置 R=1,SL=1,L2~L0=101,新的优先级循环就编程了:IR6>IR7>IR0>IR1>IR2>IR3>IR4>IR5
  • EOI,End Of Interrupt,为中断结束命令位(ICW4.AEIO=0时有意义)。EOI=1,结束中断,清 ISR 相应位
  • 第 4~3 位的 00 是 OCW2 的标识,可以认为是固定值
  • L2~L0 用来指定优先级
  • OCW3:设置特殊屏蔽方式及查询方式,其格式如下:
7 6 5 4 3 2 1 0
/ ESMM SMM 0 1 P PR RIS
  • OCW3 要写入主片的 0x20 端口或从片的 0xA0 端口
  • 第 7 位未用到
  • ESMM=0:关闭特殊屏蔽模式,ESMM=1:开启特殊屏蔽模式,
  • SMM=0:未工作于特殊屏蔽模式,SMM=1:工作于特殊屏蔽模式,
  • 第 4~3 位的 01 是 OCW3 的标识,8259A 通过这两位判断是哪个控制字
  • P,Poll command,查询命令,P=0:无意义,P=1:中断查询命令,查询当前最高中断优先级
  • RR,Read Register,读取寄存器命令,它和 RIS 位是配合在一起使用的。当 RR 为 1 时才可以读取寄存器
  • RIS,,Read Interrupt register Select,读取中断寄存器选择位。RIS=0:读取 IRR 寄存器的值,RIS=1:读取 ISR 寄存器的值
  • 有了上面的介绍,让我们来封装几个函数吧
; 手动结束主片中断
write_m_EOI:
    push ax
    mov al, 0x20  ; OCW2:固定优先级方式,结束中断,清 ISR 相应位
    out 0x20, al  ; 端口号:0x20
    pop ax
    ret
; 手动结束从片中断
write_s_EOI:
    push ax
    mov al, 0x20  ; OCW2:固定优先级方式,结束中断,清 ISR 相应位
    out 0xA0, al  ; 端口号:0xA0
    pop ax
    ret
; 读主片 ISR 寄存器的值,返回值存入 al 寄存器
read_m_ISR:
    mov al, 0x0B  ; OCW3:RR=1,RIS=1,读取 ISR 寄存器的值
    out 0x20, al  ; 端口号:0x20
    jmp $+2       ; jmp 指令占 2 个字节,$ 表示当前位置,这里就是起延时作用,给与端口处理时间
    in al, 0x20  ; 端口号:0x20  
    ret
; 读从片 ISR 寄存器的值,返回值存入 al 寄存器
read_s_ISR:
    mov al, 0x0B  ; OCW3:RR=1,RIS=1,读取 ISR 寄存器的值
    out 0xA0, al  ; 端口号:0xA0
    jmp $+2       ; jmp 指令占 2 个字节,$ 表示当前位置,这里就是起延时作用,给与端口处理时间
    in al, 0xA0   ; 端口号:0xA0
    ret
; 读主片 IRR 寄存器的值,返回值存入 al 寄存器
read_m_IRR:
    mov al, 0x0A  ; OCW3:RR=1,RIS=0,读取 IRR 寄存器的值
    out 0x20, al  ; 端口号:0x20
    jmp $+2       ; jmp 指令占 2 个字节,$ 表示当前位置,这里起延时作用,给与端口处理时间
    in al, 0x20   ; 端口号:0x20 
    ret
; 读从片 IRR 寄存器的值,返回值存入 al 寄存器
read_s_IRR:
    mov al, 0x0A  ; OCW3:RR=1,RIS=0,读取 IRR 寄存器的值
    out 0xA0, al  ; 端口号:0xA0
    jmp $+2       ; jmp 指令占 2 个字节,$ 表示当前位置,这里起延时作用,给与端口处理时间
    in al, 0xA0   ; 端口号:0xA0
    ret
; 读主片 IMR 寄存器的值,返回值存入 al 寄存器
read_m_IMR:
    in al, 0x21  ; 端口号:0x21
    ret
; 将 al 寄存器的值写入主片 IMR 寄存器中
write_m_IMR:
    out 0x21, al ; 端口号:0x21
    ret
; 读从片 IMR 寄存器的值,返回值存入 al 寄存器
read_s_IMR:
    in al, 0xA1  ; 端口号:0xA1
    ret
; 将 al 寄存器的值写入从片 IMR 寄存器中
write_s_IMR:
    out 0xA1, al ; 端口号:0xA1
    ret
; 设置主片工作在特殊屏蔽模式
set_m_smm:
    push ax
    mov al, 0x68  ; ESMM=1,SMM=1
    out 0x20, al  ; 端口号:0x20
    pop ax
    ret
目录
相关文章
|
11月前
|
机器学习/深度学习 编解码 监控
目标检测实战(六): 使用YOLOv8完成对图像的目标检测任务(从数据准备到训练测试部署的完整流程)
这篇文章详细介绍了如何使用YOLOv8进行目标检测任务,包括环境搭建、数据准备、模型训练、验证测试以及模型转换等完整流程。
17181 58
目标检测实战(六): 使用YOLOv8完成对图像的目标检测任务(从数据准备到训练测试部署的完整流程)
|
10月前
|
机器学习/深度学习 计算机视觉
【YOLOv11改进 - 注意力机制】 MSDA(Multi-Scale Dilated Attention):多尺度空洞注意力
【YOLOv11改进 - 注意力机制】 MSDA(Multi-Scale Dilated Attention):多尺度空洞注意力本文介绍了一种高效的视觉变换器——DilateFormer,通过多尺度扩张注意力(MSDA)模块,在保持高性能的同时显著降低计算成本。MSDA通过在滑动窗口内模拟局部和稀疏的块交互,实现了多尺度特征聚合。实验结果显示,DilateFormer在ImageNet-1K分类、COCO对象检测/实例分割和ADE20K语义分割任务上均取得了优异的性能,且计算成本比现有模型减少70%。
【YOLOv11改进 - 注意力机制】 MSDA(Multi-Scale Dilated Attention):多尺度空洞注意力
|
10月前
|
小程序 前端开发 算法
|
机器学习/深度学习 人工智能 算法
解密巴黎奥运会中的阿里云AI技术
2024年巴黎奥运会圆满结束,中国代表团金牌数与美国并列第一,展现了卓越实力。阿里云作为官方云服务合作伙伴,通过先进的AI技术深度融入奥运的各项环节,实现了大规模的云上转播,超越传统卫星转播,为全球观众提供流畅、高清的观赛体验。其中,“子弹时间”回放技术在多个场馆的应用,让观众享受到了电影般的多角度精彩瞬间。此外,8K超高清直播、AI智能解说和通义APP等创新,极大地提升了赛事观赏性和互动性。能耗宝(Energy Expert)的部署则助力实现了赛事的可持续发展目标。巴黎奥运会的成功举办标志着体育赛事正式进入AI时代,开启了体育与科技融合的新篇章。
解密巴黎奥运会中的阿里云AI技术
|
Rust 安全 图形学
Rust图形革新:2D与3D编程的全新体验,它能否颠覆传统?
【8月更文挑战第31天】随着Rust语言的日益成熟,其在图形编程领域的应用逐渐增多。本文将探讨Rust在图形编程中的表现,从2D扩展至3D。通过使用`pixman`库处理2D图形,以及借助`naga`库实现3D渲染,展示了Rust在图形编程中的潜力。尽管与C++相比,Rust的生态仍在发展中,但其安全性与性能使其成为图形编程的重要工具之一,值得开发者关注和学习。
427 0
|
负载均衡 算法 网络协议
【专栏】网络高可用性和负载均衡关键在于VRRP、VGMP和HRP协议
【4月更文挑战第28天】网络高可用性和负载均衡关键在于VRRP、VGMP和HRP协议。VRRP实现路由器冗余,保证流量转发;VGMP优化多播流量传输,适合多媒体服务;HRP提供无缝故障转移,适用于电信级网络。选择需考虑网络环境和业务需求,VRRP简单易部署,VGMP处理多播流量,HRP适合高稳定性场景。理解协议特点,确保网络最佳性能和可用性。
537 4
|
NoSQL Java Redis
springboot之RedisTemplate的访问单机,哨兵,集群模式
以上是配置RedisTemplate以连接到单机、哨兵和集群模式的示例。在实际应用中,还可以根据需求配置连接池、序列化方式、超时等其他参数。
744 0
|
存储 芯片
键盘驱动程序设计
键盘驱动程序设计
243 0
|
人工智能 IDE 程序员
【程序员小知识】AndroidStudio 与 IntelliJ IDEA 的版本关系
【程序员小知识】AndroidStudio 与 IntelliJ IDEA 的版本关系
646 0
|
机器学习/深度学习 传感器 存储
2022最新!视觉SLAM综述(多传感器/姿态估计/动态环境/视觉里程计)(下)
论文调查的主要目的是介绍VSLAM系统的最新进展,并讨论现有的挑战和未来趋势。论文对在VSLAM领域发表的45篇有影响力的论文进行了深入的调查,并根据不同的特点对这些方法进行了分类,包括novelty domain、目标、采用的算法和语义水平。最后论文讨论了当前的趋势和未来的方向,有助于研究人员进行研究。
2022最新!视觉SLAM综述(多传感器/姿态估计/动态环境/视觉里程计)(下)