remove trailing whitespace
[coreboot.git] / util / cbfstool / cbfs-mkstage.c
1 /*
2  * cbfs-mkstage
3  *
4  * Copyright (C) 2008 Jordan Crouse <jordan@cosmicpenguin.net>
5  *               2009 coresystems GmbH
6  *                 written by Patrick Georgi <patrick.georgi@coresystems.de>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; version 2 of the License.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
20  */
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <unistd.h>
26 #include "elf.h"
27 #include <fcntl.h>
28 #include <getopt.h>
29 #include <sys/stat.h>
30
31 #include "common.h"
32 #include "cbfs.h"
33
34 unsigned int idemp(unsigned int x)
35 {
36         return x;
37 }
38
39 /* This is a wrapper around the swab32() macro to make it
40  * usable for the current implementation of parse_elf_to_stage()
41  */
42 static unsigned int swap32(unsigned int x)
43 {
44         return swab32(x);
45 }
46
47 unsigned int (*elf32_to_native) (unsigned int) = idemp;
48
49 /* returns size of result, or -1 if error */
50 int parse_elf_to_stage(unsigned char *input, unsigned char **output,
51                        comp_algo algo, uint32_t * location)
52 {
53         Elf32_Phdr *phdr;
54         Elf32_Ehdr *ehdr = (Elf32_Ehdr *) input;
55         char *header, *buffer;
56         unsigned char *out;
57
58         int headers;
59         int i;
60         struct cbfs_stage *stage;
61         unsigned int data_start, data_end, mem_end;
62
63         int elf_bigendian = 0;
64
65         comp_func_ptr compress = compression_function(algo);
66         if (!compress)
67                 return -1;
68
69         if (!iself(input)) {
70                 fprintf(stderr, "E:  The incoming file is not an ELF\n");
71                 return -1;
72         }
73
74         if (ehdr->e_ident[EI_DATA] == ELFDATA2MSB) {
75                 elf_bigendian = 1;
76         }
77         if (elf_bigendian != host_bigendian) {
78                 elf32_to_native = swap32;
79         }
80
81         headers = ehdr->e_phnum;
82         header = (char *)ehdr;
83
84         phdr = (Elf32_Phdr *) & header[elf32_to_native(ehdr->e_phoff)];
85
86         /* Now, regular headers - we only care about PT_LOAD headers,
87          * because thats what we're actually going to load
88          */
89
90         data_start = 0xFFFFFFFF;
91         data_end = 0;
92         mem_end = 0;
93
94         for (i = 0; i < headers; i++) {
95                 unsigned int start, mend, rend;
96
97                 if (elf32_to_native(phdr[i].p_type) != PT_LOAD)
98                         continue;
99
100                 /* Empty segments are never interesting */
101                 if (elf32_to_native(phdr[i].p_memsz) == 0)
102                         continue;
103
104                 /* BSS */
105
106                 start = elf32_to_native(phdr[i].p_paddr);
107
108                 mend = start + elf32_to_native(phdr[i].p_memsz);
109                 rend = start + elf32_to_native(phdr[i].p_filesz);
110
111                 if (start < data_start)
112                         data_start = start;
113
114                 if (rend > data_end)
115                         data_end = rend;
116
117                 if (mend > mem_end)
118                         mem_end = mend;
119         }
120
121         if (data_start < *location) {
122                 data_start = *location;
123         }
124
125         if (data_end <= data_start) {
126                 fprintf(stderr, "E: data ends before it starts. Make sure the ELF file is correct and resides in ROM space.\n");
127                 exit(1);
128         }
129
130         /* allocate an intermediate buffer for the data */
131         buffer = calloc(data_end - data_start, 1);
132
133         if (buffer == NULL) {
134                 fprintf(stderr, "E: Unable to allocate memory: %m\n");
135                 return -1;
136         }
137
138         /* Copy the file data into the buffer */
139
140         for (i = 0; i < headers; i++) {
141                 unsigned int l_start, l_offset = 0;
142
143                 if (elf32_to_native(phdr[i].p_type) != PT_LOAD)
144                         continue;
145
146                 if (elf32_to_native(phdr[i].p_memsz) == 0)
147                         continue;
148
149                 l_start = elf32_to_native(phdr[i].p_paddr);
150                 if (l_start < *location) {
151                         l_offset = *location - l_start;
152                         l_start = *location;
153                 }
154
155                 memcpy(buffer + (l_start - data_start),
156                        &header[elf32_to_native(phdr[i].p_offset)+l_offset],
157                        elf32_to_native(phdr[i].p_filesz)-l_offset);
158         }
159
160         /* Now make the output buffer */
161         out = calloc(sizeof(struct cbfs_stage) + data_end - data_start, 1);
162
163         if (out == NULL) {
164                 fprintf(stderr, "E: Unable to allocate memory: %m\n");
165                 return -1;
166         }
167
168         stage = (struct cbfs_stage *)out;
169
170         stage->load = data_start; /* FIXME: htonll */
171         stage->memlen = mem_end - data_start;
172         stage->compression = algo;
173         stage->entry = ehdr->e_entry; /* FIXME: htonll */
174
175         compress(buffer, data_end - data_start,
176                  (char *)(out + sizeof(struct cbfs_stage)), (int *)&stage->len);
177
178         *output = out;
179
180         if (*location)
181                 *location -= sizeof(struct cbfs_stage);
182         return sizeof(struct cbfs_stage) + stage->len;
183 }