17 #include "mkelfImage.h"
19 static 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 },
25 static const int file_types = sizeof(file_type)/sizeof(file_type[0]);
27 void die(char *fmt, ...)
31 vfprintf(stderr, fmt, args);
38 /**************************************************************************
39 IPCHKSUM - Checksum IP Header
40 **************************************************************************/
41 uint16_t ipchksum(const void *data, unsigned long length)
47 /* In the most straight forward way possible,
48 * compute an ip style checksum.
52 for(i = 0; i < length; i++) {
58 /* Add the new value */
60 /* Wrap around the carry */
62 sum = (sum + (sum >> 16)) & 0xFFFF;
65 return (~cpu_to_le16(sum)) & 0xFFFF;
68 uint16_t add_ipchksums(unsigned long offset, uint16_t sum, uint16_t new)
70 unsigned long checksum;
74 /* byte swap the sum if it came from an odd offset
75 * since the computation is endian independant this
81 if (checksum > 0xFFFF) {
84 return (~checksum) & 0xFFFF;
87 void *xmalloc(size_t size, const char *name)
92 die("Cannot malloc %ld bytes to hold %s: %s\n",
93 size + 0UL, name, strerror(errno));
98 void *xrealloc(void *ptr, size_t size, const char *name)
101 buf = realloc(ptr, size);
103 die("Cannot realloc %ld bytes to hold %s: %s\n",
104 size + 0UL, name, strerror(errno));
110 char *slurp_file(const char *filename, off_t *r_size)
114 off_t size, progress;
123 fd = open(filename, O_RDONLY);
125 die("Cannot open `%s': %s\n",
126 filename, strerror(errno));
128 result = fstat(fd, &stats);
130 die("Cannot stat: %s: %s\n",
131 filename, strerror(errno));
133 size = stats.st_size;
135 buf = xmalloc(size, filename);
137 while(progress < size) {
138 result = read(fd, buf + progress, size - progress);
140 if ((errno == EINTR) || (errno == EAGAIN))
142 die("read on %s of %ld bytes failed: %s\n",
143 filename, (size - progress)+ 0UL, strerror(errno));
149 die("Close of %s failed: %s\n",
150 filename, strerror(errno));
156 char *slurp_decompress_file(const char *filename, off_t *r_size)
162 off_t size, allocated;
169 fp = gzopen(filename, "rb");
171 msg = gzerror(fp, &errnum);
172 if (errnum == Z_ERRNO) {
173 msg = strerror(errno);
175 die("Cannot open `%s': %s\n", filename, msg);
179 buf = xmalloc(allocated, filename);
181 if (size == allocated) {
183 buf = xrealloc(buf, allocated, filename);
185 result = gzread(fp, buf + size, allocated - size);
187 if ((errno == EINTR) || (errno == EAGAIN))
190 msg = gzerror(fp, &errnum);
191 if (errnum == Z_ERRNO) {
192 msg = strerror(errno);
194 die ("read on %s of %ld bytes failed: %s\n",
195 filename, (allocated - size) + 0UL, msg);
199 result = gzclose(fp);
200 if (result != Z_OK) {
201 msg = gzerror(fp, &errnum);
202 if (errnum == Z_ERRNO) {
203 msg = strerror(errno);
205 die ("Close of %s failed: %s\n", filename, msg);
211 char *slurp_decompress_file(const char *filename, off_t *r_size)
213 return slurp_file(filename, r_size);
217 struct memelfphdr *add_program_headers(struct memelfheader *ehdr, int count)
219 struct memelfphdr *phdr;
221 ehdr->e_phnum = count;
222 ehdr->e_phdr = phdr = xmalloc(count *sizeof(*phdr), "Program headers");
223 /* Set the default values */
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;
229 phdr[i].p_filesz = 0;
236 struct memelfnote *add_notes(struct memelfheader *ehdr, int count)
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));
245 static int sizeof_notes(struct memelfnote *note, int notes)
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);
259 static uint16_t cpu_to_elf16(struct memelfheader *ehdr, uint16_t val)
261 if (ehdr->ei_data == ELFDATA2LSB) {
262 return cpu_to_le16(val);
264 else if (ehdr->ei_data == ELFDATA2MSB) {
265 return cpu_to_be16(val);
267 die("Uknown elf layout in cpu_to_elf16");
271 static uint32_t cpu_to_elf32(struct memelfheader *ehdr, uint32_t val)
273 if (ehdr->ei_data == ELFDATA2LSB) {
274 return cpu_to_le32(val);
276 else if (ehdr->ei_data == ELFDATA2MSB) {
277 return cpu_to_be32(val);
279 die("Uknown elf layout in cpu_to_elf32");
283 static uint64_t cpu_to_elf64(struct memelfheader *ehdr, uint64_t val)
285 if (ehdr->ei_data == ELFDATA2LSB) {
286 return cpu_to_le64(val);
288 else if (ehdr->ei_data == ELFDATA2MSB) {
289 return cpu_to_be64(val);
291 die("Uknown elf layout in cpu_to_elf64");
295 static void serialize_notes(char *buf, struct memelfheader *ehdr)
298 struct memelfnote *note;
303 /* Clear the buffer */
304 note = ehdr->e_notes;
305 notes = ehdr->e_notenum;
306 size = sizeof_notes(note, notes);
307 memset(buf, 0, size);
309 /* Write the Elf Notes */
311 for(i = 0; i < notes; i++) {
312 /* Compute the note header */
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);
319 /* Copy the note into the buffer */
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);
329 static void serialize_ehdr(char *buf, struct memelfheader *ehdr)
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);
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);
377 else die("Uknown elf class: %x\n", ehdr->ei_class);
379 static void serialize_phdrs(char *buf, struct memelfheader *ehdr, size_t note_size)
382 size_t offset, note_offset;
383 if (ehdr->ei_class == ELFCLASS32) {
384 Elf32_Phdr *phdr = (Elf32_Phdr *)buf;
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);
403 offset += hdr->p_filesz;
407 else if (ehdr->ei_class == ELFCLASS64) {
408 Elf64_Phdr *phdr = (Elf64_Phdr *)buf;
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);
427 offset += hdr->p_filesz;
432 die("Unknwon elf class: %x\n", ehdr->ei_class);
436 static void write_buf(int fd, char *buf, size_t size)
440 while(progress < size) {
441 result = write(fd, buf + progress, size - progress);
443 if ((errno == EAGAIN) || (errno == EINTR)) {
446 die ("write of %ld bytes failed: %s\n",
447 size - progress, strerror(errno));
452 static void write_elf(struct memelfheader *ehdr, char *output)
463 /* Prep for adding the checksum */
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;
471 /* Compute the sizes */
475 if (ehdr->e_notenum) {
476 note_size = sizeof_notes(ehdr->e_notes, ehdr->e_notenum);
478 if (ehdr->ei_class == ELFCLASS32) {
479 ehdr_size = sizeof(Elf32_Ehdr);
480 phdr_size = sizeof(Elf32_Phdr) * ehdr->e_phnum;
482 else if (ehdr->ei_class == ELFCLASS64) {
483 ehdr_size = sizeof(Elf64_Ehdr);
484 phdr_size = sizeof(Elf64_Phdr) * ehdr->e_phnum;
487 die("Unknown elf class: %x\n", ehdr->ei_class);
490 /* Allocate a buffer to temporarily hold the serialized forms */
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);
497 /* Compute the checksum... */
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;
506 /* Compute the final form of the notes */
507 serialize_notes(buf + ehdr_size + phdr_size, ehdr);
509 /* Now write the elf image */
510 fd = open(output, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR | S_IRGRP | S_IROTH);
512 die("Cannot open ``%s'':%s\n",
513 output, strerror(errno));
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);
521 die("Close on %s failed: %s\n",
522 output, strerror(errno));
526 static void version(void)
528 printf("mkelfImage " VERSION " released " RELEASE_DATE "\n");
535 "Usage: mkelfImage [OPTION]... <kernel> <elf_kernel>\n"
536 "Build an ELF bootable kernel image from a normal kernel image\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"
544 "Supported kernel types: \n"
546 for(i = 0; i < file_types; i++) {
547 printf("%s\n", file_type[i].name);
548 file_type[i].usage();
553 void error(char *fmt, ...)
557 vfprintf(stderr, fmt, args);
563 int main(int argc, char **argv)
567 char *type, *kernel, *output;
572 struct memelfheader hdr;
574 static const struct option options[] = {
578 static const char short_options[] = MKELF_OPT_STR;
580 memset(&hdr, 0, sizeof(hdr));
584 /* Get the default type from the program name */
585 type = strrchr(argv[0], '/');
586 if (!type) type = argv[0];
587 if (memcmp(type, "mkelf-", 6) == 0) {
592 opterr = 0; /* Don't complain about unrecognized options here */
593 while ((opt = getopt_long(argc, argv, short_options, options, 0)) != -1) {
616 /* Reset getopt for the next pass */
620 if (argc - fileind > 0) {
621 kernel = argv[fileind++];
623 if (argc - fileind > 0) {
624 output = argv[fileind++];
627 error("No kernel specified!\n");
630 error("No output file specified!\n");
632 if (argc - fileind > 0) {
633 error("%d extra options specified!\n", argc - fileind);
636 /* slurp in the input kernel */
637 kernel_buf = slurp_decompress_file(kernel, &kernel_size);
639 /* Find/verify the kernel type */
640 for(i = 0; i < file_types; i++) {
642 if (type && (strcmp(type, file_type[i].name) != 0)) {
645 reason = file_type[i].probe(kernel_buf, kernel_size);
650 die("Not %s: %s\n", type, reason);
653 if (i == file_types) {
654 die("Can not determine the file type of %s\n", kernel);
656 result = file_type[i].mkelf(argc, argv, &hdr, kernel_buf, kernel_size);
658 die("Cannot create %s result: %d\n", output, result);
660 /* open the output file */
661 write_elf(&hdr, output);