WinixJ---tools/buildImage.c文件详解

WinixJ---tools/buildImage.c文件详解
      上篇文章已经将难加载的ELF文件转化成容易被loader加载的map文件,已经是一个进步,可是仔细想想可能还存在如下问题:boot文件的大小以及在软盘中的位置是固定的,在软盘的第一个扇区,大小为512字节,而且boot由BIOS自动加载,但是loader该放到哪呢?内核map文件又该放到哪呢?
按照linux0.11的思路:将bootsect、setup、head、system压缩一下,其中bootsect位于整个压缩后的文件中的前512字节,之后的文件按序排放,然后放入软盘中。这个方法真的很简洁。
      我加载WinixJ的方法同样借鉴linux,将boot文件放在image文件的最前面512字节,之后是loader文件,再之后是内核map文件。这样让boot一次性完成加载loader和内核map文件入内存的工作。其中boot位于软盘的第一扇区,loader从第二扇区开始延伸,之后是map文件。不过还需要知道的是loader文件和map文件到底有多大,这两个数字我选择放到boot文件的尾部,位于boot标志0xaa55的前面。loader和map文件的长度都是以扇区为单位,假设loader文件有1000字节长,则laoder_len = 1000 >> 9 + (1000 % 512 ? 1 : 0);map_len的含义类似。所以image中可能会含有一些空域,这些空域是由于loader或map文件并非正好占用若干扇区而造成的。
build.c文件代码如下:

  1  #include  < stdio.h >
  2  #include  < stdlib.h >
  3  #include  < string .h >
  4  #include  < unistd.h >
  5  #include  < sys / stat.h >
  6 
  7  #define  BUF_LEN 520
  8  #define  BOOT_BUF_LEN BUF_LEN
  9  #define  FILE_NAME_LEN 50
 10 
 11  unsigned  char  boot_buf[BOOT_BUF_LEN];  // 缓存boot文件内容
 12  unsigned  char  buffer[BOOT_BUF_LEN];
 13 
 14  char  boot[FILE_NAME_LEN];  // 存储boot文件名
 15  char  loader[FILE_NAME_LEN];  // 存储loader文件名
 16  char  kernel[FILE_NAME_LEN];  // 存储kernel文件名
 17  char  image[FILE_NAME_LEN];  // 存储输出文件的文件名
 18 
 19  FILE  * bootp  =  NULL;  // boot文件的文件操作句柄
 20  FILE  * loaderp  =  NULL;  // loader文件的文件操作句柄
 21  FILE  * kernelp  =  NULL;  // kernel文件的文件操作句柄
 22  FILE  * imagep  =  NULL;  // image文件的文件操作句柄
 23 
 24  static   void  usage()
 25  {
 26      fprintf(stderr,  " Usage: build [-b ../boot/boot]  " );
 27      fprintf(stderr,  " [-l ../boot/loader] [-k ../kernel/kernel.map] [-w ../Image]\n " );
 28  }
 29 
 30  static   void  init()
 31  {
 32       // 指定默认的boot、loader、kernel和输出文件的文件名
 33      strcpy(boot,  " ../boot/boot " );  // 默认情况下boot文件在顶层目录的boot子目录中
 34      strcpy(loader,  " ../boot/loader " );  // 默认情况下loader文件在顶层目录的loader子目录中
 35      strcpy(kernel,  " ../kernel/kernel.map " );  // 默认情况下kernel文件在顶层目录的kernel子目录中
 36      strcpy(image,  " ../System.Image " );  // 默认在顶层目录生成系统映像
 37  }
 38 
 39  static   void  proc_opt( int  argc,  char   *   const   * argv)
 40  {
 41       int  ch;
 42      opterr  =   0 // 不显示错误信息
 43 
 44       while  ((ch  =  getopt(argc, argv,  " b:l:k:w:h " ))  !=   - 1 )
 45      {
 46           switch  (ch)
 47          {
 48               case   ' b ' // 指定boot文件名
 49                  strcpy(boot, optarg);
 50                   break ;
 51               case   ' l ' // 指定loader文件名
 52                  strcpy(loader, optarg);
 53                   break ;
 54               case   ' k ' // 指定kernel文件名
 55                  strcpy(kernel, optarg);
 56                   break ;
 57               case   ' w ' // 指定输出的系统映像文件名
 58                  strcpy(image, optarg);
 59                   break ;
 60               case   ' h ' :
 61                  usage();
 62                  exit( 1 );
 63          }
 64      }
 65  }
 66 
 67  static   void  open_file()
 68  {
 69       // 如果指定的boot文件不存在,则退出
 70       if  ( 0   !=  access(boot, F_OK))
 71      {
 72          fprintf(stderr,  " \ " % s\ " : No such file.\n " , boot);
 73          exit( 1 );
 74      }
 75      
 76       // 如果指定的loader文件不存在,则退出
 77       if  ( 0   !=  access(loader, F_OK))
 78      {
 79          fprintf(stderr,  " \ " % s\ " : No such file.\n " , loader);
 80          exit( 1 );
 81      }
 82      
 83       // 如果指定的kernel文件不存在,则退出
 84       if  ( 0   !=  access(kernel, F_OK))
 85      {
 86          fprintf(stderr,  " \ " % s\ " : No such file.\n " , kernel);
 87          exit( 1 );
 88      }
 89 
 90       // 如果指定的image文件存在,则给出warning
 91       if  ( 0   ==  access(image, F_OK))
 92      {
 93          fprintf(stderr,  " Warning: The file \ " % s\ "  exists.\n " , image);
 94          fprintf(stderr,  " But we will go on \n " );
 95      }
 96 
 97      bootp  =  fopen(boot,  " r+ " );
 98       // 如果不能打开boot文件
 99       if  (NULL  ==  bootp)
100      {
101          fprintf(stderr,  " cannot open the file \ " % s\ " .\n " , boot);
102          exit( 1 );
103      }
104 
105      loaderp  =  fopen(loader,  " r+ " );
106       // 如果不能打开loader文件
107       if  (NULL  ==  loaderp)
108      {
109          fprintf(stderr,  " cannot open the file \ " % s\ " .\n " , loader);
110          exit( 1 );
111      }
112 
113      kernelp  =  fopen(kernel,  " r+ " );
114       // 如果不能打开kernel文件
115       if  (NULL  ==  kernelp)
116      {
117          fprintf(stderr,  " cannot open the file \ " % s\ " .\n " , kernel);
118          exit( 1 );
119      }
120 
121      imagep  =  fopen(image,  " w+ " );
122       // 如果不能创建image文件
123       if  (NULL  ==  imagep)
124      {
125          fprintf(stderr,  " cannot create the file \ " % s\ " .\n " , image);
126          exit( 1 );
127      }
128  }
129 
130  int  main( int  argc,  char   *   const   * argv)
131  {
132       int  n;
133       struct  stat loader_stat, kernel_stat;
134       int  loader_len  =   0 , kernel_len  =   0 ;
135 
136      init();  // 初始化
137 
138      proc_opt(argc, argv);  // 处理命令行参数
139 
140      open_file();  // 打开boot、loader、kernel和image文件
141 
142       // 将boot文件的512字节读入boot_buf缓冲区
143      n  =  fread(boot_buf,  512 1 , bootp);
144 
145       if  ( 1   !=  n)
146      {
147          fprintf(stderr,  " cannot read 512 bytes from %s.\n " , boot);
148          exit( 1 );
149      }
150 
151       // 检查boot文件的末尾两个字节,如果为0xaa55,则认为是合法的boot文件
152       if  ( 0xaa55   !=   * (unsigned  short   * )(boot_buf  +   510 ))
153      {
154          fprintf(stderr,  " %s is not bootable file.\n " , boot);
155          exit( 1 );
156      }
157 
158       // 获取loader文件的信息
159      n  =  stat(loader,  & loader_stat);
160      
161       if  ( - 1   ==  n)
162      {
163          fprintf(stderr,  " cannot get %s's status.\n " , loader);
164          exit( 1 );
165      }
166 
167       // 获取loader文件的长度,按字节计算
168      loader_len  =  loader_stat.st_size;
169 
170       // 获取kernel文件的信息
171      n  =  stat(kernel,  & kernel_stat);
172 
173       if  ( - 1   ==  n)
174      {
175          fprintf(stderr,  " cannot get %s's status.\n " , kernel);
176          exit( 1 );
177      }
178 
179       // 获取kernel文件的长度,按字节计算
180      kernel_len  =  kernel_stat.st_size;
181 
182       // 修改boot中LOADER_LEN和KERNEL_LEN字段,详细请查看boot.asm源码最后10行
183      boot_buf[ 507 =  ( 0   ==  (loader_len  &   0x1ff ))  ?  (loader_len  >>   9 ) : (loader_len  >>   9 +   1 ;
184       * (unsigned  short   * )(boot_buf  +   508 =  ( 0   ==  (kernel_len  &   0x1ff ))  ?  (kernel_len  >>   9 ) : (kernel_len  >>   9 +   1 ;
185 
186       // 将boot文件内容写入image文件中
187      n  =  fwrite(boot_buf,  512 1 , imagep);
188 
189       if  ( 1   !=  n)
190      {
191          fprintf(stderr,  " cannot write into %s.\n " , image);
192          exit( 1 );
193      }
194 
195       // 将loader文件写入image中,按扇区数来写入,最后一扇区不够的用0补足
196       while  (loader_len  >   0 )
197      {
198          memset(buffer,  0 sizeof (buffer));
199          n  =  fread(buffer, loader_len  >   512   ?   512  : loader_len,  1 , loaderp);
200 
201           if  ( 1   !=  n)
202          {
203              fprintf(stderr,  " cannot read %d bytes from %s.\n "
204                      loader_len  >   512   ?   512  : loader_len, boot);
205              exit( 1 );
206          }
207 
208          n  =  fwrite(buffer,  512 1 , imagep);
209          
210           if  ( 1   !=  n)
211          {
212              fprintf(stderr,  " cannot write into %s.\n " , image);
213              exit( 1 );
214          }
215 
216          loader_len  -=   512 ;
217      }
218 
219       // 将kernel文件写入image中,按扇区数来写入,最后一扇区不够的用0补足
220       while  (kernel_len  >   0 )
221      {
222          memset(buffer,  0 sizeof (buffer));
223          n  =  fread(buffer, kernel_len  >   512   ?   512  : kernel_len,  1 , kernelp);
224 
225           if  ( 1   !=  n)
226          {
227              fprintf(stderr,  " cannot read %d bytes from %s.\n "
228                      kernel_len  >   512   ?   512  : kernel_len, boot);
229              exit( 1 );
230          }
231 
232          n  =  fwrite(buffer,  512 1 , imagep);
233          
234           if  ( 1   !=  n)
235          {
236              fprintf(stderr,  " cannot write into %s.\n " , image);
237              exit( 1 );
238          }
239 
240          kernel_len  -=   512 ;
241      }
242 
243      fclose(bootp);
244      fclose(loaderp);
245      fclose(kernelp);
246      fclose(imagep);
247 
248       return   0 ;
249  }

程序还是比较好理解的,大体思想正如上面所说。最后生成的System.Image是最终的系统映像文件。它的大体组织前述已经比较清晰,不过画图更加容易理解:

你可能感兴趣的:(WinixJ---tools/buildImage.c文件详解)