]> Zhao Yanbai Git Server - kernel.git/commitdiff
已经实现了在bochs上的LBA48的DMA读,但是qemu还不行,qemu能触发中断,但没读到数据
authoracevest <zhaoyanbai@126.com>
Thu, 11 Nov 2021 03:39:55 +0000 (11:39 +0800)
committeracevest <zhaoyanbai@126.com>
Thu, 11 Nov 2021 03:39:55 +0000 (11:39 +0800)
drivers/ata.c
drivers/ata.h
drivers/ide.c
drivers/ide.h
drivers/pci.c [moved from kernel/pci.c with 100% similarity]
include/io.h
include/list.h
include/pci.h
include/types.h
kernel/setup.c
kernel/system.c

index 085d7e71a18cf94769647f615d18ca8c07a9e5be..f7dfaca1109c6fdf7f2f81be3d9d2e6337be5f12 100644 (file)
@@ -6,46 +6,35 @@
  * 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;
+void ata_dma_read_ext(int dev, uint64_t pos, uint16_t count, void *);
+
+void *mbr_buf;
+
 // 本程序参考文档《AT Attachment with Packet Interface - 6》
 
-// https://wiki.osdev.org/ATA_PIO_Mode
-// 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.
-//
-// ATAPI的情况暂时不用考虑,因为不是硬盘相关的
-// https://wiki.osdev.org/ATAPI
-// ATAPI refers to devices that use the Packet Interface of the ATA6 (or higher) standard command set. It is
-// basically a way to issue SCSI commands to a CD-ROM, CD-RW, DVD, or tape drive, attached to the ATA bus.
-//
-// 总结来说,仅考虑ATA硬盘的情况
+// 仅考虑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,发送0xA0选择master,发送0xB0选择slave。(发送 0xE0 | (drive << 4)到Device寄存器)
-//  2. 发送0到该DRIVE所在通道的寄存器NSECTOR, LBAL, LBAM, LBAH
-//  3. 发送IDENTIFY(0xEC)命令到该通道的命令寄存器
+//  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
+#if 1
     outb(0x00 | ((dev & 0x01) << 4), REG_DEVICE(dev));  // 根据文档P113,这里不用指定bit5, bit7,直接指示DRIVE就行
     outb(ATA_CMD_IDENTIFY, REG_CMD(dev));
     while (1) {
@@ -73,6 +62,71 @@ void ata_read_identify(int dev) {  // 这里所用的dev是逻辑编号 ATA0、A
         u64 lba = *(u64 *)(identify + 100);
         printk("hard disk size: %u MB\n", (lba * 512) >> 20);
     }
+#endif
+    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);
+
+    mbr_buf = kmalloc(512, 0);
+    memset(mbr_buf, 0xAA, 512);
+    ata_dma_read_ext(0, 0, 1, mbr_buf);
+}
+
+// ATA_CMD_READ_DMA_EXT
+void ata_dma_read_ext(int dev, uint64_t pos, uint16_t count, void *addr) {
+    // 停止DMA BusMasterIDEStatusRegister
+    outb(0x00, ide_pci_controller.bus_iobase + 0);
+
+    // 配置描述符表
+    unsigned long *p = (unsigned long *)addr;
+    unsigned long paddr = va2pa(addr);
+    ide_pci_controller.prdt[0].phys_addr = paddr;
+    ide_pci_controller.prdt[0].byte_count = 512;
+    ide_pci_controller.prdt[0].reserved = 0;
+    ide_pci_controller.prdt[0].eot = 1;
+    printk("paddr: %x prdt: %x %x prdte %x %x\n", paddr, ide_pci_controller.prdt, va2pa(ide_pci_controller.prdt),
+           ide_pci_controller.prdt[0].phys_addr, *(((unsigned int *)ide_pci_controller.prdt) + 1));
+    outl(va2pa(ide_pci_controller.prdt), ide_pci_controller.bus_iobase + 4);
+
+    // 清除中断位和错误位
+    // 这里清除的方式是是设置1后清除
+    uint8_t t = inb(ide_pci_controller.bus_iobase + 2);
+    printk("ide pci status %x\n", t);
+    outb(t | 0x06, ide_pci_controller.bus_iobase + 2);
+
+    // 选择DRIVE
+    outb(ATA_LBA48_DEVSEL(dev), REG_DEVICE(dev));
+
+    // 不再设置nIEN,DMA需要中断
+    outb(0x00, REG_CTL(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));
+
+    outb(ATA_CMD_READ_DMA_EXT, REG_CMD(dev));
+
+    // 设置开始停止位为1,开始DMA
+    // 并且指定为读取硬盘操作
+    // DMA对硬盘而言是写出,所以设置bit 3为1
+    outb(0x09, ide_pci_controller.bus_iobase + 0);
+}
+
+uint8_t ata_pci_bus_status() {
+    uint8_t st = 0;
+    st = inb(ide_pci_controller.bus_iobase + 2);
+    return st;
 }
 
 unsigned int ATA_CHL0_CMD_BASE = 0x1F0;
index 3f9dcac3567f35de2c684c26541f6f345df11c81..7c84b7c384b0d41687bd498ded3a1faa6c5880db 100644 (file)
@@ -38,11 +38,12 @@ extern unsigned int ATA_CHL1_CTL_BASE;
 #define ATA_LBAH 5
 
 // DEVICE寄存器
-// bit7: 1
+// bit7: Obsolete
 // bit6: L 如果为1,LBA Mode
-// bit5: 1
+// bit5: Obsolete
 // bit4: DRIVE
 // bit[0, 3] HS 如果L为0就是磁头号Head Number,如果L为1,则为LBA的24-27位
+#define ATA_LBA48_DEVSEL(dev) (0x40 | ((dev & 0x01) << 4))
 #define ATA_DEVICE 6
 
 #define ATA_CMD 7
index 4bc985dcdb290082ffceb23875ae9ce28dd6774d..d7ea5a2438d7507e0bcce8e9e484c341ed59c692 100644 (file)
@@ -8,10 +8,10 @@
  */
 
 // #include <assert.h>
-// #include <ide.h>
+#include <ide.h>
 // #include <io.h>
 // #include <irq.h>
-// #include <pci.h>
+
 // #include <printk.h>
 // #include <sched.h>
 // #include <semaphore.h>
 // #include <types.h>
 // #include <wait.h>
 
-// typedef struct _ide_drv {
-//     pci_device_t *pci;
-//     unsigned long pio_cnt;
-//     unsigned long dma_cnt;
-//     unsigned long irq_cnt;
-
-//     unsigned int iobase;
-
-//     unsigned int bus_cmd;
-//     unsigned int bus_status;
-//     unsigned int bus_prdt;
-
-//     unsigned int read_mode;
-
-//     u64_t ext_lba_base;
-//     part_t part[MAX_SUPPORT_PARTITION_CNT];
-// } ide_drive_t;
-
 // typedef struct prd {
 //     unsigned int addr;
 //     unsigned int cnt : 16;
@@ -145,42 +127,52 @@ ide_intr_func_t ide_intr_func = ide_default_intr;
 
 // unsigned int sys_clock();
 
-// void ide_pci_init(pci_device_t *pci) {
-//     unsigned int v;
+ide_pci_controller_t ide_pci_controller;
 
-//     v = pci_read_config_word(pci_cmd(pci, PCI_COMMAND));
-//     printk(" ide pci command %04x\n", v);
+extern unsigned int ATA_CHL0_CMD_BASE;
+extern unsigned int ATA_CHL1_CMD_BASE;
 
-//     v = pci_read_config_byte(pci_cmd(pci, PCI_PROGIF));
-//     printk(" ide pci program interface %02x\n", v);
+extern unsigned int ATA_CHL0_CTL_BASE;
+extern unsigned int ATA_CHL1_CTL_BASE;
 
-//     unsigned int iobase = pci_read_config_long(pci_cmd(pci, PCI_BAR4));
-//     printk(" ide pci Base IO Address Register %08x\n", iobase);
-//     iobase &= 0xFFFC;  // 最低为0是内存地址为1是端口地址
-//     drv.iobase = iobase;
-//     drv.bus_cmd = iobase + PCI_IDE_CMD;
-//     drv.bus_status = iobase + PCI_IDE_STATUS;
-//     drv.bus_prdt = iobase + PCI_IDE_PRDT;
+void ide_pci_init(pci_device_t *pci) {
+    unsigned int v;
 
-//     int i;
-//     printk(" BARS: ");
-//     for (i = 0; i < BARS_CNT; ++i) {
-//         printk("%08x ", pci->bars[i]);
-//         pci->bars[i] &= (~1UL);
-//     }
-//     printk("\n");
+    v = pci_read_config_word(pci_cmd(pci, PCI_COMMAND));
+    printk(" ide pci command %04x\n", v);
 
-//     HD_CHL0_CMD_BASE = pci->bars[0] ? pci->bars[0] : HD_CHL0_CMD_BASE;
-//     HD_CHL0_CTL_BASE = pci->bars[1] ? pci->bars[1] : HD_CHL0_CTL_BASE;
+    v = pci_read_config_byte(pci_cmd(pci, PCI_PROGIF));
+    printk(" ide pci program interface %02x\n", v);
 
-//     HD_CHL1_CMD_BASE = pci->bars[2] ? pci->bars[2] : HD_CHL1_CMD_BASE;
-//     HD_CHL1_CTL_BASE = pci->bars[3] ? pci->bars[3] : HD_CHL1_CTL_BASE;
+    unsigned int iobase = pci_read_config_long(pci_cmd(pci, PCI_BAR4));
+    printk(" ide pci Base IO Address Register %08x\n", iobase);
+    iobase &= 0xFFFC;  // 最低为0是内存地址为1是端口地址
+    ide_pci_controller.bus_iobase = iobase;
+    ide_pci_controller.bus_cmd = iobase + PCI_IDE_CMD;
+    ide_pci_controller.bus_status = iobase + PCI_IDE_STATUS;
+    ide_pci_controller.bus_prdt = iobase + PCI_IDE_PRDT;
 
-//     printk("channel0: cmd %04x ctl %04x channel1: cmd %04x ctl %04x\n", HD_CHL0_CMD_BASE, HD_CHL0_CTL_BASE,
-//            HD_CHL1_CMD_BASE, HD_CHL1_CTL_BASE);
-//     // printl(18, "channel0: cmd %04x ctl %04x channel1: cmd %04x ctl %04x", HD_CHL0_CMD_BASE, HD_CHL0_CTL_BASE,
-//     // HD_CHL1_CMD_BASE, HD_CHL1_CTL_BASE);
-// }
+    ide_pci_controller.prdt = (prdte_t *)alloc_one_page(0);
+
+    int i;
+    printk(" BARS: ");
+    for (i = 0; i < BARS_CNT; ++i) {
+        printk("%08x ", pci->bars[i]);
+        pci->bars[i] &= (~1UL);
+    }
+    printk("\n");
+
+    ATA_CHL0_CMD_BASE = pci->bars[0] ? pci->bars[0] : ATA_CHL0_CMD_BASE;
+    ATA_CHL0_CTL_BASE = pci->bars[1] ? pci->bars[1] : ATA_CHL0_CTL_BASE;
+
+    ATA_CHL1_CMD_BASE = pci->bars[2] ? pci->bars[2] : ATA_CHL1_CMD_BASE;
+    ATA_CHL1_CTL_BASE = pci->bars[3] ? pci->bars[3] : ATA_CHL1_CTL_BASE;
+
+    printk("channel0: cmd %04x ctl %04x channel1: cmd %04x ctl %04x\n", ATA_CHL0_CMD_BASE, ATA_CHL0_CTL_BASE,
+           ATA_CHL1_CMD_BASE, ATA_CHL1_CTL_BASE);
+    // printl(18, "channel0: cmd %04x ctl %04x channel1: cmd %04x ctl %04x", HD_CHL0_CMD_BASE, HD_CHL0_CTL_BASE,
+    // HD_CHL1_CMD_BASE, HD_CHL1_CTL_BASE);
+}
 
 // void ide_status() {
 //     u8_t idest = inb(REG_STATUS(0));
@@ -201,18 +193,18 @@ ide_intr_func_t ide_intr_func = ide_default_intr;
 //     kfree(buf);
 // }
 
-// void init_pci_controller(unsigned int classcode) {
-//     pci_device_t *pci = pci_find_device_by_classcode(classcode);
-//     if (pci != 0 && pci->intr_line < 16) {
-//         printk("found pci vendor %04x device %04x class %04x intr %d\n", pci->vendor, pci->device, pci->classcode,
-//                pci->intr_line);
-//         // printl(17, "found pci vendor %04x device %04x class %04x intr %d", pci->vendor, pci->device,
-//         pci->classcode,
-//         // pci->intr_line);
-//         ide_pci_init(pci);
-//         drv.pci = pci;
-//     }
-// }
+void init_pci_controller(unsigned int classcode) {
+    pci_device_t *pci = pci_find_device_by_classcode(classcode);
+    if (pci != 0 && pci->intr_line < 16) {
+        printk("found pci vendor %04x device %04x class %04x intr %d\n", pci->vendor, pci->device, pci->classcode,
+               pci->intr_line);
+        // printl(17, "found pci vendor %04x device %04x class %04x intr %d", pci->vendor, pci->device,
+        // pci->classcode,
+        // pci->intr_line);
+        ide_pci_init(pci);
+        ide_pci_controller.pci = pci;
+    }
+}
 void ide_default_intr() {}
 // void ide_default_intr() {
 //     // printd("%s\n", __func__);
@@ -545,7 +537,7 @@ void ide_init() {
     // memset((void *)&drv, 0, sizeof(drv));
 
     // init_pci_controller(0x0106);
-    // init_pci_controller(0x0101);
+    init_pci_controller(0x0101);
 
     // ide_detect();
     // return;
index 66b4e4e6f8228668dfaa9c5b99711171db9b7e7d..7c98511b689cb06848569ab12ad862af3d943eb4 100644 (file)
@@ -9,7 +9,8 @@
 
 #pragma once
 
-// #include <system.h>
+#include <pci.h>
+#include <system.h>
 
 // extern unsigned int HD_CHL0_CMD_BASE;
 // extern unsigned int HD_CHL1_CMD_BASE;
 // #define ATA_IDENT_COMMANDSETS 164
 // #define ATA_IDENT_MAX_LBA_EXT 200
 
-// #define PCI_IDE_CMD 0
-// #define PCI_IDE_CMD_STOP 0x00
-// #define PCI_IDE_CMD_READ 0x00
-// #define PCI_IDE_CMD_START 0x01
-// #define PCI_IDE_CMD_WRITE 0x08
-// #define PCI_IDE_STATUS 2
-// #define PCI_IDE_STATUS_ACT 0x01
-// #define PCI_IDE_STATUS_ERR 0x02
-// #define PCI_IDE_STATUS_INTR 0x04
-// #define PCI_IDE_STATUS_DRV0 0x20
-// #define PCI_IDE_STATUS_DRV1 0x40
-// #define PCI_IDE_STATUS_SIMPLEX 0x80
-// #define PCI_IDE_PRDT 4
+#define PCI_IDE_CMD 0
+#define PCI_IDE_CMD_STOP 0x00
+#define PCI_IDE_CMD_READ 0x00
+#define PCI_IDE_CMD_START 0x01
+#define PCI_IDE_CMD_WRITE 0x08
+#define PCI_IDE_STATUS 2
+#define PCI_IDE_STATUS_ACT 0x01
+#define PCI_IDE_STATUS_ERR 0x02
+#define PCI_IDE_STATUS_INTR 0x04
+#define PCI_IDE_STATUS_DRV0 0x20
+#define PCI_IDE_STATUS_DRV1 0x40
+#define PCI_IDE_STATUS_SIMPLEX 0x80
+#define PCI_IDE_PRDT 4
 
 // #define PARTITION_CNT 4
 // #define PARTITION_TABLE_OFFSET 0x1BE
 
 // void ide_do_read(u64_t lba, u32_t scnt, char *buf);
 // part_t *ide_get_part(dev_t dev);
+
+// Physical Region Descriptor
+typedef struct prdte {
+    uint32_t phys_addr;
+    uint32_t byte_count : 16;
+    uint32_t reserved : 15;
+    uint32_t eot : 1;
+} prdte_t;
+typedef struct _ide_pci_controller {
+    pci_device_t *pci;
+
+    unsigned int bus_iobase;
+    unsigned int bus_cmd;
+    unsigned int bus_status;
+    unsigned int bus_prdt;
+
+    prdte_t *prdt;
+} ide_pci_controller_t;
\ No newline at end of file
similarity index 100%
rename from kernel/pci.c
rename to drivers/pci.c
index 9566a24e3edc9167047f912d4c0521685a1624d1..c4c81fc16f32bdee990d8e6333f68ff0fa9b3a27 100644 (file)
         _bt;                                           \
     })
 
-#define outb(value, port) ({ __asm__("outb %%al,%%dx" : : "a"(value), "d"(port)); })
+#define outb(value, port) ({ __asm__("outb %%al,%%dx" : : "a"((uint8_t)(value)), "d"(port)); })
 
-#define outw(value, port) ({ __asm__("outw %%ax,%%dx" : : "a"(value), "d"(port)); })
-#define outl(value, port) ({ __asm__("outl %%eax,%%dx" : : "a"(value), "d"(port)); })
+#define outw(value, port) ({ __asm__("outw %%ax,%%dx" : : "a"((uint16_t)(value)), "d"(port)); })
+#define outl(value, port) ({ __asm__("outl %%eax,%%dx" : : "a"((uint32_t)(value)), "d"(port)); })
 
 #define outb_p(value, port) ({ __asm__("outb %%al,%%dx;nop;nop;nop;nop" : : "a"(value), "d"(port)); })
 
index 9ab99fb0bac0ce8ed323844c071637b5338898f3..475e7f38cbd0fd15414ec5cd4ec72df2de6a1999 100644 (file)
@@ -64,11 +64,7 @@ static inline void _list_del(list_head_t *prev, list_head_t *next) {
     prev->next = next;
 }
 
-static inline void list_del(list_head_t *entry) {
-    _list_del(entry->prev, entry->next);
-    entry->prev = NULL;
-    entry->next = NULL;
-}
+static inline void list_del(list_head_t *entry) { _list_del(entry->prev, entry->next); }
 
 static inline void list_del_init(list_head_t *entry) {
     _list_del(entry->prev, entry->next);
index 17322227a0151e0acc403b36a5765405779c951d..9dd500dede3297618602ff8b3e19826377ce4ee7 100644 (file)
@@ -17,6 +17,7 @@
 #pragma once
 
 #include <list.h>
+#include <types.h>
 
 #define PCI_ADDR 0xCF8  // CONFIG_ADDRESS
 #define PCI_DATA 0xCFC  // CONFIG_DATA
index 0c9d5ec2b0fbd434ea80320993819e6f5e0f688b..769fa3c47580500c485a9d69672d37ea24c0f60a 100644 (file)
@@ -39,9 +39,13 @@ typedef signed long long s64_t;
 typedef unsigned char u8_t;
 typedef unsigned short u16_t;
 typedef unsigned long u32_t;
-typedef unsigned long u32_t;
 typedef unsigned long long u64_t;
 
+typedef unsigned char uint8_t;
+typedef unsigned short uint16_t;
+typedef unsigned long uint32_t;
+typedef unsigned long long uint64_t;
+
 typedef unsigned long pid_t;
 typedef unsigned long mode_t;
 
index 1c72a35cb9fc3b5195055148456e27aaad6df779..f8e6413d3e2d66cf1439adb5059504c99b7c35d8 100644 (file)
@@ -79,7 +79,7 @@ void setup_kernel() {
 
     system_delay();
 
-    setup_tasks();
+    // setup_tasks();
 
     setup_irqs();
 
@@ -87,7 +87,9 @@ void setup_kernel() {
 
     void ide_init();
     ide_init();
-    asm("cli;hlt;");
+    while (1) {
+        asm("sti;hlt;");
+    }
     extern tty_t monitor_tty;
     // tty_switch(&monitor_tty);
     // asm("sti");
index 0604df130e13436b110f2aadf0d9c077b2814d57..6d6a5c4e3b8394abc14ea91fd72cbd1c2ce19ef9 100644 (file)
@@ -90,9 +90,21 @@ void setup_gate() {
 }
 
 void ide_irq();
+extern void *mbr_buf;
+uint8_t ata_pci_bus_status();
+
 void default_ide_irq_handler(unsigned int irq, pt_regs_t *regs, void *dev_id) {
-    // printk("default irq handler %d \n", irq);
-    ide_irq();
+    printk("default irq handler %d \n", irq);
+
+    printk("ide pci status after interrupt: %x", ata_pci_bus_status());
+
+    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); }
@@ -122,10 +134,16 @@ void setup_irqs() {
         }
     }
 
+    // 先关闭所有中断
     for (int i = 0; i < 16; i++) {
         close_irq(i);
     }
 
+    // 清除8259A的级连中断引脚的中断屏蔽位
+    // 以让从片的中断在放开后能发送到CPU
+    open_irq(2);
+
+    // 打开支持的中断
     open_irq(0x00);
     open_irq(0x01);
     open_irq(0x0A);