babyos2(8)——读IDE硬盘

来源:互联网 发布:淘宝网天猫童鞋 编辑:程序博客网 时间:2024/05/17 04:23
/* * guzhoudiaoke@126.com * 2017-10-29 */#ifndef _HARDDISK_H_#define _HARDDISK_H_#include "types.h"#include "spinlock.h"#include "kernel.h"#define HD_STATE_READY  0x40#define HD_STATE_BUSY   0x80#define IO_CMD_READ     0x20#define IO_CMD_WRITE    0x30#define IO_STATE_DONE   0x01/* io control block */typedef struct io_clb_s {    uint32            flags;    uint32            read;    uint32            dev;    uint32            lba;    struct io_clb_s*  next;    uint8             buffer[SECT_SIZE];} io_clb_t;class ide_t {public:    ide_t();    ~ide_t();    void init();    void do_irq();    void wait();    void request(io_clb_t *clb);    void start(io_clb_t *clb);private:    io_clb_t*   m_head;    spinlock_t  m_lock;};#endif
void ide_t::init(){    os()->get_arch()->get_8259a()->enable_irq(IRQ_HARDDISK);    wait();    outb(0x1f6, 0xe0 | (0 << 4));}

初始化只需要开启中断,并选择dev号。

void ide_t::request(io_clb_t *clb){    m_lock.lock();    clb->next = NULL;    if (m_head == NULL) {        m_head = clb;    }    else {        io_clb_t *p = m_head;        while (p->next != NULL) {            p = p->next;        }        p->next = clb;    }    m_lock.unlock();    if (m_head == clb) {        start(clb);    }    while ((clb->flags & IO_STATE_DONE) != IO_STATE_DONE) {        os()->get_arch()->get_cpu()->sleep();    }}

当需要读取硬盘时,调用request,参数时一个io_clb_t,表示一个IO控制块。首先会把这个clb添加到链表尾部去排队处理。同时,若当前仅有这一个IO需要处理,则调用start开始处理这个IO。之后一直等待处理完成,因为读盘属于慢操作,所以调用sleep,让当前进程睡眠等待。目前sleep尚未实现,也一直还处于内核态,所以这个sleep目前啥也没做,只是个空函数。

void ide_t::start(io_clb_t *clb){    int lba = clb->lba;    wait();    outb(0x3f6, 0);     // generate interrupt    outb(0x1f2, 1);     // sector num    outb(0x1f3, lba & 0xff);    outb(0x1f4, (lba >> 8)  & 0xff);    outb(0x1f5, (lba >> 16) & 0xff);    outb(0x1f6, 0xe0 | ((clb->dev & 0x1) << 4) | ((lba >> 24) & 0xff));    if (clb->read) {        outb(0x1f7, IO_CMD_READ);    }    else {        outb(0x1f7, IO_CMD_WRITE);        outsl(0x1f0, clb->buffer, SECT_SIZE/4);    }}

start 则会根据clb中的信息,将要读取的lba通过写端口告知IDE硬盘控制器,进行读操作。此时正常情况下系统应该调度到其他进程。当读硬盘完成后,会收到中断。

void ide_t::do_irq(){    console()->kprintf(WHITE, "ide_t::do_irq()\n");    m_lock.lock();    if (m_head == NULL) {        m_lock.unlock();        return;    }    io_clb_t *clb = m_head;    m_head = clb->next;    m_lock.unlock();    insl(0x1f0, clb->buffer, SECT_SIZE/4);    clb->flags |= IO_STATE_DONE;    // wakeup()    if (m_head != NULL) {        start(m_head);    }}

中断服务程序如上所示,会将数据读到clb指定的buffer,并将flag标记设为DONE,然后唤醒等待的进程。

io_clb_t clb;void test_ide(){    return;    // only test    clb.flags = 0;    clb.read = 1;    clb.dev = 0;    clb.lba = 244;    memset(clb.buffer, 0, 512);    os()->get_ide()->request(&clb);    for (int i = 0; i < SECT_SIZE/4; i++) {        if (i % 8 == 0) {            console()->kprintf(PINK, "\n");        }        console()->kprintf(PINK, "%x ", ((uint32 *)clb.buffer)[i]);    }    console()->kprintf(PINK, "\n");}

这里写图片描述

上面是一段测试代码,及结果。

原创粉丝点击