From: acevest Date: Mon, 5 Jun 2023 06:01:50 +0000 (+0800) Subject: 支持IDE Primary Secondary两个通道同时读硬盘 X-Git-Url: http://zhaoyanbai.com/repos/%22http:/www.isc.org/icons/zpipe.c?a=commitdiff_plain;h=4b0cd44c24827d03aad0d894cc320afbb698b598;p=kernel.git 支持IDE Primary Secondary两个通道同时读硬盘 --- diff --git a/drivers/ata.c b/drivers/ata.c index e7422e1..30cf4d2 100644 --- a/drivers/ata.c +++ b/drivers/ata.c @@ -15,8 +15,6 @@ #include #include -extern ide_pci_controller_t ide_pci_controller[]; - ide_drive_t ide_drives[MAX_IDE_DRIVE_CNT]; #define ATA_TIMEOUT 10 // 10次时钟中断 @@ -75,15 +73,11 @@ void ata_read_identity_string(const uint16_t *identify, int bgn, int end, char * void ide_ata_init() { for (int i = 0; i < MAX_IDE_DRIVE_CNT; i++) { int drv_no = i; + int channel = drv_no >> 1; memset(ide_drives + i, 0, sizeof(ide_drive_t)); ide_drive_t *drv = ide_drives + drv_no; - - INIT_MUTEX(&drv->request_mutex); - - drv->request_queue.count = 0; - INIT_LIST_HEAD(&drv->request_queue.list); - semaphore_init(&drv->request_queue.sem, 0); + drv->ide_pci_controller = ide_pci_controller + channel; // 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 @@ -263,10 +257,10 @@ void ata_dma_read_ext(int drv, uint64_t pos, uint16_t count, void *dest) { int channel = (drv >> 1) & 0x01; assert(channel == 0 || channel == 1); - ide_pci_controller_t *pci = ide_pci_controller + channel; + ide_pci_controller_t *ide_ctrl = ide_pci_controller + channel; // 停止DMA - outb(PCI_IDE_CMD_STOP, pci->bus_cmd); + outb(PCI_IDE_CMD_STOP, ide_ctrl->bus_cmd); // 配置描述符表 unsigned long dest_paddr = va2pa(dest); @@ -276,19 +270,19 @@ void ata_dma_read_ext(int drv, uint64_t pos, uint16_t count, void *dest) { const uint32_t _64K = 1 << 16; assert(((dest_paddr + size) & _64K) == (dest_paddr & _64K)); - pci->prdt[0].phys_addr = dest_paddr; - pci->prdt[0].byte_count = size; - pci->prdt[0].reserved = 0; - pci->prdt[0].eot = 1; - outl(va2pa(pci->prdt), pci->bus_prdt); + ide_ctrl->prdt[0].phys_addr = dest_paddr; + ide_ctrl->prdt[0].byte_count = size; + ide_ctrl->prdt[0].reserved = 0; + ide_ctrl->prdt[0].eot = 1; + outl(va2pa(ide_ctrl->prdt), ide_ctrl->bus_prdt); - // printk("paddr: %x prdt: %x %x prdte %x %x\n", dest_paddr, pci->prdt, - // va2pa(pci->prdt), - // pci->prdt[0].phys_addr, *(((unsigned int *)pci->prdt) + 1)); + // printk("paddr: %x prdt: %x %x prdte %x %x\n", dest_paddr, ide_ctrl->prdt, + // va2pa(ide_ctrl->prdt), + // ide_ctrl->prdt[0].phys_addr, *(((unsigned int *)ide_ctrl->prdt) + 1)); // 清除中断位和错误位 // 这里清除的方式是是设置1后清除 - outb(PCI_IDE_STATUS_INTR | PCI_IDE_STATUS_ERR, pci->bus_status); + outb(PCI_IDE_STATUS_INTR | PCI_IDE_STATUS_ERR, ide_ctrl->bus_status); // 不再设置nIEN,DMA需要中断 outb(0x00, REG_CTL(drv)); @@ -328,26 +322,26 @@ void ata_dma_read_ext(int drv, uint64_t pos, uint16_t count, void *dest) { // 在qemu中用DMA的方式读数据就会读不到数据,而只触是发中断,然后寄存器(Bus Master IDE Status // Register)的值会一直是5 也就是INTERRUPT和和ACTIVE位是1,正常应该是4,也就是只有INTERRUPT位为1 // 在bochs中则加不加这一句不会有影响,都能正常读到数据 - unsigned int v = pci_read_config_word(pci_cmd(pci->pci, PCI_COMMAND)); + unsigned int v = pci_read_config_word(pci_cmd(ide_ctrl->pci, PCI_COMMAND)); // printk(" ide pci command %04x\n", v); - pci_write_config_word(v | PCI_COMMAND_MASTER, pci_cmd(pci->pci, PCI_COMMAND)); - // pci_write_config_word(v, pci_cmd(pci->pci, PCI_COMMAND)); + pci_write_config_word(v | PCI_COMMAND_MASTER, pci_cmd(ide_ctrl->pci, PCI_COMMAND)); + // pci_write_config_word(v, pci_cmd(ide_ctrl->pci, PCI_COMMAND)); // 指定DMA操作为读取硬盘操作,内核用DMA读取,对硬盘而言是写出 // 并设置DMA的开始位,开始DMA - outb(PCI_IDE_CMD_WRITE | PCI_IDE_CMD_START, pci->bus_cmd); + outb(PCI_IDE_CMD_WRITE | PCI_IDE_CMD_START, ide_ctrl->bus_cmd); } // TODO int ata_dma_stop(int channel) { - ide_pci_controller_t *pci = ide_pci_controller + channel; + ide_pci_controller_t *ide_ctrl = ide_pci_controller + channel; - uint8_t x = inb(pci->bus_cmd); + uint8_t x = inb(ide_ctrl->bus_cmd); x &= ~PCI_IDE_CMD_START; - outb(x, pci->bus_cmd); + outb(x, ide_ctrl->bus_cmd); - uint8_t status = inb(pci->bus_status); - outb(status | PCI_IDE_STATUS_INTR | PCI_IDE_STATUS_ERR, pci->bus_status); + uint8_t status = inb(ide_ctrl->bus_status); + outb(status | PCI_IDE_STATUS_INTR | PCI_IDE_STATUS_ERR, ide_ctrl->bus_status); // TODO if (status & PCI_IDE_STATUS_ERR) { diff --git a/drivers/ide.c b/drivers/ide.c index 837eb00..32c8fb2 100644 --- a/drivers/ide.c +++ b/drivers/ide.c @@ -35,6 +35,16 @@ void ide_pci_init(pci_device_t *pci) { unsigned int iobase = pci_read_config_long(pci_cmd(pci, PCI_BAR4)); for (int i = 0; i < NR_IDE_CONTROLLER; i++) { + INIT_MUTEX(&ide_pci_controller[i].request_mutex); + ide_pci_controller[i].request_queue.count = 0; + INIT_LIST_HEAD(&ide_pci_controller[i].request_queue.list); + semaphore_init(&ide_pci_controller[i].request_queue.sem, 0); + semaphore_init(&ide_pci_controller[i].disk_intr_sem, 0); + + ide_pci_controller[i].request_cnt = 0; + ide_pci_controller[i].irq_cnt = 0; + ide_pci_controller[i].consumed_cnt = 0; + iobase += i * 8; // secondary channel 需要加8 printd("ide pci Base IO Address Register %08x\n", iobase); iobase &= 0xFFFC; // 最低为0是内存地址为1是端口地址 @@ -103,40 +113,42 @@ void init_pci_controller(unsigned int classcode) { } } -extern semaphore_t disk_intr_sem; - extern void *mbr_buf; -extern uint32_t disk_request_cnt; -extern uint32_t disk_handled_cnt; uint8_t ata_pci_bus_status(); -volatile uint32_t disk_inter_cnt = 0; - void ata_dma_stop(int channel); void ide_irq_bh_handler(void *arg) { - disk_inter_cnt++; - int channel = (int)arg; - // printl(MPL_IDE, "disk req %u consumed %u irq %u", disk_request_cnt, disk_handled_cnt, disk_inter_cnt); - printlxy(MPL_IDE, MPO_IDE, "disk irq %u req %u consumed %u ", disk_inter_cnt, disk_request_cnt, disk_handled_cnt); + // printk("channel %08x\n", channel); + assert(channel <= 1); + assert(channel >= 0); + + ide_pci_controller_t *ide_ctrl = ide_pci_controller + channel; + // printlxy(MPL_IDE, MPO_IDE, "disk irq %u req %u consumed %u ", disk_inter_cnt, disk_request_cnt, + // disk_handled_cnt); + + printlxy(MPL_IDE0 + channel, MPO_IDE, "IDE%d req %u irq %u consumed %u", channel, ide_ctrl->request_cnt, + ide_ctrl->irq_cnt, ide_ctrl->consumed_cnt); // up里不会立即重新调度进程 - up(&disk_intr_sem); + up(&ide_ctrl->disk_intr_sem); } void ide_irq_handler(unsigned int irq, pt_regs_t *regs, void *devid) { // printk("ide irq %d handler pci status: 0x%02x\n", irq, ata_pci_bus_status()); int channel = irq == 14 ? 0 : 1; + + ide_pci_controller_t *ide_ctrl = ide_pci_controller + channel; + atomic_inc(&ide_ctrl->irq_cnt); + ata_dma_stop(channel); - add_irq_bh_handler(ide_irq_bh_handler, &channel); + add_irq_bh_handler(ide_irq_bh_handler, (void *)channel); } -void ide1_irq_handler(unsigned int irq, pt_regs_t *regs, void *devid) { panic("ide 0"); } - void ide_ata_init(); void ide_init() { memset(ide_pci_controller, 0, sizeof(ide_pci_controller[0]) * NR_IDE_CONTROLLER); diff --git a/drivers/ide.h b/drivers/ide.h index 1a63a92..148d63e 100644 --- a/drivers/ide.h +++ b/drivers/ide.h @@ -9,6 +9,7 @@ #pragma once +#include #include #include #include @@ -177,13 +178,23 @@ typedef struct _ide_pci_controller { prdte_t *prdt; - // 这里应该改成一个请求链表 - // 先简单实现 - task_union *task; - int done; + // 提出请求的任务用这个字段互斥地添加请求到request_queue + // 同时也和disk任务互斥 + semaphore_t request_mutex; + // 请求队列 + disk_request_queue_t request_queue; + + // task disk与中断函数之间的信号量 + // 初始化成0 + semaphore_t disk_intr_sem; + + atomic_t request_cnt; + atomic_t irq_cnt; + atomic_t consumed_cnt; } ide_pci_controller_t; #define NR_IDE_CONTROLLER 2 +extern ide_pci_controller_t ide_pci_controller[NR_IDE_CONTROLLER]; typedef struct _ide_drive { int present; @@ -191,9 +202,7 @@ typedef struct _ide_drive { uint64_t lba48; uint64_t max_lba; - semaphore_t request_mutex; - - disk_request_queue_t request_queue; + ide_pci_controller_t *ide_pci_controller; } ide_drive_t; #define MAX_IDE_DRIVE_CNT 4 diff --git a/drivers/keyboard.c b/drivers/keyboard.c index e26b6f5..c3451b1 100644 --- a/drivers/keyboard.c +++ b/drivers/keyboard.c @@ -77,7 +77,7 @@ extern void tty_switch_to_next(); void kbd_debug(uint8_t scan_code) { static unsigned long kbd_cnt = 0; // printl(MPL_KEYBOARD, "keyboard irq: %d scan code %02x", kbd_cnt++, scan_code); - printlxy(MPL_IRQ, MPO_KEYBOARD, "keyboard irq: %d %02x", kbd_cnt++, scan_code); + printlxy(MPL_IRQ, MPO_KEYBOARD, "KBD irq: %d %02x", kbd_cnt++, scan_code); if (scan_code == 0x01) { // Esc // reboot(); diff --git a/include/atomic.h b/include/atomic.h index 63f5168..4afeb37 100644 --- a/include/atomic.h +++ b/include/atomic.h @@ -9,6 +9,10 @@ #pragma once +#include + +typedef uint32_t atomic_t; + #define atomic_inc(x) __sync_add_and_fetch((x), 1) #define atomic_dec(x) __sync_sub_and_fetch((x), 1) #define atomic_add(x, y) __sync_add_and_fetch((x), (y)) diff --git a/include/disk.h b/include/disk.h index d542349..920fb48 100644 --- a/include/disk.h +++ b/include/disk.h @@ -39,8 +39,10 @@ typedef struct disk_request { typedef struct { uint32_t count; - semaphore_t sem; list_head_t list; + + // 供disk任务睡眠和被唤醒用 + semaphore_t sem; } disk_request_queue_t; void send_disk_request(disk_request_t *r); diff --git a/include/printk.h b/include/printk.h index 5b2908c..001d5d4 100644 --- a/include/printk.h +++ b/include/printk.h @@ -29,7 +29,8 @@ int printlo(unsigned int line, unsigned int offset, const char *fmtstr, ...); enum { MPL_TITLE, MPL_IRQ, - MPL_IDE, + MPL_IDE0, + MPL_IDE1, MPL_CURRENT, MPL_TEST, MPL_DEBUG, diff --git a/kernel/clock.c b/kernel/clock.c index 438386a..3cf9330 100644 --- a/kernel/clock.c +++ b/kernel/clock.c @@ -28,7 +28,7 @@ void clk_bh_handler(void *arg); void clk_handler(unsigned int irq, pt_regs_t *regs, void *dev_id) { // if (jiffies % 100 == 0) { // printl(MPL_CLOCK, "clock irq: %d", jiffies); - printlxy(MPL_IRQ, MPO_CLOCK, "clock irq: %d", jiffies); + printlxy(MPL_IRQ, MPO_CLOCK, "CLK irq: %d", jiffies); // } jiffies++; diff --git a/kernel/irq.c b/kernel/irq.c index b828694..ff2d265 100644 --- a/kernel/irq.c +++ b/kernel/irq.c @@ -99,7 +99,7 @@ __attribute__((regparm(1))) void irq_handler(pt_regs_t *regs) { #if 1 unsigned long esp; asm("movl %%esp, %%eax" : "=a"(esp)); - printl(MPL_CURRENT, "current %08x %s cr3 %08x reenter %d esp %08x ticks %u", current, current->name, current->cr3, + printl(MPL_CURRENT, "current %08x %-6s cr3 %08x reenter %d esp %08x ticks %u", current, current->name, current->cr3, reenter, esp, current->ticks); #endif diff --git a/kernel/setup.c b/kernel/setup.c index 8b2aa57..c8fad04 100644 --- a/kernel/setup.c +++ b/kernel/setup.c @@ -80,7 +80,7 @@ void setup_kernel() { boot_delay(DEFAULT_BOOT_DELAY_TICKS); extern tty_t *const monitor_tty; - tty_switch(monitor_tty); + // tty_switch(monitor_tty); boot_delay(DEFAULT_BOOT_DELAY_TICKS); diff --git a/kernel/task_disk.c b/kernel/task_disk.c index 741a933..d53cd8d 100644 --- a/kernel/task_disk.c +++ b/kernel/task_disk.c @@ -12,16 +12,9 @@ #include #include -// task disk与中断函数之间的信号量 -semaphore_t disk_intr_sem; - -// task disk 之间发送命令的互斥量 -DECLARE_MUTEX(disk_cmd_mutex); - -void disk_init() { semaphore_init(&disk_intr_sem, 0); } - -volatile uint32_t disk_request_cnt = 0; -volatile uint32_t disk_handled_cnt = 0; +void disk_init() { + // ... +} void send_disk_request(disk_request_t *r) { if (NULL == r) { @@ -51,55 +44,51 @@ void send_disk_request(disk_request_t *r) { panic("disk DMA read cross 64K"); } - mutex_lock(&drv->request_mutex); - disk_request_cnt++; - list_add_tail(&r->list, &drv->request_queue.list); - mutex_unlock(&drv->request_mutex); + mutex_lock(&drv->ide_pci_controller->request_mutex); + atomic_inc(&drv->ide_pci_controller->request_cnt); + list_add_tail(&r->list, &drv->ide_pci_controller->request_queue.list); + mutex_unlock(&drv->ide_pci_controller->request_mutex); // 唤醒task_disk - up(&drv->request_queue.sem); + up(&drv->ide_pci_controller->request_queue.sem); // 等待被task_disk唤醒 down(&r->sem); } -void disk_task_entry(int arg) { +void disk_task_entry(void *arg) { int r_cnt = 0; while (1) { - // 如果要改造成每个drive对应一个内核任务的话 - // 就要注意共享disk_intr_sem的问题 - // 目前只支持drv_no == 0 - int drv_no = arg; - ide_drive_t *drv = ide_drives + drv_no; - if (drv->present == 0) { - panic("disk not present"); - } + int channel = (int)arg; + ide_pci_controller_t *ide_ctrl = ide_pci_controller + channel; // 为了在DEBUG时看到RUNNING - for (int i = 0; i < 3; i++) { + for (int i = 0; i < 1; i++) { asm("hlt;"); } // printk("wait request for hard disk %d\n", drv_no); - down(&drv->request_queue.sem); + down(&ide_ctrl->request_queue.sem); // printk("hard disk %d\n", drv_no); - mutex_lock(&drv->request_mutex); + mutex_lock(&ide_ctrl->request_mutex); disk_request_t *r; - r = list_first_entry(&drv->request_queue.list, disk_request_t, list); + r = list_first_entry(&ide_ctrl->request_queue.list, disk_request_t, list); if (NULL == r) { panic("no disk request"); } list_del(&r->list); - disk_handled_cnt++; - mutex_unlock(&drv->request_mutex); - - // 目前这个disk_cmd_mutex是用于两个通道四个DRIVE之间互斥 - // 目前还不确定两个通道之间能否同时执行 - // 后续要把disk分成两个进程,分别负责channel 0 1 - // 这里再视情况改写 - mutex_lock(&disk_cmd_mutex); + atomic_inc(&ide_ctrl->consumed_cnt); + mutex_unlock(&ide_ctrl->request_mutex); + + // TODO dev -> drv + int drv_no = r->dev; + ide_drive_t *drv = ide_drives + drv_no; + if (drv->present == 0) { + panic("disk not present"); + } + switch (r->command) { case DISK_REQ_IDENTIFY: assert(r->count == 1); @@ -117,8 +106,8 @@ void disk_task_entry(int arg) { } // 等待硬盘中断 - down(&disk_intr_sem); - mutex_unlock(&disk_cmd_mutex); + down(&ide_ctrl->disk_intr_sem); + // 读数据 if (DISK_REQ_IDENTIFY == r->command) { void ata_read_data(int drv_no, int sect_cnt, void *dst); diff --git a/kernel/task_root.c b/kernel/task_root.c index cece740..6028d41 100644 --- a/kernel/task_root.c +++ b/kernel/task_root.c @@ -97,7 +97,7 @@ u16 disk_buf1[256]; u16 disk_buf2[256]; void taskA_entry() { - current->priority = 9; + current->priority = 7; while (1) { sysc_wait(7); @@ -122,10 +122,10 @@ void taskA_entry() { } void taskB_entry() { - current->priority = 9; + current->priority = 13; while (1) { - sysc_wait(10); + sysc_wait(7); uint64_t sect_nr = get_next_deubug_sect_nr(); memset(disk_buf2, 0, 512); @@ -136,7 +136,7 @@ void taskB_entry() { r.count = 1; r.buf = disk_buf2; send_disk_request(&r); - // verify_hd_data(sect_nr, disk_buf2, current->name); + verify_hd_data(sect_nr, disk_buf2, current->name); for (int i = 0; i < 1; i++) { asm("hlt;"); @@ -171,8 +171,8 @@ void root_task_entry() { disk_init(); kernel_task("init", init_task_entry, NULL); - kernel_task("disk/0", disk_task_entry, (void *)0); - kernel_task("disk/2", disk_task_entry, (void *)2); + kernel_task("ide/0", disk_task_entry, (void *)0); + kernel_task("ide/1", disk_task_entry, (void *)1); kernel_task("user", user_task_entry, NULL); // for (int i = 0; i < 100; i++) {