--------------------------------------------------------
分区表
设备号
--------------------------------------------------------
分区表
(懒得重画了,就贴一个草稿纸吧...)
需要注意的是:
1,子扩展分区中出现的 LBA 地址是基于父"真实分区"的尾 LBA 的(你也可以将这个尾 LBA 地址看作子扩展分区的起始绝对 LBA)
2,这相当于链表!
设备号
这里应该会有人纳闷(不知道你纳闷了没有)!
- 一个硬盘(设备)有 4 个大分区,但是有 5 个主分区
- 硬盘的主设备号为 3 ,可以用它来定位硬盘对应的驱动程序号
- 第一个硬盘的驱动号必须是 0
- 一个大分区内会划分 16 个逻辑分区(不管最终会不会划分,但是逻辑上你要认为是划分的)
- 扩展分区算一个大分区
- 可以根据次设备号求出驱动器号,也可以根据次设备号求出此 sub 分区在哪个大分区
- 第一个 sub 分区号是 16 (必须大于 9 )
- 我们的文件系统写在第二个大分区的第一个 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);
}
——上面就是具体遍历磁盘分区表的两个算法!
运行:
欧克...