blob: b26356688da765aa4a33c4112313ab5592b05a48 [file] [log] [blame]
Uwe Hermann7eb845e2008-11-02 17:01:06 +00001/*
2 * This file is part of the bayou project.
3 *
4 * Copyright (C) 2008 Advanced Micro Devices, Inc.
5 *
6 * Includes code from util/lar from coreboot-v3
7 *
8 * Copyright (C) 2006-2007 coresystems GmbH
9 * Copyright (C) 2007 Patrick Georgi <patrick@georgi-clan.de>
10 * Copyright (C) 2007 Advanced Micro Devices, Inc.
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License version 2 as
14 * published by the Free Software Foundation.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 */
21
22#include <stdio.h>
23#include <string.h>
24#include <stdlib.h>
25#include <sys/stat.h>
Stefan Reinauer7b769122010-04-20 23:04:46 +000026#include "elf.h"
Uwe Hermann7eb845e2008-11-02 17:01:06 +000027#include <sys/mman.h>
28#include <unistd.h>
29#include <fcntl.h>
30#include <stdint.h>
31
32typedef uint64_t u64;
33typedef int64_t s64;
34typedef uint32_t u32;
35typedef int32_t s32;
36typedef uint8_t u8;
37
38#include "self.h"
39
40int elf_to_self(const char *filename, unsigned char **buffer,
41 void (*compress) (char *, int, char *, int *))
42{
43 struct stat s;
44 Elf32_Phdr *phdr;
45 Elf32_Ehdr *ehdr;
46 Elf32_Shdr *shdr;
47 void *filep;
48 char *header, *strtab;
49 unsigned char *sptr;
50 int headers, segments = 1, isize = 0, osize = 0, doffset = 0, fd, i;
51 struct self_segment *segs;
52
53 if (stat(filename, &s)) {
54 printf("Unable to stat %s: %m\n", filename);
55 return -1;
56 }
57
58 fd = open(filename, O_RDONLY);
59
60 if (fd == -1) {
61 printf("Unable to open %s: %m\n", filename);
62 return -1;
63 }
64
65 /* Map the file so that we can easily parse it. */
66 filep = (void *)
67 mmap(0, s.st_size, PROT_READ, MAP_SHARED, fd, 0);
68
69 if (filep == MAP_FAILED) {
70 close(fd);
71 return -1;
72 }
73
74 ehdr = (Elf32_Ehdr *) filep;
75 headers = ehdr->e_phnum;
76 header = (char *)ehdr;
77
78 phdr = (Elf32_Phdr *) & (header[ehdr->e_phoff]);
79 shdr = (Elf32_Shdr *) & (header[ehdr->e_shoff]);
80
81 strtab = &header[shdr[ehdr->e_shstrndx].sh_offset];
82
83 /* Count number of headers - look for the .notes.pinfo section. */
84 for (i = 0; i < ehdr->e_shnum; i++) {
85 char *name;
86
87 if (i == ehdr->e_shstrndx)
88 continue;
89
90 if (shdr[i].sh_size == 0)
91 continue;
92
93 name = (char *)(strtab + shdr[i].sh_name);
94
95 if (!strcmp(name, ".note.pinfo"))
96 segments++;
97 }
98
99 /*
100 * Now, regular headers - we only care about PT_LOAD headers,
101 * because thats what we're actually going to load.
102 */
103 for (i = 0; i < headers; i++) {
104 if (phdr[i].p_type != PT_LOAD)
105 continue;
106
107 /* Empty segments are never interesting. */
108 if (phdr[i].p_memsz == 0)
109 continue;
110
111 isize += phdr[i].p_filesz;
112 segments++;
113 }
114
115 /* Allocate a block of memory to store the SELF in. */
116 sptr = calloc((segments * sizeof(struct self_segment)) + isize, 1);
117 doffset = (segments * sizeof(struct self_segment));
118
119 if (sptr == NULL)
120 goto err;
121
122 segs = (struct self_segment *)sptr;
123 segments = 0;
124
125 for (i = 0; i < ehdr->e_shnum; i++) {
126 char *name;
127
128 if (i == ehdr->e_shstrndx)
129 continue;
130
131 if (shdr[i].sh_size == 0)
132 continue;
133
134 name = (char *)(strtab + shdr[i].sh_name);
135
136 if (!strcmp(name, ".note.pinfo")) {
137 segs[segments].type = SELF_TYPE_PARAMS;
138 segs[segments].load_addr = 0;
139 segs[segments].len = (u32) shdr[i].sh_size;
140 segs[segments].offset = doffset;
141
142 memcpy((unsigned long *)(sptr + doffset),
143 &header[shdr[i].sh_offset], shdr[i].sh_size);
144
145 doffset += segs[segments].len;
146 osize += segs[segments].len;
147
148 segments++;
149 }
150 }
151
152 for (i = 0; i < headers; i++) {
153 if (phdr[i].p_type != PT_LOAD)
154 continue;
155
156 if (phdr[i].p_memsz == 0)
157 continue;
158
159 segs[segments].type = SELF_TYPE_DATA;
160 segs[segments].load_addr = (u64) phdr[i].p_paddr;
161 segs[segments].mem_len = (u32) phdr[i].p_memsz;
162 segs[segments].offset = doffset;
163
164 compress((char *)&header[phdr[i].p_offset],
165 phdr[i].p_filesz,
166 (char *)(sptr + doffset), (int *)&segs[segments].len);
167
168 doffset += segs[segments].len;
169 osize += segs[segments].len;
170
171 segments++;
172 }
173
174 segs[segments].type = SELF_TYPE_ENTRY;
175 segs[segments++].load_addr = (unsigned long long)ehdr->e_entry;
176
177 *buffer = sptr;
178
179 munmap(filep, s.st_size);
180 close(fd);
181
182 return (segments * sizeof(struct self_segment)) + osize;
183
184err:
185 munmap(filep, s.st_size);
186 close(fd);
187
188 return -1;
189}
190
191int iself(char *filename)
192{
193 Elf32_Ehdr ehdr;
194 int fd = open(filename, O_RDONLY);
195 int ret = 0;
196
197 if (fd == -1)
198 return 0;
199
200 if (read(fd, &ehdr, sizeof(ehdr)) == sizeof(ehdr))
201 ret = !memcmp(ehdr.e_ident, ELFMAG, 4);
202
203 close(fd);
204
205 return ret;
206}