--------------------------------------------------------
操作硬盘
--------------------------------------------------------
上节我们已经建立起了 PIC 框架,这节我们的实现其实很简单:FS 发个消息请求服务,task_hd 处理服务!当然这是站在 PIC 的机制来说,本节的内容是尝试对硬盘端口的操作!
·task_fs 函数
PUBLIC void task_fs()
{
printl("Task FS begins.\n");
/* open the device: hard disk */
MESSAGE driver_msg;
driver_msg.type = DEV_OPEN;
send_recv(BOTH, TASK_HD, &driver_msg);
spin("FS");
}
——task_fs 一开始运行就给 task_hd 发送一个类型为 DEV_OPEN 的服务请求!
·task_hd 函数
PUBLIC void task_hd()
{
MESSAGE msg;
init_hd();
while (1)
{
send_recv(RECEIVE, ANY, &msg);
int src = msg.source;
switch (msg.type)
{
case DEV_OPEN:
hd_identify(0);
break;
default:
dump_msg("HD driver::unknown msg", &msg);
spin("FS::main_loop (invalid msg.type)");
break;
}
// 请求服务的进程在等待 HD 处理完服务的通知
send_recv(SEND, src, &msg);
}
}
——task_hd 作为一个“服务器”而存在,负责“接受请求——启动服务——通知服务结束”
·init_hd 函数
PRIVATE void init_hd()
{
// 从 BIOS 指定的 0x475 处获得硬盘数量!
u8 *pNrDrives = (u8 *)(0x475);
printl("NrDrives:%d.\n", *pNrDrives);
assert(*pNrDrives);
// 打开 8259A 从片的硬盘中断并且打开主片的级联中断!
put_irq_handler(AT_WINI_IRQ, hd_handler);
enable_irq(CASCADE_IRQ);
enable_irq(AT_WINI_IRQ);
}
——1,从 BIOS 固定位置获取硬盘数量 2,设置硬盘的中断处理函数 3,打开主片的 2 号级联中断、打开从片的 14 号硬件中断!
·hd_identify 函数
PRIVATE void hd_identify(int drive)
{
// 构造命令数据结构!
struct hd_cmd cmd;
cmd.device = MAKE_DEVICE_REG(0, drive, 0);
cmd.command = ATA_IDENTIFY;
// 发送命令
hd_cmd_out(&cmd);
// 因请求中断消息而睡眠!
interrupt_wait();
port_read(REG_DATA, hdbuf, SECTOR_SIZE);
print_identify_info((u16 *)hdbuf);
}
——给硬盘发命令——睡眠等待硬盘准备好数据之后中断唤醒自己(被唤醒之后从硬盘端口读数据然后显示其中的一些信息)
·hd_cmd_out 函数
PRIVATE void hd_cmd_out(struct hd_cmd *cmd)
{
// 等待 STATUS_BSY 位为 0 才可以写
if (!waitfor(STATUS_BSY, 0, HD_TIMEOUT))
panic("hd error.");
// 打开硬盘的中断功能,因为硬盘准备好数据之后要通过中断通知的!
out_byte(REG_DEV_CTRL, 0);
// 向硬盘写命令
out_byte(REG_FEATURES, cmd->features);
out_byte(REG_NSECTOR, cmd->count);
out_byte(REG_LBA_LOW, cmd->lba_low);
out_byte(REG_LBA_MID, cmd->lba_mid);
out_byte(REG_LBA_HIGH, cmd->lba_high);
out_byte(REG_DEVICE, cmd->device);
out_byte(REG_CMD, cmd->command);
}
——1,等待 STATUS 寄存器 BSY 位为 0! 2,使能硬盘中断 3,写命令
·interrupt_wait 函数
PRIVATE void interrupt_wait()
{
MESSAGE msg;
// 这里发起了等待 INTERRUPT 的请求,但是在检验的时候发现 p->has_int_msg == 0,
// 说明还没有中断消息让此进程可以接收,所以就会阻塞!
// 中断唤醒采取什么样的策略在 inform_int 中!
send_recv(RECEIVE, INTERRUPT, &msg);
}
——以请求 INTERRUPT 而睡眠!
·waitfor 函数
PRIVATE int waitfor(int mask, int val, int timeout)
{
int t = get_ticks();
while (((get_ticks() - t) * 1000 / HZ) < timeout)
if ((in_byte(REG_STATUS) & mask) == val)
return 1;
return 0;
}
·hd_handler 函数
PUBLIC void hd_handler(int irq)
{
// 读 Status 寄存器恢复中断响应
hd_status = in_byte(REG_STATUS);
// 唤醒驱动程序数据已经准备好!
inform_int(TASK_HD);
}
·inform_int 函数
PUBLIC void inform_int(int task_nr)
{
struct proc *p = proc_table + task_nr;
if ((p->p_flags & RECEIVING) && /* dest is waiting for the msg */
((p->p_recvfrom == INTERRUPT) || (p->p_recvfrom == ANY)))
{
p->p_msg->source = INTERRUPT;
p->p_msg->type = HARD_INT;
p->p_msg = 0;
p->has_int_msg = 0;
p->p_flags &= ~RECEIVING; /* dest has received the msg */
p->p_recvfrom = NO_TASK;
assert(p->p_flags == 0);
unblock(p);
assert(p->p_flags == 0);
assert(p->p_msg == 0);
assert(p->p_recvfrom == NO_TASK);
assert(p->p_sendto == NO_TASK);
}
else
p->has_int_msg = 1;
}
——如果 task_hd 在等,那么唤醒它,如果 task_hd 没有在等,那么给它留言!
运行:
OK,我们取 0 磁头、0 柱面、0 号扇区的数据,然后挑其中的几个数值进行了打印!