From: acevest Date: Thu, 11 Nov 2021 03:39:55 +0000 (+0800) Subject: 已经实现了在bochs上的LBA48的DMA读,但是qemu还不行,qemu能触发中断,但没读到数据 X-Git-Url: http://zhaoyanbai.com/repos/rndc.html?a=commitdiff_plain;h=5eb8ffec98f6576329561b44a494c489c2748269;p=kernel.git 已经实现了在bochs上的LBA48的DMA读,但是qemu还不行,qemu能触发中断,但没读到数据 --- diff --git a/drivers/ata.c b/drivers/ata.c index 085d7e7..f7dfaca 100644 --- a/drivers/ata.c +++ b/drivers/ata.c @@ -6,46 +6,35 @@ * Description: none * ------------------------------------------------------------------------ */ - #include +#include #include +#include #include #include +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; diff --git a/drivers/ata.h b/drivers/ata.h index 3f9dcac..7c84b7c 100644 --- a/drivers/ata.h +++ b/drivers/ata.h @@ -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 diff --git a/drivers/ide.c b/drivers/ide.c index 4bc985d..d7ea5a2 100644 --- a/drivers/ide.c +++ b/drivers/ide.c @@ -8,10 +8,10 @@ */ // #include -// #include +#include // #include // #include -// #include + // #include // #include // #include @@ -19,24 +19,6 @@ // #include // #include -// 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; diff --git a/drivers/ide.h b/drivers/ide.h index 66b4e4e..7c98511 100644 --- a/drivers/ide.h +++ b/drivers/ide.h @@ -9,7 +9,8 @@ #pragma once -// #include +#include +#include // extern unsigned int HD_CHL0_CMD_BASE; // extern unsigned int HD_CHL1_CMD_BASE; @@ -132,19 +133,19 @@ // #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 @@ -157,3 +158,21 @@ // 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 diff --git a/kernel/pci.c b/drivers/pci.c similarity index 100% rename from kernel/pci.c rename to drivers/pci.c diff --git a/include/io.h b/include/io.h index 9566a24..c4c81fc 100644 --- a/include/io.h +++ b/include/io.h @@ -40,10 +40,10 @@ _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)); }) diff --git a/include/list.h b/include/list.h index 9ab99fb..475e7f3 100644 --- a/include/list.h +++ b/include/list.h @@ -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); diff --git a/include/pci.h b/include/pci.h index 1732222..9dd500d 100644 --- a/include/pci.h +++ b/include/pci.h @@ -17,6 +17,7 @@ #pragma once #include +#include #define PCI_ADDR 0xCF8 // CONFIG_ADDRESS #define PCI_DATA 0xCFC // CONFIG_DATA diff --git a/include/types.h b/include/types.h index 0c9d5ec..769fa3c 100644 --- a/include/types.h +++ b/include/types.h @@ -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; diff --git a/kernel/setup.c b/kernel/setup.c index 1c72a35..f8e6413 100644 --- a/kernel/setup.c +++ b/kernel/setup.c @@ -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"); diff --git a/kernel/system.c b/kernel/system.c index 0604df1..6d6a5c4 100644 --- a/kernel/system.c +++ b/kernel/system.c @@ -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);