]> Zhao Yanbai Git Server - kernel.git/commitdiff
硬盘支持PIO_EXT读取模式
authoracevest <zhaoyanbai@126.com>
Mon, 13 May 2024 11:00:13 +0000 (19:00 +0800)
committeracevest <zhaoyanbai@126.com>
Mon, 13 May 2024 11:00:13 +0000 (19:00 +0800)
Makefile
drivers/ata.c
drivers/ide.c
kernel/task_disk.c
kernel/task_root.c

index 533d3512b29d046aac6de7a4816c263eab402a3e..757778ede0e0e4d38cc54534fdd3bc5ac4ddf074 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -31,6 +31,7 @@ CFLAGS     += -fcf-protection=none
 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
index a751cd9fd63d1f1ddc6de52487cb37440eb21a56..fca0bba537669d0ab11150c1f4e18aa17d797ce3 100644 (file)
@@ -20,7 +20,7 @@ ide_drive_t ide_drives[MAX_IDE_DRIVE_CNT];
 #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) {
@@ -127,6 +127,8 @@ void ide_ata_init() {
         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最大值
@@ -178,6 +180,39 @@ void ide_ata_init() {
             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);
 
@@ -437,9 +472,9 @@ int ata_dma_stop(int channel) {
 }
 
 // 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) {
@@ -465,12 +500,16 @@ int ata_pio_read_ext(int drv, uint64_t pos, uint16_t count, int timeout, void *d
     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--;
 
@@ -481,17 +520,14 @@ int ata_pio_read_ext(int drv, uint64_t pos, uint16_t count, int timeout, void *d
 
         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);
index 091ae31f6eec7fe29db62b0f0b1c0b6050f14417..48584979c39e463bb89fbd1ba73e56e65d3dfd9d 100644 (file)
@@ -154,7 +154,9 @@ void ide_irq_handler(unsigned int irq, pt_regs_t *regs, void *devid) {
     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);
 }
index 43697e5bf38a6fbde750bbd4c81bfa75eb5737d2..59bde4abfb7389746d65d4c5c1e24807eb320989 100644 (file)
@@ -7,6 +7,7 @@
  * ------------------------------------------------------------------------
  */
 
+#include <ata.h>
 #include <completion.h>
 #include <disk.h>
 #include <ide.h>
@@ -15,6 +16,7 @@
 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() {
     // ...
@@ -94,34 +96,58 @@ void disk_task_entry(void *arg) {
         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) {
index c7eeeadce9f02ddde7fbd1a207506d0c4eaa0019..2447c8c540bf424769bfe280f43ea1afbec85734 100644 (file)
@@ -129,6 +129,7 @@ void taskB_entry() {
 
     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;
@@ -141,7 +142,7 @@ void taskB_entry() {
 
         send_disk_request(&r);
         //  verify_hd_data(sect_nr, disk_buf2, current->name);
-
+#endif
         for (int i = 0; i < 1; i++) {
             asm("hlt;");
         }