上篇文章已经将难加载的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是最终的系统映像文件。它的大体组织前述已经比较清晰,不过画图更加容易理解:
posted on 2011-11-20 14:59
myjfm 阅读(428)
评论(0) 编辑 收藏 引用 所属分类:
操作系统