磁盘
视频教程以及实际代码可以看这一个教程
ATA PIO Mode - OSDev Wiki
- 下面的大部分来自这一个网址的翻译
在磁盘的第一个扇区里面可以有4个描述分区的描述符
电脑有两个总线, Primary Bus, Secondary Bus, 这两个都有一个Msater Driver和一个Slave Driver
According to the ATA specs, PIO mode must always be supported by all ATA-compliant drives as the default data transfer mechanism.
PIO mode uses a tremendous amount of CPU resources because every byte of data transferred between the disk and the CPU must be sent through the CPU’s IO port bus (not the memory). On some CPUs, PIO mode can still achieve actual transfer speeds of 16MB per sec, but no other processes on the machine will get any CPU time.
这里使用的是PIO模式, 这是ATA规定的模式, 这是一个使用CPU进行读取的模式, 这时候CPU不能处理其他的事情
这是一个简单的读取的模式
There is only one wire dedicated to selecting which drive on each bus is active. It is either electrically “high” or “low”, which means that there can never be more than two devices operational on any ATA bus. They are called the master and the slave devices, for no particular reason. The terms ‘master’ and ‘slave’ have largely been abandoned as they inaccurately portray the master drive as having some kind of superiority over the slave drive, or that the latter is dependent on the master. However, these terms will be used in this document. The functionality of the master and slave drives is almost completely identical. There is a special IO port bit that allows a driver to select either drive as the target drive for each command byte.
这一段的大致意思是主磁盘和从磁盘的区分是因为只有一条线进行选择这两个磁盘, 这两个磁盘的速度之类的属性基本没有区别, 没有依附关系
使用的寄存器
An ATA bus typically has ten I/O ports which control its behavior. For the primary bus, these I/O ports are usually 0x1F0 (the “I/O” port base) through 0x1F7 and 0x3F6 (the “Control” port base) through 0x3F7. For the secondary bus, they are usually 0x170 through 0x177 and 0x376 through 0x377.
每一个总线使用10个端口, Primary使用0x1F0-0x1F7(IO)和0x3F6-0x3F7(控制寄存器)
Secondary使用的是0x170- 0x177 and 0x376-0x377.
The standard IRQ for the Primary bus is IRQ14 and IRQ15 for the Secondary bus.
这两个磁盘使用的中断是IRQ14,15
状态寄存器
检测磁盘是不是存在
IDENTIFY command
To use the IDENTIFY command, select a target drive by sending 0xA0 for the master drive, or 0xB0 for the slave, to the “drive select” IO port. On the Primary bus, this would be port 0x1F6. Then set the Sectorcount, LBAlo, LBAmid, and LBAhi IO ports to 0 (port 0x1F2 to 0x1F5). Then send the IDENTIFY command (0xEC) to the Command IO port (0x1F7). Then read the Status port (0x1F7) again. If the value read is 0, the drive does not exist. For any other value: poll the Status port (0x1F7) until bit 7 (BSY, value = 0x80) clears. Because of some ATAPI drives that do not follow spec, at this point you need to check the LBAmid and LBAhi ports (0x1F4 and 0x1F5) to see if they are non-zero. If so, the drive is not ATA, and you should stop polling. Otherwise, continue polling one of the Status ports until bit 3 (DRQ, value = 8) sets, or until bit 0 (ERR, value = 1) sets.
At that point, if ERR is clear, the data is ready to read from the Data port (0x1F0). Read 256 16-bit values, and store them.
可以使用这一个命令选择一个磁盘, 或者检测一个磁盘是不是存在
向一个磁盘的0x1F6(0x176)写入0xA0或者0xB0选择主机和从机
这里使用的时候最好使能一下LBA, 用于读取数据
之后把LBAlo, LBAmid, and LBAhi IO ports to 0 (port 0x1F2 to 0x1F5)这几个寄存器设置为0
向0x1F7端口发送命令0xEC去检测这一个磁盘是不是存在, 可以通过读取0x1F7, 如果是0, 不存在, 如果是其他的值, 等待bit7清零
这个时候你可以看一看0x1F4 and 0x1F5是不是非零的值, 如果是的话这不是一个ATA设备, 如果是的话, 等待bit 3 为1, 或bit 0为1(出错).
At that point, if ERR is clear, the data is ready to read from the Data port (0x1F0). Read 256 16-bit values, and store them.
如果没有出错, 从0x1F0读取256字节的磁盘信息
错误处理
These devices will also write specific values to the IO ports, that can be read. Seeing ATAPI specific values on those ports after an IDENTIFY is definitive proof that the device is ATAPI – on the Primary bus, IO port 0x1F4 will read as 0x14, and IO port 0x1F5 will read as 0xEB. If a normal ATA drive should ever happen to abort an IDENTIFY command, the values in those two ports will be 0. A SATA device will report 0x3c, and 0xc3 instead
如果是其他的设备的话, 这几个端口会被设置为对应的值, 如果是一个普通的ATA设备, 端口为0
获取的数据
uint16_t 100 through 103 taken as a uint64_t contain the total number of 48 bit addressable sectors on the drive. (Probably also proof that LBA48 is supported.)
主要关注这64位, 记录的是这一个磁盘的扇区数
实际的实现
static int identify_disk (disk_t * disk) {
outb(0x1F6(状态寄存器), 根据盘符设置);
outb(命令端口, 0xEC);
// 检测状态,如果为0,则控制器不存在
int err = inb(DISK_STATUS(disk));
if (err == 0) {
log_printf("%s doesn't exist\n", disk->name);
return -1;
}
// 等待数据就绪, 此时中断还未开启,因此暂时可以使用查询模式
err = ata_wait_data(disk);//检测一下BUSY以及ERR位
if (err < 0) {
log_printf("disk[%s]: read failed!\n", disk->name);
return err;
}
uint16_t buf[256];
ata_read_data(disk, buf, sizeof(buf));//使用inw从DATA端口获取数据
disk->sector_count = *(uint32_t *)(buf + 100);
disk->sector_size = SECTOR_SIZE; // 固定为512字节大小
return 0;
}
实际的读取