OpenCores
URL https://opencores.org/ocsvn/or1k_soc_on_altera_embedded_dev_kit/or1k_soc_on_altera_embedded_dev_kit/trunk

Subversion Repositories or1k_soc_on_altera_embedded_dev_kit

[/] [or1k_soc_on_altera_embedded_dev_kit/] [trunk/] [linux-2.6/] [linux-2.6.24/] [arch/] [powerpc/] [boot/] [addRamDisk.c] - Blame information for rev 3

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 3 xianfeng
#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
#include <elf.h>
9
 
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)))
14
 
15
struct addr_range {
16
        unsigned long long addr;
17
        unsigned long memsize;
18
        unsigned long offset;
19
};
20
 
21
static int check_elf64(void *p, int size, struct addr_range *r)
22
{
23
        Elf64_Ehdr *elf64 = p;
24
        Elf64_Phdr *elf64ph;
25
 
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)
33
                return 0;
34
 
35
        if ((elf64->e_phoff + sizeof(Elf64_Phdr)) > size)
36
                return 0;
37
 
38
        elf64ph = (Elf64_Phdr *) ((unsigned long)elf64 +
39
                                  (unsigned long)elf64->e_phoff);
40
 
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;
44
 
45
#ifdef DEBUG
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);
57
#endif
58
 
59
        return 64;
60
}
61
void get4k(FILE *file, char *buf )
62
{
63
        unsigned j;
64
        unsigned num = fread(buf, 1, 4096, file);
65
        for ( j=num; j<4096; ++j )
66
                buf[j] = 0;
67
}
68
 
69
void put4k(FILE *file, char *buf )
70
{
71
        fwrite(buf, 1, 4096, file);
72
}
73
 
74
void death(const char *msg, FILE *fdesc, const char *fname)
75
{
76
        fprintf(stderr, msg);
77
        fclose(fdesc);
78
        unlink(fname);
79
        exit(1);
80
}
81
 
82
int main(int argc, char **argv)
83
{
84
        char inbuf[4096];
85
        struct addr_range vmlinux;
86
        FILE *ramDisk;
87
        FILE *inputVmlinux;
88
        FILE *outputVmlinux;
89
 
90
        char *rd_name, *lx_name, *out_name;
91
 
92
        size_t i;
93
        unsigned long ramFileLen;
94
        unsigned long ramLen;
95
        unsigned long roundR;
96
        unsigned long offset_end;
97
 
98
        unsigned long kernelLen;
99
        unsigned long actualKernelLen;
100
        unsigned long round;
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;
107
        unsigned long naca;
108
        unsigned long xRamDisk;
109
        unsigned long xRamDiskSize;
110
        long padPages;
111
 
112
 
113
        if (argc < 2) {
114
                fprintf(stderr, "Name of RAM disk file missing.\n");
115
                exit(1);
116
        }
117
        rd_name = argv[1];
118
 
119
        if (argc < 3) {
120
                fprintf(stderr, "Name of vmlinux file missing.\n");
121
                exit(1);
122
        }
123
        lx_name = argv[2];
124
 
125
        if (argc < 4) {
126
                fprintf(stderr, "Name of vmlinux output file missing.\n");
127
                exit(1);
128
        }
129
        out_name = argv[3];
130
 
131
 
132
        ramDisk = fopen(rd_name, "r");
133
        if ( ! ramDisk ) {
134
                fprintf(stderr, "RAM disk file \"%s\" failed to open.\n", rd_name);
135
                exit(1);
136
        }
137
 
138
        inputVmlinux = fopen(lx_name, "r");
139
        if ( ! inputVmlinux ) {
140
                fprintf(stderr, "vmlinux file \"%s\" failed to open.\n", lx_name);
141
                exit(1);
142
        }
143
 
144
        outputVmlinux = fopen(out_name, "w+");
145
        if ( ! outputVmlinux ) {
146
                fprintf(stderr, "output vmlinux file \"%s\" failed to open.\n", out_name);
147
                exit(1);
148
        }
149
 
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);
153
                exit(1);
154
        }
155
 
156
        i = check_elf64(inbuf, sizeof(inbuf), &vmlinux);
157
        if (i == 0) {
158
                fprintf(stderr, "You must have a linux kernel specified as argv[2]\n");
159
                exit(1);
160
        }
161
 
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);
167
 
168
        actualKernelLen = kernelLen - ElfHeaderSize;
169
 
170
        printf("actual kernel length (minus ELF header) = %lu\n", actualKernelLen);
171
 
172
        round = actualKernelLen % 4096;
173
        roundedKernelLen = actualKernelLen;
174
        if ( round )
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);
179
 
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;
183
 
184
        /* Check and see if the vmlinux is already larger than _end in System.map */
185
        if (padPages < 0) {
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);
189
                padPages = 0;
190
                printf("will insert %lx pages between the vmlinux and the start of the ram disk \n", padPages);
191
        }
192
        else {
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);
196
        }
197
 
198
 
199
 
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);
204
 
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);
209
 
210
        ramLen = ramFileLen;
211
 
212
        roundR = 4096 - (ramLen % 4096);
213
        if ( roundR ) {
214
                printf("Rounding RAM disk file up to a multiple of 4096, adding %ld/0x%lx \n", roundR, roundR);
215
                ramLen += roundR;
216
        }
217
 
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);
221
 
222
 
223
 
224
  // Copy 64K ELF header
225
        for (i=0; i<(ElfPages); ++i) {
226
                get4k( inputVmlinux, inbuf );
227
                put4k( outputVmlinux, inbuf );
228
        }
229
 
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 );
235
        }
236
 
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);
242
        }
243
 
244
        /* Copy the ram disk (as full pages). */
245
        for ( i=0; i<ramPages; ++i ) {
246
                get4k( ramDisk, inbuf );
247
                put4k( outputVmlinux, inbuf );
248
        }
249
 
250
        /* Close the input files */
251
        fclose(ramDisk);
252
        fclose(inputVmlinux);
253
        /* And flush the written output file */
254
        fflush(outputVmlinux);
255
 
256
 
257
 
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);
263
        }
264
        hvReleaseData = ntohl(hvReleaseData); /* Convert to native int */
265
        printf("hvReleaseData is at %08lx\n", hvReleaseData);
266
 
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);
271
        }
272
        /* Check hvReleaseData sanity */
273
        if (memcmp(inbuf, &eyeCatcher, 4) != 0) {
274
                death("hvReleaseData is invalid\n", outputVmlinux, out_name);
275
        }
276
        /* Get the naca pointer */
277
        naca = ntohl(*((u_int32_t*) &inbuf[0x0C])) - KERNELBASE;
278
        printf("Naca is at offset 0x%lx \n", naca);
279
 
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);
284
        }
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);
290
        }
291
        /* Fill in the values */
292
        *((u_int32_t *) &inbuf[0x0c]) = htonl(ramStartOffs);
293
        *((u_int32_t *) &inbuf[0x14]) = htonl(ramPages);
294
 
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);
300
        }
301
        printf("Ram Disk of 0x%lx pages is attached to the kernel at offset 0x%08lx\n",
302
               ramPages, ramStartOffs);
303
 
304
        /* Done */
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);
308
 
309
        return 0;
310
}
311
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.