CFLAGS += -DNR_TTYS=3
CFLAGS += -DFIXED_SYSENTER_ESP_MODE=1
CFLAGS += -DENABLE_BOOT_WAIT=0
+CFLAGS += -DDISK_DMA_MODE=0
SYSTEMMAP = System.map
KERNELBIN = KERNEL.ELF
#define ATA_TIMEOUT 10 // 10次时钟中断
void ata_dma_read_ext(int drv, uint64_t pos, uint16_t count, void *dest);
-int ata_pio_read_ext(int drv, uint64_t pos, uint16_t count, int timeout, void *dest);
+int ata_pio_read_ext(int drv, uint64_t pos, uint16_t count);
void *mbr_buf;
void ata_test(uint64_t nr) {
printk("ata[%d] status %x %s exists\n", i, status, drv->present == 1 ? "" : "not");
insl(REG_DATA(drv_no), identify, SECT_SIZE / sizeof(uint32_t));
+ // 详细IDENTIFY解析,可以参考文档《ATA/ATAPI Command Set - 3 (ACS-3)》 page 104
+
// 第49个word的第8个bit位表示是否支持DMA
// 第83个word的第10个bit位表示是否支持LBA48,为1表示支持。
// 第100~103个word的八个字节表示user的LBA最大值
break;
}
#endif
+ {
+ // bit5 supports ATA/ATAPI-5
+ // bit6 supports ATA/ATAPI-6
+ // bit7 supports ATA/ATAPI-7
+ // bit8 supports ATA8-ACS
+ // bit9 supports ACS-2
+ // bit10 supports ACS-3
+ uint16_t major_version = identify[80];
+ uint16_t minor_version = identify[81];
+
+ printk("ATA %04x %04x\n", major_version, minor_version);
+ }
+
+ {
+ // bit0 Obsolete
+ // bit1为1表示64~70为有效值,这些字段包括PIO和DMA的传输时间信息
+ // bit2为1表示第88个uint16_t为有效值,其包括了Ultra DMA的支持和当前传输模式信息
+ uint16_t field_validity = identify[53];
+
+ printk("field_validity %04x\n", field_validity);
+
+ // 高8位保留0x80
+ // 低8位0x00代表Reserved,0x01~0xFF代表每次最大传输扇区数
+ printk("A: %04x\n", identify[47]); // 高 8 位保留,低 8 位表示最大扇区数
+
+ // 第8位为1表示多扇区设置有效
+ // 当前设置的一次传送的扇区数
+ printk("B: %04x\n", identify[59]);
+
+ printk("C: %04x\n", identify[63]);
+ printk("D: %04x\n", identify[88]);
+ }
+
printk("hard disk %s %s size: %u MB\n", drv->dma == 1 ? "DMA" : "", drv->lba48 == 1 ? "LBA48" : "LBA28",
(max_lba * 512) >> 20);
}
// ATA_CMD_READ_PIO_EXT
-int ata_pio_read_ext(int drv, uint64_t pos, uint16_t count, int timeout, void *dest) {
- // PIO读,禁用中断
- outb(ATA_CTL_NIEN, REG_CTL(drv));
+int ata_pio_read_ext(int drv, uint64_t pos, uint16_t count) {
+ // 不再设置nIEN,需要中断
+ outb(0x00, REG_CTL(drv));
// 等待硬盘不BUSY
while (inb(REG_STATUS(drv)) & ATA_STATUS_BSY) {
outb((pos >> 8) & 0xFF, REG_LBAM(drv));
outb((pos >> 16) & 0xFF, REG_LBAH(drv));
- while (inb(REG_STATUS(drv)) & ATA_STATUS_RDY == 0) {
+ while ((inb(REG_STATUS(drv)) & ATA_STATUS_RDY) == 0) {
nop();
}
outb(ATA_CMD_READ_PIO_EXT, REG_CMD(drv));
+ return 0;
+}
+
+void ata_wait(int drv, int timeout) {
while (timeout > 0) {
timeout--;
asm("sti;hlt;");
}
- asm("cli");
-
- if (timeout == 0) {
- return -1;
- }
- insl(REG_DATA(drv), dest, (SECT_SIZE * count) / sizeof(uint32_t));
+ assert(timeout > 0);
- return 0;
+ // 检查硬盘是否有错误
+ if (inb(REG_STATUS(drv)) & ATA_STATUS_ERR) {
+ panic("wait disk fail");
+ }
}
-
// uint8_t ata_pci_bus_status() {
// uint8_t st = 0;
// st = inb(ide_pci_controller.bus_status);
ide_pci_controller_t *ide_ctrl = ide_pci_controller + channel;
atomic_inc(&ide_ctrl->irq_cnt);
+#if DISK_DMA_MODE
ata_dma_stop(channel);
+#endif
add_irq_bh_handler(ide_irq_bh_handler, (void *)channel);
}
* ------------------------------------------------------------------------
*/
+#include <ata.h>
#include <completion.h>
#include <disk.h>
#include <ide.h>
void ata_read_identify(int drv, int disable_intr);
void ata_pio_read_data(int drv_no, int sect_cnt, void *dst);
void ata_dma_read_ext(int drv, uint64_t pos, uint16_t count, void *dest);
+int ata_pio_read_ext(int drv, uint64_t pos, uint16_t count);
void disk_init() {
// ...
uint64_t pos = r->pos + drv->partions[part_id].lba_start;
assert(pos < drv->partions[part_id].lba_end);
- switch (r->command) {
- case DISK_REQ_IDENTIFY:
- printk("try to read disk drive %u identify", drv_no);
- assert(r->count == 1);
- ata_read_identify(drv_no, 0);
- break;
- case DISK_REQ_READ:
- assert(r->count > 0);
- assert(r->buf != NULL || r->bb->data != NULL);
- // printk("DISK READ drv_no %u pos %u count %u\n", drv_no, (uint32_t)pos, r->count);
- if (r->bb != 0) {
- ata_dma_read_ext(drv_no, pos, r->count, r->bb->data);
- } else {
- ata_dma_read_ext(drv_no, pos, r->count, r->buf);
+ // 对于DMA的方式来说,一次就能搞定
+ uint16_t send_cmd_times = 1;
+#if !DISK_DMA_MODE
+ // 对于PIO的方式来说,一次只能操作一个扇区,所以有几个扇区就要重试几次
+ send_cmd_times = r->count;
+#endif
+ for (int count = 0; count < send_cmd_times; count++) {
+ switch (r->command) {
+ case DISK_REQ_IDENTIFY:
+ printk("try to read disk drive %u identify", drv_no);
+ assert(r->count == 1);
+ ata_read_identify(drv_no, 0);
+ break;
+ case DISK_REQ_READ:
+ assert(r->count > 0);
+ assert(r->buf != NULL || r->bb->data != NULL);
+#if !DISK_DMA_MODE
+ if (r->bb != 0) {
+ ata_pio_read_ext(drv_no, pos + count, 1);
+ } else {
+ ata_pio_read_ext(drv_no, pos + count, 1);
+ }
+#else
+ if (r->bb != 0) {
+ ata_dma_read_ext(drv_no, pos, r->count, r->bb->data);
+ } else {
+ ata_dma_read_ext(drv_no, pos, r->count, r->buf);
+ }
+#endif
+ break;
+ default:
+ panic("invalid disk request command");
+ break;
}
- break;
- default:
- panic("invalid disk request command");
- break;
- }
- // 等待硬盘中断
- // printk("down ide req\n");
- down(&ide_ctrl->disk_intr_sem);
+ // 等待硬盘中断
+ // printk("down ide req\n");
+ down(&ide_ctrl->disk_intr_sem);
+
+#if !DISK_DMA_MODE
+ // void ata_wait(int drv, int timeout);
+ // ata_wait(drv_no, 100);
+ if (DISK_REQ_READ == r->command || DISK_REQ_IDENTIFY == r->command) {
+ uint32_t offset = SECT_SIZE * count;
+ if (r->bb != 0) {
+ ata_pio_read_data(drv_no, 1, r->bb->data + offset);
+ } else {
+ ata_pio_read_data(drv_no, 1, r->buf + offset);
+ }
+ }
- // 读数据
- if (DISK_REQ_IDENTIFY == r->command) {
- ata_pio_read_data(drv_no, 1, r->buf);
+#endif
}
if (r->bb != 0) {
while (1) {
sysc_wait(7);
+#if 1
uint64_t sect_nr = get_next_deubug_sect_nr();
memset(disk_buf2, 0, 512);
disk_request_t r;
send_disk_request(&r);
// verify_hd_data(sect_nr, disk_buf2, current->name);
-
+#endif
for (int i = 0; i < 1; i++) {
asm("hlt;");
}