]> Zhao Yanbai Git Server - kernel.git/commitdiff
ide irq read ata identify
authoracevest <zhaoyanbai@126.com>
Mon, 15 Nov 2021 14:06:38 +0000 (22:06 +0800)
committeracevest <zhaoyanbai@126.com>
Mon, 15 Nov 2021 14:06:38 +0000 (22:06 +0800)
drivers/ata.c
drivers/bak.ata [new file with mode: 0644]
drivers/console.c
drivers/ide.c
drivers/ide.h
drivers/keyboard.c
include/wait.h
kernel/irq.c
kernel/system.c
kernel/wait.c

index 01e32d13e6ddd7966a6914e16b593104ba3f83fa..1f070d6147725c480b3c14b7ef0ebba58fe14a79 100644 (file)
@@ -41,21 +41,14 @@ void ata_test(uint64_t nr) {
 //  2. 等到status的BSY位清除
 //  3. 等到status的DRQ位或ERR位设置
 u16 identify[256];
-void ata_read_identify(int dev) {  // 这里所用的dev是逻辑编号 ATA0、ATA1下的Master、Salve的dev分别为0,1,2,3
-
-    outb(ATA_CTL_NIEN, REG_CTL(dev));                   // 在读IDENTIFY的时候禁用硬盘中断
+void ata_send_read_identify_cmd(int dev) {
+    outb(0x00, REG_CTL(dev));
     outb(0x00 | ((dev & 0x01) << 4), REG_DEVICE(dev));  // 根据文档P113,这里不用指定bit5, bit7,直接指示DRIVE就行
     outb(ATA_CMD_IDENTIFY, REG_CMD(dev));
-    while (1) {
-        u8 status = inb(REG_STATUS(dev));
-        printk("hard disk status: %x %x\n", status, REG_STATUS(dev));
-        if (status == 0) {
-            panic("no ata device");
-        }
-        if ((status & ATA_STATUS_BSY) == 0 && (status & ATA_STATUS_DRQ) != 0) {
-            break;
-        }
-    }
+}
+void ata_read_identify(int dev) {  // 这里所用的dev是逻辑编号 ATA0、ATA1下的Master、Salve的dev分别为0,1,2,3
+
+    sleep_on_ide();
 
     insw(REG_DATA(dev), identify, SECT_SIZE / sizeof(u16));
 
diff --git a/drivers/bak.ata b/drivers/bak.ata
new file mode 100644 (file)
index 0000000..01e32d1
--- /dev/null
@@ -0,0 +1,230 @@
+/*
+ * ------------------------------------------------------------------------
+ *   File Name: ata.c
+ *      Author: Zhao Yanbai
+ *              2021-11-10 13:55:27 Wednesday CST
+ * Description: none
+ * ------------------------------------------------------------------------
+ */
+#include <ata.h>
+#include <ide.h>
+#include <io.h>
+#include <string.h>
+#include <system.h>
+#include <types.h>
+
+extern ide_pci_controller_t ide_pci_controller;
+
+#define ATA_TIMEOUT 10  // 10次时钟中断
+
+void ata_dma_read_ext(int dev, uint64_t pos, uint16_t count, void *dest);
+int ata_pio_read_ext(int dev, uint64_t pos, uint16_t count, int timeout, void *dest);
+
+void *mbr_buf;
+void ata_test(uint64_t nr) {
+    memset(mbr_buf, 0xAA, SECT_SIZE);
+    ata_dma_read_ext(0, nr, 1, mbr_buf);
+}
+
+// 本程序参考文档《AT Attachment with Packet Interface - 6》
+
+// 仅考虑ATA硬盘的情况
+// 一个IDE接口能接Master、Slave两个DRIVE。
+// 一个PC机上通常有两个IDE接口(IDE0, IDE1或ATA0, ATA1),通常称通道0、1
+// 对于同一个IDE通道的两个DRIVE,共享同一组寄存器,它们之间的区分是通过Device寄存器的第4个bit位来实现的。0为Master,1为Slave
+//
+// 使用IDENTIFY命令步骤:
+//  1. 选择DRIVE构造命令,发送到Device寄存器(发送到master: 0x00, 发送到slave: 0x40)
+//  2. 发送IDENTIFY(0xEC)命令到该通道的命令寄存器
+// 检查status寄存器:
+//  1. 若为0,就认为没有IDE
+//  2. 等到status的BSY位清除
+//  3. 等到status的DRQ位或ERR位设置
+u16 identify[256];
+void ata_read_identify(int dev) {  // 这里所用的dev是逻辑编号 ATA0、ATA1下的Master、Salve的dev分别为0,1,2,3
+
+    outb(ATA_CTL_NIEN, REG_CTL(dev));                   // 在读IDENTIFY的时候禁用硬盘中断
+    outb(0x00 | ((dev & 0x01) << 4), REG_DEVICE(dev));  // 根据文档P113,这里不用指定bit5, bit7,直接指示DRIVE就行
+    outb(ATA_CMD_IDENTIFY, REG_CMD(dev));
+    while (1) {
+        u8 status = inb(REG_STATUS(dev));
+        printk("hard disk status: %x %x\n", status, REG_STATUS(dev));
+        if (status == 0) {
+            panic("no ata device");
+        }
+        if ((status & ATA_STATUS_BSY) == 0 && (status & ATA_STATUS_DRQ) != 0) {
+            break;
+        }
+    }
+
+    insw(REG_DATA(dev), identify, SECT_SIZE / sizeof(u16));
+
+    // 第49个word的第8个bit位表示是否支持DMA
+    // 第83个word的第10个bit位表示是否支持LBA48,为1表示支持。
+    // 第100~103个word的八个字节表示user的LBA最大值
+    printk("%04x %04x %d %d\n", identify[49], 1 << 8, identify[49] & (1 << 8), (identify[49] & (1 << 8)) != 0);
+    if ((identify[49] & (1 << 8)) != 0) {
+        printk("support DMA\n");
+    }
+
+    if ((identify[83] & (1 << 10)) != 0) {
+        printk("support LBA48\n");
+
+        u64 lba = *(u64 *)(identify + 100);
+        printk("hard disk size: %u MB\n", (lba * 512) >> 20);
+    }
+
+    printk("bus iobase %x cmd %x status %x prdt %x \n", ide_pci_controller.bus_iobase, ide_pci_controller.bus_cmd,
+           ide_pci_controller.bus_status, ide_pci_controller.bus_prdt);
+
+    // TODO REMOVE
+    mbr_buf = kmalloc(SECT_SIZE, 0);
+    // ata_test(0);
+
+    // ata_pio_read_ext(0, 0, 1, ATA_TIMEOUT, mbr_buf);
+    // uint16_t *p = (uint16_t *)mbr_buf;
+    // for (int i = 0; i < 256; i++) {
+    //     if (i % 12 == 0) {
+    //         printk("\n>%03d ", i);
+    //     }
+    //     printk("%04x ", p[i]);
+    // }
+}
+
+// ATA_CMD_READ_DMA_EXT
+void ata_dma_read_ext(int dev, uint64_t pos, uint16_t count, void *dest) {
+    // 停止DMA
+    outb(PCI_IDE_CMD_STOP, ide_pci_controller.bus_cmd);
+
+    // 配置描述符表
+    unsigned long dest_paddr = va2pa(dest);
+    ide_pci_controller.prdt[0].phys_addr = dest_paddr;
+    ide_pci_controller.prdt[0].byte_count = SECT_SIZE;
+    ide_pci_controller.prdt[0].reserved = 0;
+    ide_pci_controller.prdt[0].eot = 1;
+    outl(va2pa(ide_pci_controller.prdt), ide_pci_controller.bus_prdt);
+
+    printk("paddr: %x prdt: %x %x prdte %x %x\n", dest_paddr, ide_pci_controller.prdt, va2pa(ide_pci_controller.prdt),
+           ide_pci_controller.prdt[0].phys_addr, *(((unsigned int *)ide_pci_controller.prdt) + 1));
+
+    // 清除中断位和错误位
+    // 这里清除的方式是是设置1后清除
+    outb(PCI_IDE_STATUS_INTR | PCI_IDE_STATUS_ERR, ide_pci_controller.bus_status);
+
+    // 不再设置nIEN,DMA需要中断
+    outb(0x00, REG_CTL(dev));
+
+    // 等待硬盘不BUSY
+    while (inb(REG_STATUS(dev)) & ATA_STATUS_BSY) {
+        nop();
+    }
+
+    // 选择DRIVE
+    outb(ATA_LBA48_DEVSEL(dev), REG_DEVICE(dev));
+
+    // 先写扇区数的高字节
+    outb((count >> 8) & 0xFF, REG_NSECTOR(dev));
+
+    // 接着写LBA48,高三个字节
+    outb((pos >> 24) & 0xFF, REG_LBAL(dev));
+    outb((pos >> 32) & 0xFF, REG_LBAM(dev));
+    outb((pos >> 40) & 0xFF, REG_LBAH(dev));
+
+    // 再写扇区数的低字节
+    outb((count >> 0) & 0xFF, REG_NSECTOR(dev));
+
+    // 接着写LBA48,低三个字节
+    outb((pos >> 0) & 0xFF, REG_LBAL(dev));
+    outb((pos >> 8) & 0xFF, REG_LBAM(dev));
+    outb((pos >> 16) & 0xFF, REG_LBAH(dev));
+
+    // 等待硬盘READY
+    while (inb(REG_STATUS(dev)) & ATA_STATUS_RDY == 0) {
+        nop();
+    }
+
+    outb(ATA_CMD_READ_DMA_EXT, REG_CMD(dev));
+
+    // 这一句非常重要,如果不加这一句
+    // 在qemu中用DMA的方式读数据就会读不到数据,而只触是发中断,然后寄存器(Bus Master IDE Status
+    // Register)的值会一直是5 也就是INTERRUPT和和ACTIVE位是1,正常应该是4,也就是只有INTERRUPT位为1
+    // 在bochs中则加不加这一句不会有影响,都能正常读到数据
+    unsigned int v = pci_read_config_word(pci_cmd(ide_pci_controller.pci, PCI_COMMAND));
+    printk(" ide pci command %04x\n", v);
+    pci_write_config_word(v | PCI_COMMAND_MASTER, pci_cmd(ide_pci_controller.pci, PCI_COMMAND));
+
+    // 指定DMA操作为读取硬盘操作,内核用DMA读取,对硬盘而言是写出
+    // 并设置DMA的开始位,开始DMA
+    outb(PCI_IDE_CMD_WRITE | PCI_IDE_CMD_START, ide_pci_controller.bus_cmd);
+}
+
+// ATA_CMD_READ_PIO_EXT
+int ata_pio_read_ext(int dev, uint64_t pos, uint16_t count, int timeout, void *dest) {
+    // PIO读,禁用中断
+    outb(ATA_CTL_NIEN, REG_CTL(dev));
+
+    // 等待硬盘不BUSY
+    while (inb(REG_STATUS(dev)) & ATA_STATUS_BSY) {
+        nop();
+    }
+
+    // 选择DRIVE
+    outb(ATA_LBA48_DEVSEL(dev), REG_DEVICE(dev));
+
+    // 先写扇区数的高字节
+    outb((count >> 8) & 0xFF, REG_NSECTOR(dev));
+
+    // 接着写LBA48,高三个字节
+    outb((pos >> 24) & 0xFF, REG_LBAL(dev));
+    outb((pos >> 32) & 0xFF, REG_LBAM(dev));
+    outb((pos >> 40) & 0xFF, REG_LBAH(dev));
+
+    // 再写扇区数的低字节
+    outb((count >> 0) & 0xFF, REG_NSECTOR(dev));
+
+    // 接着写LBA48,低三个字节
+    outb((pos >> 0) & 0xFF, REG_LBAL(dev));
+    outb((pos >> 8) & 0xFF, REG_LBAM(dev));
+    outb((pos >> 16) & 0xFF, REG_LBAH(dev));
+
+    while (inb(REG_STATUS(dev)) & ATA_STATUS_RDY == 0) {
+        nop();
+    }
+
+    outb(ATA_CMD_READ_PIO_EXT, REG_CMD(dev));
+
+    while (timeout > 0) {
+        timeout--;
+
+        u8 status = inb(REG_STATUS(dev));
+        if ((status & ATA_STATUS_BSY) == 0 && (status & ATA_STATUS_DRQ) != 0) {
+            break;
+        }
+
+        asm("sti;hlt;");
+    }
+    asm("cli");
+
+    if (timeout == 0) {
+        return -1;
+    }
+
+    insl(REG_DATA(dev), dest, (SECT_SIZE * count) / sizeof(uint32_t));
+
+    return 0;
+}
+
+uint8_t ata_pci_bus_status() {
+    uint8_t st = 0;
+    st = inb(ide_pci_controller.bus_status);
+
+    outb(PCI_IDE_STATUS_INTR, ide_pci_controller.bus_status);
+
+    return st;
+}
+
+unsigned int ATA_CHL0_CMD_BASE = 0x1F0;
+unsigned int ATA_CHL1_CMD_BASE = 0x170;
+
+unsigned int ATA_CHL0_CTL_BASE = 0x3F6;
+unsigned int ATA_CHL1_CTL_BASE = 0x376;
\ No newline at end of file
index 59b2f7b3abe1e02cb4b5270d60c6a2a9265b57be..e9eaf600355f96b859d010338df911207b7a2522 100644 (file)
@@ -53,7 +53,7 @@ static void cnsl_queue_init(cnsl_queue_t *cq) {
     memset((void *)cq, 0, sizeof(*cq));
     cq->head = 0;
     cq->tail = 0;
-    init_wait_queue(&cq->wait);
+    init_wait_queue_head(&cq->wait);
 }
 
 wait_queue_head_t rdwq;
@@ -62,7 +62,7 @@ void cnsl_init() {
     cnsl_queue_init(&cnsl.rd_q);
     cnsl_queue_init(&cnsl.wr_q);
     cnsl_queue_init(&cnsl.sc_q);
-    init_wait_queue(&rdwq);
+    init_wait_queue_head(&rdwq);
 }
 
 int cnsl_kbd_write(char ch) {
@@ -85,7 +85,7 @@ int cnsl_kbd_write(char ch) {
 
     if (ch == '\n') {
         clear(&cnsl.wr_q);
-       return 0; // TODO FIX
+        return 0;  // TODO FIX
         while (get(&cnsl.sc_q, &ch)) put(&cnsl.rd_q, ch);
         wake_up(&rdwq);
     }
index b970f7039d6917e7de2899d38707c91ecef6327a..2c51213571a93098cc5b16f75c22a9a545b1bb84 100644 (file)
 // #include <assert.h>
 #include <ide.h>
 // #include <io.h>
-// #include <irq.h>
+#include <irq.h>
 
 // #include <printk.h>
 // #include <sched.h>
 // #include <semaphore.h>
 // #include <string.h>
 // #include <types.h>
-// #include <wait.h>
+#include <wait.h>
 
 // typedef struct prd {
 //     unsigned int addr;
@@ -533,9 +533,40 @@ void ide_irq() { ide_intr_func(); }
 // }
 
 void ata_read_identify(int dev);
+
+DECLARE_WAIT_QUEUE_HEAD(ide_wait_queue_head);
+
+void sleep_on_ide() { sleep_on(&ide_wait_queue_head); }
+
+extern void *mbr_buf;
+uint8_t ata_pci_bus_status();
+extern ide_pci_controller_t ide_pci_controller;
+void ide_irq_handler(unsigned int irq, pt_regs_t *regs, void *devid) {
+    printk("ide irq handler %d \n", irq);
+
+    printk("ide pci status after interrupt: %x\n", ata_pci_bus_status());
+
+#if 0
+    unsigned int v = pci_read_config_word(pci_cmd(ide_pci_controller.pci, PCI_COMMAND));
+    pci_write_config_word(v & (~PCI_COMMAND_MASTER), pci_cmd(ide_pci_controller.pci, PCI_COMMAND));
+
+    uint16_t *p = (uint16_t *)mbr_buf;
+    for (int i = 0; i < 256; i++) {
+        if (i % 12 == 0) {
+            printk("\n%03d ", i);
+        }
+        printk("%04x ", p[i]);
+    }
+#endif
+
+    wake_up(&ide_wait_queue_head);
+}
+
 void ide_init() {
     // memset((void *)&drv, 0, sizeof(drv));
 
+    request_irq(0x0E, ide_irq_handler, "hard", "IDE");
+
     // init_pci_controller(0x0106);
     init_pci_controller(0x0101);
 
index cf0976744198d164d2bf41b9f4d406cbf33aa6c9..803ff55fff18d73654bf4c9af2f0b2060731fa5b 100644 (file)
@@ -173,4 +173,6 @@ typedef struct _ide_pci_controller {
     unsigned int bus_prdt;
 
     prdte_t *prdt;
-} ide_pci_controller_t;
\ No newline at end of file
+} ide_pci_controller_t;
+
+void sleep_on_ide();
\ No newline at end of file
index a7c4325a1aab6436d1686620aee874a3392f9245..4f8244677dbc33676dc15a3801e52d62ec8a9dc2 100644 (file)
@@ -102,8 +102,10 @@ void kbd_debug(unsigned char scan_code) {
     // if (scan_code == 0x43)  // F9
     //     ide_dma_pci_lba48();
     if (scan_code == 0x44) {  // F10
-        void ata_test(uint64_t nr);
-        ata_test(0);
+        // void ata_test(uint64_t nr);
+        // ata_test(0);
+        void ata_send_read_identify_cmd(int dev);
+        ata_send_read_identify_cmd(0);
     }
 
     if (scan_code == 0x57)  // F11
index 9e0430fd3cea9dd7f1facd41e11ab0cde953d49d..2f79426084c92f76138f34983edf21d2ab20c841 100644 (file)
@@ -31,6 +31,9 @@ typedef struct {
 
 #define DECLARE_WAIT_QUEUE(name, tsk) wait_queue_t name = WAIT_QUEUE_INITIALIZER(name, tsk)
 
-void init_wait_queue(wait_queue_head_t *wqh);
+void init_wait_queue_head(wait_queue_head_t *wqh);
 void add_wait_queue(wait_queue_head_t *wqh, wait_queue_t *wq);
 void del_wait_queue(wait_queue_head_t *wqh, wait_queue_t *wq);
+
+void sleep_on(wait_queue_head_t *head);
+void wake_up(wait_queue_head_t *head);
index 54beee6415429c4d348f69de20ba19fa0abc3270..b9ed8b891e1e655a2c8173f01767446cdac3e955 100644 (file)
@@ -66,18 +66,26 @@ int request_irq(unsigned int irq, void (*handler)(unsigned int, pt_regs_t *, voi
                 void *dev_id) {
     irq_action_t *p;
 
-    if (irq >= NR_IRQS) return -EINVAL;
-    if (handler == NULL) return -EINVAL;
+    if (irq >= NR_IRQS) {
+        return -EINVAL;
+    }
+    if (handler == NULL) {
+        return -EINVAL;
+    }
 
     // 检查是否已经注册过处理函数了
     p = irq_desc[irq].action;
     while (p != NULL) {
-        if (p->handler == handler) return 0;
+        if (p->handler == handler) {
+            return 0;
+        }
         p = p->next;
     }
 
     p = (irq_action_t *)kmalloc(sizeof(irq_action_t), 0);
-    if (p == NULL) return -ENOMEM;
+    if (p == NULL) {
+        return -ENOMEM;
+    }
 
     p->dev_name = devname;
     p->dev_id = dev_id;
index 0b90a7e728c89d8fff02258f62801396cf107ab8..f5efd71ef614c411e9d58c10fc04146fda831632 100644 (file)
@@ -90,25 +90,6 @@ void setup_gate() {
 }
 
 void ide_irq();
-extern void *mbr_buf;
-uint8_t ata_pci_bus_status();
-extern ide_pci_controller_t ide_pci_controller;
-void default_ide_irq_handler(unsigned int irq, pt_regs_t *regs, void *dev_id) {
-    printk("default irq handler %d \n", irq);
-
-    printk("ide pci status after interrupt: %x", ata_pci_bus_status());
-
-    unsigned int v = pci_read_config_word(pci_cmd(ide_pci_controller.pci, PCI_COMMAND));
-    pci_write_config_word(v & (~PCI_COMMAND_MASTER), pci_cmd(ide_pci_controller.pci, PCI_COMMAND));
-
-    uint16_t *p = (uint16_t *)mbr_buf;
-    for (int i = 0; i < 256; i++) {
-        if (i % 12 == 0) {
-            printk("\n%03d ", i);
-        }
-        printk("%04x ", p[i]);
-    }
-}
 
 void default_irq_handler(unsigned int irq, pt_regs_t *regs, void *dev_id) { printk("default irq handler %d \n", irq); }
 
@@ -129,8 +110,7 @@ void setup_irqs() {
 
     request_irq(0x00, clk_handler, "Intel 8254", "Clock Chip");
     request_irq(0x01, kbd_handler, "Intel 8042", "PS/2 Keyboard");
-    request_irq(0x0A, default_ide_irq_handler, "hard", "IDE");
-    request_irq(0x0E, default_ide_irq_handler, "hard", "IDE");
+    // request_irq(0x0E, default_ide_irq_handler, "hard", "IDE");
     for (int i = 0; i < 16; i++) {
         if (i != 0 && i != 1 && i != 10 && i != 14) {
             request_irq(i, default_irq_handler, "default", "default");
@@ -149,7 +129,6 @@ void setup_irqs() {
     // 打开支持的中断
     open_irq(0x00);
     open_irq(0x01);
-    open_irq(0x0A);
     open_irq(0x0E);
 }
 void set_tss() {
index e8cb71d212f0aa469b5e152144818518e55f9aec..bcee2bb8c6fa48271fb6a214f883e557656d9af5 100644 (file)
 #include <sched.h>
 #include <wait.h>
 
-void init_wait_queue(wait_queue_head_t *wqh) { INIT_LIST_HEAD(&wqh->task_list); }
+void init_wait_queue_head(wait_queue_head_t *wqh) { INIT_LIST_HEAD(&wqh->task_list); }
 
-void add_wait_queue(wait_queue_head_t *wqh, wait_queue_t *wq) {
+void add_wait_queue(wait_queue_head_t *head, wait_queue_t *wq) {
     unsigned long flags;
     irq_save(flags);
-    list_add_tail(&wq->task_list, &wqh->task_list);
+    list_add_tail(&wq->task_list, &head->task_list);
     irq_restore(flags);
 }
 
-void del_wait_queue(wait_queue_head_t *wqh, wait_queue_t *wq) {
+void del_wait_queue(wait_queue_head_t *head, wait_queue_t *wq) {
     unsigned long flags;
     irq_save(flags);
     list_del(&wq->task_list);
     irq_restore(flags);
 }
 
-void wake_up(wait_queue_head_t *wqh) {
+void sleep_on(wait_queue_head_t *head) {
+    DECLARE_WAIT_QUEUE(wait, current);
+
+    current->state = TASK_WAIT;
+
+    unsigned long flags;
+    irq_save(flags);
+
+    list_add_tail(&wait.task_list, &head->task_list);
+
+    irq_restore(flags);
+
+    schedule();
+}
+
+void __wake_up(wait_queue_head_t *head, int nr) {
     unsigned long flags;
     wait_queue_t *p, *tmp;
     irq_save(flags);
-    list_for_each_entry_safe(p, tmp, &wqh->task_list, task_list) { p->task->state = TASK_RUNNING; }
+    list_for_each_entry_safe(p, tmp, &head->task_list, task_list) {
+        list_del(&p->task_list);
+        printk("wakeup: %s\n", p->task->name);
+        p->task->state = TASK_RUNNING;
+
+        --nr;
+        if (nr == 0) {
+            break;
+        }
+    }
     irq_restore(flags);
 
     // no schedule() here.
 }
 
+void wake_up(wait_queue_head_t *head) { __wake_up(head, 1); }
+
 #include <irq.h>
 DECLARE_WAIT_QUEUE_HEAD(debug_wq);
 unsigned int debug_global_var = 0;