冬天OS(二十六):完善硬盘的驱动程序

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

完善硬盘驱动程序

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

上节我们的驱动程序只有一个简单的 identify 功能(基于的是 CHS 寻址),这节我们完善驱动程序,并且基于 LBA 寻址!

 

·枚举
#define CNT u.m3.m3i2
#define REQUEST u.m3.m3i2
#define PROC_NR u.m3.m3i3
#define DEVICE u.m3.m3i4
#define POSITION u.m3.m3l1
#define BUF u.m3.m3p2

 —— POSITION 和 REQUEST 不同时使用!

 

· hd_ioctl 函数
PRIVATE void hd_ioctl(MESSAGE *p)
{
	int device = p->DEVICE;
	int drive = DRV_OF_DEV(device);

	struct hd_info *hdi = &hd_info[drive];

	if (p->REQUEST == DIOCTL_GET_GEO)
	{
		void *dst = va2la(p->PROC_NR, p->BUF);
		void *src = va2la(TASK_HD,
						  device < MAX_PRIM ? &hdi->primary[device] : &hdi->logical[(device - MINOR_hd1a) % NR_SUB_PER_DRIVE]);

		phys_copy(dst, src, sizeof(struct part_info));
	}
	else
		assert(0);
}

——当请求者发送 p->type 等于 DEV_IOCTL 的时候,还要在 DEV_IOCTL 服务里进一步指明具体的服务(由 p->REQUEST 指明)!

 

·hd_rdwt
PRIVATE void hd_rdwt(MESSAGE *p)
{
	int drive = DRV_OF_DEV(p->DEVICE);

	u64 pos = p->POSITION;
	assert((pos >> SECTOR_SIZE_SHIFT) < (1 << 31));

	/**
	 * We only allow to R/W from a SECTOR boundary:
	 */
	assert((pos & 0x1FF) == 0);

	// p->POSITION 求得扇区号
	u32 sect_nr = (u32)(pos >> SECTOR_SIZE_SHIFT); /* pos / SECTOR_SIZE */
	// 第几个逻辑扇区,这里是第 16 个
	int logidx = (p->DEVICE - MINOR_hd1a) % NR_SUB_PER_DRIVE;
	// 根据请求的扇区位于哪一个分区,加等于这个分区的起始 LBA
	sect_nr += p->DEVICE < MAX_PRIM ? hd_info[drive].primary[p->DEVICE].base : hd_info[drive].logical[logidx].base;

	struct hd_cmd cmd;
	cmd.features = 0;
	// 读取几个扇区
	cmd.count = (p->CNT + SECTOR_SIZE - 1) / SECTOR_SIZE;
	cmd.lba_low = sect_nr & 0xFF;
	cmd.lba_mid = (sect_nr >> 8) & 0xFF;
	cmd.lba_high = (sect_nr >> 16) & 0xFF;
	cmd.device = MAKE_DEVICE_REG(1, drive, (sect_nr >> 24) & 0xF);
	// 读/写 的行为在这里决定
	cmd.command = (p->type == DEV_READ) ? ATA_READ : ATA_WRITE;
	hd_cmd_out(&cmd);

	int bytes_left = p->CNT;
	// 请求者的缓冲区
	void *la = (void *)va2la(p->PROC_NR, p->BUF);

	while (bytes_left)
	{
		int bytes = min(SECTOR_SIZE, bytes_left);
		if (p->type == DEV_READ)
		{
			interrupt_wait();
			port_read(REG_DATA, hdbuf, SECTOR_SIZE);
			// 这里 p->BUF 的地址是相对于请求者的段基址的,所以需要求出物理地址
			// 但 hdbuf 并不需要!还有,这里可以直接读到 la 中,不需要额外拷贝!
			phys_copy(la, (void *)va2la(TASK_HD, hdbuf), bytes);
		}
		else
		{
			if (!waitfor(STATUS_DRQ, STATUS_DRQ, HD_TIMEOUT))
				panic("hd writing error.");

			port_write(REG_DATA, la, bytes);
			interrupt_wait();
		}
		bytes_left -= SECTOR_SIZE;
		la += SECTOR_SIZE;
	}
}

1,读和写都是 512 字节对齐的
2,因为满足 512 字节对齐的原因,所以在索取的时候和索取到了使用之前都要做处理!
 

·hd_close 函数
PRIVATE void hd_close(int device)
{
	int drive = DRV_OF_DEV(device);
	assert(drive == 0); /* only one drive */

	hd_info[drive].open_cnt--;
}

 

·task_fs 函数
PUBLIC void task_fs()
{
	printl("Task FS begins.\n");

	/* open the device: hard disk */
	MESSAGE driver_msg;
	driver_msg.type = DEV_OPEN;
	driver_msg.DEVICE = MINOR(ROOT_DEV);
	assert(dd_map[MAJOR(ROOT_DEV)].driver_nr != INVALID_DRIVER);
	send_recv(BOTH, dd_map[MAJOR(ROOT_DEV)].driver_nr, &driver_msg);

	struct part_info _tempBuf;
	driver_msg.type = DEV_IOCTL;
	driver_msg.DEVICE = MINOR(ROOT_DEV);
	driver_msg.REQUEST = DIOCTL_GET_GEO;
	driver_msg.BUF = (void *)&_tempBuf;
	send_recv(BOTH, dd_map[MAJOR(ROOT_DEV)].driver_nr, &driver_msg);
	printf("Tinix's partition's Base address is [ 0X%d ]\n",_tempBuf.base);
	printf("Tinix's partition's Size is [ 0x%d ]\n",_tempBuf.size);
	spin("FS");
}

运行:

——有了 read/write 之后我们的驱动程序就算可以用了,详细驱动程序的建立过程,可以体会到微内核的魅力!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

sssnial-jz

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

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

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

打赏作者

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

抵扣说明:

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

余额充值