Example #1
0
File: ide.c Project: YMChenLiye/os
//硬盘数据结构初始化
void ide_init(){
	printk("ide_init start\n");
	uint8_t hd_cnt = *((uint8_t*)(0x475));			//获取硬盘的数量
	ASSERT(hd_cnt > 0);
	list_init(&partition_list);
	channel_cnt = DIV_ROUND_UP(hd_cnt,2);			//一个ide通道上有两个硬盘,根据硬盘数量反推有几个ide通道
	struct ide_channel* channel;
	uint8_t channel_no = 0,dev_no = 0;

	//处理每个通道上的硬盘
	while(channel_no < channel_cnt){
		channel = &channels[channel_no];
		sprintf(channel->name,"ide%d",channel_no);

		//为每个ide通道初始化端口基址及中断向量
		switch(channel_no){
			case 0:
				channel->port_base = 0x1f0;			//ide0通道的起始端口号为0x1f0
				channel->irq_no = 0x20 + 14;		//从片8259a上倒数第二的中断引脚,也就是ide0通道的中断向量号
				break;
			case 1:
				channel->port_base = 0x170;			//ide1通道的起始端口号为0x170
				channel->irq_no = 0x20 + 15;		//从片8259a上最后一个引脚,我们用来响应ide1通道上的硬盘中断
				break;
		}

		channel->expecting_intr = false;			//为向硬盘写入指令时不期待硬盘的中断
		lock_init(&channel->lock);

		//初始化为0,目的是向硬盘控制器请求数据后,硬盘驱动sema_down此信号量会阻塞线程
		//直到硬盘完成后通过发中断,以后中断处理程序将此信号量sema_up,唤醒线程
		sema_init(&channel->disk_done,0);

		register_handler(channel->irq_no,intr_hd_handler);
		/* 分别获取两个硬盘的参数及分区信息 */
		while (dev_no < 2) {
			struct disk* hd = &channel->devices[dev_no];
			hd->my_channel = channel;
			hd->dev_no = dev_no;
			sprintf(hd->name, "sd%c", 'a' + channel_no * 2 + dev_no);
			identify_disk(hd);	 // 获取硬盘参数
			if (dev_no != 0) {	 // 内核本身的裸硬盘(hd60M.img)不处理
				partition_scan(hd, 0);  // 扫描该硬盘上的分区  
			}
			p_no = 0, l_no = 0;
			dev_no++; 
		}
		dev_no = 0;	

		channel_no++;								//下一个channel
	}

	printk("\n   all partition info\n");
	/* 打印所有分区信息 */
	list_traversal(&partition_list, partition_info, (int)NULL);
	printk("ide_init done\n");
}
Example #2
0
File: ide.c Project: YMChenLiye/os
/* 扫描硬盘hd中地址为ext_lba的扇区中的所有分区 */
static void partition_scan(struct disk* hd, uint32_t ext_lba) {
	struct boot_sector* bs = sys_malloc(sizeof(struct boot_sector));
	ide_read(hd, ext_lba, bs, 1);
	uint8_t part_idx = 0;
	struct partition_table_entry* p = bs->partition_table;

	/* 遍历分区表4个分区表项 */
	while (part_idx++ < 4) {
		if (p->fs_type == 0x5) {	 // 若为扩展分区
			if (ext_lba_base != 0) { 
				/* 子扩展分区的start_lba是相对于主引导扇区中的总扩展分区地址 */
				partition_scan(hd, p->start_lba + ext_lba_base);
			} else { // ext_lba_base为0表示是第一次读取引导块,也就是主引导记录所在的扇区
				/* 记录下扩展分区的起始lba地址,后面所有的扩展分区地址都相对于此 */
				ext_lba_base = p->start_lba;
				partition_scan(hd, p->start_lba);
			}
		} else if (p->fs_type != 0) { // 若是有效的分区类型
			if (ext_lba == 0) {	 // 此时全是主分区
				hd->prim_parts[p_no].start_lba = ext_lba + p->start_lba;
				hd->prim_parts[p_no].sec_cnt = p->sec_cnt;
				hd->prim_parts[p_no].my_disk = hd;
				list_append(&partition_list, &hd->prim_parts[p_no].part_tag);
				sprintf(hd->prim_parts[p_no].name, "%s%d", hd->name, p_no + 1);
				p_no++;
				ASSERT(p_no < 4);	    // 0,1,2,3
			} else {
				hd->logic_parts[l_no].start_lba = ext_lba + p->start_lba;
				hd->logic_parts[l_no].sec_cnt = p->sec_cnt;
				hd->logic_parts[l_no].my_disk = hd;
				list_append(&partition_list, &hd->logic_parts[l_no].part_tag);
				sprintf(hd->logic_parts[l_no].name, "%s%d", hd->name, l_no + 5);	 // 逻辑分区数字是从5开始,主分区是1~4.
				l_no++;
				if (l_no >= 8)    // 只支持8个逻辑分区,避免数组越界
					return;
			}
		} 
		p++;
	}
	sys_free(bs);
}
Example #3
0
/* load the (virtual) file system */
int init_vfs()
{
/* TODO: scan all drives */
if (drive[0].exists == 1)
	{
	/* needed for readblock to function. Should figure out this mess, maybe readblock should take these parameters? */
	ata_drsel(ATA_PRI_DATAPORT, MASTER_HD);
	partition_scan(&drive[0]);
	fat_scan(&drive[0].part[0]);
	}

return 1;
}