#include <string.h>
#include <system.h>
-extern ide_pci_controller_t ide_pci_controller[];
-
ide_drive_t ide_drives[MAX_IDE_DRIVE_CNT];
#define ATA_TIMEOUT 10 // 10次时钟中断
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
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);
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));
// 在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) {
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是端口地址
}
}
-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);
#pragma once
+#include <atomic.h>
#include <disk.h>
#include <pci.h>
#include <semaphore.h>
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;
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
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();
#pragma once
+#include <types.h>
+
+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))
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);
enum {
MPL_TITLE,
MPL_IRQ,
- MPL_IDE,
+ MPL_IDE0,
+ MPL_IDE1,
MPL_CURRENT,
MPL_TEST,
MPL_DEBUG,
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++;
#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
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);
#include <ide.h>
#include <sched.h>
-// 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) {
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);
}
// 等待硬盘中断
- 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);
u16 disk_buf2[256];
void taskA_entry() {
- current->priority = 9;
+ current->priority = 7;
while (1) {
sysc_wait(7);
}
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);
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;");
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++) {