1#include <stdarg.h>
2#include <errno.h>
3#include <string.h>
4#include <stdint.h>
5#include <stdlib.h>
6#include <sys/types.h>
7#include <sys/stat.h>
8#include <fcntl.h>
9#include <unistd.h>
10#include <stdio.h>
11#include <getopt.h>
12#ifdef HAVE_ZLIB_H
13#include <zlib.h>
14#endif
15#include "elf.h"
16#include "elf_boot.h"
17#include "mkelfImage.h"
18
19static struct file_type file_type[] = {
20 { "linux-i386", linux_i386_probe, linux_i386_mkelf, linux_i386_usage },
21 { "bzImage-i386", bzImage_i386_probe, linux_i386_mkelf, linux_i386_usage },
22 { "vmlinux-i386", vmlinux_i386_probe, linux_i386_mkelf, linux_i386_usage },
23 { "linux-ia64", linux_ia64_probe, linux_ia64_mkelf, linux_ia64_usage },
24};
25static const int file_types = sizeof(file_type)/sizeof(file_type[0]);
26
27void die(char *fmt, ...)
28{
29 va_list args;
30 va_start(args, fmt);
31 vfprintf(stderr, fmt, args);
32 va_end(args);
33 exit(1);
34}
35
36
37
38
39
40
41uint16_t ipchksum(const void *data, unsigned long length)
42{
43 unsigned long sum;
44 unsigned long i;
45 const uint8_t *ptr;
46
47
48
49
50 sum = 0;
51 ptr = data;
52 for(i = 0; i < length; i++) {
53 unsigned long value;
54 value = ptr[i];
55 if (i & 1) {
56 value <<= 8;
57 }
58
59 sum += value;
60
61 if (sum > 0xFFFF) {
62 sum = (sum + (sum >> 16)) & 0xFFFF;
63 }
64 }
65 return (~cpu_to_le16(sum)) & 0xFFFF;
66}
67
68uint16_t add_ipchksums(unsigned long offset, uint16_t sum, uint16_t new)
69{
70 unsigned long checksum;
71 sum = ~sum & 0xFFFF;
72 new = ~new & 0xFFFF;
73 if (offset & 1) {
74
75
76
77
78 new = bswap_16(new);
79 }
80 checksum = sum + new;
81 if (checksum > 0xFFFF) {
82 checksum -= 0xFFFF;
83 }
84 return (~checksum) & 0xFFFF;
85}
86
87void *xmalloc(size_t size, const char *name)
88{
89 void *buf;
90 buf = malloc(size);
91 if (!buf) {
92 die("Cannot malloc %ld bytes to hold %s: %s\n",
93 size + 0UL, name, strerror(errno));
94 }
95 return buf;
96}
97
98void *xrealloc(void *ptr, size_t size, const char *name)
99{
100 void *buf;
101 buf = realloc(ptr, size);
102 if (!buf) {
103 die("Cannot realloc %ld bytes to hold %s: %s\n",
104 size + 0UL, name, strerror(errno));
105 }
106 return buf;
107}
108
109
110char *slurp_file(const char *filename, off_t *r_size)
111{
112 int fd;
113 char *buf;
114 off_t size, progress;
115 ssize_t result;
116 struct stat stats;
117
118
119 if (!filename) {
120 *r_size = 0;
121 return 0;
122 }
123 fd = open(filename, O_RDONLY);
124 if (fd < 0) {
125 die("Cannot open `%s': %s\n",
126 filename, strerror(errno));
127 }
128 result = fstat(fd, &stats);
129 if (result < 0) {
130 die("Cannot stat: %s: %s\n",
131 filename, strerror(errno));
132 }
133 size = stats.st_size;
134 *r_size = size;
135 buf = xmalloc(size, filename);
136 progress = 0;
137 while(progress < size) {
138 result = read(fd, buf + progress, size - progress);
139 if (result < 0) {
140 if ((errno == EINTR) || (errno == EAGAIN))
141 continue;
142 die("read on %s of %ld bytes failed: %s\n",
143 filename, (size - progress)+ 0UL, strerror(errno));
144 }
145 progress += result;
146 }
147 result = close(fd);
148 if (result < 0) {
149 die("Close of %s failed: %s\n",
150 filename, strerror(errno));
151 }
152 return buf;
153}
154
155#if HAVE_ZLIB_H
156char *slurp_decompress_file(const char *filename, off_t *r_size)
157{
158 gzFile fp;
159 int errnum;
160 const char *msg;
161 char *buf;
162 off_t size, allocated;
163 ssize_t result;
164
165 if (!filename) {
166 *r_size = 0;
167 return 0;
168 }
169 fp = gzopen(filename, "rb");
170 if (fp == 0) {
171 msg = gzerror(fp, &errnum);
172 if (errnum == Z_ERRNO) {
173 msg = strerror(errno);
174 }
175 die("Cannot open `%s': %s\n", filename, msg);
176 }
177 size = 0;
178 allocated = 65536;
179 buf = xmalloc(allocated, filename);
180 do {
181 if (size == allocated) {
182 allocated <<= 1;
183 buf = xrealloc(buf, allocated, filename);
184 }
185 result = gzread(fp, buf + size, allocated - size);
186 if (result < 0) {
187 if ((errno == EINTR) || (errno == EAGAIN))
188 continue;
189
190 msg = gzerror(fp, &errnum);
191 if (errnum == Z_ERRNO) {
192 msg = strerror(errno);
193 }
194 die ("read on %s of %ld bytes failed: %s\n",
195 filename, (allocated - size) + 0UL, msg);
196 }
197 size += result;
198 } while(result > 0);
199 result = gzclose(fp);
200 if (result != Z_OK) {
201 msg = gzerror(fp, &errnum);
202 if (errnum == Z_ERRNO) {
203 msg = strerror(errno);
204 }
205 die ("Close of %s failed: %s\n", filename, msg);
206 }
207 *r_size = size;
208 return buf;
209}
210#else
211char *slurp_decompress_file(const char *filename, off_t *r_size)
212{
213 return slurp_file(filename, r_size);
214}
215#endif
216
217struct memelfphdr *add_program_headers(struct memelfheader *ehdr, int count)
218{
219 struct memelfphdr *phdr;
220 int i;
221 ehdr->e_phnum = count;
222 ehdr->e_phdr = phdr = xmalloc(count *sizeof(*phdr), "Program headers");
223
224 for(i = 0; i < count; i++) {
225 phdr[i].p_type = PT_LOAD;
226 phdr[i].p_flags = PF_R | PF_W | PF_X;
227 phdr[i].p_vaddr = 0;
228 phdr[i].p_paddr = 0;
229 phdr[i].p_filesz = 0;
230 phdr[i].p_memsz = 0;
231 phdr[i].p_data = 0;
232 }
233 return phdr;
234}
235
236struct memelfnote *add_notes(struct memelfheader *ehdr, int count)
237{
238 struct memelfnote *notes;
239 ehdr->e_notenum = count;
240 ehdr->e_notes = notes = xmalloc(count *sizeof(*notes), "Notes");
241 memset(notes, 0, count *sizeof(*notes));
242 return notes;
243}
244
245static int sizeof_notes(struct memelfnote *note, int notes)
246{
247 int size;
248 int i;
249
250 size = 0;
251 for(i = 0; i < notes; i++) {
252 size += sizeof(Elf_Nhdr);
253 size += roundup(strlen(note[i].n_name)+1, 4);
254 size += roundup(note[i].n_descsz, 4);
255 }
256 return size;
257}
258
259static uint16_t cpu_to_elf16(struct memelfheader *ehdr, uint16_t val)
260{
261 if (ehdr->ei_data == ELFDATA2LSB) {
262 return cpu_to_le16(val);
263 }
264 else if (ehdr->ei_data == ELFDATA2MSB) {
265 return cpu_to_be16(val);
266 }
267 die("Uknown elf layout in cpu_to_elf16");
268 return 0;
269}
270
271static uint32_t cpu_to_elf32(struct memelfheader *ehdr, uint32_t val)
272{
273 if (ehdr->ei_data == ELFDATA2LSB) {
274 return cpu_to_le32(val);
275 }
276 else if (ehdr->ei_data == ELFDATA2MSB) {
277 return cpu_to_be32(val);
278 }
279 die("Uknown elf layout in cpu_to_elf32");
280 return 0;
281}
282
283static uint64_t cpu_to_elf64(struct memelfheader *ehdr, uint64_t val)
284{
285 if (ehdr->ei_data == ELFDATA2LSB) {
286 return cpu_to_le64(val);
287 }
288 else if (ehdr->ei_data == ELFDATA2MSB) {
289 return cpu_to_be64(val);
290 }
291 die("Uknown elf layout in cpu_to_elf64");
292 return 0;
293}
294
295static void serialize_notes(char *buf, struct memelfheader *ehdr)
296{
297 struct Elf_Nhdr hdr;
298 struct memelfnote *note;
299 int notes;
300 size_t size, offset;
301 int i;
302
303
304 note = ehdr->e_notes;
305 notes = ehdr->e_notenum;
306 size = sizeof_notes(note, notes);
307 memset(buf, 0, size);
308
309
310 offset = 0;
311 for(i = 0; i < notes; i++) {
312
313 size_t n_namesz;
314 n_namesz = strlen(note[i].n_name) +1;
315 hdr.n_namesz = cpu_to_elf32(ehdr, n_namesz);
316 hdr.n_descsz = cpu_to_elf32(ehdr, note[i].n_descsz);
317 hdr.n_type = cpu_to_elf32(ehdr, note[i].n_type);
318
319
320 memcpy(buf + offset, &hdr, sizeof(hdr));
321 offset += sizeof(hdr);
322 memcpy(buf + offset, note[i].n_name, n_namesz);
323 offset += roundup(n_namesz, 4);
324 memcpy(buf + offset, note[i].n_desc, note[i].n_descsz);
325 offset += roundup(note[i].n_descsz, 4);
326
327 }
328}
329static void serialize_ehdr(char *buf, struct memelfheader *ehdr)
330{
331 if (ehdr->ei_class == ELFCLASS32) {
332 Elf32_Ehdr *hdr = (Elf32_Ehdr *)buf;
333 hdr->e_ident[EI_MAG0] = ELFMAG0;
334 hdr->e_ident[EI_MAG1] = ELFMAG1;
335 hdr->e_ident[EI_MAG2] = ELFMAG2;
336 hdr->e_ident[EI_MAG3] = ELFMAG3;
337 hdr->e_ident[EI_CLASS] = ehdr->ei_class;
338 hdr->e_ident[EI_DATA] = ehdr->ei_data;
339 hdr->e_ident[EI_VERSION] = EV_CURRENT;
340 hdr->e_type = cpu_to_elf16(ehdr, ehdr->e_type);
341 hdr->e_machine = cpu_to_elf16(ehdr, ehdr->e_machine);
342 hdr->e_version = cpu_to_elf32(ehdr, EV_CURRENT);
343 hdr->e_entry = cpu_to_elf32(ehdr, ehdr->e_entry);
344 hdr->e_phoff = cpu_to_elf32(ehdr, sizeof(*hdr));
345 hdr->e_shoff = cpu_to_elf32(ehdr, 0);
346 hdr->e_flags = cpu_to_elf32(ehdr, ehdr->e_flags);
347 hdr->e_ehsize = cpu_to_elf16(ehdr, sizeof(*hdr));
348 hdr->e_phentsize = cpu_to_elf16(ehdr, sizeof(Elf32_Phdr));
349 hdr->e_phnum = cpu_to_elf16(ehdr, ehdr->e_phnum);
350 hdr->e_shentsize = cpu_to_elf16(ehdr, 0);
351 hdr->e_shnum = cpu_to_elf16(ehdr, 0);
352 hdr->e_shstrndx = cpu_to_elf16(ehdr, 0);
353 }
354 else if (ehdr->ei_class == ELFCLASS64) {
355 Elf64_Ehdr *hdr = (Elf64_Ehdr *)buf;
356 hdr->e_ident[EI_MAG0] = ELFMAG0;
357 hdr->e_ident[EI_MAG1] = ELFMAG1;
358 hdr->e_ident[EI_MAG2] = ELFMAG2;
359 hdr->e_ident[EI_MAG3] = ELFMAG3;
360 hdr->e_ident[EI_CLASS] = ehdr->ei_class;
361 hdr->e_ident[EI_DATA] = ehdr->ei_data;
362 hdr->e_ident[EI_VERSION] = EV_CURRENT;
363 hdr->e_type = cpu_to_elf16(ehdr, ehdr->e_type);
364 hdr->e_machine = cpu_to_elf16(ehdr, ehdr->e_machine);
365 hdr->e_version = cpu_to_elf32(ehdr, EV_CURRENT);
366 hdr->e_entry = cpu_to_elf64(ehdr, ehdr->e_entry);
367 hdr->e_phoff = cpu_to_elf64(ehdr, sizeof(*hdr));
368 hdr->e_shoff = cpu_to_elf64(ehdr, 0);
369 hdr->e_flags = cpu_to_elf32(ehdr, ehdr->e_flags);
370 hdr->e_ehsize = cpu_to_elf16(ehdr, sizeof(*hdr));
371 hdr->e_phentsize = cpu_to_elf16(ehdr, sizeof(Elf64_Phdr));
372 hdr->e_phnum = cpu_to_elf16(ehdr, ehdr->e_phnum);
373 hdr->e_shentsize = cpu_to_elf16(ehdr, 0);
374 hdr->e_shnum = cpu_to_elf16(ehdr, 0);
375 hdr->e_shstrndx = cpu_to_elf16(ehdr, 0);
376 }
377 else die("Uknown elf class: %x\n", ehdr->ei_class);
378}
379static void serialize_phdrs(char *buf, struct memelfheader *ehdr, size_t note_size)
380{
381 int i;
382 size_t offset, note_offset;
383 if (ehdr->ei_class == ELFCLASS32) {
384 Elf32_Phdr *phdr = (Elf32_Phdr *)buf;
385 note_offset =
386 sizeof(Elf32_Ehdr) + (sizeof(Elf32_Phdr)*ehdr->e_phnum);
387 offset = note_offset + note_size;
388 for(i = 0; i < ehdr->e_phnum; i++) {
389 struct memelfphdr *hdr = ehdr->e_phdr + i;
390 phdr[i].p_type = cpu_to_elf32(ehdr, hdr->p_type);
391 phdr[i].p_offset = cpu_to_elf32(ehdr, offset);
392 phdr[i].p_vaddr = cpu_to_elf32(ehdr, hdr->p_vaddr);
393 phdr[i].p_paddr = cpu_to_elf32(ehdr, hdr->p_paddr);
394 phdr[i].p_filesz = cpu_to_elf32(ehdr, hdr->p_filesz);
395 phdr[i].p_memsz = cpu_to_elf32(ehdr, hdr->p_memsz);
396 phdr[i].p_flags = cpu_to_elf32(ehdr, hdr->p_flags);
397 phdr[i].p_align = cpu_to_elf32(ehdr, 0);
398 if (phdr[i].p_type == PT_NOTE) {
399 phdr[i].p_filesz = cpu_to_elf32(ehdr, note_size);
400 phdr[i].p_memsz = cpu_to_elf32(ehdr, note_size);
401 phdr[i].p_offset = cpu_to_elf32(ehdr, note_offset);
402 } else {
403 offset += hdr->p_filesz;
404 }
405 }
406 }
407 else if (ehdr->ei_class == ELFCLASS64) {
408 Elf64_Phdr *phdr = (Elf64_Phdr *)buf;
409 note_offset =
410 sizeof(Elf64_Ehdr) + (sizeof(Elf64_Phdr)*ehdr->e_phnum);
411 offset = note_offset + note_size;
412 for(i = 0; i < ehdr->e_phnum; i++) {
413 struct memelfphdr *hdr = ehdr->e_phdr + i;
414 phdr[i].p_type = cpu_to_elf32(ehdr, hdr->p_type);
415 phdr[i].p_flags = cpu_to_elf32(ehdr, hdr->p_flags);
416 phdr[i].p_offset = cpu_to_elf64(ehdr, offset);
417 phdr[i].p_vaddr = cpu_to_elf64(ehdr, hdr->p_vaddr);
418 phdr[i].p_paddr = cpu_to_elf64(ehdr, hdr->p_paddr);
419 phdr[i].p_filesz = cpu_to_elf64(ehdr, hdr->p_filesz);
420 phdr[i].p_memsz = cpu_to_elf64(ehdr, hdr->p_memsz);
421 phdr[i].p_align = cpu_to_elf64(ehdr, 0);
422 if (phdr[i].p_type == PT_NOTE) {
423 phdr[i].p_filesz = cpu_to_elf64(ehdr, note_size);
424 phdr[i].p_memsz = cpu_to_elf64(ehdr, note_size);
425 phdr[i].p_offset = cpu_to_elf64(ehdr, note_offset);
426 } else {
427 offset += hdr->p_filesz;
428 }
429 }
430 }
431 else {
432 die("Unknwon elf class: %x\n", ehdr->ei_class);
433 }
434}
435
436static void write_buf(int fd, char *buf, size_t size)
437{
438 size_t progress = 0;
439 ssize_t result;
440 while(progress < size) {
441 result = write(fd, buf + progress, size - progress);
442 if (result < 0) {
443 if ((errno == EAGAIN) || (errno == EINTR)) {
444 continue;
445 }
446 die ("write of %ld bytes failed: %s\n",
447 size - progress, strerror(errno));
448 }
449 progress += result;
450 }
451}
452static void write_elf(struct memelfheader *ehdr, char *output)
453{
454 size_t ehdr_size;
455 size_t phdr_size;
456 size_t note_size;
457 size_t size;
458 uint16_t checksum;
459 size_t bytes;
460 char *buf;
461 int result, fd;
462 int i;
463
464 for(i = 0; i < ehdr->e_notenum; i++) {
465 if ((memcmp(ehdr->e_notes[i].n_name, "ELFBoot", 8) == 0) &&
466 (ehdr->e_notes[i].n_type == EIN_PROGRAM_CHECKSUM)) {
467 ehdr->e_notes[i].n_desc = &checksum;
468 ehdr->e_notes[i].n_descsz = 2;
469 }
470 }
471
472 ehdr_size = 0;
473 phdr_size = 0;
474 note_size = 0;
475 if (ehdr->e_notenum) {
476 note_size = sizeof_notes(ehdr->e_notes, ehdr->e_notenum);
477 }
478 if (ehdr->ei_class == ELFCLASS32) {
479 ehdr_size = sizeof(Elf32_Ehdr);
480 phdr_size = sizeof(Elf32_Phdr) * ehdr->e_phnum;
481 }
482 else if (ehdr->ei_class == ELFCLASS64) {
483 ehdr_size = sizeof(Elf64_Ehdr);
484 phdr_size = sizeof(Elf64_Phdr) * ehdr->e_phnum;
485 }
486 else {
487 die("Unknown elf class: %x\n", ehdr->ei_class);
488 }
489
490
491 size = ehdr_size + phdr_size + note_size;
492 buf = xmalloc(size, "Elf Headers");
493 memset(buf, 0, size);
494 serialize_ehdr(buf, ehdr);
495 serialize_phdrs(buf + ehdr_size, ehdr, note_size);
496
497
498 checksum = ipchksum(buf, ehdr_size + phdr_size);
499 bytes = ehdr_size + phdr_size;
500 for(i = 0; i < ehdr->e_phnum; i++) {
501 checksum = add_ipchksums(bytes, checksum,
502 ipchksum(ehdr->e_phdr[i].p_data, ehdr->e_phdr[i].p_filesz));
503 bytes += ehdr->e_phdr[i].p_memsz;
504 }
505
506
507 serialize_notes(buf + ehdr_size + phdr_size, ehdr);
508
509
510 fd = open(output, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR | S_IRGRP | S_IROTH);
511 if (fd < 0) {
512 die("Cannot open ``%s'':%s\n",
513 output, strerror(errno));
514 }
515 write_buf(fd, buf, size);
516 for(i = 0; i < ehdr->e_phnum; i++) {
517 write_buf(fd, ehdr->e_phdr[i].p_data, ehdr->e_phdr[i].p_filesz);
518 }
519 result = close(fd);
520 if (result < 0) {
521 die("Close on %s failed: %s\n",
522 output, strerror(errno));
523 }
524}
525
526static void version(void)
527{
528 printf("mkelfImage " VERSION " released " RELEASE_DATE "\n");
529}
530void usage(void)
531{
532 int i;
533 version();
534 printf(
535 "Usage: mkelfImage [OPTION]... <kernel> <elf_kernel>\n"
536 "Build an ELF bootable kernel image from a normal kernel image\n"
537 "\n"
538 " -h, --help Print this help.\n"
539 " -v, --version Print the version of kexec.\n"
540 " --kernel=<filename> Set the kernel to <filename>\n"
541 " --output=<filename> Output to <filename>\n"
542 " -t, --type=TYPE Specify the new kernel is of <type>.\n"
543 "\n"
544 "Supported kernel types: \n"
545 );
546 for(i = 0; i < file_types; i++) {
547 printf("%s\n", file_type[i].name);
548 file_type[i].usage();
549 }
550 printf("\n");
551}
552
553void error(char *fmt, ...)
554{
555 va_list args;
556 va_start(args, fmt);
557 vfprintf(stderr, fmt, args);
558 va_end(args);
559 usage();
560 exit(1);
561}
562
563int main(int argc, char **argv)
564{
565 int opt;
566 int fileind;
567 char *type, *kernel, *output;
568 off_t kernel_size;
569 char *kernel_buf;
570 int result;
571 int i;
572 struct memelfheader hdr;
573
574 static const struct option options[] = {
575 MKELF_OPTIONS
576 { 0, 0, 0, 0 },
577 };
578 static const char short_options[] = MKELF_OPT_STR;
579
580 memset(&hdr, 0, sizeof(hdr));
581 kernel = 0;
582 output = 0;
583
584
585 type = strrchr(argv[0], '/');
586 if (!type) type = argv[0];
587 if (memcmp(type, "mkelf-", 6) == 0) {
588 type = type + 6;
589 } else {
590 type = 0;
591 }
592 opterr = 0;
593 while ((opt = getopt_long(argc, argv, short_options, options, 0)) != -1) {
594 switch(opt) {
595 case OPT_HELP:
596 usage();
597 return 0;
598 case OPT_VERSION:
599 version();
600 return 0;
601 case OPT_KERNEL:
602 kernel = optarg;
603 break;
604 case OPT_OUTPUT:
605 output = optarg;
606 break;
607 case OPT_TYPE:
608 type = optarg;
609 break;
610 default:
611 break;
612 }
613 }
614 fileind = optind;
615
616
617 opterr = 1;
618 optind = 1;
619
620 if (argc - fileind > 0) {
621 kernel = argv[fileind++];
622 }
623 if (argc - fileind > 0) {
624 output = argv[fileind++];
625 }
626 if (!kernel) {
627 error("No kernel specified!\n");
628 }
629 if (!output) {
630 error("No output file specified!\n");
631 }
632 if (argc - fileind > 0) {
633 error("%d extra options specified!\n", argc - fileind);
634 }
635
636
637 kernel_buf = slurp_decompress_file(kernel, &kernel_size);
638
639
640 for(i = 0; i < file_types; i++) {
641 char *reason;
642 if (type && (strcmp(type, file_type[i].name) != 0)) {
643 continue;
644 }
645 reason = file_type[i].probe(kernel_buf, kernel_size);
646 if (reason == 0) {
647 break;
648 }
649 if (type) {
650 die("Not %s: %s\n", type, reason);
651 }
652 }
653 if (i == file_types) {
654 die("Can not determine the file type of %s\n", kernel);
655 }
656 result = file_type[i].mkelf(argc, argv, &hdr, kernel_buf, kernel_size);
657 if (result < 0) {
658 die("Cannot create %s result: %d\n", output, result);
659 }
660
661 write_elf(&hdr, output);
662 return 0;
663}
664