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 }
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是最终的系统映像文件。它的大体组织前述已经比较清晰,不过画图更加容易理解: