3 #include <netinet/in.h>
10 #define ElfHeaderSize (64 * 1024)
11 #define ElfPages (ElfHeaderSize / 4096)
12 #define KERNELBASE (0xc000000000000000)
13 #define _ALIGN_UP(addr,size) (((addr)+((size)-1))&(~((size)-1)))
16 unsigned long long addr
;
17 unsigned long memsize
;
21 static int check_elf64(void *p
, int size
, struct addr_range
*r
)
23 Elf64_Ehdr
*elf64
= p
;
26 if (elf64
->e_ident
[EI_MAG0
] != ELFMAG0
||
27 elf64
->e_ident
[EI_MAG1
] != ELFMAG1
||
28 elf64
->e_ident
[EI_MAG2
] != ELFMAG2
||
29 elf64
->e_ident
[EI_MAG3
] != ELFMAG3
||
30 elf64
->e_ident
[EI_CLASS
] != ELFCLASS64
||
31 elf64
->e_ident
[EI_DATA
] != ELFDATA2MSB
||
32 elf64
->e_type
!= ET_EXEC
|| elf64
->e_machine
!= EM_PPC64
)
35 if ((elf64
->e_phoff
+ sizeof(Elf64_Phdr
)) > size
)
38 elf64ph
= (Elf64_Phdr
*) ((unsigned long)elf64
+
39 (unsigned long)elf64
->e_phoff
);
41 r
->memsize
= (unsigned long)elf64ph
->p_memsz
;
42 r
->offset
= (unsigned long)elf64ph
->p_offset
;
43 r
->addr
= (unsigned long long)elf64ph
->p_vaddr
;
46 printf("PPC64 ELF file, ph:\n");
47 printf("p_type 0x%08x\n", elf64ph
->p_type
);
48 printf("p_flags 0x%08x\n", elf64ph
->p_flags
);
49 printf("p_offset 0x%016llx\n", elf64ph
->p_offset
);
50 printf("p_vaddr 0x%016llx\n", elf64ph
->p_vaddr
);
51 printf("p_paddr 0x%016llx\n", elf64ph
->p_paddr
);
52 printf("p_filesz 0x%016llx\n", elf64ph
->p_filesz
);
53 printf("p_memsz 0x%016llx\n", elf64ph
->p_memsz
);
54 printf("p_align 0x%016llx\n", elf64ph
->p_align
);
55 printf("... skipping 0x%08lx bytes of ELF header\n",
56 (unsigned long)elf64ph
->p_offset
);
61 void get4k(FILE *file
, char *buf
)
64 unsigned num
= fread(buf
, 1, 4096, file
);
65 for ( j
=num
; j
<4096; ++j
)
69 void put4k(FILE *file
, char *buf
)
71 fwrite(buf
, 1, 4096, file
);
74 void death(const char *msg
, FILE *fdesc
, const char *fname
)
82 int main(int argc
, char **argv
)
85 struct addr_range vmlinux
;
90 char *rd_name
, *lx_name
, *out_name
;
93 unsigned long ramFileLen
;
96 unsigned long offset_end
;
98 unsigned long kernelLen
;
99 unsigned long actualKernelLen
;
101 unsigned long roundedKernelLen
;
102 unsigned long ramStartOffs
;
103 unsigned long ramPages
;
104 unsigned long roundedKernelPages
;
105 unsigned long hvReleaseData
;
106 u_int32_t eyeCatcher
= 0xc8a5d9c4;
108 unsigned long xRamDisk
;
109 unsigned long xRamDiskSize
;
114 fprintf(stderr
, "Name of RAM disk file missing.\n");
120 fprintf(stderr
, "Name of vmlinux file missing.\n");
126 fprintf(stderr
, "Name of vmlinux output file missing.\n");
132 ramDisk
= fopen(rd_name
, "r");
134 fprintf(stderr
, "RAM disk file \"%s\" failed to open.\n", rd_name
);
138 inputVmlinux
= fopen(lx_name
, "r");
139 if ( ! inputVmlinux
) {
140 fprintf(stderr
, "vmlinux file \"%s\" failed to open.\n", lx_name
);
144 outputVmlinux
= fopen(out_name
, "w+");
145 if ( ! outputVmlinux
) {
146 fprintf(stderr
, "output vmlinux file \"%s\" failed to open.\n", out_name
);
150 i
= fread(inbuf
, 1, sizeof(inbuf
), inputVmlinux
);
151 if (i
!= sizeof(inbuf
)) {
152 fprintf(stderr
, "can not read vmlinux file %s: %u\n", lx_name
, i
);
156 i
= check_elf64(inbuf
, sizeof(inbuf
), &vmlinux
);
158 fprintf(stderr
, "You must have a linux kernel specified as argv[2]\n");
162 /* Input Vmlinux file */
163 fseek(inputVmlinux
, 0, SEEK_END
);
164 kernelLen
= ftell(inputVmlinux
);
165 fseek(inputVmlinux
, 0, SEEK_SET
);
166 printf("kernel file size = %lu\n", kernelLen
);
168 actualKernelLen
= kernelLen
- ElfHeaderSize
;
170 printf("actual kernel length (minus ELF header) = %lu\n", actualKernelLen
);
172 round
= actualKernelLen
% 4096;
173 roundedKernelLen
= actualKernelLen
;
175 roundedKernelLen
+= (4096 - round
);
176 printf("Vmlinux length rounded up to a 4k multiple = %ld/0x%lx \n", roundedKernelLen
, roundedKernelLen
);
177 roundedKernelPages
= roundedKernelLen
/ 4096;
178 printf("Vmlinux pages to copy = %ld/0x%lx \n", roundedKernelPages
, roundedKernelPages
);
180 offset_end
= _ALIGN_UP(vmlinux
.memsize
, 4096);
181 /* calc how many pages we need to insert between the vmlinux and the start of the ram disk */
182 padPages
= offset_end
/4096 - roundedKernelPages
;
184 /* Check and see if the vmlinux is already larger than _end in System.map */
186 /* vmlinux is larger than _end - adjust the offset to the start of the embedded ram disk */
187 offset_end
= roundedKernelLen
;
188 printf("vmlinux is larger than _end indicates it needs to be - offset_end = %lx \n", offset_end
);
190 printf("will insert %lx pages between the vmlinux and the start of the ram disk \n", padPages
);
193 /* _end is larger than vmlinux - use the offset to _end that we calculated from the system map */
194 printf("vmlinux is smaller than _end indicates is needed - offset_end = %lx \n", offset_end
);
195 printf("will insert %lx pages between the vmlinux and the start of the ram disk \n", padPages
);
200 /* Input Ram Disk file */
201 // Set the offset that the ram disk will be started at.
202 ramStartOffs
= offset_end
; /* determined from the input vmlinux file and the system map */
203 printf("Ram Disk will start at offset = 0x%lx \n", ramStartOffs
);
205 fseek(ramDisk
, 0, SEEK_END
);
206 ramFileLen
= ftell(ramDisk
);
207 fseek(ramDisk
, 0, SEEK_SET
);
208 printf("%s file size = %ld/0x%lx \n", rd_name
, ramFileLen
, ramFileLen
);
212 roundR
= 4096 - (ramLen
% 4096);
214 printf("Rounding RAM disk file up to a multiple of 4096, adding %ld/0x%lx \n", roundR
, roundR
);
218 printf("Rounded RAM disk size is %ld/0x%lx \n", ramLen
, ramLen
);
219 ramPages
= ramLen
/ 4096;
220 printf("RAM disk pages to copy = %ld/0x%lx\n", ramPages
, ramPages
);
224 // Copy 64K ELF header
225 for (i
=0; i
<(ElfPages
); ++i
) {
226 get4k( inputVmlinux
, inbuf
);
227 put4k( outputVmlinux
, inbuf
);
230 /* Copy the vmlinux (as full pages). */
231 fseek(inputVmlinux
, ElfHeaderSize
, SEEK_SET
);
232 for ( i
=0; i
<roundedKernelPages
; ++i
) {
233 get4k( inputVmlinux
, inbuf
);
234 put4k( outputVmlinux
, inbuf
);
237 /* Insert pad pages (if appropriate) that are needed between */
238 /* | the end of the vmlinux and the ram disk. */
239 for (i
=0; i
<padPages
; ++i
) {
240 memset(inbuf
, 0, 4096);
241 put4k(outputVmlinux
, inbuf
);
244 /* Copy the ram disk (as full pages). */
245 for ( i
=0; i
<ramPages
; ++i
) {
246 get4k( ramDisk
, inbuf
);
247 put4k( outputVmlinux
, inbuf
);
250 /* Close the input files */
252 fclose(inputVmlinux
);
253 /* And flush the written output file */
254 fflush(outputVmlinux
);
258 /* Fixup the new vmlinux to contain the ram disk starting offset (xRamDisk) and the ram disk size (xRamDiskSize) */
259 /* fseek to the hvReleaseData pointer */
260 fseek(outputVmlinux
, ElfHeaderSize
+ 0x24, SEEK_SET
);
261 if (fread(&hvReleaseData
, 4, 1, outputVmlinux
) != 1) {
262 death("Could not read hvReleaseData pointer\n", outputVmlinux
, out_name
);
264 hvReleaseData
= ntohl(hvReleaseData
); /* Convert to native int */
265 printf("hvReleaseData is at %08lx\n", hvReleaseData
);
267 /* fseek to the hvReleaseData */
268 fseek(outputVmlinux
, ElfHeaderSize
+ hvReleaseData
, SEEK_SET
);
269 if (fread(inbuf
, 0x40, 1, outputVmlinux
) != 1) {
270 death("Could not read hvReleaseData\n", outputVmlinux
, out_name
);
272 /* Check hvReleaseData sanity */
273 if (memcmp(inbuf
, &eyeCatcher
, 4) != 0) {
274 death("hvReleaseData is invalid\n", outputVmlinux
, out_name
);
276 /* Get the naca pointer */
277 naca
= ntohl(*((u_int32_t
*) &inbuf
[0x0C])) - KERNELBASE
;
278 printf("Naca is at offset 0x%lx \n", naca
);
280 /* fseek to the naca */
281 fseek(outputVmlinux
, ElfHeaderSize
+ naca
, SEEK_SET
);
282 if (fread(inbuf
, 0x18, 1, outputVmlinux
) != 1) {
283 death("Could not read naca\n", outputVmlinux
, out_name
);
285 xRamDisk
= ntohl(*((u_int32_t
*) &inbuf
[0x0c]));
286 xRamDiskSize
= ntohl(*((u_int32_t
*) &inbuf
[0x14]));
287 /* Make sure a RAM disk isn't already present */
288 if ((xRamDisk
!= 0) || (xRamDiskSize
!= 0)) {
289 death("RAM disk is already attached to this kernel\n", outputVmlinux
, out_name
);
291 /* Fill in the values */
292 *((u_int32_t
*) &inbuf
[0x0c]) = htonl(ramStartOffs
);
293 *((u_int32_t
*) &inbuf
[0x14]) = htonl(ramPages
);
295 /* Write out the new naca */
296 fflush(outputVmlinux
);
297 fseek(outputVmlinux
, ElfHeaderSize
+ naca
, SEEK_SET
);
298 if (fwrite(inbuf
, 0x18, 1, outputVmlinux
) != 1) {
299 death("Could not write naca\n", outputVmlinux
, out_name
);
301 printf("Ram Disk of 0x%lx pages is attached to the kernel at offset 0x%08lx\n",
302 ramPages
, ramStartOffs
);
305 fclose(outputVmlinux
);
306 /* Set permission to executable */
307 chmod(out_name
, S_IRUSR
|S_IWUSR
|S_IXUSR
|S_IRGRP
|S_IXGRP
|S_IROTH
|S_IXOTH
);