x86保护模式下使用LBA进行磁盘读取--代码实现

进一步读取磁盘

视频教程以及实际代码可以看这一个教程
具体的寄存器在检测磁盘是否存在那一篇里面有
ATA PIO Mode - OSDev Wiki大部分来自这一个的翻译

保护模式由于不能使用BIOS, 所以需要用到LBA模式进行读取

这个模式将所有的扇区当做是线性排列的, 没有磁盘柱头等模式, 访问起来更加简单

访问使用的序列

设置读取模式

image-20231015131611883

主要是bit4驱动器号(使用主盘的时候使用0), 以及使用LBA模式, 这里设置为0xE0, 根据实际使用的是哪一个盘设置bit4, 0为主盘

实际的代码实现

image-20231015131554050

//sector开始的扇区, sector_count扇区的个数
outb(0x1F6, (uint8_t) (0xE0)); //选则硬盘, 主盘或者从盘, 设置为LBA模式进行读取
//一次记录一下各个位的值
outb(0x1F2, (uint8_t) (sector_count >> 8));
outb(0x1F3, (uint8_t) (sector >> 24));		// LBA4参数的24~31位
outb(0x1F4, (uint8_t) (0));					// LBA5参数的32~39位  这里这个程序只使用了32位
outb(0x1F5, (uint8_t) (0));					// LBA6参数的40~47位

outb(0x1F2, (uint8_t) (sector_count));
outb(0x1F3, (uint8_t) (sector));			// LBA1参数的0~7位
outb(0x1F4, (uint8_t) (sector >> 8));		// LBA2参数的8~15位
outb(0x1F5, (uint8_t) (sector >> 16));		// LBA3参数的16~23位

outb(0x1F7, (uint8_t) 0x24);

(Notes: A sector count of 0 means 65536 sectors = 32MB. Try not to send bytes to the same IO port twice in a row. Doing so is much slower than doing two outb() commands to different IO ports. The important thing is that the high byte of the sector count, features and LBA bytes 4, 5, & 6 go to their respective ports before the low bytes.)

使用一个16位的数字保存一次读取的扇区的个数, 一共可以用65535块, 32Mde大小

Assume you have a sectorcount uint16_t and a 6 byte LBA value. Mentally number the LBA bytes as 1 to 6, from low to high. Send the 2 byte sector count to port 0x1F2 (high byte first), and the six LBA byte pairs to ports 0x1F3 through 0x1F5 in some appropriate order.

使用16位的扇区个数以及48位的扇区起始位置, 按照这个顺序发送, 最后发送读取的命令0x24

这是一个48位的扇区号以及读取的大小

An example:

Send 0x40 for the "master" or 0x50 for the "slave" to port 0x1F6: outb(0x1F6, 0x40 | (slavebit << 4))
outb (0x1F2, sectorcount high byte)
outb (0x1F3, LBA4)
outb (0x1F4, LBA5)
outb (0x1F5, LBA6)
outb (0x1F2, sectorcount low byte)
outb (0x1F3, LBA1)
outb (0x1F4, LBA2)
outb (0x1F5, LBA3)
Send the "READ SECTORS EXT" command (0x24) to port 0x1F7: outb(0x1F7, 0x24)

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.

uint16_t *data_buf = (uint16_t*) buf;
while (sector_count-- > 0) {
    // 每次扇区读之前都要检查,等待数据就绪
    while ((inb(0x1F7) & 0x88) != 0x8) {}

    // 读取并将数据写入到缓存中
    for (int i = 0; i < SECTOR_SIZE / 2; i++) {
        *data_buf++ = inw(0x1F0);
    }
}

发送命令以后可以读取0x1f0, 获取对应的数据

To write sectors in 48 bit PIO mode, send command “WRITE SECTORS EXT” (0x34), instead. (As before, do not use REP OUTSW when writing.) And remember to do a Cache Flush after each write command completes.

写的时候需要改一下命令, 以及使用outw

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值