1#include <stdio.h> 2#include <stdlib.h> 3#include <byteswap.h> 4#include <sys/types.h> 5#include <sys/stat.h> 6#include <string.h> 7 8void xlate( char * inb, char * trb, unsigned len ) 9{ 10 unsigned i; 11 for ( i=0; i<len; ++i ) 12 { 13 char c = *inb++; 14 char c1 = c >> 4; 15 char c2 = c & 0xf; 16 if ( c1 > 9 ) 17 c1 = c1 + 'A' - 10; 18 else 19 c1 = c1 + '0'; 20 if ( c2 > 9 ) 21 c2 = c2 + 'A' - 10; 22 else 23 c2 = c2 + '0'; 24 *trb++ = c1; 25 *trb++ = c2; 26 } 27 *trb = 0; 28} 29 30#define ElfHeaderSize (64 * 1024) 31#define ElfPages (ElfHeaderSize / 4096) 32 33void get4k( /*istream *inf*/FILE *file, char *buf ) 34{ 35 unsigned j; 36 unsigned num = fread(buf, 1, 4096, file); 37 for ( j=num; j<4096; ++j ) 38 buf[j] = 0; 39} 40 41void put4k( /*ostream *outf*/FILE *file, char *buf ) 42{ 43 fwrite(buf, 1, 4096, file); 44} 45 46int main(int argc, char **argv) 47{ 48 char inbuf[4096]; 49 FILE *sysmap = NULL; 50 char* ptr_end = NULL; 51 FILE *inputVmlinux = NULL; 52 FILE *outputVmlinux = NULL; 53 long i = 0; 54 unsigned long sysmapFileLen = 0; 55 unsigned long sysmapLen = 0; 56 unsigned long roundR = 0; 57 unsigned long kernelLen = 0; 58 unsigned long actualKernelLen = 0; 59 unsigned long round = 0; 60 unsigned long roundedKernelLen = 0; 61 unsigned long sysmapStartOffs = 0; 62 unsigned long sysmapPages = 0; 63 unsigned long roundedKernelPages = 0; 64 long padPages = 0; 65 if ( argc < 2 ) 66 { 67 fprintf(stderr, "Name of System Map file missing.\n"); 68 exit(1); 69 } 70 71 if ( argc < 3 ) 72 { 73 fprintf(stderr, "Name of vmlinux file missing.\n"); 74 exit(1); 75 } 76 77 if ( argc < 4 ) 78 { 79 fprintf(stderr, "Name of vmlinux output file missing.\n"); 80 exit(1); 81 } 82 83 sysmap = fopen(argv[1], "r"); 84 if ( ! sysmap ) 85 { 86 fprintf(stderr, "System Map file \"%s\" failed to open.\n", argv[1]); 87 exit(1); 88 } 89 inputVmlinux = fopen(argv[2], "r"); 90 if ( ! inputVmlinux ) 91 { 92 fprintf(stderr, "vmlinux file \"%s\" failed to open.\n", argv[2]); 93 exit(1); 94 } 95 outputVmlinux = fopen(argv[3], "w"); 96 if ( ! outputVmlinux ) 97 { 98 fprintf(stderr, "output vmlinux file \"%s\" failed to open.\n", argv[3]); 99 exit(1); 100 } 101 102 103 104 fseek(inputVmlinux, 0, SEEK_END); 105 kernelLen = ftell(inputVmlinux); 106 fseek(inputVmlinux, 0, SEEK_SET); 107 printf("kernel file size = %ld\n", kernelLen); 108 if ( kernelLen == 0 ) 109 { 110 fprintf(stderr, "You must have a linux kernel specified as argv[2]\n"); 111 exit(1); 112 } 113 114 115 actualKernelLen = kernelLen - ElfHeaderSize; 116 117 printf("actual kernel length (minus ELF header) = %ld/%lxx \n", actualKernelLen, actualKernelLen); 118 119 round = actualKernelLen % 4096; 120 roundedKernelLen = actualKernelLen; 121 if ( round ) 122 roundedKernelLen += (4096 - round); 123 124 printf("Kernel length rounded up to a 4k multiple = %ld/%lxx \n", roundedKernelLen, roundedKernelLen); 125 roundedKernelPages = roundedKernelLen / 4096; 126 printf("Kernel pages to copy = %ld/%lxx\n", roundedKernelPages, roundedKernelPages); 127 128 129 130 /* Sysmap file */ 131 fseek(sysmap, 0, SEEK_END); 132 sysmapFileLen = ftell(sysmap); 133 fseek(sysmap, 0, SEEK_SET); 134 printf("%s file size = %ld\n", argv[1], sysmapFileLen); 135 136 sysmapLen = sysmapFileLen; 137 138 roundR = 4096 - (sysmapLen % 4096); 139 if (roundR) 140 { 141 printf("Rounding System Map file up to a multiple of 4096, adding %ld\n", roundR); 142 sysmapLen += roundR; 143 } 144 printf("Rounded System Map size is %ld\n", sysmapLen); 145 146 /* Process the Sysmap file to determine the true end of the kernel */ 147 sysmapPages = sysmapLen / 4096; 148 printf("System map pages to copy = %ld\n", sysmapPages); 149 for (i=0; i<sysmapPages; ++i) 150 { 151 get4k(sysmap, inbuf); 152 } 153 /* search for _end in the last page of the system map */ 154 ptr_end = strstr(inbuf, " _end"); 155 if (!ptr_end) 156 { 157 fprintf(stderr, "Unable to find _end in the sysmap file \n"); 158 fprintf(stderr, "inbuf: \n"); 159 fprintf(stderr, "%s \n", inbuf); 160 exit(1); 161 } 162 printf("Found _end in the last page of the sysmap - backing up 10 characters it looks like %s", ptr_end-10); 163 sysmapStartOffs = (unsigned int)strtol(ptr_end-10, NULL, 16); 164 /* calc how many pages we need to insert between the vmlinux and the start of the sysmap */ 165 padPages = sysmapStartOffs/4096 - roundedKernelPages; 166 167 /* Check and see if the vmlinux is larger than _end in System.map */ 168 if (padPages < 0) 169 { /* vmlinux is larger than _end - adjust the offset to start the embedded system map */ 170 sysmapStartOffs = roundedKernelLen; 171 printf("vmlinux is larger than _end indicates it needs to be - sysmapStartOffs = %lx \n", sysmapStartOffs); 172 padPages = 0; 173 printf("will insert %lx pages between the vmlinux and the start of the sysmap \n", padPages); 174 } 175 else 176 { /* _end is larger than vmlinux - use the sysmapStartOffs we calculated from the system map */ 177 printf("vmlinux is smaller than _end indicates is needed - sysmapStartOffs = %lx \n", sysmapStartOffs); 178 printf("will insert %lx pages between the vmlinux and the start of the sysmap \n", padPages); 179 } 180 181 182 183 184 /* Copy 64K ELF header */ 185 for (i=0; i<(ElfPages); ++i) 186 { 187 get4k( inputVmlinux, inbuf ); 188 put4k( outputVmlinux, inbuf ); 189 } 190 191 192 /* Copy the vmlinux (as full pages). */ 193 fseek(inputVmlinux, ElfHeaderSize, SEEK_SET); 194 for ( i=0; i<roundedKernelPages; ++i ) 195 { 196 get4k( inputVmlinux, inbuf ); 197 198 /* Set the offsets (of the start and end) of the embedded sysmap so it is set in the vmlinux.sm */ 199 if ( i == 0 ) 200 { 201 unsigned long * p; 202 printf("Storing embedded_sysmap_start at 0x3c\n"); 203 p = (unsigned long *)(inbuf + 0x3c); 204 205#if BYTE_ORDER == __BIG_ENDIAN 206 *p = sysmapStartOffs; 207#else 208 *p = bswap_32(sysmapStartOffs); 209#endif 210 211 printf("Storing embedded_sysmap_end at 0x44\n"); 212 p = (unsigned long *)(inbuf + 0x44); 213 214#if BYTE_ORDER == __BIG_ENDIAN 215 *p = sysmapStartOffs + sysmapFileLen; 216#else 217 *p = bswap_32(sysmapStartOffs + sysmapFileLen); 218#endif 219 } 220 221 put4k( outputVmlinux, inbuf ); 222 } 223 224 225 /* Insert any pad pages between the end of the vmlinux and where the system map needs to be. */ 226 for (i=0; i<padPages; ++i) 227 { 228 memset(inbuf, 0, 4096); 229 put4k(outputVmlinux, inbuf); 230 } 231 232 233 /* Copy the system map (as full pages). */ 234 fseek(sysmap, 0, SEEK_SET); /* start reading from begining of the system map */ 235 for ( i=0; i<sysmapPages; ++i ) 236 { 237 get4k( sysmap, inbuf ); 238 put4k( outputVmlinux, inbuf ); 239 } 240 241 242 fclose(sysmap); 243 fclose(inputVmlinux); 244 fclose(outputVmlinux); 245 /* Set permission to executable */ 246 chmod(argv[3], S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH); 247 248 return 0; 249} 250 251