linux-old/arch/ppc64/boot/addRamDisk.c
<<
>>
Prefs
   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 (0xc000000000000000)
  12
  13void 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
  21void put4k(FILE *file, char *buf )
  22{
  23        fwrite(buf, 1, 4096, file);
  24}
  25
  26void death(const char *msg, FILE *fdesc, const char *fname) 
  27{
  28        fprintf(stderr, msg);
  29        fclose(fdesc);
  30        unlink(fname);
  31        exit(1);
  32}
  33
  34int main(int argc, char **argv)
  35{
  36        char inbuf[4096];
  37        FILE *ramDisk = NULL;
  38        FILE *sysmap = NULL;
  39        FILE *inputVmlinux = NULL;
  40        FILE *outputVmlinux = NULL;
  41  
  42        unsigned i = 0;
  43        unsigned long ramFileLen = 0;
  44        unsigned long ramLen = 0;
  45        unsigned long roundR = 0;
  46  
  47        unsigned long sysmapFileLen = 0;
  48        unsigned long sysmapLen = 0;
  49        unsigned long sysmapPages = 0;
  50        char* ptr_end = NULL; 
  51        unsigned long offset_end = 0;
  52
  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;
  65        long padPages = 0;
  66  
  67  
  68        if (argc < 2) {
  69                fprintf(stderr, "Name of RAM disk file missing.\n");
  70                exit(1);
  71        }
  72
  73        if (argc < 3) {
  74                fprintf(stderr, "Name of System Map input file is missing.\n");
  75                exit(1);
  76        }
  77  
  78        if (argc < 4) {
  79                fprintf(stderr, "Name of vmlinux file missing.\n");
  80                exit(1);
  81        }
  82
  83        if (argc < 5) {
  84                fprintf(stderr, "Name of vmlinux output file missing.\n");
  85                exit(1);
  86        }
  87
  88
  89        ramDisk = fopen(argv[1], "r");
  90        if ( ! ramDisk ) {
  91                fprintf(stderr, "RAM disk file \"%s\" failed to open.\n", argv[1]);
  92                exit(1);
  93        }
  94
  95        sysmap = fopen(argv[2], "r");
  96        if ( ! sysmap ) {
  97                fprintf(stderr, "System Map file \"%s\" failed to open.\n", argv[2]);
  98                exit(1);
  99        }
 100  
 101        inputVmlinux = fopen(argv[3], "r");
 102        if ( ! inputVmlinux ) {
 103                fprintf(stderr, "vmlinux file \"%s\" failed to open.\n", argv[3]);
 104                exit(1);
 105        }
 106  
 107        outputVmlinux = fopen(argv[4], "w+");
 108        if ( ! outputVmlinux ) {
 109                fprintf(stderr, "output vmlinux file \"%s\" failed to open.\n", argv[4]);
 110                exit(1);
 111        }
 112  
 113  
 114  
 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");
 122                exit(1);
 123        }
 124
 125        actualKernelLen = kernelLen - ElfHeaderSize;
 126
 127        printf("actual kernel length (minus ELF header) = %d\n", actualKernelLen);
 128
 129        round = actualKernelLen % 4096;
 130        roundedKernelLen = actualKernelLen;
 131        if ( round )
 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);
 136
 137
 138
 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);
 145
 146        sysmapLen = sysmapFileLen;
 147
 148        roundR = 4096 - (sysmapLen % 4096);
 149        if (roundR) {
 150                printf("Rounding System Map file up to a multiple of 4096, adding %ld/0x%lx \n", roundR, roundR);
 151                sysmapLen += roundR;
 152        }
 153        printf("Rounded System Map size is %ld/0x%lx \n", sysmapLen, sysmapLen);
 154  
 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 doesnt 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");
 161        if (!ptr_end) {
 162                fprintf(stderr, "Unable to find _end in the sysmap file \n");
 163                fprintf(stderr, "inbuf: \n");
 164                fprintf(stderr, "%s \n", inbuf);
 165                exit(1);
 166        }
 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;
 172
 173        /* Check and see if the vmlinux is already larger than _end in System.map */
 174        if (padPages < 0) {
 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);
 178                padPages = 0;
 179                printf("will insert %lx pages between the vmlinux and the start of the ram disk \n", padPages);
 180        }
 181        else {
 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);
 185        }
 186
 187
 188
 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);
 193  
 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);
 198
 199        ramLen = ramFileLen;
 200
 201        roundR = 4096 - (ramLen % 4096);
 202        if ( roundR ) {
 203                printf("Rounding RAM disk file up to a multiple of 4096, adding %ld/0x%lx \n", roundR, roundR);
 204                ramLen += roundR;
 205        }
 206
 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);
 210
 211
 212
 213  // Copy 64K ELF header
 214        for (i=0; i<(ElfPages); ++i) {
 215                get4k( inputVmlinux, inbuf );
 216                put4k( outputVmlinux, inbuf );
 217        }
 218
 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 );
 224        }
 225  
 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);
 231        }
 232
 233        /* Copy the ram disk (as full pages). */
 234        for ( i=0; i<ramPages; ++i ) {
 235                get4k( ramDisk, inbuf );
 236                put4k( outputVmlinux, inbuf );
 237        }
 238
 239        /* Close the input files */
 240        fclose(ramDisk);
 241        fclose(inputVmlinux);
 242        /* And flush the written output file */
 243        fflush(outputVmlinux);
 244
 245
 246
 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]);
 252        }
 253        hvReleaseData = ntohl(hvReleaseData); /* Convert to native int */
 254        printf("hvReleaseData is at %08x\n", hvReleaseData);
 255
 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]);
 260        }
 261        /* Check hvReleaseData sanity */
 262        if (ntohl(*(u_int32_t *)inbuf) != eyeCatcher) {
 263                death("hvReleaseData is invalid\n", outputVmlinux, argv[4]);
 264        }
 265        /* Get the naca pointer */
 266        naca = ntohl(*((u_int32_t*) &inbuf[0x0C])) - KERNELBASE;
 267        printf("Naca is at offset 0x%lx \n", naca);
 268
 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]);
 273        }
 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]);
 279        }
 280        /* Fill in the values */
 281        *((u_int32_t *) &inbuf[0x0c]) = htonl(ramStartOffs);
 282        *((u_int32_t *) &inbuf[0x14]) = htonl(ramPages);
 283
 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]);
 289        }
 290        printf("Ram Disk of 0x%lx pages is attached to the kernel at offset 0x%08x\n",
 291               ramPages, ramStartOffs);
 292
 293        /* Done */
 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);
 297
 298        return 0;
 299}
 300
 301
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.