/* * This file is part of the bayou project. * * Copyright (C) 2008 Advanced Micro Devices, Inc. * * Includes code from util/lar from coreboot-v3 * * Copyright (C) 2006-2007 coresystems GmbH * Copyright (C) 2007 Patrick Georgi * Copyright (C) 2007 Advanced Micro Devices, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #include #include #include #include #include "elf.h" #include #include #include #include typedef uint64_t u64; typedef int64_t s64; typedef uint32_t u32; typedef int32_t s32; typedef uint8_t u8; #include "self.h" int elf_to_self(const char *filename, unsigned char **buffer, void (*compress) (char *, int, char *, int *)) { struct stat s; Elf32_Phdr *phdr; Elf32_Ehdr *ehdr; Elf32_Shdr *shdr; void *filep; char *header, *strtab; unsigned char *sptr; int headers, segments = 1, isize = 0, osize = 0, doffset = 0, fd, i; struct self_segment *segs; if (stat(filename, &s)) { printf("Unable to stat %s: %m\n", filename); return -1; } fd = open(filename, O_RDONLY); if (fd == -1) { printf("Unable to open %s: %m\n", filename); return -1; } /* Map the file so that we can easily parse it. */ filep = (void *) mmap(0, s.st_size, PROT_READ, MAP_SHARED, fd, 0); if (filep == MAP_FAILED) { close(fd); return -1; } ehdr = (Elf32_Ehdr *) filep; headers = ehdr->e_phnum; header = (char *)ehdr; phdr = (Elf32_Phdr *) & (header[ehdr->e_phoff]); shdr = (Elf32_Shdr *) & (header[ehdr->e_shoff]); strtab = &header[shdr[ehdr->e_shstrndx].sh_offset]; /* Count number of headers - look for the .notes.pinfo section. */ for (i = 0; i < ehdr->e_shnum; i++) { char *name; if (i == ehdr->e_shstrndx) continue; if (shdr[i].sh_size == 0) continue; name = (char *)(strtab + shdr[i].sh_name); if (!strcmp(name, ".note.pinfo")) segments++; } /* * Now, regular headers - we only care about PT_LOAD headers, * because thats what we're actually going to load. */ for (i = 0; i < headers; i++) { if (phdr[i].p_type != PT_LOAD) continue; /* Empty segments are never interesting. */ if (phdr[i].p_memsz == 0) continue; isize += phdr[i].p_filesz; segments++; } /* Allocate a block of memory to store the SELF in. */ sptr = calloc((segments * sizeof(struct self_segment)) + isize, 1); doffset = (segments * sizeof(struct self_segment)); if (sptr == NULL) goto err; segs = (struct self_segment *)sptr; segments = 0; for (i = 0; i < ehdr->e_shnum; i++) { char *name; if (i == ehdr->e_shstrndx) continue; if (shdr[i].sh_size == 0) continue; name = (char *)(strtab + shdr[i].sh_name); if (!strcmp(name, ".note.pinfo")) { segs[segments].type = SELF_TYPE_PARAMS; segs[segments].load_addr = 0; segs[segments].len = (u32) shdr[i].sh_size; segs[segments].offset = doffset; memcpy((unsigned long *)(sptr + doffset), &header[shdr[i].sh_offset], shdr[i].sh_size); doffset += segs[segments].len; osize += segs[segments].len; segments++; } } for (i = 0; i < headers; i++) { if (phdr[i].p_type != PT_LOAD) continue; if (phdr[i].p_memsz == 0) continue; segs[segments].type = SELF_TYPE_DATA; segs[segments].load_addr = (u64) phdr[i].p_paddr; segs[segments].mem_len = (u32) phdr[i].p_memsz; segs[segments].offset = doffset; compress((char *)&header[phdr[i].p_offset], phdr[i].p_filesz, (char *)(sptr + doffset), (int *)&segs[segments].len); doffset += segs[segments].len; osize += segs[segments].len; segments++; } segs[segments].type = SELF_TYPE_ENTRY; segs[segments++].load_addr = (unsigned long long)ehdr->e_entry; *buffer = sptr; munmap(filep, s.st_size); close(fd); return (segments * sizeof(struct self_segment)) + osize; err: munmap(filep, s.st_size); close(fd); return -1; } int iself(char *filename) { Elf32_Ehdr ehdr; int fd = open(filename, O_RDONLY); int ret = 0; if (fd == -1) return 0; if (read(fd, &ehdr, sizeof(ehdr)) == sizeof(ehdr)) ret = !memcmp(ehdr.e_ident, ELFMAG, 4); close(fd); return ret; }