首先把我们要用的硬盘映像分好区,如下图所示:
在hd.h写一个硬盘分区表表项的结构。
include/hd.h
- /* 分区表表项的结构 */
- typedef struct s_prt_tbl_entry
- {
- u8 is_boot; /*
- 是否可以引导,可取值如下:
- 0x80可引导,0不可引导
- 其它值非法
- */
- u8 start_head; /* 起始磁头号 */
- u8 start_sec; /* 起始扇区号,仅用了低6位,高2位为起始柱面号的第8,9位 */
- u8 start_cyl; /* 起始柱面号的第8位 */
- u8 system_id; /* 分区类型 */
- u8 end_head; /* 结束磁头号 */
- u8 end_sec; /* 结束扇区号,仅用了低6位,高2位为结束柱面号的第8,9位 */
- u8 end_cyl; /* 结束柱面号的低8位 */
- u32 start_sec_lba; /* 起始扇区的LBA */
- u32 sec_num; /* 扇区数目 */
- }Prt_Tbl_Entry;
在hd.h写一个我们感兴趣的分区信息结构和一个整个硬盘所有分区信息组成的结构,并在hd.c定义一个后者的变量,因为我们当前只有一个硬盘,接在IDE0的master口。
include/hd.h
- /* 我们感兴趣的分区信息结构 */
- typedef struct s_prt_info
- {
- u32 base; /* 此分区开始的扇区数 */
- u32 sec_num; /* 此分区占有的扇区数 */
- }Prt_Info;
- /* 整个硬盘所有分区信息组成的结构 */
- typedef struct s_hd_prt_info
- {
- Prt_Info primary[5]; /* 主分区的信息 */
- Prt_Info logical[64]; /* 逻辑分区的信息 */
- }HD_Prt_Info;
kernel/hd.c
- static HD_Prt_Info hd_prt_info; /* 整个硬盘的分区信息 */
接下就在hd.c中添加相应的函数,直接上代码。。
kernel/hd.c
- /*--------------------------------------------------------------Disp_HD_Ptr_Info
- 打印硬盘分区信息的管家
- */
- static void Disp_HD_Prt_Info()
- {
- /* 把hd_prt_info初始化为0 */
- u8 *p = (u8*)&hd_prt_info;
- int size = sizeof(HD_Prt_Info);
- int i;
- for(i = 0;i < size;i++)
- {
- *p = 0;
- }
- /* hd_prt_info.primary[0]代表整块硬盘,把整个硬盘相应信息赋过去 */
- u16 *buf = (u16*)hd_buf;
- hd_prt_info.primary[0].base = 0;
- hd_prt_info.primary[0].sec_num = ((int)buf[61] << 16) + buf[60];
- Put_Some_Prt_Info_2_Buf(0,PRT_TBL_SEC_DUMMY); /* 读取硬盘的分区到hd_prt_info中 */
- Show_HD_Prt_Info(&hd_prt_info); /* 打印硬盘分区信息 */
- }
- /*------------------------------------------------------------Read_Prt_Tbl_2_Buf
- 读取指定的硬盘分区表到指定的缓冲区中
- */
- static void Read_Prt_Tbl_2_Buf(int begin_sec,Prt_Tbl_Entry *entry_buf)
- {
- HD_Command hd_cmd;
- hd_cmd.features = 0;
- hd_cmd.sector_count = 1; /* 只读一个扇区 */
- hd_cmd.lba_low = begin_sec & 0xff;
- hd_cmd.lba_mid = (begin_sec >> 8) & 0xff;
- hd_cmd.lba_high = (begin_sec >> 16) & 0xff;
- hd_cmd.device = MAKE_DEVICE_REG(1,0,((begin_sec >> 24) & 0xf));
- hd_cmd.command = READ_HD; /* 读取硬盘指定的扇区的命令 */
- HD_Cmd_Out(&hd_cmd); /* 开始填充寄存器 */
- Wait_Int(); /* 等待硬盘中断处理程序执行完毕 */
- /* 把包含分区表的扇区读出来放到缓冲区中 */
- Read_Port_2_Buffer(REG_DATA,hd_buf,256);
- /* 分区表在某扇区起始的0x1be处,把分区表从缓冲区拷贝到entry_buf中 */
- Memory_Copy(entry_buf,hd_buf + PARTITION_TABLE_OFFSET,sizeof(Prt_Tbl_Entry) * 4);
- }
- /*-------------------------------------------------------Put_Some_Prt_Info_2_Buf
- 读指定的某些相应的分区信息到hd_prt_info
- */
- static void Put_Some_Prt_Info_2_Buf(int device,int begin_sec)
- {
- Prt_Tbl_Entry entry[4]; /* 暂存分区表缓存 */
- int i;
- /* 如果是读取整块硬盘的分区表 */
- if(device == 0)
- {
- Read_Prt_Tbl_2_Buf(0,entry); /* 从引导扇区读分区表到entry中 */
- /* 遍历引导扇区的分区表 */
- for(i = 1;i < 5;i++)
- {
- /* 如果是空分区,则跳过 */
- if(entry[i - 1].system_id == EMPTY_PRT)
- {
- continue;
- }
- /*
- 如果不是空分区,则把起始扇区和扇区长度写到
- hd_prt_info的主分区的相应字段
- */
- hd_prt_info.primary[i].base = entry[i - 1].start_sec_lba;
- hd_prt_info.primary[i].sec_num = entry[i - 1].sec_num;
- /* 如果当前分区是扩展分区,则递归调用本函数寻找此扩展分区表述的其它分区 */
- if(entry[i - 1].system_id == EXT_PRT)
- {
- Put_Some_Prt_Info_2_Buf(i,-1);
- }
- }
- }
- /*
- 执行到这表示设备号所代表的分区为扩展分区
- 如果设备号合法的话,则执行。
- 为硬盘设备号策略如下。
- 整块硬盘的设备号为0。
- 4个主分区的设备号依次为1-4。
- 如果第1个主分区是扩展分区,则它描述的其它分扩展分区的设备号为16到32。
- 其它以此类推。
- */
- else if((device >= 1 && device <= 5) || (device >= 16 && device <= 80))
- {
- int read_sec; /* 如果要读分区表,则代表分区表所在的扇区 */
- int which_primary; /* 当前设备号代表的主分区设备号,1-4 */
- int cur_base; /* 填充hd_prt_info的逻辑分区的起始扇区所用,说明如后 */
- int index; /* 填充hd_prt_info的逻辑分区的索引 */
- /* 设备号为主分区 */
- if(device >= 1 && device <= 5)
- {
- read_sec = hd_prt_info.primary[device].base; /* 从primary分区表获得 */
- which_primary = device; /* 原样传递 */
- index = (device - 1) * 16; /* 不解释。。 */
- }
- /* 设备号为扩展分区 */
- else
- {
- read_sec = begin_sec; /* 从参数获得 */
- which_primary = device / 16; /* 不解释。。 */
- index = (device % 16) + (which_primary - 1) * 16; /* 拗口。。不解释。。 */
- }
- Read_Prt_Tbl_2_Buf(read_sec,entry); /* 读分区信息到entry */
- /* 遍历entry */
- for(i = 0;i < 4;i++)
- {
- /* 空分区则直接break */
- if(entry[i].system_id == EMPTY_PRT)
- {
- break;
- }
- /* 嵌套扩展分区则又递归调用 */
- else if(entry[i].system_id == EXT_PRT)
- {
- Put_Some_Prt_Info_2_Buf(index + i + 16,
- hd_prt_info.primary[which_primary].base + entry[i].start_sec_lba);
- }
- /* 普通分区则把信息转移到hd_prt_info相应的位置 */
- else
- {
- /* 如果当前分区设备号为16,32,48,64,则那个那个。。具体看书上解释,很拗口*/
- if((index % 16) == 0)
- {
- cur_base = hd_prt_info.primary[which_primary].base;
- }
- /* 否则上一个挨着的分区的base + sec_num = cur_base */
- else
- {
- cur_base = hd_prt_info.logical[index + i - 1].base + hd_prt_info.logical[index + i - 1].sec_num;
- }
- hd_prt_info.logical[index + i].base = entry[i].start_sec_lba + cur_base;
- hd_prt_info.logical[index + i].sec_num = entry[i].sec_num;
- }
- }
- }
- else
- {
- Assert(0);
- }
- }
- /*--------------------------------------------------------------Show_HD_Prt_Info
- 打印硬盘分区表
- */
- static void Show_HD_Prt_Info(HD_Prt_Info *hd_prt_info)
- {
- int i;
- for(i = 0;i < 5;i++)
- {
- Printf(" DEVICE %d base:0x%x sector num:0x%x/n",i,
- hd_prt_info->primary[i].base,
- hd_prt_info->primary[i].sec_num);
- }
- for(i = 0;i < 64;i++)
- {
- /* 空的逻辑分区跳过 */
- if(hd_prt_info->logical[i].sec_num == 0)
- {
- continue;
- }
- Printf(" DEVICE %d base:0x%x sector num:0x%x/n",
- i + 16,hd_prt_info->logical[i].base,
- hd_prt_info->logical[i].sec_num);
- }
- }
用到宏如下:
include/hd.h
- #define READ_HD 0x20 /* 读取硬盘的送给硬盘驱动器寄存器的值 */
- #define PARTITION_TABLE_OFFSET 0x1BE /* 分区表相对扇区首址之偏移 */
- #define PRT_TBL_SEC_DUMMY -1 /* 表示不需要的值 */
- #define EMPTY_PRT 0 /* 空分区 */
- #define EXT_PRT 5 /* 扩展分区 */
最后在Proc_Hard_Disk()函数中调用Disp_HD_Prt_Info()函数。
make,bochs,结果如下: