From: acevest Date: Thu, 18 Nov 2021 09:13:19 +0000 (+0800) Subject: 在发送读硬盘命令前和wait的时候关中断,解决硬盘中断快于wait的问题 X-Git-Url: http://zhaoyanbai.com/repos/%22http:/www.isc.org/icons/CHANGES?a=commitdiff_plain;h=80af755037a4fb4a3aa90b75fa48273a7de7e6b5;p=kernel.git 在发送读硬盘命令前和wait的时候关中断,解决硬盘中断快于wait的问题 --- diff --git a/drivers/ata.c b/drivers/ata.c index 156c7c7..344d579 100644 --- a/drivers/ata.c +++ b/drivers/ata.c @@ -50,7 +50,7 @@ void ata_read_identify(int dev) { // 这里所用的dev是逻辑编号 ATA0、A // DECLARE_WAIT_QUEUE_HEAD(wq_head); // DECLARE_WAIT_QUEUE(wait, current); // add_wait_queue(&wq_head, &wait); - ide_pci_controller.task = current; + // ide_pci_controller.task = current; outb(0x00, REG_CTL(dev)); outb(0x00 | ((dev & 0x01) << 4), REG_DEVICE(dev)); // 根据文档P113,这里不用指定bit5, bit7,直接指示DRIVE就行 @@ -58,15 +58,11 @@ void ata_read_identify(int dev) { // 这里所用的dev是逻辑编号 ATA0、A unsigned long flags; irq_save(flags); - current->state = TASK_WAIT; outb(ATA_CMD_IDENTIFY, REG_CMD(dev)); + wait_on_ide(); irq_restore(flags); - schedule(); - - // del_wait_queue(&wq_head, &wait); - insw(REG_DATA(dev), identify, SECT_SIZE / sizeof(u16)); // 第49个word的第8个bit位表示是否支持DMA diff --git a/drivers/ide.c b/drivers/ide.c index 14e6cbe..781b28e 100644 --- a/drivers/ide.c +++ b/drivers/ide.c @@ -537,6 +537,7 @@ void ata_read_identify(int dev); DECLARE_WAIT_QUEUE_HEAD(ide_wait_queue_head); void sleep_on_ide() { sleep_on(&ide_wait_queue_head); } +void wait_on_ide() { wait_event(&ide_wait_queue_head, ide_pci_controller.done); } extern void *mbr_buf; uint8_t ata_pci_bus_status(); @@ -560,13 +561,16 @@ void ide_irq_handler(unsigned int irq, pt_regs_t *regs, void *devid) { } #endif - // wake_up(&ide_wait_queue_head); + ide_pci_controller.done = 1; - ide_pci_controller.task->state = TASK_RUNNING; + wake_up(&ide_wait_queue_head); + + // ide_pci_controller.task->state = TASK_RUNNING; } void ide_init() { // memset((void *)&drv, 0, sizeof(drv)); + memset(&ide_pci_controller, 0, sizeof(ide_pci_controller)); request_irq(0x0E, ide_irq_handler, "hard", "IDE"); diff --git a/drivers/ide.h b/drivers/ide.h index 62979d1..46df6c0 100644 --- a/drivers/ide.h +++ b/drivers/ide.h @@ -178,6 +178,8 @@ typedef struct _ide_pci_controller { // 这里应该改成一个请求链表 // 先简单实现 task_union *task; + int done; } ide_pci_controller_t; -void sleep_on_ide(); \ No newline at end of file +void sleep_on_ide(); +void wait_on_ide(); \ No newline at end of file diff --git a/include/wait.h b/include/wait.h index 7fe371a..616634e 100644 --- a/include/wait.h +++ b/include/wait.h @@ -40,17 +40,18 @@ void __end_wait(wait_queue_head_t *head, wait_queue_t *wq); void sleep_on(wait_queue_head_t *head); void wake_up(wait_queue_head_t *head); -#define __wait_event(head, condition) \ - do { \ - DECLARE_WAIT_QUEUE(__wait, current); \ - while (1) { \ - __do_wait(head, wa, TASK_WAIT); \ - if ((condition)) { \ - break; \ - } \ - schedule(); \ - } \ - __end_wait(head, &__wait); \ +unsigned long schedule(); +#define __wait_event(head, condition) \ + do { \ + DECLARE_WAIT_QUEUE(__wait, current); \ + while (1) { \ + __do_wait(head, &__wait, TASK_WAIT); \ + if ((condition)) { \ + break; \ + } \ + schedule(); \ + } \ + __end_wait(head, &__wait); \ } while (0) #define wait_event(head, condition) \ diff --git a/kernel/task_disk.c b/kernel/task_disk.c index 5ba8cbb..02ca8cb 100644 --- a/kernel/task_disk.c +++ b/kernel/task_disk.c @@ -8,11 +8,61 @@ */ #include +#include +#if 0 + +typedef enum { + DISK_REQ_IDENTIFY, + DISK_REQ_READ, +} disk_request_cmd_t; + +typedef struct disk_request { + uint64_t pos; // 扇区号 + uint16_t count; // 扇区数 + void *buf; // 到的缓冲区 + disk_request_cmd_t command; // 命令 + wait_queue_head_t wait; // 等待队列 + // 驱动器完全有可能在进程在进程睡眠到等待队列前返回数据并执行唤醒操作 + // 这时等待队列上无进程,就相当于不执行任何操作 + // 然后进程再睡眠到等待队列上,就会造成永远无法唤醒该进程 + // 因此要添加一个字段,标志驱动器已经对该请求做过唤醒操作 + // 进程在睡眠前需要检查该字段 + int done; +} disk_request_t; + +void send_disk_request() { + disk_request_t r; + r.pos = 0; + r.count = 1; + r.buf = kmalloc(512, 0); + r.command = DISK_REQ_IDENTIFY; + INIT_LIST_HEAD(&r.wait.task_list); + r.done = 0; + + list_add_tail(&wq->task_list, &head->task_list); + + // 发送命令 + //.... + + unsigned long flags; + irq_save(flags); + if (0 == r.done) { // 驱动器还没完成 + set_current_state(TASK_WAIT); + irq_restore(flags); + // 就算在schedule前驱动器触发中断也没有问题 + // 因为该进程已经加到等待队列上了 + // 所以它一定以唤醒该进程 + schedule(); + } else { // 驱动器已经完成 + irq_restore(flags); + } +} +#endif void disk_task_entry() { while (1) { - // TODO - asm("hlt;"); - //schedule(); + // TODO + asm("hlt;"); + // schedule(); } }