Merge with rsync://fileserver/linux
[linux-3.10.git] / arch / ppc / boot / utils / addRamDisk.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <netinet/in.h>
4 #include <unistd.h>
5 #include <sys/types.h>
6 #include <sys/stat.h>
7 #include <string.h>
8
9 #define ElfHeaderSize  (64 * 1024)
10 #define ElfPages  (ElfHeaderSize / 4096)
11 #define KERNELBASE (0xc0000000)
12
13 void get4k(FILE *file, char *buf )
14 {
15     unsigned j;
16     unsigned num = fread(buf, 1, 4096, file);
17     for (  j=num; j<4096; ++j )
18         buf[j] = 0;
19 }
20
21 void put4k(FILE *file, char *buf )
22 {
23     fwrite(buf, 1, 4096, file);
24 }
25
26 void death(const char *msg, FILE *fdesc, const char *fname)
27 {
28     printf(msg);
29     fclose(fdesc);
30     unlink(fname);
31     exit(1);
32 }
33
34 int main(int argc, char **argv)
35 {
36     char inbuf[4096];
37     FILE *ramDisk = NULL;
38     FILE *inputVmlinux = NULL;
39     FILE *outputVmlinux = NULL;
40     unsigned i = 0;
41     u_int32_t ramFileLen = 0;
42     u_int32_t ramLen = 0;
43     u_int32_t roundR = 0;
44     u_int32_t kernelLen = 0;
45     u_int32_t actualKernelLen = 0;
46     u_int32_t round = 0;
47     u_int32_t roundedKernelLen = 0;
48     u_int32_t ramStartOffs = 0;
49     u_int32_t ramPages = 0;
50     u_int32_t roundedKernelPages = 0;
51     u_int32_t hvReleaseData = 0;
52     u_int32_t eyeCatcher = 0xc8a5d9c4;
53     u_int32_t naca = 0;
54     u_int32_t xRamDisk = 0;
55     u_int32_t xRamDiskSize = 0;
56     if ( argc < 2 ) {
57         printf("Name of RAM disk file missing.\n");
58         exit(1);
59     }
60
61     if ( argc < 3 ) {
62         printf("Name of vmlinux file missing.\n");
63         exit(1);
64     }
65
66     if ( argc < 4 ) {
67         printf("Name of vmlinux output file missing.\n");
68         exit(1);
69     }
70
71     ramDisk = fopen(argv[1], "r");
72     if ( ! ramDisk ) {
73         printf("RAM disk file \"%s\" failed to open.\n", argv[1]);
74         exit(1);
75     }
76     inputVmlinux = fopen(argv[2], "r");
77     if ( ! inputVmlinux ) {
78         printf("vmlinux file \"%s\" failed to open.\n", argv[2]);
79         exit(1);
80     }
81     outputVmlinux = fopen(argv[3], "w+");
82     if ( ! outputVmlinux ) {
83         printf("output vmlinux file \"%s\" failed to open.\n", argv[3]);
84         exit(1);
85     }
86     fseek(ramDisk, 0, SEEK_END);
87     ramFileLen = ftell(ramDisk);
88     fseek(ramDisk, 0, SEEK_SET);
89     printf("%s file size = %d\n", argv[1], ramFileLen);
90
91     ramLen = ramFileLen;
92
93     roundR = 4096 - (ramLen % 4096);
94     if ( roundR ) {
95         printf("Rounding RAM disk file up to a multiple of 4096, adding %d\n", roundR);
96         ramLen += roundR;
97     }
98
99     printf("Rounded RAM disk size is %d\n", ramLen);
100     fseek(inputVmlinux, 0, SEEK_END);
101     kernelLen = ftell(inputVmlinux);
102     fseek(inputVmlinux, 0, SEEK_SET);
103     printf("kernel file size = %d\n", kernelLen);
104     if ( kernelLen == 0 ) {
105         printf("You must have a linux kernel specified as argv[2]\n");
106         exit(1);
107     }
108
109     actualKernelLen = kernelLen - ElfHeaderSize;
110
111     printf("actual kernel length (minus ELF header) = %d\n", actualKernelLen);
112
113     round = actualKernelLen % 4096;
114     roundedKernelLen = actualKernelLen;
115     if ( round )
116         roundedKernelLen += (4096 - round);
117
118     printf("actual kernel length rounded up to a 4k multiple = %d\n", roundedKernelLen);
119
120     ramStartOffs = roundedKernelLen;
121     ramPages = ramLen / 4096;
122
123     printf("RAM disk pages to copy = %d\n", ramPages);
124
125     // Copy 64K ELF header
126       for (i=0; i<(ElfPages); ++i) {
127           get4k( inputVmlinux, inbuf );
128           put4k( outputVmlinux, inbuf );
129       }
130
131     roundedKernelPages = roundedKernelLen / 4096;
132
133     fseek(inputVmlinux, ElfHeaderSize, SEEK_SET);
134
135     for ( i=0; i<roundedKernelPages; ++i ) {
136         get4k( inputVmlinux, inbuf );
137         put4k( outputVmlinux, inbuf );
138     }
139
140     for ( i=0; i<ramPages; ++i ) {
141         get4k( ramDisk, inbuf );
142         put4k( outputVmlinux, inbuf );
143     }
144
145     /* Close the input files */
146     fclose(ramDisk);
147     fclose(inputVmlinux);
148     /* And flush the written output file */
149     fflush(outputVmlinux);
150
151     /* fseek to the hvReleaseData pointer */
152     fseek(outputVmlinux, ElfHeaderSize + 0x24, SEEK_SET);
153     if (fread(&hvReleaseData, 4, 1, outputVmlinux) != 1) {
154         death("Could not read hvReleaseData pointer\n", outputVmlinux, argv[3]);
155     }
156     hvReleaseData = ntohl(hvReleaseData); /* Convert to native int */
157     printf("hvReleaseData is at %08x\n", hvReleaseData);
158
159     /* fseek to the hvReleaseData */
160     fseek(outputVmlinux, ElfHeaderSize + hvReleaseData, SEEK_SET);
161     if (fread(inbuf, 0x40, 1, outputVmlinux) != 1) {
162         death("Could not read hvReleaseData\n", outputVmlinux, argv[3]);
163     }
164     /* Check hvReleaseData sanity */
165     if (memcmp(inbuf, &eyeCatcher, 4) != 0) {
166         death("hvReleaseData is invalid\n", outputVmlinux, argv[3]);
167     }
168     /* Get the naca pointer */
169     naca = ntohl(*((u_int32_t *) &inbuf[0x0c])) - KERNELBASE;
170     printf("naca is at %08x\n", naca);
171
172     /* fseek to the naca */
173     fseek(outputVmlinux, ElfHeaderSize + naca, SEEK_SET);
174     if (fread(inbuf, 0x18, 1, outputVmlinux) != 1) {
175         death("Could not read naca\n", outputVmlinux, argv[3]);
176     }
177     xRamDisk = ntohl(*((u_int32_t *) &inbuf[0x0c]));
178     xRamDiskSize = ntohl(*((u_int32_t *) &inbuf[0x14]));
179     /* Make sure a RAM disk isn't already present */
180     if ((xRamDisk != 0) || (xRamDiskSize != 0)) {
181         death("RAM disk is already attached to this kernel\n", outputVmlinux, argv[3]);
182     }
183     /* Fill in the values */
184     *((u_int32_t *) &inbuf[0x0c]) = htonl(ramStartOffs);
185     *((u_int32_t *) &inbuf[0x14]) = htonl(ramPages);
186
187     /* Write out the new naca */
188     fflush(outputVmlinux);
189     fseek(outputVmlinux, ElfHeaderSize + naca, SEEK_SET);
190     if (fwrite(inbuf, 0x18, 1, outputVmlinux) != 1) {
191         death("Could not write naca\n", outputVmlinux, argv[3]);
192     }
193     printf("RAM Disk of 0x%x pages size is attached to the kernel at offset 0x%08x\n",
194             ramPages, ramStartOffs);
195
196     /* Done */
197     fclose(outputVmlinux);
198     /* Set permission to executable */
199     chmod(argv[3], S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH);
200
201     return 0;
202 }
203