summaryrefslogtreecommitdiff
path: root/payloads/bayou/util/pbuilder/liblar/self.c
diff options
context:
space:
mode:
Diffstat (limited to 'payloads/bayou/util/pbuilder/liblar/self.c')
-rw-r--r--payloads/bayou/util/pbuilder/liblar/self.c206
1 files changed, 206 insertions, 0 deletions
diff --git a/payloads/bayou/util/pbuilder/liblar/self.c b/payloads/bayou/util/pbuilder/liblar/self.c
new file mode 100644
index 0000000000..c7fff3d97f
--- /dev/null
+++ b/payloads/bayou/util/pbuilder/liblar/self.c
@@ -0,0 +1,206 @@
+/*
+ * 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 <patrick@georgi-clan.de>
+ * 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 <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <elf.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdint.h>
+
+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;
+}