3 #include <netinet/in.h>
9 #define ElfHeaderSize (64 * 1024)
10 #define ElfPages (ElfHeaderSize / 4096)
11 #define KERNELBASE (0xc000000000000000)
13 void get4k(FILE *file
, char *buf
)
16 unsigned num
= fread(buf
, 1, 4096, file
);
17 for ( j
=num
; j
<4096; ++j
)
21 void put4k(FILE *file
, char *buf
)
23 fwrite(buf
, 1, 4096, file
);
26 void death(const char *msg
, FILE *fdesc
, const char *fname
)
34 int main(int argc
, char **argv
)
39 FILE *inputVmlinux
= NULL
;
40 FILE *outputVmlinux
= NULL
;
43 unsigned long ramFileLen
= 0;
44 unsigned long ramLen
= 0;
45 unsigned long roundR
= 0;
47 unsigned long sysmapFileLen
= 0;
48 unsigned long sysmapLen
= 0;
49 unsigned long sysmapPages
= 0;
51 unsigned long offset_end
= 0;
53 unsigned long kernelLen
= 0;
54 unsigned long actualKernelLen
= 0;
55 unsigned long round
= 0;
56 unsigned long roundedKernelLen
= 0;
57 unsigned long ramStartOffs
= 0;
58 unsigned long ramPages
= 0;
59 unsigned long roundedKernelPages
= 0;
60 unsigned long hvReleaseData
= 0;
61 u_int32_t eyeCatcher
= 0xc8a5d9c4;
62 unsigned long naca
= 0;
63 unsigned long xRamDisk
= 0;
64 unsigned long xRamDiskSize
= 0;
69 fprintf(stderr
, "Name of RAM disk file missing.\n");
74 fprintf(stderr
, "Name of System Map input file is missing.\n");
79 fprintf(stderr
, "Name of vmlinux file missing.\n");
84 fprintf(stderr
, "Name of vmlinux output file missing.\n");
89 ramDisk
= fopen(argv
[1], "r");
91 fprintf(stderr
, "RAM disk file \"%s\" failed to open.\n", argv
[1]);
95 sysmap
= fopen(argv
[2], "r");
97 fprintf(stderr
, "System Map file \"%s\" failed to open.\n", argv
[2]);
101 inputVmlinux
= fopen(argv
[3], "r");
102 if ( ! inputVmlinux
) {
103 fprintf(stderr
, "vmlinux file \"%s\" failed to open.\n", argv
[3]);
107 outputVmlinux
= fopen(argv
[4], "w+");
108 if ( ! outputVmlinux
) {
109 fprintf(stderr
, "output vmlinux file \"%s\" failed to open.\n", argv
[4]);
115 /* Input Vmlinux file */
116 fseek(inputVmlinux
, 0, SEEK_END
);
117 kernelLen
= ftell(inputVmlinux
);
118 fseek(inputVmlinux
, 0, SEEK_SET
);
119 printf("kernel file size = %d\n", kernelLen
);
120 if ( kernelLen
== 0 ) {
121 fprintf(stderr
, "You must have a linux kernel specified as argv[3]\n");
125 actualKernelLen
= kernelLen
- ElfHeaderSize
;
127 printf("actual kernel length (minus ELF header) = %d\n", actualKernelLen
);
129 round
= actualKernelLen
% 4096;
130 roundedKernelLen
= actualKernelLen
;
132 roundedKernelLen
+= (4096 - round
);
133 printf("Vmlinux length rounded up to a 4k multiple = %ld/0x%lx \n", roundedKernelLen
, roundedKernelLen
);
134 roundedKernelPages
= roundedKernelLen
/ 4096;
135 printf("Vmlinux pages to copy = %ld/0x%lx \n", roundedKernelPages
, roundedKernelPages
);
139 /* Input System Map file */
140 /* (needs to be processed simply to determine if we need to add pad pages due to the static variables not being included in the vmlinux) */
141 fseek(sysmap
, 0, SEEK_END
);
142 sysmapFileLen
= ftell(sysmap
);
143 fseek(sysmap
, 0, SEEK_SET
);
144 printf("%s file size = %ld/0x%lx \n", argv
[2], sysmapFileLen
, sysmapFileLen
);
146 sysmapLen
= sysmapFileLen
;
148 roundR
= 4096 - (sysmapLen
% 4096);
150 printf("Rounding System Map file up to a multiple of 4096, adding %ld/0x%lx \n", roundR
, roundR
);
153 printf("Rounded System Map size is %ld/0x%lx \n", sysmapLen
, sysmapLen
);
155 /* Process the Sysmap file to determine where _end is */
156 sysmapPages
= sysmapLen
/ 4096;
157 /* read the whole file line by line, expect that it doesn't fail */
158 while ( fgets(inbuf
, 4096, sysmap
) ) ;
159 /* search for _end in the last page of the system map */
160 ptr_end
= strstr(inbuf
, " _end");
162 fprintf(stderr
, "Unable to find _end in the sysmap file \n");
163 fprintf(stderr
, "inbuf: \n");
164 fprintf(stderr
, "%s \n", inbuf
);
167 printf("Found _end in the last page of the sysmap - backing up 10 characters it looks like %s", ptr_end
-10);
168 /* convert address of _end in system map to hex offset. */
169 offset_end
= (unsigned int)strtol(ptr_end
-10, NULL
, 16);
170 /* calc how many pages we need to insert between the vmlinux and the start of the ram disk */
171 padPages
= offset_end
/4096 - roundedKernelPages
;
173 /* Check and see if the vmlinux is already larger than _end in System.map */
175 /* vmlinux is larger than _end - adjust the offset to the start of the embedded ram disk */
176 offset_end
= roundedKernelLen
;
177 printf("vmlinux is larger than _end indicates it needs to be - offset_end = %lx \n", offset_end
);
179 printf("will insert %lx pages between the vmlinux and the start of the ram disk \n", padPages
);
182 /* _end is larger than vmlinux - use the offset to _end that we calculated from the system map */
183 printf("vmlinux is smaller than _end indicates is needed - offset_end = %lx \n", offset_end
);
184 printf("will insert %lx pages between the vmlinux and the start of the ram disk \n", padPages
);
189 /* Input Ram Disk file */
190 // Set the offset that the ram disk will be started at.
191 ramStartOffs
= offset_end
; /* determined from the input vmlinux file and the system map */
192 printf("Ram Disk will start at offset = 0x%lx \n", ramStartOffs
);
194 fseek(ramDisk
, 0, SEEK_END
);
195 ramFileLen
= ftell(ramDisk
);
196 fseek(ramDisk
, 0, SEEK_SET
);
197 printf("%s file size = %ld/0x%lx \n", argv
[1], ramFileLen
, ramFileLen
);
201 roundR
= 4096 - (ramLen
% 4096);
203 printf("Rounding RAM disk file up to a multiple of 4096, adding %ld/0x%lx \n", roundR
, roundR
);
207 printf("Rounded RAM disk size is %ld/0x%lx \n", ramLen
, ramLen
);
208 ramPages
= ramLen
/ 4096;
209 printf("RAM disk pages to copy = %ld/0x%lx\n", ramPages
, ramPages
);
213 // Copy 64K ELF header
214 for (i
=0; i
<(ElfPages
); ++i
) {
215 get4k( inputVmlinux
, inbuf
);
216 put4k( outputVmlinux
, inbuf
);
219 /* Copy the vmlinux (as full pages). */
220 fseek(inputVmlinux
, ElfHeaderSize
, SEEK_SET
);
221 for ( i
=0; i
<roundedKernelPages
; ++i
) {
222 get4k( inputVmlinux
, inbuf
);
223 put4k( outputVmlinux
, inbuf
);
226 /* Insert pad pages (if appropriate) that are needed between */
227 /* | the end of the vmlinux and the ram disk. */
228 for (i
=0; i
<padPages
; ++i
) {
229 memset(inbuf
, 0, 4096);
230 put4k(outputVmlinux
, inbuf
);
233 /* Copy the ram disk (as full pages). */
234 for ( i
=0; i
<ramPages
; ++i
) {
235 get4k( ramDisk
, inbuf
);
236 put4k( outputVmlinux
, inbuf
);
239 /* Close the input files */
241 fclose(inputVmlinux
);
242 /* And flush the written output file */
243 fflush(outputVmlinux
);
247 /* Fixup the new vmlinux to contain the ram disk starting offset (xRamDisk) and the ram disk size (xRamDiskSize) */
248 /* fseek to the hvReleaseData pointer */
249 fseek(outputVmlinux
, ElfHeaderSize
+ 0x24, SEEK_SET
);
250 if (fread(&hvReleaseData
, 4, 1, outputVmlinux
) != 1) {
251 death("Could not read hvReleaseData pointer\n", outputVmlinux
, argv
[4]);
253 hvReleaseData
= ntohl(hvReleaseData
); /* Convert to native int */
254 printf("hvReleaseData is at %08x\n", hvReleaseData
);
256 /* fseek to the hvReleaseData */
257 fseek(outputVmlinux
, ElfHeaderSize
+ hvReleaseData
, SEEK_SET
);
258 if (fread(inbuf
, 0x40, 1, outputVmlinux
) != 1) {
259 death("Could not read hvReleaseData\n", outputVmlinux
, argv
[4]);
261 /* Check hvReleaseData sanity */
262 if (memcmp(inbuf
, &eyeCatcher
, 4) != 0) {
263 death("hvReleaseData is invalid\n", outputVmlinux
, argv
[4]);
265 /* Get the naca pointer */
266 naca
= ntohl(*((u_int32_t
*) &inbuf
[0x0C])) - KERNELBASE
;
267 printf("Naca is at offset 0x%lx \n", naca
);
269 /* fseek to the naca */
270 fseek(outputVmlinux
, ElfHeaderSize
+ naca
, SEEK_SET
);
271 if (fread(inbuf
, 0x18, 1, outputVmlinux
) != 1) {
272 death("Could not read naca\n", outputVmlinux
, argv
[4]);
274 xRamDisk
= ntohl(*((u_int32_t
*) &inbuf
[0x0c]));
275 xRamDiskSize
= ntohl(*((u_int32_t
*) &inbuf
[0x14]));
276 /* Make sure a RAM disk isn't already present */
277 if ((xRamDisk
!= 0) || (xRamDiskSize
!= 0)) {
278 death("RAM disk is already attached to this kernel\n", outputVmlinux
, argv
[4]);
280 /* Fill in the values */
281 *((u_int32_t
*) &inbuf
[0x0c]) = htonl(ramStartOffs
);
282 *((u_int32_t
*) &inbuf
[0x14]) = htonl(ramPages
);
284 /* Write out the new naca */
285 fflush(outputVmlinux
);
286 fseek(outputVmlinux
, ElfHeaderSize
+ naca
, SEEK_SET
);
287 if (fwrite(inbuf
, 0x18, 1, outputVmlinux
) != 1) {
288 death("Could not write naca\n", outputVmlinux
, argv
[4]);
290 printf("Ram Disk of 0x%lx pages is attached to the kernel at offset 0x%08x\n",
291 ramPages
, ramStartOffs
);
294 fclose(outputVmlinux
);
295 /* Set permission to executable */
296 chmod(argv
[4], S_IRUSR
|S_IWUSR
|S_IXUSR
|S_IRGRP
|S_IXGRP
|S_IROTH
|S_IXOTH
);