From: acevest Date: Mon, 13 May 2024 11:00:13 +0000 (+0800) Subject: 硬盘支持PIO_EXT读取模式 X-Git-Url: http://zhaoyanbai.com/repos/?a=commitdiff_plain;h=e874c21cfa81339c72ad04f3a659499d4c044f9e;p=kernel.git 硬盘支持PIO_EXT读取模式 --- diff --git a/Makefile b/Makefile index 533d351..757778e 100644 --- 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 diff --git a/drivers/ata.c b/drivers/ata.c index a751cd9..fca0bba 100644 --- a/drivers/ata.c +++ b/drivers/ata.c @@ -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); diff --git a/drivers/ide.c b/drivers/ide.c index 091ae31..4858497 100644 --- a/drivers/ide.c +++ b/drivers/ide.c @@ -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); } diff --git a/kernel/task_disk.c b/kernel/task_disk.c index 43697e5..59bde4a 100644 --- a/kernel/task_disk.c +++ b/kernel/task_disk.c @@ -7,6 +7,7 @@ * ------------------------------------------------------------------------ */ +#include #include #include #include @@ -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) { diff --git a/kernel/task_root.c b/kernel/task_root.c index c7eeead..2447c8c 100644 --- a/kernel/task_root.c +++ b/kernel/task_root.c @@ -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;"); }