冬天OS(二十五):分区表和设备号

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

分区表

设备号

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

 

分区表

 (懒得重画了,就贴一个草稿纸吧...)


需要注意的是:
1,子扩展分区中出现的 LBA 地址是基于父"真实分区"的尾 LBA 的(你也可以将这个尾 LBA 地址看作子扩展分区的起始绝对 LBA)
2,这相当于链表!
 

设备号
这里应该会有人纳闷(不知道你纳闷了没有)!

  1. 一个硬盘(设备)有 4 个大分区,但是有 5 个主分区
  2. 硬盘的主设备号为 3 ,可以用它来定位硬盘对应的驱动程序号
  3. 第一个硬盘的驱动号必须是 0 
  4. 一个大分区内会划分 16 个逻辑分区(不管最终会不会划分,但是逻辑上你要认为是划分的)
  5. 扩展分区算一个大分区
  6. 可以根据次设备号求出驱动器号,也可以根据次设备号求出此 sub 分区在哪个大分区
  7. 第一个 sub 分区号是 16 (必须大于 9 )
  8. 我们的文件系统写在第二个大分区的第一个 sub 分区,所以其次设备号为 16(orign sub number) + 16 == 32

——看看,注意的还真不少呢...
 

程序
我们从磁盘读出的 512 字节的数据既可以用来打印磁盘的整体信息,也可以通过从由 0x1BE 开始的两个分区表项通过链表的方式获取所有的分区表信息(分区对应的 LBA 基址,分区大小)
 

·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);

	spin("FS");
}

1,driver_msg.DEVICE 是个次设备号,因为 task_hd 中要求出驱动器号,所以需要次设备号!
2,选择发送给哪个驱动程序不是裸指定了,而是根据主设备号选择发送给哪个驱动程序!

 

·hd_open 函数
PRIVATE void hd_open(int device)
{
	// 由次设备号得到驱动器号!
	int drive = DRV_OF_DEV(device);
	assert(drive == 0); /* only one drive */

	hd_identify(drive);

	// hd_info[drive].open_cnt 第一次调用的时候为 0 !
	if (hd_info[drive].open_cnt++ == 0)
	{
		partition(drive * (NR_PART_PER_DRIVE + 1), P_PRIMARY);
		print_hdinfo(&hd_info[drive]);
	}
}

——要注意的是根据次设备号得驱动器号,这里驱动器号必须是 0 ,因为我们只有一个硬盘,然后获取磁盘第一个扇区的信息,之后通过这个扇区的信息获取分区信息!

 

·partition 函数
PRIVATE void partition(int device, int style)
{
	int i;
	// 从设备号获得驱动器号
	int drive = DRV_OF_DEV(device);

	// 获得 hd_info 结构!
	struct hd_info *hdi = &hd_info[drive];

	// struct part_ent 分区表结构体,但是只用了其中两个成员!
	struct part_ent part_tbl[NR_SUB_PER_DRIVE];

	if (style == P_PRIMARY)
	{

		get_part_table(drive, drive, part_tbl);
		int nr_prim_parts = 0;
		for (i = 0; i < NR_PART_PER_DRIVE; i++)
		{ /* 0~3 */
			if (part_tbl[i].sys_id == NO_PART)
				continue;

			nr_prim_parts++;
			int dev_nr = i + 1; /* 1~4 */
			hdi->primary[dev_nr].base = part_tbl[i].start_sect;
			hdi->primary[dev_nr].size = part_tbl[i].nr_sects;

			if (part_tbl[i].sys_id == EXT_PART) /* extended */
				partition(device + dev_nr, P_EXTENDED);
		}
		assert(nr_prim_parts != 0);
	}
	else if (style == P_EXTENDED)
	{
		int j = device % NR_PRIM_PER_DRIVE; /* 1~4 */
		int ext_start_sect = hdi->primary[j].base;
		int s = ext_start_sect;
		int nr_1st_sub = (j - 1) * NR_SUB_PER_PART; /* 0/16/32/48 */

		for (i = 0; i < NR_SUB_PER_PART; i++)
		{
			int dev_nr = nr_1st_sub + i; /* 0~15/16~31/32~47/48~63 */

			get_part_table(drive, s, part_tbl);

			hdi->logical[dev_nr].base = s + part_tbl[0].start_sect;
			hdi->logical[dev_nr].size = part_tbl[0].nr_sects;

			s = ext_start_sect + part_tbl[1].start_sect;

			/* no more logical partitions
			   in this extended partition */
			if (part_tbl[1].sys_id == NO_PART)
				break;
		}
	}
	else
	{
		assert(0);
	}
}

 

·get_part_table 函数
PRIVATE void get_part_table(int drive, int sect_nr, struct part_ent *entry)
{
	struct hd_cmd cmd;
	cmd.features = 0;
	cmd.count = 1;
	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, /* LBA mode*/
								 drive,
								 (sect_nr >> 24) & 0xF);
	cmd.command = ATA_READ;
	hd_cmd_out(&cmd);
	interrupt_wait();

	port_read(REG_DATA, hdbuf, SECTOR_SIZE);

	// 复制读到两个分区表项!
	memcpy(entry,
		   hdbuf + PARTITION_TABLE_OFFSET,
		   sizeof(struct part_ent) * NR_PART_PER_DRIVE);
}

——上面就是具体遍历磁盘分区表的两个算法!

 

运行:

欧克...

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

sssnial-jz

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

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

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

打赏作者

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

抵扣说明:

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

余额充值