冬天OS(二十四):操作硬盘

--------------------------------------------------------

操作硬盘

--------------------------------------------------------

上节我们已经建立起了 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 号扇区的数据,然后挑其中的几个数值进行了打印!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

sssnial-jz

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值