//硬盘数据结构初始化 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"); }
/* 扫描硬盘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); }
/* 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; }