pci初始化时,遍历pci上的设置,如果BaseClassCode==1,则为大容量存储控制器,包括硬盘控制器、固态硬盘控制器、光盘驱动控制器、RAID控制器等。
BaseAdder4为DMA控制器基地址,包含两个控制器,主控制器,次控制器,每个占8字节。
dma只能使用物理地址,最好开启硬盘状态中断。
具体过程见代码
//主控制器占8位,次控制器占用8字节,意义相同
#define DMA_COMMAND_REG 0 // dma主控命令寄存器的偏移 1字节,第1、3字节保留,没有用途
//第3位置为0时,表示读扇区,DMA传送方向为从IDE设备到内存;为1时,表示写扇区,方向为从内存到IDE设备。
//第0位置为0时,表示停止DMA传输;为1时表示启动DMA传输
//
#define DMA_STATUS_REG 2 // dma主控状态寄存器的偏移
//第0位置为1时,正在进行DMA传输;第1位置为1时,表示DMA传送出现了一个错误;
//第2位置为1时,IDE设备已产生一个中断请求(DMA传输已完成);
//第5位置为1时,表示设备0(主盘)能够执行DMA操作;
//第6位置为1时,表示设备1(从盘)能够执行DMA操作;
//第7位置为1时,表示设备0和设备1不能同时执行DMA操作。#define DMA_PRD_ADDR_REG 4 // 物理区域描述符指针寄存器的偏移
//物理区域描述符表,连续排列,每个项占8字节,typedef struct {DWORD addr; //前4位为缓存区物理地址,WORD len; //当前块长度,WORD EOT; //只使用最高位
}__attribute__((packed)) PRD_ADD;
#define pio_base_addr1 0x01F0 // 主ATA设备控制块寄存器基地址
#define pio_base_addr2 0x03F0 // 主ATA命令命令块寄存器基地址
void dma_read_sectors(DWORD bmcr_base_addr, DWORD lbaSector, PVOID buf,WORD len) {PRD_ADD prdBufAddr; //物理区域描述符地址// bufferaddr // 内存缓冲区地址// Start/Stop=0, 停止以前的DMA传输WritePortByte(bmcr_base_addr + DMA_COMMAND_REG, 0x00);// 清除主控状态寄存器的Interrupt和Error位WritePortByte(bmcr_base_addr + DMA_STATUS_REG, 6);//物理区域描述符表,连续排列 EOT=1 表示为最后一个prdBufAddr.addr = (DWORD) buf; //这里应为物理地址prdBufAddr.len= len; //len应小于或等于0x200prdBufAddr.EOT = 0x8000; //最高位为EOT// 物理区域描述符的地址写入PRDTRWritePortDword(bmcr_base_addr + DMA_PRD_ADDR_REG,MiGetPhysics(&prdBufAddr));// 主控命令寄存器的R/W=1, 表示写入内存(读取硬盘)WritePortByte(bmcr_base_addr + DMA_COMMAND_REG, 8);// 等待硬盘BSY=0和DRQ=0//busy_wait();// 设置设备/磁头寄存器的DEV=0WritePortByte( pio_base_addr1 + 6, 00);// 等待硬盘BSY=0和DRQ=0//busy_wait();// 设备控制寄存器的nIEN=0, 允许中断WritePortByte( pio_base_addr2 + 6, 00);// 设置ATA寄存器WritePortByte( pio_base_addr1 + 1, 00); // =00WritePortByte( pio_base_addr1 + 2, 1); // numSect扇区数量WritePortByte( pio_base_addr1 + 3, lbaSector >> 0); // LBA第7~0位WritePortByte( pio_base_addr1 + 4, lbaSector >> 8); // LBA第15~8位WritePortByte( pio_base_addr1 + 5, lbaSector >> 16); // LBA第23~16位// 设备/磁头寄存器:LBA=1, DEV=0, LBA第27~24位WritePortByte( pio_base_addr1 + 6, 0x40 | (lbaSector >> 24));// 设置ATA命令寄存器WritePortByte( pio_base_addr1 + 7, 0x0C8); // 0C8h=Read DMA// 读取主控命令寄存器和主控状态寄存器ReadPortByte(bmcr_base_addr + DMA_COMMAND_REG);ReadPortByte(bmcr_base_addr + DMA_STATUS_REG);// 主控命令寄存器的R/W=1,Start/Stop=1, 启动DMA传输WritePortByte(bmcr_base_addr + DMA_COMMAND_REG, 9);// 现在开始DMA数据传送// 检查主控状态寄存器, Interrupt=1时,传送结束//mov ecx, 4000hnotAsserted: while (!(ReadPortByte(bmcr_base_addr + DMA_STATUS_REG) & 4)) {hlt();};// 清除主控状态寄存器的Interrupt位WritePortByte(bmcr_base_addr + DMA_STATUS_REG, 4);// 读取主控状态寄存器ReadPortByte(bmcr_base_addr + DMA_STATUS_REG);// 主控命令寄存器的Start/Stop=0, 结束DMA传输WritePortByte(bmcr_base_addr + DMA_COMMAND_REG, 00);
}