硬盘DMA编程

采用PIO方式访问硬盘,硬盘扇区数据的读写完全由CPU通过INOUT指令执行,一个扇区占512字节,需要256I/O操作,占用CPU资源。读取硬盘扇区时,每次I/O操作包括一个IN指令和一个内存写操作,CPU先读取16位数据到AX中,再将16位数据写入到内存中。写入硬盘扇区时,每次I/O操作则包括一个内存读操作和一个OUT指令。

使用DMA方式,硬盘读写由DMA控制,数据在内存和I/O端口之间直接传输,而不需要CPU中转,传输速度比PIO方式快,降低了CPU的开销。

10.1 获取PCI-IDE配置

早期的IDE控制器挂接在ISA总线上,而目前主板上的芯片组一般都集成了一个PCI-IDE控制器,支持两个IDE通道。PCI-IDE控制器支持DMA功能,能够在IDE通道和内存之间建立直接的数据传输,而不必通过CPU。也就是说,PCI-IDE控制器可以作为总线主控设备,从IDE接口中读出数据写入到内存中(读扇区),或者从内存中读出数据写入到IDE接口中(写扇区)

1. PCI-IDE控制器

如图10-1PCI-IDE控制器就像一座桥梁一样,一端连接PCI总线,另一端连接IDE设备,能够在控制器中的DMA的指挥下,通过PCI总线在内存和IDE设备之间传输数据。

CPU

PCI总线

内存

北桥、南桥

其它PCI设备

ATA设备

PCI-IDE控制器

IDE接口

2. PCI设备的配置空间

PCI具有即插即用的功能,支持自动的设备检测和配置。在系统启动时,操作系统扫描系统的各条PCI总线,枚举出总线上存在的PCI设备。操作系统读取PCI设备配置空间的寄存器,确定设备所需的地址空间、分配中断以及主设备对总线的访问要求等。

1)总线、设备、功能

系统可以最多连接256PCI 总线,每条PCI总线可以连接32个物理PCI设备。每个PCI设备可以包含一个到八个独立的PCI功能(即逻辑设备)

2)配置空间

对每一个功能,PCI设备都给它提供一个256字节的配置空间,由6432位的配置寄存器组成。

10-2显示了PCI功能配置空间中前面16个双字寄存器。这个区域的格式和用法由PCI规范定义,PCI设备必须按照PCI规范设置配置头区域有关字段。系统启动时,系统软件的配置程序读取配置头中的设备信息并根据设备的要求按照PCI规范配置设备。

31

16

15

0

 

设备ID

供应商ID

00H

状态寄存器

命令寄存器

04H

类代码

版本

08H

内建自测

配置头类型

延迟时间

Cache行大小

0CH

基地址寄存器0

10H

基地址寄存器1

14H

基地址寄存器2

18H

基地址寄存器3

1CH

基地址寄存器4

20H

基地址寄存器5

24H

卡总线指针

28H

子系统版本ID

子系统供应商ID

2CH

扩展ROM基地址寄存器

30H

保留

性能指针

34H

保留

38H

优先级请求

时间片请求

中断引脚

中断线

3CH

10-2  PCI配置空间头部的16个双字寄存器

供应商ID、设备ID、版本、类代码、子系统供应商ID、子系统版本ID,这6个寄存器用于识别设备类型,操作系统根据它们的内容,确定为设备装载哪个驱动程序。

•供应商ID:设备制造商的代码,由PCI SIG组织来分配。例如,值8086h代表Intel公司。

•设备ID16位,由设备制造商分配,表示设备类型。例如,2416h代表Intel 82801AA (ICHAA) AC'97 Modem Controller

•版本:8位,由设备制造商分配,表示设备的版本号。

•类代码:24位内容包含:基类型、子类型和可编程接口,每一项占1个字节。基类型代表设备的基本功能,设备子类型表示了该基类型中的设备的详细分类,可编程接口则表示该设备的寄存器编程接口。

·命令寄存器:提供了对设备响应和执行PCI访问能力的基本控制。

·状态寄存器:把功能的状态记录在PCI设备中。

·配置头类型:第6~0位定义了配置空间头部的格式(00H=普通PCI设备,01H=PCI桥,02H=CardBus)。第7位定义了设备是单功能设备(=0)还是多功能设备(=1)

·内建自测:BISTBuilt-In Self-Test)寄存器,可以由主设备和/或目标设备提供,设置后,设备可以实现内置自检。延迟定时器也叫时间片寄存器,它对于执行猝发交易的主设备是强制性(可读/可写)

·延迟时间:定义了以PCI时钟周期为单位的最小时间量,在这个时间片中,总线主设备只要起动一次新交易,就能保持总线所有权。起动交易后,总线主设备在每个时钟上升沿将延迟定时器减1

·Cache行大小:用于存储器写和使失效命令,指出系统以双字为单位的Cache行大小(例如,一该寄存器的值为08h,表示Cache行容量为8个双字即32字节)

·优先级请求:表示主设备访问总线的频度(多少时间访问总线一次,从仲裁器收到GNT #计算,250ns递增),决定总线仲裁器分配给主设备(假设仲裁器可编程)的优先级(以及仲裁器使用的仲裁方案)

·时间片请求:由总线主设备提供,表示主设备要达到好的性能而希望保持PCI总线所有权的时间,指出设备进行一个猝发周期需要多长时间(以250ns为单位)。

·中脚引脚:指出功能连接了哪一个中断请求引脚。值01h04h对应于PCI中断请求引脚INTA #INTD #

·中脚线:用于识别功能的PCI中断请求引脚(由中断引脚寄存器指定)连接到中断控制器的哪个输入端。

·基地址寄存器:为设备内的存储器和IO空间提供基地址的寄存器。第0位定义了该寄存器描述的是存储器(=0)还是I/O地址(=1)。存储器的基地址可以是64位的(2-1=10b),这时,使用2个基地址寄存器表示64位基地址。

·扩展ROM基地址寄存器:指出PCI设备内的扩展ROM起始存储器地址和长度。

3. 枚举PCI设备

微机系统提供了两个32位的I/O端口寄存器来访问PCI设备的配置空间。

·配置地址端口:I/O地址为0CF8H。将要访问的总线号、设备号、功能号和寄存器号写入到这个端口,前3项确定要读写哪一个PCI设备的配置空间,最后1项确定了要读写该配置空间的哪一个寄存器。如图10-3所示。

在配置地址端口中,总线号占8位,范围是0~255;设备号占5位,范围是0~31;功能号占3位,范围是0~7

寄存器号共6位,其范围是0~63,指定256字节的配置空间中的某一个32位寄存器。例如,要读出配置头中的子系统版本ID,在图10-2中其偏移为2CH,寄存器号为2CH/4=9

31

30

 

 

 

 

 

24

23

 

 

 

 

 

 

16

15

 

 

 

11

10

 

8

7

 

 

 

 

2

1

0

1

保留

总线号

设备号

功能号

寄存器号

0

0

10-3  配置地址端口寄存器的格式

·配置数据端口:I/O地址为0CFCH。对配置空间的读、写都要通过这个端口进行,但程序首先要写入配置地址端口来指定要对哪一个PCI设备的寄存器。

按图10-3构造一个双字,写入到0CF8H端口后,再从0CFCH读入一个32位的值。在前面的例子中,从这个32位的值中取出其第31~16位,就是子系统版本ID

枚举PCI设备的步骤为:

(1)    列出所有的总线号和设备号的组合,对每一个组合,设总线号为bus,设备号为dev,执行以下(2)(5)步;

(2)    对功能号func,从07循环执行以下(3)(5)步;

(3)    index063循环,读取<bus, dec, func>的全部64个寄存器。

(4)    如果func等于0,检查<bus, dec, func>的“配置头类型”寄存器的第7位。如果等于0,则该设备是单功能设备,退出第(2)步开始的循环;等于1时,该设备是多功能设备。

下列程序在DOS下运行,在枚举过程发现基类型=01H及子类型=01h的设备时,枚举结束,并显示出256个字节的配置空间。

;程序清单: pciide.asm(获取PCI-IDE配置空间)

.386P

DSEG            SEGMENT USE16       ;16位数据段

CfgSpace        DB      256 DUP(0)  ;PCI设备的256字节配置空间

bus             DW      0           ;bus,0~255

dev             DW      0           ;dev,0~31

func            DW      0           ;func,0~7

index           DW      0           ;index,0~63

DSEG            ENDS                ;数据段结束

 

SSEG            SEGMENT PARA STACK  ;堆栈段

                DB      512 DUP (0)

SSEG            ENDS                ;堆栈段结束

 

;字符显示宏指令的定义

EchoCh          MACRO   ascii

                mov     ah,2

                mov     dl,ascii

                int     21h

                ENDM

 

CSEG            SEGMENT USE16       ;1代码段

                ASSUME  CS:CSEG,DS:DSEG

; 搜索PCI-IDE设备, 获取PCI配置空间

FindPCIIDE      PROC

                ; bus号从0循环到255

                mov     bus, 0

loop_bus:

                ; dev号从0循环到31

                mov     dev, 0

loop_dev:

                ; func号从0循环到7

                mov     func, 0

loop_func:

                ; index号从0循环到63

                mov     index, 0

loop_index:

                ;构造eax为一个32位双字, 写入0cf8h端口

                ;(1 << 31)|(bus << 16)|(dev << 11)|(func << 8)|(index << 2)

                movzx   eax,bus         ;eax=bus               

                movzx   ebx,dev         ;ebx=dev               

                movzx   ecx,func        ;ecx=func

                movzx   edx,index       ;dex=index

                shl     eax,16          ;eax=(bus<<16)

                shl     ebx,11          ;ebx=(dev<<11)

                shl     ecx,8           ;ecx=(func<<8)

                shl     edx,2           ;edx=(index<<2)

                or      eax,80000000h   ;eax=(1<<31)||(bus<<16)

                or      eax,ebx         ;eax=..||(dev << 11)

                or      eax,ecx         ;eax=..||(func << 8)

                or      eax,edx         ;eax=..||(index << 2)

                ;0cf8h端口读取的配置寄存器将保存在CfgSpace[index*4]

                lea     edi,CfgSpace[edx]

                mov     dx,0cf8h

                out     dx,eax          ;eax写入到0cf8h端口

                mov     dx,0cfch

                in      eax,dx          ;0cfch端口读入

               

                cld

                stosd                   ;配置寄存器保存在CfgSpace    

                           

                inc     index

                cmp     index, 64

                jb      loop_index      ;index=0~63

 

                cmp     WORD PTR CfgSpace[0ah],0101h    ;检查类代码寄存器

                jz      FindValidOne        ;BaseClass=01h,Sub-Class=01h

                               

                cmp     func,0              ;func=0,检查为多功能设备

                jnz     NotFunc0            ;func=1,不检查

 

                test    CfgSpace[0eh],80h   ;Bit7=1,<bus,dev>是多功能设备

                jz      NotMultiFunc        ;Bit7=0,不是

NotFunc0:

                inc     func

                cmp     func, 8

                jb      loop_func       ;index=0~7

NotMultiFunc:

                inc     dev

                cmp     dev, 32

                jb      loop_dev        ;dev=0~31

 

                inc     bus

                cmp     bus, 256

                jb      loop_bus        ;bus=0~255

               

FindValidOne:

                ret

FindPCIIDE      ENDP

               

Start           PROC

                mov     ax,DSEG

                mov     ds,ax           ;ds指向数据段

                mov     es,ax           ;es指向数据段

 

                call    FindPCIIDE      ;搜索PCI-IDE设备

               

                lea     si,CfgSpace     ;显示配置空间中的256字节数据

                cld

                mov     bp,256/16

NextLine:       mov     cx,16

NextCh:         lodsb

                push    ax

                shr     al,4

                call    ToASCII

                EchoCh  al

                pop     ax

                call    ToASCII

                EchoCh  al

                EchoCh  ' '

                loop    NextCh

                EchoCh  0dh

                EchoCh  0ah

                dec     bp

                jnz     NextLine

 

                mov     ax,4c00h

                int     21h

Start           ENDP

 

ToASCII         PROC

                and     al,0fh

                cmp     al,10

                jae     Over10

                add     al,'0'

                ret

Over10:

                add     al,'A'-10

                ret

ToASCII         ENDP

 

CSEG            ENDS                           ;代码段结束

                END     Start

VirtualBoxDOS环境中,运行结果显示为:

86 80 10 70 07 00 00 00 00 8A 01 01 00 00 00 00

00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

01 C0 00 00 00 00 00 00 00 00 00 00 00 00 00 00

00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

00 80 00 80 00 00 00 00 00 00 00 00 00 00 00 00

00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

PCI-IDE设备的配置空间遵循图10-2的格式。PCI规范中规定,基类型(Base Class=01h,表示大容量存储控制器(mass storage controller)。在这个基类型之下,又分为若干子类型(Sub-Class)。子类型=00h,表示SCSI总线控制器;子类型=01h,表示IDE控制器;子类型=02h,表示软盘控制器等等。在基类型=01H,子类型=01h时,可编程接口(Interface)的最高位(Bit 7)表示该设备是否具有DMA主控功能。

在以上数据中,类代码为“8A 01 01”,其中基类型=01h,子类型=01h,可编程接口=8Ah

10.2 硬盘DMA传输实验

PCI总线上的设备既可以作为PCI总线目标设备(Slave),也可以作为PCI总线的主控设备(Master)Slave设备只能响应来自于CPU或其他设备的读写操作,不能主动地向总线发出读写操作;而Master设备除了能够响应读写操作外,还能够读写其他PCI设备、内存等。

PCI-IDE控制器中含有一个DMA控制器,它能够在硬盘和内存之间直接传送数据。在数据传送期间,这个DMA控制器接管PCI总线,产生对硬盘的I/O操作和对内存的读写操作,根据设定的传送字节数,在全部数据传送完成后,结束DMA传输。

1. PCI-IDE控制器中的DMA寄存器

PCI-IDE控制器作为一个PCI设备,在256字节的配置空间中,偏移020h处的基地址寄存器5作为DMA主控寄存器的首地址。在上面实验中,基地址寄存器5的内容为“01 C0 00 00”,即0000C001H。最后1位等于1,表示这个基地址属于I/O空间。DMA主控寄存器的首地址为0000C000H

每个通道有3个寄存器,主控命令寄存器、主控状态寄存器和描述符指针寄存器。

1)主控命令寄存器

主控命令寄存器的格式如图10‑4所示。第3位置为0时,表示读扇区,DMA传送方向为从IDE设备到内存;为1时,表示写扇区,方向为从内存到IDE设备。第0位置为0时,表示停止DMA传输;为1时表示启动DMA传输。

7

6

5

4

3

2

1

0

保留

保留

保留

保留

R/W

保留

保留

Start/Stop

10‑4 主控命令寄存器

2)主控状态寄存器

主控状态寄存器的格式如图10‑5所示。第0位置为1时,正在进行DMA传输;第1位置为1时,表示DMA传送出现了一个错误;第2位置为1时,IDE设备已产生一个中断请求(DMA传输已完成);第5位置为1时,表示设备0(主盘)能够执行DMA操作;第6位置为1时,表示设备1(从盘)能够执行DMA操作;第7位置为1时,表示设备0和设备1不能同时执行DMA操作。

7

6

5

4

3

2

1

0

Simplex

D1DC

D0DC

保留

Interrupt

Error

Active

10‑5 主控状态寄存器

3)物理区域描述符表指针寄存器

物理区域描述符表指针寄存器(Physical Region Descriptor Table RegisterPRDTR)的格式如图10‑6所示。它是一个指向描述符表的指针,指针的第1位和第0位必须为0。描述符表中包含一个或多个物理区域描述符(Physical Region Descriptor)。每个描述符占8个字节,它的格式如图10‑7所示。

31

 

 

 

 

 

2

1   0

描述符表地址 [31..2]

保留

10-6 物理区域描述符表指针寄存器

31

16

15

1

0

 

 

缓冲区的物理地址[31..1]

 

 

 

EOT

保留

缓冲区的长度[15..1]

 














10‑7 物理区域描述符的格式

每个描述符指出一个内存缓冲区的物理地址及缓冲区长度。物理地址的第0位和缓冲区长度的第0位必须为0。当缓冲区长度为0时,传送65536个字节。EOT位代表这个缓冲区是否为最后一个。如果有多个内存缓冲区,前面几个缓冲区的描述符中的EOT0,而最后一个为1

例如,图10‑8中有2个不连续的内存缓冲区,地址分别为00060000H00063000H,长度都为200H。可以通过一次DMA操作将这2个缓冲区的内容传送给设备,写到硬盘上的2个连续的扇区。这就需要构造一个描述符表,表中的2项描述符分别描述一个物理区域(起始地址和长度),第2项的EOT位设为0。设描述符表的地址为00070000H,将描述符表的地址写入描述符表指针寄存器,在执行DMA操作时,PCI-IDE控制器就能够获得内存中的2个缓冲区的地址和长度。

 

00070000H


00060000H

 

1个缓冲区

00060000H

描述符表指针寄存器

 

00000200H

 

 

 

00063000H

 

 

 

80000200H

 

 

 

 

描述符表

 

2个缓冲区

00063000H

 

 

 

 

 

 

 

 

 

 

10‑8 不连续缓冲区

4)端口地址分配

PCI-IDE控制器支持2IDE通道(/Primary通道和次/Secondary通道),每个通道分配了8个字节的端口地址,从基地址寄存器5(BAR5)开始,一共16个地址。主控命令寄存器、主控状态寄存器和描述符指针寄存器的端口地址如表10-1所示。

10‑1 PCI-IDE控制器的寄存器分配

主通道

 

次通道

端口地址

寄存器名称

实例

 

端口地址

寄存器名称

实例

BAR5+00H

主控命令寄存器

0C000H

 

BAR5+08H

主控命令寄存器

0C008H

BAR5+01H

保留

0C001H

 

BAR5+09H

保留

0C009H

BAR5+02H

主控状态寄存器

0C002H

 

BAR5+0AH

主控状态寄存器

0C00AH

BAR5+03H

保留

0C003H

 

BAR5+0BH

保留

0C00BH

BAR5+04H

物理区域描述符指针寄存器

0C004H

 

BAR5+0CH

物理区域描述符指针寄存器

0C00CH

2. PCI-IDE控制器的DMA

通过DMA读写硬盘的步骤为:

(1)      在内存中构造一个描述符表,指向缓冲区。

(2)      把描述符表的地址写入描述符表指针寄存器。

(3)      设置主控命令寄存器的R/W位。读硬盘时,设为1;写硬盘时,设为0

(4)      1写入主控状态寄存器的InterruptError位,将这2个位复位为0

(5)      要传输的扇区数、扇区地址等写入ATA设备寄存器。将命令码(C8HCAH)写入ATA命令寄存器。

(6)      1写入主控命令寄存器的Start/Stop位。

(7)      PCI-IDE控制器就会在内存缓冲区和硬盘之间进行DMA数据传输。

(8)      传输完毕后,硬盘发出一个中断请求。PCI-IDE控制器随之向CPU发出中断请求。

(9)      响应中断请求后,将0写入主控命令寄存器的Start/Stop位,将1写入主控状态寄存器的Interrupt位,以清除中断请求

(10)  读取主控状态寄存器和ATA状态寄存器,确认命令是否成功。

下面的示例程序在VirtualBoxDOS环境下运行。如图10-9所示,VirtualBox的硬盘作为主通道上的主盘,即“第一IDE控制器”。因此,其ATA设备寄存器地址为(1F0~1F7H3F6H)。

文件c:/asm/tool/vbox/HDD0.vdi作为VirtualBox的硬盘,硬盘大小设置为80MBVirtualBox采用了动态分配技术,HDD0.vdi并没有占据80MB空间,在客户机向硬盘写入数据时,该文件会逐渐增大。

硬盘作为主盘,因此程序在写入“设备/磁头寄存器”时,DEV被设置为0

10‑9 VirtualBox的硬盘设置

程序中使用的主要端口为:

(1)      PCI-IDE3个寄存器:主控命令寄存器(端口地址0C000H8位)、主控状态寄存器(端口地址0C002H8位)、物理区域描述符指针寄存器(端口地址0C004H32位)。

(2)      ATA设备寄存器(1F0~1F7H3F6H)。

该程序向硬盘发送0C8h命令(READ DMA),该命令所要求的其他寄存器格式如图10-10所示。

10‑10 ATA规范中的READ DMA命令

为简化起见,程序没有采用中断,而是将CPU中的IF位清0。在DMA传输完成时,PCI-IDE控制器向CPU发出的中断请求被屏蔽。程序通过检查主控状态寄存器的Interrupt位是否为1,来确定DMA是否传输完成。

;程序清单: hdddma-r.asm(实模式下的硬盘DMA)

.386P

bmcr_base_addr  EQU    0C000H       ; DMA主控寄存器首地址

numSect         EQU    1            ; 读取1个扇区

lbaSector       EQU    0            ; LBA=0

BM_COMMAND_REG  EQU    0            ; 主控命令寄存器的偏移

BM_STATUS_REG   EQU    2            ; 主控状态寄存器的偏移

BM_PRD_ADDR_REG EQU    4            ; 物理区域描述符指针寄存器的偏移

pio_base_addr1  EQU    01F0H        ; ATA设备控制块寄存器基地址

pio_base_addr2  EQU    03F0H        ; ATA命令命令块寄存器基地址

 

DSEG            SEGMENT USE16       ; 16位数据段

ALIGN 2                        

_Buffer         db      512*numSect dup (0)   ; 内存缓冲区

_BufferLen      equ     $-_Buffer

ALIGN 4                       

prdBuf          dd      0           ; 物理区域描述符

                dd      0

prdBufAddr      dd      0           ; 物理区域描述符地址

bufferaddr      dd      0           ; 内存缓冲区地址

DSEG            ENDS                ; 数据段结束

 

SSEG            SEGMENT PARA STACK  ; 堆栈段

                DB      512 DUP (0)

SSEG            ENDS                ; 堆栈段结束

 

outx            MACRO   Reg, Val    ; Reg端口写入数据Val

                mov     dx, Reg

                mov     al, Val

                out     dx, al

                ENDM

 

inx             MACRO   Reg         ; Reg端口读入数据, 存放在AL

                mov     dx, Reg

                in      al, dx

                ENDM

               

CSEG            SEGMENT USE16       ; 代码段

                ASSUME  CS:CSEG,DS:DSEG

; 检查ATA状态寄存器, 直到BSY=0DRQ=0

waitDeviceReady proc

waitReady:

                inx     pio_base_addr1+7    ; 读取ATA状态寄存器

                and     al, 10001000b       ; BSY=1DRQ=1,继续查询

                jnz     waitReady

                ret

waitDeviceReady endp

; 采用DMA方式读取硬盘扇区

ReadSectors     proc              

                ; Start/Stop=0, 停止以前的DMA传输

                outx    bmcr_base_addr+BM_COMMAND_REG, 00h

                ; 清除主控状态寄存器的InterruptError

                outx    bmcr_base_addr+BM_STATUS_REG, 00000110b

                ; 建立一个物理区域描述符

                mov     eax, bufferaddr

                mov     prdBuf, eax                   ; Physical Address

                mov     word ptr prdBuf+4, _BufferLen ; Byte Count [15:1]

                mov     word ptr prdBuf+6, 8000h      ; EOT=1

                ; 物理区域描述符的地址写入PRDTR

                mov     eax, prdBufAddr

                mov     dx, bmcr_base_addr+BM_PRD_ADDR_REG

                out     dx, eax

                ; 主控命令寄存器的R/W=1, 表示写入内存(读取硬盘)

                outx    bmcr_base_addr+BM_COMMAND_REG, 08h

                ; 等待硬盘BSY=0DRQ=0

                call    waitDeviceReady

                ; 设置设备/磁头寄存器的DEV=0

                outx    pio_base_addr1+6, 00h

                ; 等待硬盘BSY=0DRQ=0

                call    waitDeviceReady

                ; 设备控制寄存器的nIEN=0, 允许中断

                outx    pio_base_addr2+6, 00

                ; 设置ATA寄存器

                outx    pio_base_addr1+1, 00h              ; =00

                outx    pio_base_addr1+2, numSect          ; 扇区号

                outx    pio_base_addr1+3, lbaSector >> 0   ; LBA7~0

                outx    pio_base_addr1+4, lbaSector >> 8   ; LBA15~8

                outx    pio_base_addr1+5, lbaSector >> 16  ; LBA23~16

                ; 设备/磁头寄存器:LBA=1, DEV=0, LBA27~24

                outx    pio_base_addr1+6, 01000000b or (lbaSector >> 24)  

                ; 设置ATA命令寄存器

                outx    pio_base_addr1+7, 0C8h             ; 0C8h=Read DMA

                ; 读取主控命令寄存器和主控状态寄存器

                inx     bmcr_base_addr + BM_COMMAND_REG

                inx     bmcr_base_addr + BM_STATUS_REG

                ; 主控命令寄存器的R/W=1,Start/Stop=1, 启动DMA传输

                outx    bmcr_base_addr+BM_COMMAND_REG, 09h

                ; 现在开始DMA数据传送

                ; 检查主控状态寄存器, Interrupt=1,传送结束

                mov     ecx, 4000h

notAsserted:

                inx     bmcr_base_addr+BM_STATUS_REG

                and     al, 00000100b

                jz      notAsserted

                ; 清除主控状态寄存器的Interrupt

                outx    bmcr_base_addr+BM_STATUS_REG, 00000100b

                ; 读取主控状态寄存器

                inx     bmcr_base_addr+BM_STATUS_REG

                ; 主控命令寄存器的Start/Stop=, 结束DMA传输

                outx    bmcr_base_addr+BM_COMMAND_REG, 00h

                ret

ReadSectors     endp              

             

Start           PROC

                mov     ax,DSEG

                mov     ds,ax                   ; ds指向数据段

                mov     es,ax                   ; es指向数据段

 

                mov     bx,16

                mov     ax,ds

                mul     bx                      ; 计算并设置数据段基址

                add     ax, offset prdBuf       ; 数据段基址+offset prdBuf

                adc     dx, 0                   ; dx:ax = prdBuf的物理地址

                mov     WORD PTR prdBufAddr, ax

                mov     WORD PTR prdBufAddr+2, dx

 

                mov     ax,ds

                mul     bx

                add     ax, offset _Buffer      ; 段基址+offset _Buffer

                adc     dx, 0                   ; dx:ax = _Buffer的物理地址

                mov     WORD PTR bufferaddr, ax

                mov     WORD PTR bufferaddr+2, dx

 

                cli                             ; 关中断

                call    ReadSectors             ; DMA方式读取硬盘扇区

                sti                             ; 允许中断

 

                call    ShowBuffer              ; 显示缓冲区内容

 

                mov     ax,4c00h

                int     21h

Start           ENDP

 

;字符显示宏指令的定义

EchoCh          MACRO   ascii

                mov     ah,2

                mov     dl,ascii

                int     21h

                ENDM

               

ShowBuffer      PROC

                lea     si,_Buffer     ; 显示_Buffer内容

                cld

                mov     bp,_BufferLen/16

NextLine:       mov     cx,16

NextCh:         lodsb

                push    ax

                shr     al,4

                call    ToASCII

                EchoCh  al

                pop     ax

                call    ToASCII

                EchoCh  al

                EchoCh  ' '

                loop    NextCh

                EchoCh  0dh

                EchoCh  0ah

                dec     bp

                jnz     NextLine

                ret

ShowBuffer      ENDP

               

ToASCII         PROC

                and     al,0fh

                cmp     al,10

                jae     Over10

                add     al,'0'

                ret

Over10:

                add     al,'A'-10

                ret

ToASCII         ENDP

 

CSEG            ENDS                           ; 代码段结束

                END     start

10.4 实验题:保护方式下的硬盘DMA传输实验

程序hdddma-r.asm工作在实模式下,未采用中断技术。在该程序的基础上,在保护模式下实现硬盘DMA传输,编写中断处理程序来检测DMA传输是否结束。

PCI-IDE控制器有2IDE通道,主通道DMA传输结束后产生中断请求IRQ14,次通道产生中断请求IRQ15

IRQ14IRQ15连接在从片8259上,从片8259连接到主片8259IRQ2

要求:

1.    hdddma-r.asm修改为保护模式运行,可结合interpt.asm进行;

2.    设置从片8259的中断类型号为28H~2FHIRQ14对应的中断类型号为2EH。在IDT中为该中断设置处理程序;

3.    设置从片8259OCW1,第6位必须为0,允许IRQ14。主片8259OCW1,第2位必须为0,允许IRQ2

4.    IRQ14中断处理结束时,必须先后向从片8259、主片8259发送EOI命令。

5.    c:/asm/tool/vbox/HDD0.vdi挂接在VirtualBox的第二IDE控制器的从盘,修改程序,使之能够以DMA方式读取硬盘扇区;

6.    修改程序,使之能够以DMA方式写入硬盘扇区。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值