将文件系统安装到指定的分区

    开始之前先修正一个BUG,害叔找了半天,就是硬盘驱动进程的栈空间太小了,搞得栈溢出波及到其它的数据,在proc.h把栈空间设为2K就好。

    下面再来补充硬盘驱动程序,我们先取得对应分区的信息,则先增加相应的宏:

    include/const.h

Code:
  1. #define HD_GET_PRT_INFO             5           /* 得到指定分区的信息 */  

    再在硬盘驱动进程的执行体中添加:

    kernel/hd.c

Code:
  1. case HD_GET_PRT_INFO:   
  2.     Get_Prt_Info(&m);   
  3.     break;  

    接着添加Get_Prt_Info函数,hd.c追加:

Code:
  1. /*------------------------------------------------------------------Get_Prt_Info  
  2.     获得指定分区(设备号指出)的信息  
  3. */  
  4. static void Get_Prt_Info(Message *m)   
  5. {   
  6.     int device = m->i1;     /* 得到设备号 */  
  7.     /* 得到要返回的缓冲区,强制转换为分区信息结构 */  
  8.     Prt_Info *ret_prt_info = (Prt_Info*)m->r1;   
  9.     /* 主分区 */  
  10.     if(device >= 0 && device <= 5)   
  11.     {   
  12.         ret_prt_info->base = hd_prt_info.primary[device].base;   
  13.         ret_prt_info->sec_num = hd_prt_info.primary[device].sec_num;   
  14.     }   
  15.     /* 扩展分区 */  
  16.     else if(device >=16 && device <=80)   
  17.     {   
  18.         ret_prt_info->base = hd_prt_info.logical[device - 16].base;   
  19.         ret_prt_info->sec_num = hd_prt_info.logical[device - 16].sec_num;   
  20.     }   
  21. }  

    OK,现在来进行文件系统的设计,文件系统有两方面的意思:一是在硬盘上的一组数据结构,二是一组能对与之对应的数据结构管理文件的机制,我们先来做物理意义的工作,就是数据结构的定义。

    在前面写boot和loader的时候已经接触过这方面的内容,就是FAT12文件系统。在这里我们的文件系统也很类似。

    在指定的分区中,0扇区为引导扇区,我们单纯的在里面放置引导代码,先不管它。

    下一步就是超级块,放在1扇区,记录此文件系统的各种信息,比如最多可以存放多少个文件等等,下面给出结构,以下结构均在include/fs.h中定义:

Code:
  1. /* 超级块 */  
  2.     typedef struct s_super_block   
  3.     {   
  4.         u32 identity;           /* 表示本文件系统的信息 */  
  5.         u32 inode_num;          /* i结点的个数 */  
  6.         u32 sector_total;       /* 此文件系统所在分区的扇区总数 */  
  7.         u32 imap_sec_total;     /* i结点映射表所占用的扇区总数 */  
  8.         u32 smap_sec_total;     /* 数据区的扇区的使用映射表的扇区总数 */  
  9.         u32 first_data_sec;     /* 数据区的第一个扇区的索引 */  
  10.         u32 inodes_sec_total;   /* i结点数组所占用的扇区数 */  
  11.         u32 root_dir_inode;     /* 根目录所占用的文件所属的i节点索引 */  
  12.         u32 inode_size;         /* 一个i结点的字节数 */  
  13.         u32 dir_entry_size;     /* 一个目录项的字节数 */  
  14.     }Super_Block;   
  15.        
  16.     #define SUPER_BLOCK_SIZE    10 * 4  /* 超级块占用的字节数 */  

    再下面是i结点的映射表,放在1扇区。记录i结点的使用情况,占据一个扇区,每一位记录一个i结点的使用情况,1代表已使用,0表示未使用。这样就可以记录512*8=4096个i结点,就是说此文件系统最多可以记录4096个文件,但索引为0的i结点不使用,表示错误的i结点。根目录也是一个文件,占用一个i结点。并且3个TTY也算是一个文件,这是借鉴LINUX的结果。所以最多只有4096-5=4091个文件。i结点的作用稍后再说。

    接着是文件数据区的扇区部分的映射表,起始扇区在2扇区,作用与i结点的映射表一样,用来管理扇区的使用情况,占据扇区个数为:整个硬盘的扇区数/512*8,我们知道实际上有些扇区是不能来存放数据的,这里懒得算了,就当浪费一些扇区吧,但要在这个表的第0位是代表实际的数据区的第一个扇区的使用情况的,这里需要注意。还有第0个数据扇区我们是不用的。

    再下面是i结点数据,,i结点的作用是指明一个文件的类型,占用的扇区大小等信息,下面是定义:

Code:
  1. /* i结点 */  
  2. typedef struct s_i_node   
  3. {   
  4.     u32 i_mode;             /* 访问模式 */  
  5.     u32 i_size;             /* 所表示的文件实际占用的字节数 */  
  6.     u32 i_start_sec;        /* 所表示的文件的首扇区的索引 */  
  7.     u32 i_sect_total;       /* 所表示的文件实际占用的扇区数,是固定的 */  
  8.     u8  unused[16];         /* 无意义,用于对齐 */  
  9. }I_Node;   
  10.   
  11. #define I_NODE_SIZE         8 * 4   /* 一个i结点所占用的字节数 */  

    最后就是根目录区了,是一个Dir_Entry数组,根目录区也算一个文件,所以它的起始扇区位于数据区的第1个扇区,第0个扇区不使用,这里的结构如下:

Code:
  1. #define MAX_FILENAME_SIZE   12      /* 一个文件的最长的文件名 */   
  2.        
  3. typedef struct s_dir_entry    
  4. {   
  5.     u32 inode_index;                    /* 此文件所属的i结点的索引 */  
  6.     char file_name[MAX_FILENAME_SIZE];  /* 文件名 */  
  7. }Dir_Entry;   
  8.        
  9. #define DIR_ENTRY_SIZE  sizeof(Dir_Entry)   /* 一个根目录文件项的字节大小 */  

    OK,整个系统就设计好了,下面的工作就是在实际的硬盘上填充这些信息了。

    kernel/fs.c

Code:
  1. /*-----------------------------------------------------------------------Init_FS  
  2.     初始化文件系统,取得硬盘的分区信息  
  3. */  
  4. static void Init_FS()   
  5. {   
  6.     Message m;   
  7.     m.msg_type = HD_INFO;   
  8.     Send_Receive_Shell(BOTH,PROC_HD_PID,&m);   
  9. }   
  10.   
  11. /*-----------------------------------------------------------------------Make_FS  
  12.     把文件系统的信息写到磁盘中  
  13. */  
  14. static void Make_FS()   
  15. {   
  16.     /* 取得文件系统的宿主分区的信息 */  
  17.     Message m;   
  18.     Prt_Info prt_info;   
  19.        
  20.     m.msg_type = HD_GET_PRT_INFO;   
  21.     m.i1 = FS_DEV;   
  22.     m.r1 = &prt_info;   
  23.     Send_Receive_Shell(BOTH,PROC_HD_PID,&m);   
  24.        
  25.     Printf("FILE SYSTEM PARTITION HAS 0x%x SECTORS/n",prt_info.sec_num);   
  26.        
  27.     /* 开始填充填充超级块 */  
  28.     Super_Block sb;   
  29.     sb.identity = IDENTITY;                 /* 填充文件系统的标识 */  
  30.     sb.inode_num = 4096;                    /* i结点的个数 */  
  31.     sb.sector_total = prt_info.sec_num;     /* 此文件系统所在分区的扇区总数 */  
  32.     sb.imap_sec_total = 1;                  /* i结点映射表所占用的扇区总数 */  
  33.     sb.smap_sec_total = prt_info.sec_num / 4096 + 1;                /* 数据区的映射表所占的扇区数 */  
  34.     sb.inodes_sec_total = I_NODE_SIZE * sb.inode_num / SECTOR_SIZE; /* i结点数组所占用的扇区数 */  
  35.     /* 数据区的第一个扇区的索引 */  
  36.     sb.first_data_sec = 1 + 1 + sb.imap_sec_total + sb.smap_sec_total + sb.inodes_sec_total;           
  37.     sb.root_dir_inode = 1;                  /* 根目录所占用的文件所属的i节点索引 */  
  38.     sb.inode_size = I_NODE_SIZE;            /* 一个i结点的字节数 */  
  39.     sb.dir_entry_size = DIR_ENTRY_SIZE;     /* 一个目录项的字节数 */  
  40.        
  41.     Memory_Set((u8*)FS_BUF,0,FS_BUF_SIZE);  /* 缓冲区清零 */  
  42.     Memory_Copy((void*)FS_BUF,&sb,sizeof(Super_Block)); /* 复制超级块到缓冲区中 */  
  43.        
  44.     Write_Sector(FS_DEV,1); /* 写入硬盘 */  
  45.        
  46.     /* 打印文件系统各部分在分区的偏移字节 */  
  47.     Printf("DEV:0x%x00 SUPER BLOCK:0x%x00/nINODE MAP:0x%x00 SECTOR MAP:0x%x00/nINODE ARRAY:0x%x00,FIRST DATA SECTOR:0x%x00/n",   
  48.             prt_info.base * 2,(prt_info.base + 1) * 2,(prt_info.base + 2) * 2,   
  49.             (prt_info.base + 3) * 2,(prt_info.base + 3 + sb.smap_sec_total) * 2,   
  50.             (prt_info.base + sb.first_data_sec) * 2);   
  51.                
  52.     /* 填充i结点映射表 */  
  53.     Memory_Set((u8*)FS_BUF,0,SECTOR_SIZE);  /* 缓冲区清零 */  
  54.     /*   
  55.         前5个文件被占用,分别是:  
  56.         保留的i结点  
  57.         根目录区代表的文件  
  58.         TTY0-3  
  59.     */  
  60.     *(u8*)FS_BUF = 0x1f;               
  61.        
  62.     Write_Sector(FS_DEV,2); /* 写入硬盘 */  
  63.        
  64.     /* 填充扇区使用映射表 */  
  65.        
  66.     /* 先把硬盘中相关的扇区清零 */  
  67.     Memory_Set((u8*)FS_BUF,0,FS_BUF_SIZE);  /* 缓冲区清零 */  
  68.     int i;   
  69.     int j;   
  70.     for(i = 0;i < sb.smap_sec_total;i++)   
  71.     {   
  72.         Write_Sector(FS_DEV,3 + i);   
  73.     }   
  74.        
  75.     /* 根目录区占用ROOT_DIR_SEC_NUM个扇区 + 保留扇区 */  
  76.     int occupy_data_sec_num = ROOT_DIR_SEC_NUM + 1;   
  77.        
  78.     /* 在缓冲中先写入正确的值 */  
  79.     for(i = 0;i < occupy_data_sec_num / 8;i++)   
  80.     {   
  81.         *(u8*)(FS_BUF + i) = 0xff;   
  82.     }   
  83.        
  84.     for(j = 0;j < occupy_data_sec_num % 8;j++)   
  85.     {   
  86.         *(u8*)(FS_BUF + i) |= (1 << j);    
  87.     }   
  88.        
  89.     Write_Sector(FS_DEV,3); /* 写入硬盘 */  
  90.        
  91.     /* 填充i结点数组 */  
  92.     Memory_Set((u8*)FS_BUF,0,SECTOR_SIZE);  /* 缓冲区清零 */  
  93.        
  94.     /* 先把硬盘中相关的扇区清零 */  
  95.     for(i = 0;i < sb.inodes_sec_total;i++)   
  96.     {   
  97.         Write_Sector(FS_DEV,3 + sb.smap_sec_total + i);   
  98.     }   
  99.        
  100.     /* 填充根目录区的i结点 */  
  101.        
  102.     /* 执行缓冲区的下一个i结点的位置,因为0结点不用 */  
  103.     I_Node *i_node = (I_Node*)(FS_BUF + I_NODE_SIZE);      
  104.        
  105.     /* 填充根目录的i结点 */  
  106.     i_node->i_mode = INODE_MODE_DIR;            /* 文件类型为根目录 */  
  107.     i_node->i_size = DIR_ENTRY_SIZE * 4;        /* 实际字节数为4个Dir_Entry的大小 */  
  108.     i_node->i_start_sec = sb.first_data_sec;    /* 起始扇区为数据区的第一个字节 */  
  109.     i_node->i_sect_total = ROOT_DIR_SEC_NUM;    /* 实际占用扇区大小为ROOT_DIR_SEC_NUM */  
  110.        
  111.     /* 填充TTY的i结点 */  
  112.     for(i = 0;i < TTY_NUM;i++)   
  113.     {   
  114.         i_node++;      
  115.         i_node->i_mode = INODE_MODE_SPECIAL;    /* 文件类型为特殊的 */  
  116.         i_node->i_size = 0;                     /* 不占磁盘,当然为0 */  
  117.         i_node->i_start_sec = i;                /* 这里表示TTY的编号 */  
  118.         i_node->i_sect_total = 0;               /* 不占磁盘,当然为0 */  
  119.     }   
  120.        
  121.     Write_Sector(FS_DEV,3 + sb.smap_sec_total); /* 写入硬盘 */  
  122.        
  123.     /* 填充根目录区的Dir_Entry数组 */  
  124.     Memory_Set((u8*)FS_BUF,0,SECTOR_SIZE);      /* 缓冲区清零 */  
  125.        
  126.     /* 先把硬盘中相关的扇区清零,加1是因为数据区的第一个扇区不用 */  
  127.     for(i = 0;i < ROOT_DIR_SEC_NUM;i++)   
  128.     {   
  129.         Write_Sector(FS_DEV,sb.first_data_sec + i + 1);   
  130.     }   
  131.        
  132.     /* 填充根目录文件的Dir_Entry */  
  133.     Dir_Entry *dir_entry = (Dir_Entry*)FS_BUF;   
  134.     dir_entry->inode_index = 1;         /* 填充i结点的索引 */  
  135.     Str_Cpy(dir_entry->file_name,".");  /* 名字复制 */  
  136.        
  137.     /* 填充各TTY文件 */  
  138.     char *tty_name[] = {"tty0","tty1","tty2"};   
  139.     for(i = 0;i < TTY_NUM;i++)   
  140.     {   
  141.         dir_entry++;   
  142.         dir_entry->inode_index = i + 2;   
  143.         Str_Cpy(dir_entry->file_name,tty_name[i]);   
  144.     }   
  145.        
  146.     Write_Sector(FS_DEV,sb.first_data_sec + 1);  /* 写入硬盘 */ 
  147. }   
  148.   
  149. /*------------------------------------------------------------------Write_Sector  
  150.     填充一个扇区的数据到指定的device的分区的offset_sec个扇区中  
  151.     数据来自FS_BUF缓冲区  
  152. */  
  153. static void Write_Sector(int device,int offset_sec)   
  154. {   
  155.     Message m;   
  156.     m.msg_type = HD_WRITE;   
  157.     m.i1 = device;   
  158.     m.i2 = offset_sec;   
  159.     m.i3 = SECTOR_SIZE;   
  160.     m.r1 = (void*)FS_BUF;   
  161.     Send_Receive_Shell(BOTH,PROC_HD_PID,&m);   
  162. }   

    注释得还可以了。。不赘述。。

    用到的宏如下:

    include/fs.h

Code:
  1. #define FS_BUF              0x600000    /* 填充FS信息使用的缓冲区 */   
  2. #define FS_BUF_SIZE         0x100000    /* 此缓冲区的大小 */   
  3. #define FS_DEV              32          /* FS安装的逻辑分区的设备号 */   
  4. #define ROOT_DIR_SEC_NUM    128         /* 根目录占用的扇区数 */   
  5.   
  6. #define IDENTITY            0xabcd      /* 此文件系统的标识 */     
  7.   
  8. /* 以下为i结点的模式 */  
  9. #define INODE_MODE_DIR      0x1         /* 表示目录 */   
  10. #define INODE_MODE_FILE     0x2         /* 表示普通文件 */   
  11. #define INODE_MODE_SPECIAL  0x4         /* 表示特殊文件 */  

    还添加了一个Memory_Set函数,如下:

    lib/lib_kernel_in_c.c

Code:
  1. /*--------------------------------------------------------------------Memory_Set  
  2.     把addr指定的内存开始的size个字节置为set_value  
  3. */  
  4. void Memory_Set(u8 *addr,u8 set_value,u32 size)   
  5. {   
  6.     while(size-- > 0)   
  7.     {   
  8.         *addr++ = set_value;   
  9.     }   
  10. }  

    下面是检验结果的时候了,运行结果如下:

     从中我们得到了文件系统的各部分在硬盘的偏移字节数,下面依次来查看。

    首先是超级块:

    i结点映射表:

    数据区扇区映射表:

    i结点数组:

    最后是根目录区:

    仔细对照下,嗯,没错。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值